@directus/api 17.1.0 → 18.0.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 (95) hide show
  1. package/dist/app.js +8 -2
  2. package/dist/auth/drivers/ldap.js +14 -16
  3. package/dist/auth/drivers/local.js +16 -10
  4. package/dist/auth/drivers/oauth2.js +16 -11
  5. package/dist/auth/drivers/openid.js +16 -11
  6. package/dist/auth/drivers/saml.js +27 -12
  7. package/dist/cli/commands/init/index.js +3 -3
  8. package/dist/cli/commands/security/key.js +2 -2
  9. package/dist/cli/utils/create-env/env-stub.liquid +19 -4
  10. package/dist/cli/utils/create-env/index.js +2 -2
  11. package/dist/constants.d.ts +2 -1
  12. package/dist/constants.js +11 -4
  13. package/dist/controllers/auth.js +54 -19
  14. package/dist/controllers/extensions.js +102 -5
  15. package/dist/controllers/items.js +3 -2
  16. package/dist/controllers/permissions.js +1 -1
  17. package/dist/controllers/shares.js +19 -4
  18. package/dist/database/migrations/20220429A-add-flows.js +3 -3
  19. package/dist/database/migrations/20230526A-migrate-translation-strings.js +2 -2
  20. package/dist/database/migrations/20240204A-marketplace.d.ts +3 -0
  21. package/dist/database/migrations/20240204A-marketplace.js +68 -0
  22. package/dist/database/migrations/run.js +3 -2
  23. package/dist/extensions/lib/get-extensions-settings.d.ts +6 -2
  24. package/dist/extensions/lib/get-extensions-settings.js +70 -22
  25. package/dist/extensions/lib/get-extensions.d.ts +5 -1
  26. package/dist/extensions/lib/get-extensions.js +7 -31
  27. package/dist/extensions/lib/installation/index.d.ts +2 -0
  28. package/dist/extensions/lib/installation/index.js +9 -0
  29. package/dist/extensions/lib/installation/manager.d.ts +5 -0
  30. package/dist/extensions/lib/installation/manager.js +90 -0
  31. package/dist/extensions/lib/sandbox/generate-api-extensions-sandbox-entrypoint.d.ts +1 -1
  32. package/dist/extensions/lib/sync-extensions.js +11 -10
  33. package/dist/extensions/manager.d.ts +27 -25
  34. package/dist/extensions/manager.js +214 -183
  35. package/dist/middleware/authenticate.d.ts +1 -0
  36. package/dist/middleware/error-handler.js +22 -18
  37. package/dist/middleware/extract-token.d.ts +6 -5
  38. package/dist/middleware/extract-token.js +27 -11
  39. package/dist/middleware/merge-content-versions.d.ts +2 -0
  40. package/dist/middleware/merge-content-versions.js +26 -0
  41. package/dist/middleware/respond.js +0 -12
  42. package/dist/middleware/validate-batch.d.ts +1 -0
  43. package/dist/request/agent-with-ip-validation.d.ts +1 -1
  44. package/dist/request/agent-with-ip-validation.js +5 -1
  45. package/dist/services/activity.js +3 -3
  46. package/dist/services/assets.js +2 -3
  47. package/dist/services/authentication.d.ts +7 -2
  48. package/dist/services/authentication.js +21 -13
  49. package/dist/services/extensions.d.ts +4 -8
  50. package/dist/services/extensions.js +110 -93
  51. package/dist/services/fields.js +28 -22
  52. package/dist/services/graphql/index.js +98 -42
  53. package/dist/services/index.d.ts +1 -1
  54. package/dist/services/index.js +1 -1
  55. package/dist/services/mail/index.d.ts +1 -1
  56. package/dist/services/mail/index.js +4 -2
  57. package/dist/services/payload.js +2 -2
  58. package/dist/services/{permissions.d.ts → permissions/index.d.ts} +3 -4
  59. package/dist/services/{permissions.js → permissions/index.js} +6 -23
  60. package/dist/services/permissions/lib/with-app-minimal-permissions.d.ts +2 -0
  61. package/dist/services/permissions/lib/with-app-minimal-permissions.js +13 -0
  62. package/dist/services/relations.d.ts +2 -3
  63. package/dist/services/relations.js +2 -2
  64. package/dist/services/roles.js +1 -1
  65. package/dist/services/server.js +3 -0
  66. package/dist/services/shares.d.ts +3 -1
  67. package/dist/services/shares.js +9 -5
  68. package/dist/storage/index.js +5 -4
  69. package/dist/types/auth.d.ts +6 -4
  70. package/dist/types/graphql.d.ts +1 -0
  71. package/dist/utils/apply-query.js +3 -3
  72. package/dist/utils/filter-items.d.ts +2 -2
  73. package/dist/utils/filter-items.js +1 -3
  74. package/dist/utils/get-cache-headers.d.ts +1 -0
  75. package/dist/utils/get-cache-key.d.ts +1 -0
  76. package/dist/utils/get-graphql-query-and-variables.d.ts +1 -0
  77. package/dist/utils/get-ip-from-req.d.ts +1 -0
  78. package/dist/utils/get-milliseconds.d.ts +1 -1
  79. package/dist/utils/get-milliseconds.js +4 -1
  80. package/dist/utils/is-login-redirect-allowed.d.ts +4 -0
  81. package/dist/utils/is-login-redirect-allowed.js +34 -0
  82. package/dist/utils/is-url-allowed.d.ts +1 -1
  83. package/dist/utils/is-url-allowed.js +5 -5
  84. package/dist/utils/is-valid-uuid.d.ts +3 -0
  85. package/dist/utils/is-valid-uuid.js +21 -0
  86. package/dist/utils/jwt.d.ts +1 -1
  87. package/dist/utils/jwt.js +3 -3
  88. package/dist/utils/merge-version-data.d.ts +3 -0
  89. package/dist/utils/merge-version-data.js +134 -0
  90. package/dist/utils/sanitize-query.js +2 -0
  91. package/dist/utils/should-skip-cache.d.ts +1 -0
  92. package/dist/utils/validate-keys.js +2 -2
  93. package/dist/utils/validate-query.js +1 -0
  94. package/dist/websocket/controllers/base.js +2 -2
  95. package/package.json +44 -45
