@directus/api 32.2.0 → 33.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (297) hide show
  1. package/dist/ai/chat/controllers/chat.post.js +19 -4
  2. package/dist/ai/chat/lib/create-ui-stream.d.ts +8 -7
  3. package/dist/ai/chat/lib/create-ui-stream.js +28 -25
  4. package/dist/ai/chat/middleware/load-settings.js +31 -7
  5. package/dist/ai/chat/models/chat-request.d.ts +135 -2
  6. package/dist/ai/chat/models/chat-request.js +56 -2
  7. package/dist/ai/chat/models/providers.d.ts +16 -2
  8. package/dist/ai/chat/models/providers.js +16 -2
  9. package/dist/ai/chat/utils/chat-request-tool-to-ai-sdk-tool.js +3 -4
  10. package/dist/ai/chat/utils/format-context.d.ts +5 -0
  11. package/dist/ai/chat/utils/format-context.js +122 -0
  12. package/dist/ai/mcp/server.d.ts +27 -1
  13. package/dist/ai/providers/index.d.ts +3 -0
  14. package/dist/ai/providers/index.js +3 -0
  15. package/dist/ai/providers/options.d.ts +14 -0
  16. package/dist/ai/providers/options.js +26 -0
  17. package/dist/ai/providers/registry.d.ts +6 -0
  18. package/dist/ai/providers/registry.js +65 -0
  19. package/dist/ai/providers/types.d.ts +34 -0
  20. package/dist/ai/providers/types.js +1 -0
  21. package/dist/ai/tools/assets/index.js +1 -1
  22. package/dist/ai/tools/collections/index.js +2 -2
  23. package/dist/ai/tools/fields/index.js +2 -2
  24. package/dist/ai/tools/files/index.js +1 -1
  25. package/dist/ai/tools/flows/index.js +1 -1
  26. package/dist/ai/tools/folders/index.js +1 -1
  27. package/dist/ai/tools/items/index.js +6 -3
  28. package/dist/ai/tools/items/prompt.md +7 -9
  29. package/dist/ai/tools/relations/index.js +1 -1
  30. package/dist/ai/tools/schema.js +1 -1
  31. package/dist/ai/tools/trigger-flow/index.js +1 -1
  32. package/dist/app.js +12 -8
  33. package/dist/auth/drivers/ldap.d.ts +1 -1
  34. package/dist/auth/drivers/ldap.js +144 -139
  35. package/dist/auth/drivers/local.js +1 -1
  36. package/dist/auth/drivers/oauth2.d.ts +1 -2
  37. package/dist/auth/drivers/oauth2.js +22 -17
  38. package/dist/auth/drivers/openid.d.ts +1 -2
  39. package/dist/auth/drivers/openid.js +18 -13
  40. package/dist/auth/drivers/saml.js +3 -3
  41. package/dist/auth/utils/generate-callback-url.d.ts +11 -0
  42. package/dist/auth/utils/generate-callback-url.js +40 -0
  43. package/dist/auth/utils/is-login-redirect-allowed.d.ts +7 -0
  44. package/dist/{utils → auth/utils}/is-login-redirect-allowed.js +12 -9
  45. package/dist/cache.d.ts +12 -0
  46. package/dist/cache.js +27 -3
  47. package/dist/cli/commands/bootstrap/index.js +2 -2
  48. package/dist/cli/commands/database/install.js +1 -1
  49. package/dist/cli/commands/database/migrate.js +1 -1
  50. package/dist/cli/commands/init/index.js +2 -2
  51. package/dist/cli/commands/roles/create.js +4 -4
  52. package/dist/cli/commands/schema/apply.js +3 -3
  53. package/dist/cli/commands/schema/snapshot.js +1 -1
  54. package/dist/cli/utils/create-db-connection.d.ts +1 -1
  55. package/dist/cli/utils/create-db-connection.js +1 -1
  56. package/dist/cli/utils/create-env/env-stub.liquid +3 -0
  57. package/dist/cli/utils/create-env/index.js +1 -1
  58. package/dist/constants.d.ts +7 -3
  59. package/dist/constants.js +7 -3
  60. package/dist/controllers/access.js +1 -1
  61. package/dist/controllers/assets.js +1 -1
  62. package/dist/controllers/deployment.js +481 -0
  63. package/dist/controllers/extensions.js +1 -1
  64. package/dist/controllers/fields.js +8 -6
  65. package/dist/controllers/files.js +1 -1
  66. package/dist/controllers/items.js +1 -1
  67. package/dist/controllers/not-found.js +1 -1
  68. package/dist/controllers/relations.js +1 -1
  69. package/dist/database/errors/dialects/mysql.d.ts +1 -1
  70. package/dist/database/errors/dialects/postgres.d.ts +1 -1
  71. package/dist/database/errors/dialects/sqlite.d.ts +1 -1
  72. package/dist/database/errors/translate.d.ts +1 -1
  73. package/dist/database/errors/translate.js +1 -1
  74. package/dist/database/get-ast-from-query/lib/parse-fields.js +2 -2
  75. package/dist/database/helpers/date/dialects/mssql.js +1 -1
  76. package/dist/database/helpers/date/dialects/mysql.js +1 -1
  77. package/dist/database/helpers/date/types.js +1 -1
  78. package/dist/database/helpers/schema/dialects/cockroachdb.d.ts +1 -0
  79. package/dist/database/helpers/schema/dialects/cockroachdb.js +24 -1
  80. package/dist/database/helpers/schema/dialects/mssql.d.ts +1 -1
  81. package/dist/database/helpers/schema/dialects/mysql.d.ts +2 -1
  82. package/dist/database/helpers/schema/dialects/mysql.js +16 -3
  83. package/dist/database/helpers/schema/dialects/postgres.d.ts +1 -1
  84. package/dist/database/helpers/schema/types.d.ts +13 -0
  85. package/dist/database/helpers/schema/types.js +24 -0
  86. package/dist/database/index.js +4 -4
  87. package/dist/database/migrations/20220429A-add-flows.js +1 -1
  88. package/dist/database/migrations/20230526A-migrate-translation-strings.js +1 -1
  89. package/dist/database/migrations/20231009A-update-csv-fields-to-text.js +1 -1
  90. package/dist/database/migrations/20240204A-marketplace.js +9 -7
  91. package/dist/database/migrations/20240311A-deprecate-webhooks.d.ts +15 -0
  92. package/dist/database/migrations/20240311A-deprecate-webhooks.js +1 -1
  93. package/dist/database/migrations/20240806A-permissions-policies.js +2 -2
  94. package/dist/database/migrations/20240924A-migrate-legacy-comments.js +1 -1
  95. package/dist/database/migrations/20251014A-add-project-owner.js +1 -1
  96. package/dist/database/migrations/20251224A-remove-webhooks.d.ts +3 -0
  97. package/dist/database/migrations/20251224A-remove-webhooks.js +19 -0
  98. package/dist/database/migrations/20260110A-add-ai-provider-settings.d.ts +3 -0
  99. package/dist/database/migrations/20260110A-add-ai-provider-settings.js +35 -0
  100. package/dist/database/migrations/20260113A-add-revisions-index.d.ts +3 -0
  101. package/dist/database/migrations/20260113A-add-revisions-index.js +41 -0
  102. package/dist/database/migrations/20260128A-add-collaborative-editing.d.ts +3 -0
  103. package/dist/database/migrations/20260128A-add-collaborative-editing.js +10 -0
  104. package/dist/database/migrations/20260204A-add-deployment.d.ts +3 -0
  105. package/dist/database/migrations/20260204A-add-deployment.js +32 -0
  106. package/dist/database/migrations/run.js +3 -3
  107. package/dist/database/run-ast/lib/apply-query/add-join.js +1 -1
  108. package/dist/database/run-ast/lib/apply-query/filter/get-filter-type.d.ts +2 -2
  109. package/dist/database/run-ast/lib/apply-query/filter/get-filter-type.js +1 -1
  110. package/dist/database/run-ast/lib/apply-query/filter/index.js +1 -1
  111. package/dist/database/run-ast/lib/apply-query/filter/operator.js +1 -1
  112. package/dist/database/run-ast/lib/apply-query/sort.js +1 -1
  113. package/dist/database/run-ast/utils/get-column-pre-processor.js +2 -2
  114. package/dist/database/run-ast/utils/get-column.js +1 -1
  115. package/dist/database/seeds/run.js +3 -3
  116. package/dist/deployment/deployment.d.ts +94 -0
  117. package/dist/deployment/deployment.js +29 -0
  118. package/dist/deployment/drivers/index.d.ts +1 -0
  119. package/dist/deployment/drivers/index.js +1 -0
  120. package/dist/deployment/drivers/vercel.d.ts +32 -0
  121. package/dist/deployment/drivers/vercel.js +208 -0
  122. package/dist/deployment/index.d.ts +2 -0
  123. package/dist/deployment/index.js +2 -0
  124. package/dist/deployment.d.ts +24 -0
  125. package/dist/deployment.js +39 -0
  126. package/dist/extensions/lib/get-extensions-path.js +1 -1
  127. package/dist/extensions/lib/get-extensions-settings.js +1 -1
  128. package/dist/extensions/lib/get-extensions.js +1 -1
  129. package/dist/extensions/lib/get-shared-deps-mapping.js +3 -3
  130. package/dist/extensions/lib/installation/manager.js +3 -3
  131. package/dist/extensions/lib/sandbox/register/route.d.ts +1 -1
  132. package/dist/extensions/lib/sync/status.js +1 -1
  133. package/dist/extensions/lib/sync/sync.js +7 -7
  134. package/dist/extensions/lib/sync/utils.js +2 -2
  135. package/dist/extensions/manager.d.ts +1 -1
  136. package/dist/extensions/manager.js +8 -8
  137. package/dist/flows.d.ts +1 -1
  138. package/dist/logger/index.js +1 -1
  139. package/dist/logger/logs-stream.d.ts +1 -1
  140. package/dist/logger/logs-stream.js +1 -1
  141. package/dist/mailer.js +1 -1
  142. package/dist/metrics/lib/create-metrics.js +2 -2
  143. package/dist/middleware/authenticate.js +3 -3
  144. package/dist/middleware/collection-exists.js +1 -1
  145. package/dist/middleware/extract-token.js +1 -1
  146. package/dist/middleware/graphql.js +2 -2
  147. package/dist/middleware/respond.js +27 -14
  148. package/dist/middleware/validate-batch.js +1 -1
  149. package/dist/operations/exec/index.js +2 -1
  150. package/dist/operations/mail/index.js +1 -1
  151. package/dist/operations/mail/rate-limiter.js +2 -2
  152. package/dist/permissions/cache.js +5 -0
  153. package/dist/permissions/modules/fetch-allowed-collections/fetch-allowed-collections.js +1 -1
  154. package/dist/permissions/modules/fetch-allowed-field-map/fetch-allowed-field-map.js +1 -1
  155. package/dist/permissions/modules/fetch-inconsistent-field-map/fetch-inconsistent-field-map.js +2 -2
  156. package/dist/permissions/modules/process-ast/lib/inject-cases.js +1 -1
  157. package/dist/permissions/modules/process-ast/process-ast.js +1 -1
  158. package/dist/permissions/modules/process-ast/utils/find-related-collection.js +1 -1
  159. package/dist/permissions/modules/process-payload/process-payload.js +1 -1
  160. package/dist/permissions/modules/validate-access/lib/validate-item-access.d.ts +14 -2
  161. package/dist/permissions/modules/validate-access/lib/validate-item-access.js +72 -13
  162. package/dist/permissions/modules/validate-access/validate-access.js +3 -2
  163. package/dist/rate-limiter.js +1 -1
  164. package/dist/request/is-denied-ip.js +1 -1
  165. package/dist/schedules/project.js +1 -1
  166. package/dist/schedules/telemetry.js +1 -1
  167. package/dist/schedules/tus.js +1 -1
  168. package/dist/server.js +6 -5
  169. package/dist/services/assets.d.ts +2 -1
  170. package/dist/services/assets.js +35 -8
  171. package/dist/services/authentication.js +2 -2
  172. package/dist/services/collections.js +1 -1
  173. package/dist/services/deployment-projects.d.ts +20 -0
  174. package/dist/services/deployment-projects.js +34 -0
  175. package/dist/services/deployment-runs.d.ts +13 -0
  176. package/dist/services/deployment-runs.js +6 -0
  177. package/dist/services/deployment.d.ts +40 -0
  178. package/dist/services/deployment.js +202 -0
  179. package/dist/services/extensions.d.ts +1 -1
  180. package/dist/services/files/utils/get-metadata.d.ts +1 -1
  181. package/dist/services/files/utils/get-metadata.js +1 -1
  182. package/dist/services/files.d.ts +1 -1
  183. package/dist/services/files.js +4 -4
  184. package/dist/services/graphql/index.d.ts +1 -1
  185. package/dist/services/graphql/index.js +1 -1
  186. package/dist/services/graphql/resolvers/mutation.js +1 -1
  187. package/dist/services/graphql/resolvers/system-admin.js +2 -3
  188. package/dist/services/graphql/schema/get-types.d.ts +1 -1
  189. package/dist/services/graphql/schema/read.js +1 -1
  190. package/dist/services/graphql/subscription.d.ts +1 -1
  191. package/dist/services/graphql/types/date.js +1 -1
  192. package/dist/services/graphql/types/hash.js +1 -1
  193. package/dist/services/graphql/utils/add-path-to-validation-error.js +1 -1
  194. package/dist/services/graphql/utils/filter-replace-m2a.js +3 -4
  195. package/dist/services/import-export.d.ts +1 -1
  196. package/dist/services/import-export.js +2 -2
  197. package/dist/services/index.d.ts +3 -1
  198. package/dist/services/index.js +3 -1
  199. package/dist/services/mail/index.js +2 -2
  200. package/dist/services/mail/rate-limiter.js +2 -2
  201. package/dist/services/payload.js +2 -2
  202. package/dist/services/schema.js +1 -1
  203. package/dist/services/server.js +13 -4
  204. package/dist/services/settings.js +2 -2
  205. package/dist/services/specifications.js +2 -2
  206. package/dist/services/tfa.js +1 -1
  207. package/dist/services/translations.js +1 -1
  208. package/dist/services/tus/data-store.d.ts +1 -3
  209. package/dist/services/tus/data-store.js +2 -5
  210. package/dist/services/tus/server.js +6 -6
  211. package/dist/services/users.js +4 -4
  212. package/dist/services/versions.js +1 -1
  213. package/dist/telemetry/lib/get-report.js +2 -0
  214. package/dist/telemetry/lib/send-report.d.ts +1 -1
  215. package/dist/telemetry/lib/send-report.js +1 -1
  216. package/dist/telemetry/lib/track.js +1 -1
  217. package/dist/telemetry/types/report.d.ts +8 -0
  218. package/dist/telemetry/utils/get-settings.d.ts +2 -0
  219. package/dist/telemetry/utils/get-settings.js +5 -0
  220. package/dist/test-utils/knex.js +1 -1
  221. package/dist/types/collection.d.ts +1 -1
  222. package/dist/utils/async-handler.d.ts +1 -1
  223. package/dist/utils/calculate-field-depth.js +1 -1
  224. package/dist/utils/compress.js +1 -1
  225. package/dist/utils/deep-map-response.d.ts +1 -1
  226. package/dist/utils/deep-map-response.js +2 -2
  227. package/dist/utils/get-cache-key.js +1 -1
  228. package/dist/utils/get-column-path.js +1 -1
  229. package/dist/utils/get-field-system-rows.js +1 -1
  230. package/dist/utils/get-ip-from-req.d.ts +1 -1
  231. package/dist/utils/get-ip-from-req.js +1 -1
  232. package/dist/utils/get-local-type.js +7 -3
  233. package/dist/utils/get-service.js +7 -3
  234. package/dist/utils/get-snapshot-diff.js +1 -1
  235. package/dist/utils/is-field-allowed.d.ts +4 -0
  236. package/dist/utils/is-field-allowed.js +9 -0
  237. package/dist/utils/is-url-allowed.js +1 -1
  238. package/dist/utils/jwt.js +1 -1
  239. package/dist/utils/sanitize-schema.d.ts +1 -1
  240. package/dist/utils/should-clear-cache.d.ts +1 -1
  241. package/dist/utils/should-skip-cache.js +2 -2
  242. package/dist/utils/validate-diff.js +1 -1
  243. package/dist/utils/validate-snapshot.js +3 -3
  244. package/dist/utils/validate-storage.js +2 -2
  245. package/dist/utils/verify-session-jwt.js +1 -1
  246. package/dist/utils/versioning/handle-version.js +1 -1
  247. package/dist/websocket/collab/calculate-cache-metadata.d.ts +9 -0
  248. package/dist/websocket/collab/calculate-cache-metadata.js +121 -0
  249. package/dist/websocket/collab/collab.d.ts +63 -0
  250. package/dist/websocket/collab/collab.js +481 -0
  251. package/dist/websocket/collab/constants.d.ts +1 -0
  252. package/dist/websocket/collab/constants.js +13 -0
  253. package/dist/websocket/collab/filter-to-fields.d.ts +2 -0
  254. package/dist/websocket/collab/filter-to-fields.js +11 -0
  255. package/dist/websocket/collab/messenger.d.ts +43 -0
  256. package/dist/websocket/collab/messenger.js +225 -0
  257. package/dist/websocket/collab/payload-permissions.d.ts +18 -0
  258. package/dist/websocket/collab/payload-permissions.js +158 -0
  259. package/dist/websocket/collab/permissions-cache.d.ts +52 -0
  260. package/dist/websocket/collab/permissions-cache.js +204 -0
  261. package/dist/websocket/collab/room.d.ts +125 -0
  262. package/dist/websocket/collab/room.js +593 -0
  263. package/dist/websocket/collab/store.d.ts +7 -0
  264. package/dist/websocket/collab/store.js +33 -0
  265. package/dist/websocket/collab/types.d.ts +21 -0
  266. package/dist/websocket/collab/types.js +1 -0
  267. package/dist/websocket/collab/verify-permissions.d.ts +11 -0
  268. package/dist/websocket/collab/verify-permissions.js +100 -0
  269. package/dist/websocket/controllers/base.d.ts +2 -2
  270. package/dist/websocket/controllers/base.js +3 -3
  271. package/dist/websocket/controllers/graphql.d.ts +1 -1
  272. package/dist/websocket/controllers/graphql.js +1 -1
  273. package/dist/websocket/controllers/logs.d.ts +1 -1
  274. package/dist/websocket/controllers/rest.d.ts +1 -1
  275. package/dist/websocket/controllers/rest.js +2 -2
  276. package/dist/websocket/handlers/heartbeat.js +1 -1
  277. package/dist/websocket/handlers/index.d.ts +2 -0
  278. package/dist/websocket/handlers/index.js +9 -0
  279. package/dist/websocket/handlers/items.js +2 -2
  280. package/dist/websocket/handlers/subscribe.js +1 -1
  281. package/dist/websocket/types.d.ts +1 -1
  282. package/dist/websocket/utils/items.d.ts +2 -2
  283. package/dist/websocket/utils/message.d.ts +1 -1
  284. package/dist/websocket/utils/message.js +2 -2
  285. package/dist/websocket/utils/wait-for-message.js +1 -1
  286. package/package.json +35 -33
  287. package/dist/controllers/webhooks.js +0 -74
  288. package/dist/services/webhooks.d.ts +0 -14
  289. package/dist/services/webhooks.js +0 -32
  290. package/dist/utils/get-relation-info.d.ts +0 -6
  291. package/dist/utils/get-relation-info.js +0 -43
  292. package/dist/utils/get-relation-type.d.ts +0 -6
  293. package/dist/utils/get-relation-type.js +0 -18
  294. package/dist/utils/is-login-redirect-allowed.d.ts +0 -4
  295. package/dist/utils/versioning/deep-map-with-schema.d.ts +0 -23
  296. package/dist/utils/versioning/deep-map-with-schema.js +0 -81
  297. /package/dist/controllers/{webhooks.d.ts → deployment.d.ts} +0 -0
