@directus/api 14.0.2 → 14.1.1
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.
- package/dist/__utils__/mock-env.d.ts +18 -0
- package/dist/__utils__/mock-env.js +41 -0
- package/dist/auth/drivers/oauth2.js +4 -2
- package/dist/auth/drivers/openid.js +4 -2
- package/dist/cli/load-extensions.js +1 -2
- package/dist/constants.js +1 -1
- package/dist/controllers/assets.js +10 -10
- package/dist/controllers/files.js +1 -5
- package/dist/controllers/server.js +1 -1
- package/dist/database/index.js +2 -1
- package/dist/database/migrations/run.js +2 -2
- package/dist/database/system-data/collections/collections.yaml +1 -1
- package/dist/database/system-data/fields/settings.yaml +12 -13
- package/dist/database/system-data/fields/users.yaml +10 -10
- package/dist/env.d.ts +2 -4
- package/dist/env.js +12 -9
- package/dist/extensions/lib/get-extensions-path.d.ts +1 -0
- package/dist/extensions/lib/get-extensions-path.js +8 -0
- package/dist/extensions/lib/get-extensions.js +3 -2
- package/dist/extensions/lib/sync-extensions.d.ts +1 -0
- package/dist/extensions/lib/sync-extensions.js +59 -0
- package/dist/extensions/lib/sync-status.d.ts +10 -0
- package/dist/extensions/lib/sync-status.js +27 -0
- package/dist/extensions/manager.js +14 -5
- package/dist/logger.d.ts +2 -1
- package/dist/logger.js +13 -2
- package/dist/messenger.js +1 -3
- package/dist/request/validate-ip.js +1 -2
- package/dist/services/extensions.js +1 -1
- package/dist/services/files.d.ts +2 -2
- package/dist/services/files.js +90 -23
- package/dist/services/mail/index.js +5 -4
- package/dist/services/mail/templates/base.liquid +383 -138
- package/dist/services/mail/templates/password-reset.liquid +35 -17
- package/dist/services/mail/templates/user-invitation.liquid +32 -13
- package/dist/services/server.js +4 -0
- package/dist/services/specifications.d.ts +3 -16
- package/dist/services/specifications.js +63 -64
- package/dist/storage/register-drivers.js +1 -2
- package/dist/storage/register-locations.js +1 -2
- package/dist/types/services.d.ts +1 -1
- package/dist/utils/get-auth-providers.d.ts +1 -1
- package/dist/utils/get-config-from-env.js +1 -2
- package/dist/utils/merge-permissions.js +11 -19
- package/dist/utils/sanitize-query.js +1 -2
- package/dist/utils/should-clear-cache.js +1 -2
- package/dist/utils/should-skip-cache.js +3 -4
- package/dist/utils/validate-env.js +1 -2
- package/dist/utils/validate-storage.js +12 -9
- package/package.json +16 -15
- package/dist/__mocks__/cache.d.mts +0 -5
- package/dist/__mocks__/cache.mjs +0 -7
package/dist/services/server.js
CHANGED
|
@@ -34,6 +34,10 @@ export class ServerService {
|
|
|
34
34
|
'project_logo',
|
|
35
35
|
'project_color',
|
|
36
36
|
'default_appearance',
|
|
37
|
+
'default_theme_light',
|
|
38
|
+
'default_theme_dark',
|
|
39
|
+
'theme_light_overrides',
|
|
40
|
+
'theme_dark_overrides',
|
|
37
41
|
'default_language',
|
|
38
42
|
'public_foreground',
|
|
39
43
|
'public_background',
|
|
@@ -2,20 +2,14 @@ import type { Accountability, SchemaOverview } from '@directus/types';
|
|
|
2
2
|
import type { Knex } from 'knex';
|
|
3
3
|
import type { OpenAPIObject } from 'openapi3-ts/oas30';
|
|
4
4
|
import type { AbstractServiceOptions } from '../types/index.js';
|
|
5
|
-
import { CollectionsService } from './collections.js';
|
|
6
|
-
import { FieldsService } from './fields.js';
|
|
7
5
|
import { GraphQLService } from './graphql/index.js';
|
|
8
|
-
import { RelationsService } from './relations.js';
|
|
9
6
|
export declare class SpecificationService {
|
|
10
7
|
accountability: Accountability | null;
|
|
11
8
|
knex: Knex;
|
|
12
9
|
schema: SchemaOverview;
|
|
13
|
-
fieldsService: FieldsService;
|
|
14
|
-
collectionsService: CollectionsService;
|
|
15
|
-
relationsService: RelationsService;
|
|
16
10
|
oas: OASSpecsService;
|
|
17
11
|
graphql: GraphQLSpecsService;
|
|
18
|
-
constructor(
|
|
12
|
+
constructor({ accountability, knex, schema }: AbstractServiceOptions);
|
|
19
13
|
}
|
|
20
14
|
interface SpecificationSubService {
|
|
21
15
|
generate: (_?: any) => Promise<any>;
|
|
@@ -24,15 +18,8 @@ declare class OASSpecsService implements SpecificationSubService {
|
|
|
24
18
|
accountability: Accountability | null;
|
|
25
19
|
knex: Knex;
|
|
26
20
|
schema: SchemaOverview;
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
relationsService: RelationsService;
|
|
30
|
-
constructor(options: AbstractServiceOptions, { fieldsService, collectionsService, relationsService, }: {
|
|
31
|
-
fieldsService: FieldsService;
|
|
32
|
-
collectionsService: CollectionsService;
|
|
33
|
-
relationsService: RelationsService;
|
|
34
|
-
});
|
|
35
|
-
generate(): Promise<OpenAPIObject>;
|
|
21
|
+
constructor({ knex, schema, accountability }: AbstractServiceOptions);
|
|
22
|
+
generate(host?: string): Promise<OpenAPIObject>;
|
|
36
23
|
private generateTags;
|
|
37
24
|
private generatePaths;
|
|
38
25
|
private generateComponents;
|
|
@@ -6,57 +6,39 @@ import getDatabase from '../database/index.js';
|
|
|
6
6
|
import env from '../env.js';
|
|
7
7
|
import { getRelationType } from '../utils/get-relation-type.js';
|
|
8
8
|
import { version } from '../utils/package.js';
|
|
9
|
-
import { CollectionsService } from './collections.js';
|
|
10
|
-
import { FieldsService } from './fields.js';
|
|
11
9
|
import { GraphQLService } from './graphql/index.js';
|
|
12
|
-
import {
|
|
10
|
+
import { reduceSchema } from '../utils/reduce-schema.js';
|
|
13
11
|
export class SpecificationService {
|
|
14
12
|
accountability;
|
|
15
13
|
knex;
|
|
16
14
|
schema;
|
|
17
|
-
fieldsService;
|
|
18
|
-
collectionsService;
|
|
19
|
-
relationsService;
|
|
20
15
|
oas;
|
|
21
16
|
graphql;
|
|
22
|
-
constructor(
|
|
23
|
-
this.accountability =
|
|
24
|
-
this.knex =
|
|
25
|
-
this.schema =
|
|
26
|
-
this.
|
|
27
|
-
this.
|
|
28
|
-
this.relationsService = new RelationsService(options);
|
|
29
|
-
this.oas = new OASSpecsService(options, {
|
|
30
|
-
fieldsService: this.fieldsService,
|
|
31
|
-
collectionsService: this.collectionsService,
|
|
32
|
-
relationsService: this.relationsService,
|
|
33
|
-
});
|
|
34
|
-
this.graphql = new GraphQLSpecsService(options);
|
|
17
|
+
constructor({ accountability, knex, schema }) {
|
|
18
|
+
this.accountability = accountability || null;
|
|
19
|
+
this.knex = knex || getDatabase();
|
|
20
|
+
this.schema = schema;
|
|
21
|
+
this.oas = new OASSpecsService({ knex, schema, accountability });
|
|
22
|
+
this.graphql = new GraphQLSpecsService({ knex, schema });
|
|
35
23
|
}
|
|
36
24
|
}
|
|
37
25
|
class OASSpecsService {
|
|
38
26
|
accountability;
|
|
39
27
|
knex;
|
|
40
28
|
schema;
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
this.knex = options.knex || getDatabase();
|
|
47
|
-
this.schema = options.schema;
|
|
48
|
-
this.fieldsService = fieldsService;
|
|
49
|
-
this.collectionsService = collectionsService;
|
|
50
|
-
this.relationsService = relationsService;
|
|
29
|
+
constructor({ knex, schema, accountability }) {
|
|
30
|
+
this.accountability = accountability || null;
|
|
31
|
+
this.knex = knex || getDatabase();
|
|
32
|
+
this.schema =
|
|
33
|
+
this.accountability?.admin === true ? schema : reduceSchema(schema, accountability?.permissions || null);
|
|
51
34
|
}
|
|
52
|
-
async generate() {
|
|
53
|
-
const collections = await this.collectionsService.readByQuery();
|
|
54
|
-
const fields = await this.fieldsService.readAll();
|
|
55
|
-
const relations = (await this.relationsService.readAll());
|
|
35
|
+
async generate(host) {
|
|
56
36
|
const permissions = this.accountability?.permissions ?? [];
|
|
57
|
-
const tags = await this.generateTags(
|
|
37
|
+
const tags = await this.generateTags();
|
|
58
38
|
const paths = await this.generatePaths(permissions, tags);
|
|
59
|
-
const components = await this.generateComponents(
|
|
39
|
+
const components = await this.generateComponents(tags);
|
|
40
|
+
const isDefaultPublicUrl = env['PUBLIC_URL'] === '/';
|
|
41
|
+
const url = isDefaultPublicUrl && host ? host : env['PUBLIC_URL'];
|
|
60
42
|
const spec = {
|
|
61
43
|
openapi: '3.0.1',
|
|
62
44
|
info: {
|
|
@@ -66,7 +48,7 @@ class OASSpecsService {
|
|
|
66
48
|
},
|
|
67
49
|
servers: [
|
|
68
50
|
{
|
|
69
|
-
url
|
|
51
|
+
url,
|
|
70
52
|
description: 'Your current Directus instance.',
|
|
71
53
|
},
|
|
72
54
|
],
|
|
@@ -78,11 +60,17 @@ class OASSpecsService {
|
|
|
78
60
|
spec.components = components;
|
|
79
61
|
return spec;
|
|
80
62
|
}
|
|
81
|
-
async generateTags(
|
|
63
|
+
async generateTags() {
|
|
82
64
|
const systemTags = cloneDeep(spec.tags);
|
|
65
|
+
const collections = Object.values(this.schema.collections);
|
|
83
66
|
const tags = [];
|
|
84
|
-
// System tags that don't have an associated collection are always readable to the user
|
|
85
67
|
for (const systemTag of systemTags) {
|
|
68
|
+
// Check if necessary authentication level is given
|
|
69
|
+
if (systemTag['x-authentication'] === 'admin' && !this.accountability?.admin)
|
|
70
|
+
continue;
|
|
71
|
+
if (systemTag['x-authentication'] === 'user' && !this.accountability?.user)
|
|
72
|
+
continue;
|
|
73
|
+
// Remaining system tags that don't have an associated collection are publicly available
|
|
86
74
|
if (!systemTag['x-collection']) {
|
|
87
75
|
tags.push(systemTag);
|
|
88
76
|
}
|
|
@@ -103,8 +91,8 @@ class OASSpecsService {
|
|
|
103
91
|
name: 'Items' + formatTitle(collection.collection).replace(/ /g, ''),
|
|
104
92
|
'x-collection': collection.collection,
|
|
105
93
|
};
|
|
106
|
-
if (collection.
|
|
107
|
-
tag.description = collection.
|
|
94
|
+
if (collection.note) {
|
|
95
|
+
tag.description = collection.note;
|
|
108
96
|
}
|
|
109
97
|
tags.push(tag);
|
|
110
98
|
}
|
|
@@ -256,33 +244,38 @@ class OASSpecsService {
|
|
|
256
244
|
}
|
|
257
245
|
return paths;
|
|
258
246
|
}
|
|
259
|
-
async generateComponents(
|
|
247
|
+
async generateComponents(tags) {
|
|
248
|
+
if (!tags)
|
|
249
|
+
return;
|
|
260
250
|
let components = cloneDeep(spec.components);
|
|
261
251
|
if (!components)
|
|
262
252
|
components = {};
|
|
263
253
|
components.schemas = {};
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
254
|
+
const tagSchemas = tags.reduce((schemas, tag) => [...schemas, ...(tag['x-schemas'] ? tag['x-schemas'] : [])], []);
|
|
255
|
+
const requiredSchemas = [...OAS_REQUIRED_SCHEMAS, ...tagSchemas];
|
|
256
|
+
for (const [name, schema] of Object.entries(spec.components?.schemas ?? {})) {
|
|
257
|
+
if (requiredSchemas.includes(name)) {
|
|
258
|
+
const collection = spec.tags?.find((tag) => tag.name === name)?.['x-collection'];
|
|
259
|
+
components.schemas[name] = {
|
|
260
|
+
...cloneDeep(schema),
|
|
261
|
+
...(collection && { 'x-collection': collection }),
|
|
262
|
+
};
|
|
270
263
|
}
|
|
271
264
|
}
|
|
272
|
-
|
|
273
|
-
return;
|
|
265
|
+
const collections = Object.values(this.schema.collections);
|
|
274
266
|
for (const collection of collections) {
|
|
275
267
|
const tag = tags.find((tag) => tag['x-collection'] === collection.collection);
|
|
276
268
|
if (!tag)
|
|
277
269
|
continue;
|
|
278
270
|
const isSystem = collection.collection.startsWith('directus_');
|
|
279
|
-
const fieldsInCollection =
|
|
271
|
+
const fieldsInCollection = Object.values(collection.fields);
|
|
280
272
|
if (isSystem) {
|
|
281
273
|
const schemaComponent = cloneDeep(spec.components.schemas[tag.name]);
|
|
282
274
|
schemaComponent.properties = {};
|
|
275
|
+
schemaComponent['x-collection'] = collection.collection;
|
|
283
276
|
for (const field of fieldsInCollection) {
|
|
284
277
|
schemaComponent.properties[field.field] =
|
|
285
|
-
cloneDeep(spec.components.schemas[tag.name].properties[field.field]) || this.generateField(
|
|
278
|
+
cloneDeep(spec.components.schemas[tag.name].properties[field.field]) || this.generateField(collection.collection, field, tags);
|
|
286
279
|
}
|
|
287
280
|
components.schemas[tag.name] = schemaComponent;
|
|
288
281
|
}
|
|
@@ -293,7 +286,7 @@ class OASSpecsService {
|
|
|
293
286
|
'x-collection': collection.collection,
|
|
294
287
|
};
|
|
295
288
|
for (const field of fieldsInCollection) {
|
|
296
|
-
schemaComponent.properties[field.field] = this.generateField(
|
|
289
|
+
schemaComponent.properties[field.field] = this.generateField(collection.collection, field, tags);
|
|
297
290
|
}
|
|
298
291
|
components.schemas[tag.name] = schemaComponent;
|
|
299
292
|
}
|
|
@@ -316,16 +309,14 @@ class OASSpecsService {
|
|
|
316
309
|
return 'read';
|
|
317
310
|
}
|
|
318
311
|
}
|
|
319
|
-
generateField(
|
|
312
|
+
generateField(collection, field, tags) {
|
|
320
313
|
let propertyObject = {};
|
|
321
|
-
|
|
322
|
-
|
|
314
|
+
propertyObject.nullable = field.nullable;
|
|
315
|
+
if (field.note) {
|
|
316
|
+
propertyObject.description = field.note;
|
|
323
317
|
}
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
}
|
|
327
|
-
const relation = relations.find((relation) => (relation.collection === field.collection && relation.field === field.field) ||
|
|
328
|
-
(relation.related_collection === field.collection && relation.meta?.one_field === field.field));
|
|
318
|
+
const relation = this.schema.relations.find((relation) => (relation.collection === collection && relation.field === field.field) ||
|
|
319
|
+
(relation.related_collection === collection && relation.meta?.one_field === field.field));
|
|
329
320
|
if (!relation) {
|
|
330
321
|
propertyObject = {
|
|
331
322
|
...propertyObject,
|
|
@@ -336,13 +327,17 @@ class OASSpecsService {
|
|
|
336
327
|
const relationType = getRelationType({
|
|
337
328
|
relation,
|
|
338
329
|
field: field.field,
|
|
339
|
-
collection:
|
|
330
|
+
collection: collection,
|
|
340
331
|
});
|
|
341
332
|
if (relationType === 'm2o') {
|
|
342
333
|
const relatedTag = tags.find((tag) => tag['x-collection'] === relation.related_collection);
|
|
343
|
-
|
|
344
|
-
|
|
334
|
+
if (!relatedTag ||
|
|
335
|
+
!relation.related_collection ||
|
|
336
|
+
relation.related_collection in this.schema.collections === false) {
|
|
345
337
|
return propertyObject;
|
|
338
|
+
}
|
|
339
|
+
const relatedCollection = this.schema.collections[relation.related_collection];
|
|
340
|
+
const relatedPrimaryKeyField = relatedCollection.fields[relatedCollection.primary];
|
|
346
341
|
propertyObject.oneOf = [
|
|
347
342
|
{
|
|
348
343
|
...this.fieldTypes[relatedPrimaryKeyField.type],
|
|
@@ -354,7 +349,11 @@ class OASSpecsService {
|
|
|
354
349
|
}
|
|
355
350
|
else if (relationType === 'o2m') {
|
|
356
351
|
const relatedTag = tags.find((tag) => tag['x-collection'] === relation.collection);
|
|
357
|
-
|
|
352
|
+
if (!relatedTag || !relation.related_collection || relation.collection in this.schema.collections === false) {
|
|
353
|
+
return propertyObject;
|
|
354
|
+
}
|
|
355
|
+
const relatedCollection = this.schema.collections[relation.collection];
|
|
356
|
+
const relatedPrimaryKeyField = relatedCollection.fields[relatedCollection.primary];
|
|
358
357
|
if (!relatedTag || !relatedPrimaryKeyField)
|
|
359
358
|
return propertyObject;
|
|
360
359
|
propertyObject.type = 'array';
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import
|
|
1
|
+
import env from '../env.js';
|
|
2
2
|
import { getStorageDriver } from './get-storage-driver.js';
|
|
3
3
|
export const registerDrivers = async (storage) => {
|
|
4
|
-
const env = getEnv();
|
|
5
4
|
const usedDrivers = [];
|
|
6
5
|
for (const [key, value] of Object.entries(env)) {
|
|
7
6
|
if ((key.startsWith('STORAGE_') && key.endsWith('_DRIVER')) === false)
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { toArray } from '@directus/utils';
|
|
2
|
-
import
|
|
2
|
+
import env from '../env.js';
|
|
3
3
|
import { getConfigFromEnv } from '../utils/get-config-from-env.js';
|
|
4
4
|
export const registerLocations = async (storage) => {
|
|
5
|
-
const env = getEnv();
|
|
6
5
|
const locations = toArray(env['STORAGE_LOCATIONS']);
|
|
7
6
|
locations.forEach((location) => {
|
|
8
7
|
location = location.trim();
|
package/dist/types/services.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { Accountability, Query, SchemaOverview } from '@directus/types';
|
|
|
2
2
|
import type { Knex } from 'knex';
|
|
3
3
|
import type { Item, PrimaryKey } from './items.js';
|
|
4
4
|
export type AbstractServiceOptions = {
|
|
5
|
-
knex?: Knex;
|
|
5
|
+
knex?: Knex | undefined;
|
|
6
6
|
accountability?: Accountability | null | undefined;
|
|
7
7
|
schema: SchemaOverview;
|
|
8
8
|
};
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import camelcase from 'camelcase';
|
|
2
2
|
import { set } from 'lodash-es';
|
|
3
|
-
import
|
|
3
|
+
import env from '../env.js';
|
|
4
4
|
export function getConfigFromEnv(prefix, omitPrefix, type = 'camelcase') {
|
|
5
|
-
const env = getEnv();
|
|
6
5
|
const config = {};
|
|
7
6
|
for (const [key, value] of Object.entries(env)) {
|
|
8
7
|
if (key.toLowerCase().startsWith(prefix.toLowerCase()) === false)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { flatten, intersection,
|
|
1
|
+
import { flatten, intersection, isEmpty, merge, omit } from 'lodash-es';
|
|
2
2
|
export function mergePermissions(strategy, ...permissions) {
|
|
3
3
|
const allPermissions = flatten(permissions);
|
|
4
4
|
const mergedPermissions = allPermissions
|
|
@@ -27,15 +27,11 @@ export function mergePermission(strategy, currentPerm, newPerm) {
|
|
|
27
27
|
};
|
|
28
28
|
}
|
|
29
29
|
else if (currentPerm.permissions) {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
permissions = {
|
|
36
|
-
[logicalKey]: [currentPerm.permissions, newPerm.permissions],
|
|
37
|
-
};
|
|
38
|
-
}
|
|
30
|
+
permissions = {
|
|
31
|
+
[logicalKey]: strategy === 'or'
|
|
32
|
+
? [currentPerm.permissions, newPerm.permissions].filter((p) => !isEmpty(p))
|
|
33
|
+
: [currentPerm.permissions, newPerm.permissions],
|
|
34
|
+
};
|
|
39
35
|
}
|
|
40
36
|
else {
|
|
41
37
|
permissions = {
|
|
@@ -53,15 +49,11 @@ export function mergePermission(strategy, currentPerm, newPerm) {
|
|
|
53
49
|
};
|
|
54
50
|
}
|
|
55
51
|
else if (currentPerm.validation) {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
validation = {
|
|
62
|
-
[logicalKey]: [currentPerm.validation, newPerm.validation],
|
|
63
|
-
};
|
|
64
|
-
}
|
|
52
|
+
validation = {
|
|
53
|
+
[logicalKey]: strategy === 'or'
|
|
54
|
+
? [currentPerm.validation, newPerm.validation].filter((p) => !isEmpty(p))
|
|
55
|
+
: [currentPerm.validation, newPerm.validation],
|
|
56
|
+
};
|
|
65
57
|
}
|
|
66
58
|
else {
|
|
67
59
|
validation = {
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { parseFilter, parseJSON } from '@directus/utils';
|
|
2
2
|
import { flatten, get, isPlainObject, merge, set } from 'lodash-es';
|
|
3
|
-
import
|
|
3
|
+
import env from '../env.js';
|
|
4
4
|
import logger from '../logger.js';
|
|
5
5
|
import { Meta } from '../types/index.js';
|
|
6
6
|
export function sanitizeQuery(rawQuery, accountability) {
|
|
7
7
|
const query = {};
|
|
8
|
-
const env = getEnv();
|
|
9
8
|
const hasMaxLimit = 'QUERY_LIMIT_MAX' in env &&
|
|
10
9
|
Number(env['QUERY_LIMIT_MAX']) >= 0 &&
|
|
11
10
|
!Number.isNaN(Number(env['QUERY_LIMIT_MAX'])) &&
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import env from '../env.js';
|
|
2
2
|
/**
|
|
3
3
|
* Check whether cache should be cleared
|
|
4
4
|
*
|
|
@@ -7,7 +7,6 @@ import { getEnv } from '../env.js';
|
|
|
7
7
|
* @param collection Collection name to check if cache purging should be ignored
|
|
8
8
|
*/
|
|
9
9
|
export function shouldClearCache(cache, opts, collection) {
|
|
10
|
-
const env = getEnv();
|
|
11
10
|
if (env['CACHE_AUTO_PURGE']) {
|
|
12
11
|
if (collection && env['CACHE_AUTO_PURGE_IGNORE_LIST'].includes(collection)) {
|
|
13
12
|
return false;
|
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
import { getEnv } from '../env.js';
|
|
2
|
-
import { Url } from './url.js';
|
|
3
|
-
import url from 'url';
|
|
4
1
|
import { getEndpoint } from '@directus/utils';
|
|
2
|
+
import url from 'url';
|
|
3
|
+
import env from '../env.js';
|
|
4
|
+
import { Url } from './url.js';
|
|
5
5
|
/**
|
|
6
6
|
* Whether to skip caching for the current request
|
|
7
7
|
*
|
|
8
8
|
* @param req Express request object
|
|
9
9
|
*/
|
|
10
10
|
export function shouldSkipCache(req) {
|
|
11
|
-
const env = getEnv();
|
|
12
11
|
// Always skip cache for requests coming from the data studio based on Referer header
|
|
13
12
|
const referer = req.get('Referer');
|
|
14
13
|
if (referer) {
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import
|
|
1
|
+
import env from '../env.js';
|
|
2
2
|
import logger from '../logger.js';
|
|
3
3
|
export function validateEnv(requiredKeys) {
|
|
4
|
-
const env = getEnv();
|
|
5
4
|
for (const requiredKey of requiredKeys) {
|
|
6
5
|
if (requiredKey in env === false) {
|
|
7
6
|
logger.error(`"${requiredKey}" Environment Variable is missing.`);
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import
|
|
2
|
-
import logger from '../logger.js';
|
|
3
|
-
import { access } from 'node:fs/promises';
|
|
1
|
+
import { toArray } from '@directus/utils';
|
|
4
2
|
import { constants } from 'fs';
|
|
3
|
+
import { access } from 'node:fs/promises';
|
|
5
4
|
import path from 'path';
|
|
6
|
-
import
|
|
5
|
+
import env from '../env.js';
|
|
6
|
+
import { getExtensionsPath } from '../extensions/lib/get-extensions-path.js';
|
|
7
|
+
import logger from '../logger.js';
|
|
7
8
|
export async function validateStorage() {
|
|
8
9
|
if (env['DB_CLIENT'] === 'sqlite3') {
|
|
9
10
|
try {
|
|
@@ -22,10 +23,12 @@ export async function validateStorage() {
|
|
|
22
23
|
logger.warn(`Upload directory (${path.resolve(env['STORAGE_LOCAL_ROOT'])}) is not read/writeable!`);
|
|
23
24
|
}
|
|
24
25
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
if (!env['EXTENSIONS_LOCATION']) {
|
|
27
|
+
try {
|
|
28
|
+
await access(getExtensionsPath(), constants.R_OK);
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
logger.warn(`Extensions directory (${path.resolve(getExtensionsPath())}) is not readable!`);
|
|
32
|
+
}
|
|
30
33
|
}
|
|
31
34
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@directus/api",
|
|
3
|
-
"version": "14.
|
|
3
|
+
"version": "14.1.1",
|
|
4
4
|
"description": "Directus is a real-time API and App dashboard for managing SQL database content",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"directus",
|
|
@@ -122,6 +122,7 @@
|
|
|
122
122
|
"openid-client": "5.4.2",
|
|
123
123
|
"ora": "6.3.1",
|
|
124
124
|
"otplib": "12.0.1",
|
|
125
|
+
"p-queue": "7.4.1",
|
|
125
126
|
"papaparse": "5.4.1",
|
|
126
127
|
"pino": "8.14.1",
|
|
127
128
|
"pino-http": "8.3.3",
|
|
@@ -144,23 +145,23 @@
|
|
|
144
145
|
"ws": "8.14.2",
|
|
145
146
|
"zod": "3.22.4",
|
|
146
147
|
"zod-validation-error": "1.0.1",
|
|
147
|
-
"@directus/app": "10.
|
|
148
|
+
"@directus/app": "10.13.1",
|
|
148
149
|
"@directus/constants": "11.0.1",
|
|
149
|
-
"@directus/extensions": "0.
|
|
150
|
+
"@directus/extensions": "0.2.0",
|
|
151
|
+
"@directus/extensions-sdk": "10.2.0",
|
|
150
152
|
"@directus/errors": "0.2.0",
|
|
151
|
-
"@directus/
|
|
152
|
-
"@directus/pressure": "1.0.12",
|
|
153
|
+
"@directus/pressure": "1.0.13",
|
|
153
154
|
"@directus/schema": "11.0.0",
|
|
154
|
-
"@directus/specs": "10.2.1",
|
|
155
155
|
"@directus/storage": "10.0.7",
|
|
156
|
-
"@directus/
|
|
157
|
-
"@directus/storage-driver-
|
|
158
|
-
"@directus/storage-driver-
|
|
159
|
-
"@directus/storage-driver-
|
|
160
|
-
"@directus/storage-driver-
|
|
161
|
-
"@directus/storage-driver-
|
|
162
|
-
"@directus/
|
|
163
|
-
"@directus/utils": "11.0.
|
|
156
|
+
"@directus/specs": "10.2.3",
|
|
157
|
+
"@directus/storage-driver-azure": "10.0.14",
|
|
158
|
+
"@directus/storage-driver-local": "10.0.14",
|
|
159
|
+
"@directus/storage-driver-cloudinary": "10.0.14",
|
|
160
|
+
"@directus/storage-driver-s3": "10.0.14",
|
|
161
|
+
"@directus/storage-driver-gcs": "10.0.14",
|
|
162
|
+
"@directus/storage-driver-supabase": "1.0.6",
|
|
163
|
+
"@directus/utils": "11.0.2",
|
|
164
|
+
"@directus/validation": "0.0.9"
|
|
164
165
|
},
|
|
165
166
|
"devDependencies": {
|
|
166
167
|
"@ngneat/falso": "6.4.0",
|
|
@@ -210,7 +211,7 @@
|
|
|
210
211
|
"vitest": "0.31.1",
|
|
211
212
|
"@directus/random": "0.2.3",
|
|
212
213
|
"@directus/tsconfig": "1.0.1",
|
|
213
|
-
"@directus/types": "11.0.
|
|
214
|
+
"@directus/types": "11.0.2"
|
|
214
215
|
},
|
|
215
216
|
"optionalDependencies": {
|
|
216
217
|
"@keyv/redis": "2.5.8",
|
package/dist/__mocks__/cache.mjs
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { vi } from 'vitest';
|
|
2
|
-
export const getCache = vi
|
|
3
|
-
.fn()
|
|
4
|
-
.mockReturnValue({ cache: undefined, systemCache: undefined, lockCache: undefined });
|
|
5
|
-
export const flushCaches = vi.fn();
|
|
6
|
-
export const clearSystemCache = vi.fn();
|
|
7
|
-
export const setSystemCache = vi.fn();
|