@@ -1,2 +1,2 @@
1
- import type { Query } from '@directus/types';
2
- export declare function filterItems(items: Record<string, any>[], filter: Query['filter']): Record<string, any>[];
1
+ import type { Item, Query } from '@directus/types';
2
+ export declare function filterItems<T extends Item[]>(items: T, filter: Query['filter']): T;
@@ -6,9 +6,7 @@ import { generateJoi } from '@directus/utils';
6
6
  export function filterItems(items, filter) {
7
7
  if (!filter)
8
8
  return items;
9
- return items.filter((item) => {
10
- return passesFilter(item, filter);
11
- });
9
+ return items.filter((item) => passesFilter(item, filter));
12
10
  function passesFilter(item, filter) {
13
11
  if (!filter || Object.keys(filter).length === 0)
14
12
  return true;
@@ -1,3 +1,4 @@
1
+ /// <reference types="cookie-parser" />
1
2
  import type { Request } from 'express';
2
3
  /**
3
4
  * Returns the Cache-Control header for the current request
@@ -1,2 +1,3 @@
1
+ /// <reference types="cookie-parser" />
1
2
  import type { Request } from 'express';
2
3
  export declare function getCacheKey(req: Request): string;
@@ -1,2 +1,3 @@
1
+ /// <reference types="cookie-parser" />
1
2
  import type { Request } from 'express';
2
3
  export declare function getGraphqlQueryAndVariables(req: Request): Pick<any, "query" | "variables">;
@@ -1,2 +1,3 @@
1
+ /// <reference types="cookie-parser" />
1
2
  import type { Request } from 'express';
2
3
  export declare function getIPFromReq(req: Request): string | null;
@@ -1,4 +1,4 @@
1
1
  /**
2
2
  * Safely parse human readable time format into milliseconds
3
3
  */
4
- export declare function getMilliseconds<T>(value: unknown, fallback?: T): number | T;
4
+ export declare function getMilliseconds<T = undefined>(value: unknown, fallback?: T): number | T;
@@ -1,5 +1,8 @@
1
1
  import ms from 'ms';
2
- export function getMilliseconds(value, fallback = undefined) {
2
+ /**
3
+ * Safely parse human readable time format into milliseconds
4
+ */
5
+ export function getMilliseconds(value, fallback) {
3
6
  if ((typeof value !== 'string' && typeof value !== 'number') || value === '') {
4
7
  return fallback;
5
8
  }
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Checks if the defined redirect after successful SSO login is in the allow list
3
+ */
4
+ export declare function isLoginRedirectAllowed(redirect: unknown, provider: string): boolean;
@@ -0,0 +1,34 @@
1
+ import { useEnv } from '@directus/env';
2
+ import { toArray } from '@directus/utils';
3
+ import isUrlAllowed from './is-url-allowed.js';
4
+ /**
5
+ * Checks if the defined redirect after successful SSO login is in the allow list
6
+ */
7
+ export function isLoginRedirectAllowed(redirect, provider) {
8
+ if (!redirect)
9
+ return true; // empty redirect
10
+ if (typeof redirect !== 'string')
11
+ return false; // invalid type
12
+ const env = useEnv();
13
+ const publicUrl = env['PUBLIC_URL'];
14
+ if (URL.canParse(redirect) === false) {
15
+ if (redirect.startsWith('//') === false) {
16
+ // should be a relative path like `/admin/test`
17
+ return true;
18
+ }
19
+ // domain without protocol `//example.com/test`
20
+ return false;
21
+ }
22
+ const { protocol: redirectProtocol, hostname: redirectDomain } = new URL(redirect);
23
+ const envKey = `AUTH_${provider.toUpperCase()}_REDIRECT_ALLOW_LIST`;
24
+ if (envKey in env) {
25
+ if (isUrlAllowed(redirect, [...toArray(env[envKey]), publicUrl]))
26
+ return true;
27
+ }
28
+ if (URL.canParse(publicUrl) === false) {
29
+ return false;
30
+ }
31
+ // allow redirects to the defined PUBLIC_URL
32
+ const { protocol: publicProtocol, hostname: publicDomain } = new URL(publicUrl);
33
+ return `${redirectProtocol}//${redirectDomain}` === `${publicProtocol}//${publicDomain}`;
34
+ }
@@ -1,4 +1,4 @@
1
1
  /**
2
- * Check if url matches allow list either exactly or by domain+path
2
+ * Check if URL matches allow list either exactly or by origin (protocol+domain+port) + pathname
3
3
  */
4
4
  export default function isUrlAllowed(url: string, allowList: string | string[]): boolean;
@@ -2,7 +2,7 @@ import { toArray } from '@directus/utils';
2
2
  import { URL } from 'url';
3
3
  import { useLogger } from '../logger.js';
4
4
  /**
5
- * Check if url matches allow list either exactly or by domain+path
5
+ * Check if URL matches allow list either exactly or by origin (protocol+domain+port) + pathname
6
6
  */
7
7
  export default function isUrlAllowed(url, allowList) {
8
8
  const logger = useLogger();
@@ -12,8 +12,8 @@ export default function isUrlAllowed(url, allowList) {
12
12
  const parsedWhitelist = urlAllowList
13
13
  .map((allowedURL) => {
14
14
  try {
15
- const { hostname, pathname } = new URL(allowedURL);
16
- return hostname + pathname;
15
+ const { origin, pathname } = new URL(allowedURL);
16
+ return origin + pathname;
17
17
  }
18
18
  catch {
19
19
  logger.warn(`Invalid URL used "${url}"`);
@@ -22,8 +22,8 @@ export default function isUrlAllowed(url, allowList) {
22
22
  })
23
23
  .filter((f) => f);
24
24
  try {
25
- const { hostname, pathname } = new URL(url);
26
- return parsedWhitelist.includes(hostname + pathname);
25
+ const { origin, pathname } = new URL(url);
26
+ return parsedWhitelist.includes(origin + pathname);
27
27
  }
28
28
  catch {
29
29
  return false;
@@ -0,0 +1,3 @@
1
+ type UUID = `${string}-${string}-${string}-${string}-${string}`;
2
+ export declare function isValidUuid(value: string): value is UUID;
3
+ export {};
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Based on the patterns found in the 'uuid' and 'uuid-validate' npm packages, both of which are MIT licensed.
3
+ *
4
+ * The primary difference between this pattern and the patterns found in the referenced packages is that
5
+ * no validation over the version component (the 14th character) is performed, while the
6
+ * packages fail if the version is not a known one (only versions 1 through 5 are accepted).
7
+ *
8
+ * This specification complies with all major database vendors.
9
+ *
10
+ * e22f209d-9e85-4ef5-b1fe-7dc09d2b67cf
11
+ * ^ version
12
+ *
13
+ * @see https://datatracker.ietf.org/doc/html/rfc4122
14
+ * @see https://github.com/uuidjs/uuid/blob/bc46e198ab06311a9d82d3c9c6222062dd27f760/src/regex.js
15
+ * @see https://github.com/microsoft/uuid-validate/blob/06554db1b093aa6bb429156fa8964e1cde2b750c/index.js
16
+ * @see https://github.com/directus/directus/issues/21573
17
+ */
18
+ const regex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
19
+ export function isValidUuid(value) {
20
+ return regex.test(value);
21
+ }
@@ -1,3 +1,3 @@
1
1
  import type { DirectusTokenPayload } from '../types/index.js';
2
- export declare function verifyJWT(token: string, secret: string): Record<string, any>;
2
+ export declare function verifyJWT(token: string, secret: string): Record<string, unknown>;
3
3
  export declare function verifyAccessJWT(token: string, secret: string): DirectusTokenPayload;
package/dist/utils/jwt.js CHANGED
@@ -21,9 +21,9 @@ export function verifyJWT(token, secret) {
21
21
  return payload;
22
22
  }
23
23
  export function verifyAccessJWT(token, secret) {
24
- const { id, role, app_access, admin_access, share, share_scope } = verifyJWT(token, secret);
25
- if (role === undefined || app_access === undefined || admin_access === undefined) {
24
+ const payload = verifyJWT(token, secret);
25
+ if (payload.role === undefined || payload.app_access === undefined || payload.admin_access === undefined) {
26
26
  throw new InvalidTokenError();
27
27
  }
28
- return { id, role, app_access, admin_access, share, share_scope };
28
+ return payload;
29
29
  }
@@ -0,0 +1,3 @@
1
+ import type { Item, SchemaOverview } from '@directus/types';
2
+ export declare function mergeVersionsRaw(item: Item, versionData: Partial<Item>[]): Item;
3
+ export declare function mergeVersionsRecursive(item: Item, versionData: Item[], collection: string, schema: SchemaOverview): Item;
@@ -0,0 +1,134 @@
1
+ import Joi from 'joi';
2
+ import { isObject } from '@directus/utils';
3
+ import { cloneDeep } from 'lodash-es';
4
+ const alterationSchema = Joi.object({
5
+ create: Joi.array().items(Joi.object().unknown()),
6
+ update: Joi.array().items(Joi.object().unknown()),
7
+ delete: Joi.array().items(Joi.string(), Joi.number()),
8
+ });
9
+ export function mergeVersionsRaw(item, versionData) {
10
+ const result = cloneDeep(item);
11
+ for (const versionRecord of versionData) {
12
+ for (const key of Object.keys(versionRecord)) {
13
+ result[key] = versionRecord[key];
14
+ }
15
+ }
16
+ return result;
17
+ }
18
+ export function mergeVersionsRecursive(item, versionData, collection, schema) {
19
+ if (versionData.length === 0)
20
+ return item;
21
+ return recursiveMerging(item, versionData, collection, schema);
22
+ }
23
+ function recursiveMerging(data, versionData, collection, schema) {
24
+ const result = cloneDeep(data);
25
+ const relations = getRelations(collection, schema);
26
+ for (const versionRecord of versionData) {
27
+ if (!isObject(versionRecord)) {
28
+ continue;
29
+ }
30
+ for (const key of Object.keys(data)) {
31
+ if (key in versionRecord === false) {
32
+ continue;
33
+ }
34
+ const currentValue = data[key];
35
+ const newValue = versionRecord[key];
36
+ if (typeof newValue !== 'object' || newValue === null) {
37
+ // primitive type substitution, json and non relational array values are handled in the next check
38
+ result[key] = newValue;
39
+ continue;
40
+ }
41
+ if (key in relations === false) {
42
+ // check for m2a exception
43
+ if (isManyToAnyCollection(collection, schema) && key === 'item') {
44
+ const item = addMissingKeys(isObject(currentValue) ? currentValue : {}, newValue);
45
+ result[key] = recursiveMerging(item, [newValue], data['collection'], schema);
46
+ }
47
+ else {
48
+ // item is not a relation
49
+ result[key] = newValue;
50
+ }
51
+ continue;
52
+ }
53
+ const { error } = alterationSchema.validate(newValue);
54
+ if (error) {
55
+ if (typeof newValue === 'object' && key in relations) {
56
+ const newItem = !currentValue || typeof currentValue !== 'object' ? newValue : currentValue;
57
+ result[key] = recursiveMerging(newItem, [newValue], relations[key], schema);
58
+ }
59
+ continue;
60
+ }
61
+ const alterations = newValue;
62
+ const currentPrimaryKeyField = schema.collections[collection].primary;
63
+ const relatedPrimaryKeyField = schema.collections[relations[key]].primary;
64
+ const mergedRelation = [];
65
+ if (Array.isArray(currentValue)) {
66
+ if (alterations.delete.length > 0) {
67
+ for (const currentItem of currentValue) {
68
+ const currentId = typeof currentItem === 'object' ? currentItem[currentPrimaryKeyField] : currentItem;
69
+ if (alterations.delete.includes(currentId) === false) {
70
+ mergedRelation.push(currentItem);
71
+ }
72
+ }
73
+ }
74
+ else {
75
+ mergedRelation.push(...currentValue);
76
+ }
77
+ if (alterations.update.length > 0) {
78
+ for (const updatedItem of alterations.update) {
79
+ // find existing item to update
80
+ const itemIndex = mergedRelation.findIndex((currentItem) => currentItem[relatedPrimaryKeyField] === updatedItem[currentPrimaryKeyField]);
81
+ if (itemIndex === -1) {
82
+ // check for raw primary keys
83
+ const pkIndex = mergedRelation.findIndex((currentItem) => currentItem === updatedItem[currentPrimaryKeyField]);
84
+ if (pkIndex === -1) {
85
+ // nothing to update so add the item as is
86
+ mergedRelation.push(updatedItem);
87
+ }
88
+ else {
89
+ mergedRelation[pkIndex] = updatedItem;
90
+ }
91
+ continue;
92
+ }
93
+ const item = addMissingKeys(mergedRelation[itemIndex], updatedItem);
94
+ mergedRelation[itemIndex] = recursiveMerging(item, [updatedItem], relations[key], schema);
95
+ }
96
+ }
97
+ }
98
+ if (alterations.create.length > 0) {
99
+ for (const createdItem of alterations.create) {
100
+ const item = addMissingKeys({}, createdItem);
101
+ mergedRelation.push(recursiveMerging(item, [createdItem], relations[key], schema));
102
+ }
103
+ }
104
+ result[key] = mergedRelation;
105
+ }
106
+ }
107
+ return result;
108
+ }
109
+ function addMissingKeys(item, edits) {
110
+ const result = { ...item };
111
+ for (const key of Object.keys(edits)) {
112
+ if (key in item === false) {
113
+ result[key] = null;
114
+ }
115
+ }
116
+ return result;
117
+ }
118
+ function isManyToAnyCollection(collection, schema) {
119
+ const relation = schema.relations.find((relation) => relation.collection === collection && relation.meta?.many_collection === collection);
120
+ if (!relation || !relation.meta?.one_field || !relation.related_collection)
121
+ return false;
122
+ return Boolean(schema.collections[relation.related_collection]?.fields[relation.meta.one_field]?.special.includes('m2a'));
123
+ }
124
+ function getRelations(collection, schema) {
125
+ return schema.relations.reduce((result, relation) => {
126
+ if (relation.related_collection === collection && relation.meta?.one_field) {
127
+ result[relation.meta.one_field] = relation.collection;
128
+ }
129
+ if (relation.collection === collection && relation.related_collection) {
130
+ result[relation.field] = relation.related_collection;
131
+ }
132
+ return result;
133
+ }, {});
134
+ }
@@ -48,6 +48,8 @@ export function sanitizeQuery(rawQuery, accountability) {
48
48
  }
49
49
  if (rawQuery['version']) {
50
50
  query.version = rawQuery['version'];
51
+ // whether or not to merge the relational results
52
+ query.versionRaw = Boolean('versionRaw' in rawQuery && (rawQuery['versionRaw'] === '' || rawQuery['versionRaw'] === 'true'));
51
53
  }
52
54
  if (rawQuery['export']) {
53
55
  query.export = rawQuery['export'];
@@ -1,3 +1,4 @@
1
+ /// <reference types="cookie-parser" />
1
2
  import type { Request } from 'express';
2
3
  /**
3
4
  * Whether to skip caching for the current request
@@ -1,5 +1,5 @@
1
1
  import { ForbiddenError } from '@directus/errors';
2
- import validateUUID from 'uuid-validate';
2
+ import { isValidUuid } from './is-valid-uuid.js';
3
3
  /**
4
4
  * Validate keys based on its type
5
5
  */
@@ -11,7 +11,7 @@ export function validateKeys(schema, collection, keyField, keys) {
11
11
  }
12
12
  else {
13
13
  const primaryKeyFieldType = schema.collections[collection]?.fields[keyField]?.type;
14
- if (primaryKeyFieldType === 'uuid' && !validateUUID(String(keys))) {
14
+ if (primaryKeyFieldType === 'uuid' && !isValidUuid(String(keys))) {
15
15
  throw new ForbiddenError();
16
16
  }
17
17
  else if (primaryKeyFieldType === 'integer' && !Number.isInteger(Number(keys))) {
@@ -22,6 +22,7 @@ const querySchema = Joi.object({
22
22
  search: Joi.string(),
23
23
  export: Joi.string().valid('csv', 'json', 'xml', 'yaml'),
24
24
  version: Joi.string(),
25
+ versionRaw: Joi.boolean(),
25
26
  aggregate: Joi.object(),
26
27
  deep: Joi.object(),
27
28
  alias: Joi.object(),
@@ -1,8 +1,8 @@
1
1
  import { useEnv } from '@directus/env';
2
2
  import { InvalidProviderConfigError, TokenExpiredError } from '@directus/errors';
3
3
  import { parseJSON, toBoolean } from '@directus/utils';
4
+ import { randomUUID } from 'node:crypto';
4
5
  import { parse } from 'url';
5
- import { v4 as uuid } from 'uuid';
6
6
  import WebSocket, { WebSocketServer } from 'ws';
7
7
  import { fromZodError } from 'zod-validation-error';
8
8
  import emitter from '../../emitter.js';
@@ -157,7 +157,7 @@ export default class SocketController {
157
157
  const client = ws;
158
158
  client.accountability = accountability;
159
159
  client.expires_at = expires_at;
160
- client.uid = uuid();
160
+ client.uid = randomUUID();
161
161
  client.auth_timer = null;
162
162
  ws.on('message', async (data) => {
163
163
  if (this.rateLimiter !== null) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@directus/api",
3
- "version": "17.1.0",
3
+ "version": "18.0.0",
4
4
  "description": "Directus is a real-time API and App dashboard for managing SQL database content",
5
5
  "keywords": [
6
6
  "directus",
@@ -59,13 +59,13 @@
59
59
  ],
60
60
  "dependencies": {
61
61
  "@authenio/samlify-node-xmllint": "2.0.0",
62
- "@aws-sdk/client-ses": "3.513.0",
62
+ "@aws-sdk/client-ses": "3.525.0",
63
63
  "@directus/format-title": "10.1.0",
64
64
  "@godaddy/terminus": "4.12.1",
65
65
  "@rollup/plugin-alias": "5.1.0",
66
66
  "@rollup/plugin-node-resolve": "15.2.3",
67
67
  "@rollup/plugin-virtual": "3.0.2",
68
- "argon2": "0.31.2",
68
+ "argon2": "0.40.1",
69
69
  "async": "3.2.5",
70
70
  "axios": "1.6.7",
71
71
  "busboy": "1.6.0",
@@ -81,12 +81,12 @@
81
81
  "date-fns": "3.3.1",
82
82
  "deep-diff": "1.0.2",
83
83
  "destroy": "1.2.0",
84
- "dotenv": "16.4.4",
84
+ "dotenv": "16.4.5",
85
85
  "encodeurl": "1.0.2",
86
86
  "eventemitter2": "6.4.9",
87
87
  "execa": "8.0.1",
88
88
  "exif-reader": "2.0.1",
89
- "express": "4.18.2",
89
+ "express": "4.18.3",
90
90
  "flat": "6.0.1",
91
91
  "fs-extra": "11.2.0",
92
92
  "glob-to-regexp": "0.4.1",
@@ -99,7 +99,7 @@
99
99
  "ioredis": "5.3.2",
100
100
  "ip-matching": "2.1.2",
101
101
  "isolated-vm": "4.7.2",
102
- "joi": "17.12.1",
102
+ "joi": "17.12.2",
103
103
  "js-yaml": "4.1.0",
104
104
  "js2xmlparser": "5.0.0",
105
105
  "json2csv": "5.0.7",
@@ -117,9 +117,9 @@
117
117
  "nanoid": "5.0.6",
118
118
  "node-machine-id": "1.1.12",
119
119
  "node-schedule": "2.1.1",
120
- "nodemailer": "6.9.9",
120
+ "nodemailer": "6.9.11",
121
121
  "object-hash": "3.0.0",
122
- "openapi3-ts": "4.2.1",
122
+ "openapi3-ts": "4.2.2",
123
123
  "openid-client": "5.6.4",
124
124
  "ora": "8.0.1",
125
125
  "otplib": "12.0.1",
@@ -131,41 +131,41 @@
131
131
  "pino-http-print": "3.1.0",
132
132
  "pino-pretty": "10.3.1",
133
133
  "qs": "6.11.2",
134
- "rate-limiter-flexible": "4.0.1",
135
- "rollup": "4.10.0",
136
- "samlify": "2.8.10",
137
- "sanitize-html": "2.12.0",
134
+ "rate-limiter-flexible": "5.0.0",
135
+ "rollup": "4.12.0",
136
+ "samlify": "2.8.11",
137
+ "sanitize-html": "2.12.1",
138
138
  "sharp": "0.33.2",
139
139
  "snappy": "7.2.2",
140
140
  "stream-json": "1.8.0",
141
+ "tar": "6.2.0",
141
142
  "tsx": "4.7.1",
142
- "uuid": "9.0.1",
143
- "uuid-validate": "0.0.3",
144
143
  "wellknown": "0.5.0",
145
144
  "ws": "8.16.0",
146
145
  "zod": "3.22.4",
147
- "zod-validation-error": "3.0.2",
148
- "@directus/app": "10.15.2",
146
+ "zod-validation-error": "3.0.3",
147
+ "@directus/app": "11.0.0",
149
148
  "@directus/constants": "11.0.3",
150
- "@directus/errors": "0.2.3",
151
- "@directus/env": "1.0.2",
152
- "@directus/extensions": "0.3.3",
153
- "@directus/extensions-sdk": "10.3.4",
154
- "@directus/memory": "1.0.3",
149
+ "@directus/env": "1.0.3",
150
+ "@directus/errors": "0.2.4",
151
+ "@directus/extensions-registry": "1.0.0",
152
+ "@directus/extensions": "1.0.0",
153
+ "@directus/extensions-sdk": "11.0.0",
154
+ "@directus/memory": "1.0.4",
155
+ "@directus/pressure": "1.0.17",
155
156
  "@directus/schema": "11.0.1",
156
- "@directus/specs": "10.2.6",
157
- "@directus/pressure": "1.0.16",
158
- "@directus/storage-driver-azure": "10.0.17",
159
- "@directus/storage": "10.0.10",
160
- "@directus/storage-driver-cloudinary": "10.0.17",
161
- "@directus/storage-driver-gcs": "10.0.17",
162
- "@directus/storage-driver-s3": "10.0.18",
163
- "@directus/storage-driver-local": "10.0.17",
164
- "@directus/storage-driver-supabase": "1.0.9",
165
- "@directus/system-data": "1.0.0",
166
- "@directus/utils": "11.0.5",
167
- "directus": "10.9.3",
168
- "@directus/validation": "0.0.12"
157
+ "@directus/specs": "10.2.7",
158
+ "@directus/storage": "10.0.11",
159
+ "@directus/storage-driver-azure": "10.0.18",
160
+ "@directus/storage-driver-cloudinary": "10.0.18",
161
+ "@directus/storage-driver-gcs": "10.0.18",
162
+ "@directus/storage-driver-s3": "10.0.19",
163
+ "@directus/storage-driver-local": "10.0.18",
164
+ "@directus/storage-driver-supabase": "1.0.10",
165
+ "@directus/system-data": "1.0.1",
166
+ "@directus/utils": "11.0.6",
167
+ "directus": "10.10.0",
168
+ "@directus/validation": "0.0.13"
169
169
  },
170
170
  "devDependencies": {
171
171
  "@ngneat/falso": "7.2.0",
@@ -173,7 +173,7 @@
173
173
  "@types/busboy": "1.5.3",
174
174
  "@types/bytes": "3.1.4",
175
175
  "@types/content-disposition": "0.5.8",
176
- "@types/cookie-parser": "1.4.6",
176
+ "@types/cookie-parser": "1.4.7",
177
177
  "@types/cors": "2.8.17",
178
178
  "@types/deep-diff": "1.0.5",
179
179
  "@types/destroy": "1.0.3",
@@ -185,21 +185,20 @@
185
185
  "@types/inquirer": "9.0.7",
186
186
  "@types/js-yaml": "4.0.9",
187
187
  "@types/json2csv": "5.0.7",
188
- "@types/jsonwebtoken": "9.0.5",
188
+ "@types/jsonwebtoken": "9.0.6",
189
189
  "@types/ldapjs": "2.2.5",
190
190
  "@types/lodash-es": "4.17.12",
191
191
  "@types/mime-types": "2.1.4",
192
192
  "@types/ms": "0.7.34",
193
- "@types/node": "18.19.17",
193
+ "@types/node": "18.19.21",
194
194
  "@types/node-schedule": "2.1.6",
195
195
  "@types/nodemailer": "6.4.14",
196
196
  "@types/object-hash": "3.0.6",
197
197
  "@types/papaparse": "5.3.14",
198
- "@types/qs": "6.9.11",
198
+ "@types/qs": "6.9.12",
199
199
  "@types/sanitize-html": "2.11.0",
200
200
  "@types/stream-json": "1.7.7",
201
- "@types/uuid": "9.0.8",
202
- "@types/uuid-validate": "0.0.3",
201
+ "@types/tar": "6.1.11",
203
202
  "@types/wellknown": "0.5.8",
204
203
  "@types/ws": "8.5.10",
205
204
  "@vitest/coverage-v8": "1.3.1",
@@ -207,10 +206,10 @@
207
206
  "form-data": "4.0.0",
208
207
  "knex-mock-client": "2.0.1",
209
208
  "typescript": "5.3.3",
210
- "vitest": "1.3.0",
209
+ "vitest": "1.3.1",
210
+ "@directus/random": "0.2.7",
211
211
  "@directus/tsconfig": "1.0.1",
212
- "@directus/random": "0.2.6",
213
- "@directus/types": "11.0.6"
212
+ "@directus/types": "11.0.7"
214
213
  },
215
214
  "optionalDependencies": {
216
215
  "@keyv/redis": "2.8.4",
@@ -220,7 +219,7 @@
220
219
  "oracledb": "6.3.0",
221
220
  "pg": "8.11.3",
222
221
  "sqlite3": "5.1.7",
223
- "tedious": "16.7.1"
222
+ "tedious": "17.0.0"
224
223
  },
225
224
  "engines": {
226
225
  "node": ">=18.17.0"
@@ -228,7 +227,7 @@
228
227
  "scripts": {
229
228
  "build": "tsc --project tsconfig.prod.json && copyfiles \"src/**/*.{yaml,liquid}\" -u 1 dist",
230
229
  "cli": "NODE_ENV=development SERVE_APP=false tsx src/cli/run.ts",
231
- "dev": "NODE_ENV=development SERVE_APP=false tsx watch --clear-screen=false src/start.ts",
230
+ "dev": "NODE_ENV=development SERVE_APP=true tsx watch --clear-screen=false src/start.ts",
232
231
  "test": "vitest --watch=false"
233
232
  }
234
233
  }