@@ -1,11 +1,11 @@
1
+ import { Readable } from 'node:stream';
2
+ import { performance } from 'perf_hooks';
1
3
  import { useEnv } from '@directus/env';
2
4
  import { toArray, toBoolean } from '@directus/utils';
3
5
  import { version } from 'directus/version';
4
6
  import { merge } from 'lodash-es';
5
- import { Readable } from 'node:stream';
6
- import { performance } from 'perf_hooks';
7
7
  import { getCache } from '../cache.js';
8
- import { RESUMABLE_UPLOADS } from '../constants.js';
8
+ import { FILE_UPLOADS, RESUMABLE_UPLOADS } from '../constants.js';
9
9
  import getDatabase, { hasDatabaseConnection } from '../database/index.js';
10
10
  import { useLogger } from '../logger/index.js';
11
11
  import getMailer from '../mailer.js';
@@ -57,9 +57,10 @@ export class ServerService {
57
57
  ],
58
58
  });
59
59
  info['project'] = projectInfo;
60
- info['mcp_enabled'] = toBoolean(env['MCP_ENABLED'] ?? true);
61
60
  info['setupCompleted'] = setupComplete;
62
61
  if (this.accountability?.user) {
62
+ info['mcp_enabled'] = toBoolean(env['MCP_ENABLED'] ?? true);
63
+ info['ai_enabled'] = toBoolean(env['AI_ENABLED'] ?? true);
63
64
  if (env['RATE_LIMITER_ENABLED']) {
64
65
  info['rateLimit'] = {
65
66
  points: env['RATE_LIMITER_POINTS'],
@@ -102,6 +103,7 @@ export class ServerService {
102
103
  info['websocket'].heartbeat = toBoolean(env['WEBSOCKETS_HEARTBEAT_ENABLED'])
103
104
  ? env['WEBSOCKETS_HEARTBEAT_PERIOD']
104
105
  : false;
106
+ info['websocket'].collaborativeEditing = toBoolean(env['WEBSOCKETS_COLLAB_ENABLED']);
105
107
  info['websocket'].logs =
106
108
  toBoolean(env['WEBSOCKETS_LOGS_ENABLED']) && this.accountability.admin
107
109
  ? {
@@ -112,8 +114,15 @@ export class ServerService {
112
114
  else {
113
115
  info['websocket'] = false;
114
116
  }
117
+ if (FILE_UPLOADS.MAX_CONCURRENCY && FILE_UPLOADS.MAX_CONCURRENCY !== Infinity) {
118
+ info['uploads'] = {
119
+ maxConcurrency: FILE_UPLOADS.MAX_CONCURRENCY,
120
+ };
121
+ }
115
122
  if (RESUMABLE_UPLOADS.ENABLED) {
116
123
  info['uploads'] = {
124
+ ...info['uploads'],
125
+ tus: true,
117
126
  chunkSize: RESUMABLE_UPLOADS.CHUNK_SIZE,
118
127
  };
119
128
  }
@@ -1,6 +1,6 @@
1
- import { ItemsService } from './items.js';
2
- import { sendReport } from '../telemetry/index.js';
3
1
  import { version } from 'directus/version';
2
+ import { sendReport } from '../telemetry/index.js';
3
+ import { ItemsService } from './items.js';
4
4
  export class SettingsService extends ItemsService {
5
5
  constructor(options) {
6
6
  super('directus_settings', options);
@@ -2,7 +2,7 @@ import { useEnv } from '@directus/env';
2
2
  import formatTitle from '@directus/format-title';
3
3
  import { spec } from '@directus/specs';
4
4
  import { isSystemCollection } from '@directus/system-data';
5
- import { getRelation } from '@directus/utils';
5
+ import { getRelation, getRelationType } from '@directus/utils';
6
6
  import { cloneDeep, mergeWith } from 'lodash-es';
7
7
  import hash from 'object-hash';
8
8
  import { OAS_REQUIRED_SCHEMAS } from '../constants.js';
@@ -10,7 +10,6 @@ import getDatabase from '../database/index.js';
10
10
  import { fetchPermissions } from '../permissions/lib/fetch-permissions.js';
11
11
  import { fetchPolicies } from '../permissions/lib/fetch-policies.js';
12
12
  import { fetchAllowedFieldMap } from '../permissions/modules/fetch-allowed-field-map/fetch-allowed-field-map.js';
13
- import { getRelationType } from '../utils/get-relation-type.js';
14
13
  import { reduceSchema } from '../utils/reduce-schema.js';
15
14
  import { GraphQLService } from './graphql/index.js';
16
15
  const env = useEnv();
@@ -362,6 +361,7 @@ class OASSpecsService {
362
361
  relation,
363
362
  field: field.field,
364
363
  collection: collection,
364
+ useA2O: true,
365
365
  });
366
366
  if (relationType === 'm2o') {
367
367
  const relatedTag = tags.find((tag) => tag['x-collection'] === relation.related_collection);
@@ -1,8 +1,8 @@
1
1
  import { InvalidPayloadError } from '@directus/errors';
2
2
  import { authenticator } from 'otplib';
3
+ import { DEFAULT_AUTH_PROVIDER } from '../constants.js';
3
4
  import getDatabase from '../database/index.js';
4
5
  import { ItemsService } from './items.js';
5
- import { DEFAULT_AUTH_PROVIDER } from '../constants.js';
6
6
  export class TFAService {
7
7
  knex;
8
8
  itemsService;
@@ -1,5 +1,5 @@
1
- import getDatabase from '../database/index.js';
2
1
  import { InvalidPayloadError } from '@directus/errors';
2
+ import getDatabase from '../database/index.js';
3
3
  import { ItemsService } from './items.js';
4
4
  export class TranslationsService extends ItemsService {
5
5
  constructor(options) {
@@ -1,12 +1,11 @@
1
+ import stream from 'node:stream';
1
2
  import type { TusDriver } from '@directus/storage';
2
3
  import type { Accountability, File, SchemaOverview } from '@directus/types';
3
4
  import { DataStore, Upload } from '@tus/utils';
4
- import stream from 'node:stream';
5
5
  export type TusDataStoreConfig = {
6
6
  constants: {
7
7
  ENABLED: boolean;
8
8
  CHUNK_SIZE: number | null;
9
- MAX_SIZE: number | null;
10
9
  EXPIRATION_TIME: number;
11
10
  SCHEDULE: string;
12
11
  };
@@ -18,7 +17,6 @@ export type TusDataStoreConfig = {
18
17
  };
19
18
  export declare class TusDataStore extends DataStore {
20
19
  protected chunkSize: number | undefined;
21
- protected maxSize: number | undefined;
22
20
  protected expirationTime: number;
23
21
  protected location: string;
24
22
  protected storageDriver: TusDriver;
@@ -1,15 +1,14 @@
1
+ import { extname } from 'node:path';
2
+ import stream from 'node:stream';
1
3
  import formatTitle from '@directus/format-title';
2
4
  import { DataStore, ERRORS, Upload } from '@tus/utils';
3
5
  import { omit } from 'lodash-es';
4
6
  import { extension } from 'mime-types';
5
- import { extname } from 'node:path';
6
- import stream from 'node:stream';
7
7
  import getDatabase from '../../database/index.js';
8
8
  import { useLogger } from '../../logger/index.js';
9
9
  import { ItemsService } from '../items.js';
10
10
  export class TusDataStore extends DataStore {
11
11
  chunkSize;
12
- maxSize;
13
12
  expirationTime;
14
13
  location;
15
14
  storageDriver;
@@ -19,8 +18,6 @@ export class TusDataStore extends DataStore {
19
18
  super();
20
19
  if (config.constants.CHUNK_SIZE !== null)
21
20
  this.chunkSize = config.constants.CHUNK_SIZE;
22
- if (config.constants.MAX_SIZE !== null)
23
- this.maxSize = config.constants.MAX_SIZE;
24
21
  this.expirationTime = config.constants.EXPIRATION_TIME;
25
22
  this.location = config.location;
26
23
  this.storageDriver = config.driver;
@@ -7,16 +7,16 @@ import { useEnv } from '@directus/env';
7
7
  import { supportsTus } from '@directus/storage';
8
8
  import { toArray } from '@directus/utils';
9
9
  import { Server } from '@tus/server';
10
- import { RESUMABLE_UPLOADS } from '../../constants.js';
10
+ import { pick } from 'lodash-es';
11
+ import { FILE_UPLOADS, RESUMABLE_UPLOADS } from '../../constants.js';
12
+ import getDatabase from '../../database/index.js';
13
+ import emitter from '../../emitter.js';
11
14
  import { getStorage } from '../../storage/index.js';
15
+ import { getSchema } from '../../utils/get-schema.js';
12
16
  import { extractMetadata } from '../files/lib/extract-metadata.js';
13
17
  import { ItemsService } from '../index.js';
14
18
  import { TusDataStore } from './data-store.js';
15
19
  import { getTusLocker } from './lockers.js';
16
- import { pick } from 'lodash-es';
17
- import emitter from '../../emitter.js';
18
- import getDatabase from '../../database/index.js';
19
- import { getSchema } from '../../utils/get-schema.js';
20
20
  async function createTusStore(context) {
21
21
  const env = useEnv();
22
22
  const storage = await getStorage();
@@ -40,7 +40,7 @@ export async function createTusServer(context) {
40
40
  path: '/files/tus',
41
41
  datastore: store,
42
42
  locker: getTusLocker(),
43
- ...(RESUMABLE_UPLOADS.MAX_SIZE !== null && { maxSize: RESUMABLE_UPLOADS.MAX_SIZE }),
43
+ ...(FILE_UPLOADS.MAX_SIZE !== null && { maxSize: FILE_UPLOADS.MAX_SIZE }),
44
44
  async onUploadFinish(_req, upload) {
45
45
  const schema = await getSchema();
46
46
  const service = new ItemsService('directus_files', {
@@ -1,3 +1,4 @@
1
+ import { performance } from 'perf_hooks';
1
2
  import { useEnv } from '@directus/env';
2
3
  import { ForbiddenError, InvalidPayloadError, RecordNotUniqueError } from '@directus/errors';
3
4
  import { UserIntegrityCheckFlag } from '@directus/types';
@@ -6,7 +7,6 @@ import { FailedValidationError, joiValidationErrorItemToErrorExtensions } from '
6
7
  import Joi from 'joi';
7
8
  import jwt from 'jsonwebtoken';
8
9
  import { isEmpty } from 'lodash-es';
9
- import { performance } from 'perf_hooks';
10
10
  import { clearSystemCache } from '../cache.js';
11
11
  import getDatabase from '../database/index.js';
12
12
  import { useLogger } from '../logger/index.js';
@@ -451,14 +451,14 @@ export class UsersService extends ItemsService {
451
451
  async requestPasswordReset(email, url, subject) {
452
452
  const STALL_TIME = 500;
453
453
  const timeStart = performance.now();
454
+ if (url && isUrlAllowed(url, env['PASSWORD_RESET_URL_ALLOW_LIST']) === false) {
455
+ throw new InvalidPayloadError({ reason: `URL "${url}" can't be used to reset passwords` });
456
+ }
454
457
  const user = await this.getUserByEmail(email);
455
458
  if (user?.status !== 'active') {
456
459
  await stall(STALL_TIME, timeStart);
457
460
  throw new ForbiddenError();
458
461
  }
459
- if (url && isUrlAllowed(url, env['PASSWORD_RESET_URL_ALLOW_LIST']) === false) {
460
- throw new InvalidPayloadError({ reason: `URL "${url}" can't be used to reset passwords` });
461
- }
462
462
  const mailService = new MailService({
463
463
  schema: this.schema,
464
464
  knex: this.knex,
@@ -1,5 +1,6 @@
1
1
  import { Action } from '@directus/constants';
2
2
  import { ForbiddenError, InvalidPayloadError, UnprocessableContentError } from '@directus/errors';
3
+ import { deepMapWithSchema } from '@directus/utils';
3
4
  import Joi from 'joi';
4
5
  import { assign, get, isEqual, isPlainObject, pick } from 'lodash-es';
5
6
  import objectHash from 'object-hash';
@@ -13,7 +14,6 @@ import { ActivityService } from './activity.js';
13
14
  import { ItemsService } from './items.js';
14
15
  import { PayloadService } from './payload.js';
15
16
  import { RevisionsService } from './revisions.js';
16
- import { deepMapWithSchema } from '../utils/versioning/deep-map-with-schema.js';
17
17
  export class VersionsService extends ItemsService {
18
18
  constructor(options) {
19
19
  super('directus_versions', options);
@@ -1,4 +1,5 @@
1
1
  import { useEnv } from '@directus/env';
2
+ import { toBoolean } from '@directus/utils';
2
3
  import { version } from 'directus/version';
3
4
  import { getHelpers } from '../../database/helpers/index.js';
4
5
  import { getDatabase, getDatabaseClient } from '../../database/index.js';
@@ -55,6 +56,7 @@ export const getReport = async () => {
55
56
  extensions: extensionsCounts.totalEnabled,
56
57
  database_size: databaseSize ?? 0,
57
58
  files_size_total: filesizes.total,
59
+ websockets_enabled: toBoolean(env['WEBSOCKETS_ENABLED'] ?? false),
58
60
  ...settings,
59
61
  };
60
62
  };
@@ -1,5 +1,5 @@
1
- import type { TelemetryReport } from '../types/report.js';
2
1
  import type { OwnerInformation } from '@directus/types';
2
+ import type { TelemetryReport } from '../types/report.js';
3
3
  export type OwnerReport = OwnerInformation & {
4
4
  project_id: string;
5
5
  version: string;
@@ -1,5 +1,5 @@
1
- import { useEnv } from '@directus/env';
2
1
  import { URL } from 'node:url';
2
+ import { useEnv } from '@directus/env';
3
3
  /**
4
4
  * Post an anonymous usage report to the centralized intake server
5
5
  */
@@ -1,5 +1,5 @@
1
- import { getNodeEnv } from '@directus/utils/node';
2
1
  import { setTimeout } from 'timers/promises';
2
+ import { getNodeEnv } from '@directus/utils/node';
3
3
  import { useLogger } from '../../logger/index.js';
4
4
  import { getRandomWaitTime } from '../utils/get-random-wait-time.js';
5
5
  import { getReport } from './get-report.js';
@@ -91,4 +91,12 @@ export interface TelemetryReport {
91
91
  * Number of Visual Editor URLs configured in the system
92
92
  */
93
93
  visual_editor_urls: number;
94
+ /**
95
+ * Whether collaborative editing is enabled
96
+ */
97
+ collaborative_editing_enabled: boolean;
98
+ /**
99
+ * Whether WebSockets are enabled
100
+ */
101
+ websockets_enabled: boolean;
94
102
  }
@@ -8,6 +8,7 @@ export type TelemetrySettings = {
8
8
  ai_openai_api_key: boolean;
9
9
  ai_anthropic_api_key: boolean;
10
10
  ai_system_prompt: boolean;
11
+ collaborative_editing_enabled: boolean;
11
12
  };
12
13
  export type DatabaseSettings = {
13
14
  project_id: string;
@@ -20,5 +21,6 @@ export type DatabaseSettings = {
20
21
  ai_openai_api_key?: string;
21
22
  ai_anthropic_api_key?: string;
22
23
  ai_system_prompt?: string;
24
+ collaborative_editing_enabled?: boolean;
23
25
  };
24
26
  export declare const getSettings: (db: Knex) => Promise<TelemetrySettings>;
@@ -1,6 +1,9 @@
1
+ import { useEnv } from '@directus/env';
2
+ import { toBoolean } from '@directus/utils';
1
3
  import { SettingsService } from '../../services/settings.js';
2
4
  import { getSchema } from '../../utils/get-schema.js';
3
5
  export const getSettings = async (db) => {
6
+ const env = useEnv();
4
7
  const settingsService = new SettingsService({
5
8
  knex: db,
6
9
  schema: await getSchema({ database: db }),
@@ -15,6 +18,7 @@ export const getSettings = async (db) => {
15
18
  'ai_openai_api_key',
16
19
  'ai_anthropic_api_key',
17
20
  'ai_system_prompt',
21
+ 'collaborative_editing_enabled',
18
22
  ],
19
23
  }));
20
24
  return {
@@ -26,5 +30,6 @@ export const getSettings = async (db) => {
26
30
  ai_openai_api_key: Boolean(settings?.ai_openai_api_key),
27
31
  ai_anthropic_api_key: Boolean(settings?.ai_anthropic_api_key),
28
32
  ai_system_prompt: Boolean(settings?.ai_system_prompt),
33
+ collaborative_editing_enabled: toBoolean(env['WEBSOCKETS_COLLAB_ENABLED'] ?? true) && (settings?.collaborative_editing_enabled ?? false),
29
34
  };
30
35
  };
@@ -4,7 +4,7 @@
4
4
  */
5
5
  import { systemCollectionNames } from '@directus/system-data';
6
6
  import knex from 'knex';
7
- import { MockClient, createTracker } from 'knex-mock-client';
7
+ import { createTracker, MockClient } from 'knex-mock-client';
8
8
  import { vi } from 'vitest';
9
9
  /**
10
10
  * Creates a mocked knex instance with tracker and schema builder support
@@ -1,6 +1,6 @@
1
- import type { Field } from '@directus/types';
2
1
  import type { Table } from '@directus/schema';
3
2
  import type { BaseCollectionMeta } from '@directus/system-data';
3
+ import type { Field } from '@directus/types';
4
4
  export type Collection = {
5
5
  collection: string;
6
6
  fields?: Field[];
@@ -1,3 +1,3 @@
1
- import type { RequestHandler, Request, Response, NextFunction } from 'express';
1
+ import type { NextFunction, Request, RequestHandler, Response } from 'express';
2
2
  declare const asyncHandler: (fn: RequestHandler) => (req: Request, res: Response, next: NextFunction) => Promise<void>;
3
3
  export default asyncHandler;
@@ -1,4 +1,4 @@
1
- import { isPlainObject, isArray } from 'lodash-es';
1
+ import { isArray, isPlainObject } from 'lodash-es';
2
2
  /**
3
3
  * Calculates the depth of a given JSON structure, not counting any _ prefixed properties
4
4
  *
@@ -1,5 +1,5 @@
1
- import { compress as compressSnappy, uncompress as uncompressSnappy } from 'snappy';
2
1
  import { compress as compressJSON, decompress as decompressJSON } from '@directus/utils';
2
+ import { compress as compressSnappy, uncompress as uncompressSnappy } from 'snappy';
3
3
  export async function compress(raw) {
4
4
  if (!raw)
5
5
  return raw;
@@ -1,5 +1,5 @@
1
1
  import type { CollectionOverview, FieldOverview, Relation, SchemaOverview } from '@directus/types';
2
- import { type RelationInfo } from './get-relation-info.js';
2
+ import { type RelationInfo } from '@directus/utils';
3
3
  /**
4
4
  * Allows to deep map the response from the ItemsService with collection, field and relation context for each entry.
5
5
  * Bottom to Top depth first mapping of values.
@@ -1,7 +1,7 @@
1
- import { isPlainObject } from 'lodash-es';
2
1
  import assert from 'node:assert';
3
- import { getRelationInfo } from './get-relation-info.js';
4
2
  import { InvalidQueryError } from '@directus/errors';
3
+ import { getRelationInfo } from '@directus/utils';
4
+ import { isPlainObject } from 'lodash-es';
5
5
  /**
6
6
  * Allows to deep map the response from the ItemsService with collection, field and relation context for each entry.
7
7
  * Bottom to Top depth first mapping of values.
@@ -1,7 +1,7 @@
1
+ import url from 'url';
1
2
  import { ipInNetworks } from '@directus/utils/node';
2
3
  import { version } from 'directus/version';
3
4
  import hash from 'object-hash';
4
- import url from 'url';
5
5
  import getDatabase from '../database/index.js';
6
6
  import { fetchPoliciesIpAccess } from '../permissions/modules/fetch-policies-ip-access/fetch-policies-ip-access.js';
7
7
  import { getGraphqlQueryAndVariables } from './get-graphql-query-and-variables.js';
@@ -1,5 +1,5 @@
1
1
  import { InvalidQueryError } from '@directus/errors';
2
- import { getRelationInfo } from './get-relation-info.js';
2
+ import { getRelationInfo } from '@directus/utils';
3
3
  /**
4
4
  * Converts a Directus field list path to the correct SQL names based on the constructed alias map.
5
5
  * For example: ['author', 'role', 'name'] -> 'ljnsv.name'
@@ -1,5 +1,5 @@
1
- import { systemFieldRows } from '@directus/system-data';
2
1
  import formatTitle from '@directus/format-title';
2
+ import { systemFieldRows } from '@directus/system-data';
3
3
  import { getAuthProviders } from './get-auth-providers.js';
4
4
  // Dynamically populate auth providers field
5
5
  export function getSystemFieldRowsWithAuthProviders() {
@@ -1,3 +1,3 @@
1
- import type { Request } from 'express';
2
1
  import type { IncomingMessage } from 'http';
2
+ import type { Request } from 'express';
3
3
  export declare function getIPFromReq(req: IncomingMessage | Request): string | null;
@@ -1,5 +1,5 @@
1
- import { useEnv } from '@directus/env';
2
1
  import { isIP } from 'net';
2
+ import { useEnv } from '@directus/env';
3
3
  import proxyAddr from 'proxy-addr';
4
4
  import { useLogger } from '../logger/index.js';
5
5
  /**
@@ -61,15 +61,15 @@ const localTypeMap = {
61
61
  binary: 'binary',
62
62
  varbinary: 'binary',
63
63
  uniqueidentifier: 'uuid',
64
- // Postgres
64
+ // Postgres / Cockroachdb
65
65
  json: 'json',
66
66
  jsonb: 'json',
67
67
  uuid: 'uuid',
68
68
  int2: 'integer',
69
69
  serial4: 'integer',
70
70
  int4: 'integer',
71
- serial8: 'integer',
72
- int8: 'integer',
71
+ serial8: 'bigInteger',
72
+ int8: 'bigInteger',
73
73
  bool: 'boolean',
74
74
  'character varying': 'string',
75
75
  character: 'string',
@@ -124,5 +124,9 @@ export default function getLocalType(column, field) {
124
124
  if (column.data_type === 'nvarchar' && column.max_length === -1) {
125
125
  return 'text';
126
126
  }
127
+ /** Handle CockroachDB 64-bit integers (reported as 'integer' with precision 64) */
128
+ if ((dataType === 'integer' || dataType === 'int') && column.numeric_precision === 64) {
129
+ return 'bigInteger';
130
+ }
127
131
  return type ?? 'unknown';
128
132
  }
@@ -1,5 +1,5 @@
1
1
  import { ForbiddenError } from '@directus/errors';
2
- import { AccessService, ActivityService, CommentsService, DashboardsService, FilesService, FlowsService, FoldersService, ItemsService, NotificationsService, OperationsService, PanelsService, PermissionsService, PoliciesService, PresetsService, RevisionsService, RolesService, SettingsService, SharesService, TranslationsService, UsersService, VersionsService, WebhooksService, } from '../services/index.js';
2
+ import { AccessService, ActivityService, CommentsService, DashboardsService, DeploymentProjectsService, DeploymentRunsService, DeploymentService, FilesService, FlowsService, FoldersService, ItemsService, NotificationsService, OperationsService, PanelsService, PermissionsService, PoliciesService, PresetsService, RevisionsService, RolesService, SettingsService, SharesService, TranslationsService, UsersService, VersionsService, } from '../services/index.js';
3
3
  /**
4
4
  * Select the correct service for the given collection. This allows the individual services to run
5
5
  * their custom checks (f.e. it allows `UsersService` to prevent updating TFA secret from outside).
@@ -46,8 +46,12 @@ export function getService(collection, opts) {
46
46
  return new UsersService(opts);
47
47
  case 'directus_versions':
48
48
  return new VersionsService(opts);
49
- case 'directus_webhooks':
50
- return new WebhooksService(opts);
49
+ case 'directus_deployments':
50
+ return new DeploymentService(opts);
51
+ case 'directus_deployment_projects':
52
+ return new DeploymentProjectsService(opts);
53
+ case 'directus_deployment_runs':
54
+ return new DeploymentRunsService(opts);
51
55
  default:
52
56
  // Deny usage of other system collections via ItemsService
53
57
  if (collection.startsWith('directus_'))
@@ -1,5 +1,5 @@
1
- import deepDiff from 'deep-diff';
2
1
  import { DiffKind } from '@directus/types';
2
+ import deepDiff from 'deep-diff';
3
3
  import { sanitizeCollection, sanitizeField, sanitizeRelation, sanitizeSystemField } from './sanitize-schema.js';
4
4
  export function getSnapshotDiff(current, after) {
5
5
  const diffedSnapshot = {
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Check if a specific field is allowed within a set of allowed fields
3
+ */
4
+ export declare function isFieldAllowed(allowedFields: string[] | Set<string>, field: string): boolean;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Check if a specific field is allowed within a set of allowed fields
3
+ */
4
+ export function isFieldAllowed(allowedFields, field) {
5
+ if (Array.isArray(allowedFields)) {
6
+ return allowedFields.includes(field) || allowedFields.includes('*');
7
+ }
8
+ return allowedFields.has(field) || allowedFields.has('*');
9
+ }
@@ -1,5 +1,5 @@
1
- import { toArray } from '@directus/utils';
2
1
  import { URL } from 'url';
2
+ import { toArray } from '@directus/utils';
3
3
  import { useLogger } from '../logger/index.js';
4
4
  /**
5
5
  * Check if URL matches allow list either exactly or by origin (protocol+domain+port) + pathname
package/dist/utils/jwt.js CHANGED
@@ -1,5 +1,5 @@
1
- import jwt from 'jsonwebtoken';
2
1
  import { InvalidTokenError, ServiceUnavailableError, TokenExpiredError } from '@directus/errors';
2
+ import jwt from 'jsonwebtoken';
3
3
  export function verifyJWT(token, secret) {
4
4
  let payload;
5
5
  try {
@@ -16,7 +16,7 @@ export declare function sanitizeCollection(collection: Collection): SnapshotColl
16
16
  * @returns sanitized field
17
17
  */
18
18
  export declare function sanitizeField(field: Field, sanitizeAllSchema?: boolean): SnapshotField;
19
- export declare function sanitizeColumn(column: Column): Pick<Column, "table" | "foreign_key_table" | "foreign_key_column" | "name" | "data_type" | "default_value" | "max_length" | "numeric_precision" | "numeric_scale" | "is_nullable" | "is_unique" | "is_indexed" | "is_primary_key" | "is_generated" | "generation_expression" | "has_auto_increment">;
19
+ export declare function sanitizeColumn(column: Column): Pick<Column, "name" | "table" | "foreign_key_table" | "foreign_key_column" | "data_type" | "default_value" | "max_length" | "numeric_precision" | "numeric_scale" | "is_nullable" | "is_unique" | "is_indexed" | "is_primary_key" | "is_generated" | "generation_expression" | "has_auto_increment">;
20
20
  /**
21
21
  * Pick certain database vendor specific relation properties that should be compared when performing diff
22
22
  *
@@ -1,5 +1,5 @@
1
- import type Keyv from 'keyv';
2
1
  import type { MutationOptions } from '@directus/types';
2
+ import type Keyv from 'keyv';
3
3
  /**
4
4
  * Check whether cache should be cleared
5
5
  *
@@ -1,7 +1,7 @@
1
- import { useEnv } from '@directus/env';
2
1
  import url from 'url';
3
- import { Url } from './url.js';
2
+ import { useEnv } from '@directus/env';
4
3
  import { getEndpoint } from '@directus/utils';
4
+ import { Url } from './url.js';
5
5
  /**
6
6
  * Whether to skip caching for the current request
7
7
  *
@@ -1,6 +1,6 @@
1
- import Joi from 'joi';
2
1
  import { InvalidPayloadError } from '@directus/errors';
3
2
  import { DiffKind } from '@directus/types';
3
+ import Joi from 'joi';
4
4
  const deepDiffSchema = Joi.object({
5
5
  kind: Joi.string()
6
6
  .valid(...Object.values(DiffKind))
@@ -1,10 +1,10 @@
1
1
  import { TYPES } from '@directus/constants';
2
- import Joi from 'joi';
3
- import { ALIAS_TYPES } from '../constants.js';
4
- import { getDatabaseClient } from '../database/index.js';
5
2
  import { InvalidPayloadError } from '@directus/errors';
6
3
  import { DatabaseClients } from '@directus/types';
7
4
  import { version } from 'directus/version';
5
+ import Joi from 'joi';
6
+ import { ALIAS_TYPES } from '../constants.js';
7
+ import { getDatabaseClient } from '../database/index.js';
8
8
  const snapshotJoiSchema = Joi.object({
9
9
  version: Joi.number().valid(1).required(),
10
10
  directus: Joi.string().required(),
@@ -1,8 +1,8 @@
1
- import { useEnv } from '@directus/env';
2
- import { toArray } from '@directus/utils';
3
1
  import { constants } from 'fs';
4
2
  import { access } from 'node:fs/promises';
5
3
  import path from 'path';
4
+ import { useEnv } from '@directus/env';
5
+ import { toArray } from '@directus/utils';
6
6
  import { getExtensionsPath } from '../extensions/lib/get-extensions-path.js';
7
7
  import { useLogger } from '../logger/index.js';
8
8
  export async function validateStorage() {
@@ -1,5 +1,5 @@
1
- import getDatabase from '../database/index.js';
2
1
  import { InvalidCredentialsError } from '@directus/errors';
2
+ import getDatabase from '../database/index.js';
3
3
  /**
4
4
  * Verifies the associated session is still available and valid.
5
5
  *
@@ -1,6 +1,6 @@
1
1
  import { ForbiddenError } from '@directus/errors';
2
+ import { deepMapWithSchema } from '@directus/utils';
2
3
  import { transaction } from '../transaction.js';
3
- import { deepMapWithSchema } from './deep-map-with-schema.js';
4
4
  import { splitRecursive } from './split-recursive.js';
5
5
  export async function handleVersion(self, key, queryWithKey, opts) {
6
6
  const { VersionsService } = await import('../../services/versions.js');
@@ -0,0 +1,9 @@
1
+ import type { Accountability, SchemaOverview } from '@directus/types';
2
+ export declare const DYNAMIC_VARIABLE_MAP: Record<string, string>;
3
+ /**
4
+ * Calculate logical expiry (TTL) and dependencies for permissions caching.
5
+ */
6
+ export declare function calculateCacheMetadata(collection: string, itemData: any, rawPermissions: any[], schema: SchemaOverview, accountability: Accountability): {
7
+ ttlMs: number | undefined;
8
+ dependencies: string[];
9
+ };