@directus/api 15.0.0 → 17.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.
- package/dist/app.js +6 -4
- package/dist/auth/drivers/ldap.js +7 -4
- package/dist/auth/drivers/local.js +3 -2
- package/dist/auth/drivers/oauth2.js +9 -2
- package/dist/auth/drivers/openid.js +9 -2
- package/dist/auth/drivers/saml.js +6 -4
- package/dist/auth.js +7 -4
- package/dist/bus/index.d.ts +1 -0
- package/dist/bus/index.js +1 -0
- package/dist/bus/lib/use-bus.d.ts +9 -0
- package/dist/bus/lib/use-bus.js +21 -0
- package/dist/cache.js +9 -9
- package/dist/cli/commands/bootstrap/index.js +6 -2
- package/dist/cli/commands/count/index.js +2 -1
- package/dist/cli/commands/database/install.js +2 -1
- package/dist/cli/commands/database/migrate.js +2 -1
- package/dist/cli/commands/roles/create.js +2 -1
- package/dist/cli/commands/schema/apply.js +2 -1
- package/dist/cli/commands/schema/snapshot.js +6 -5
- package/dist/cli/commands/users/create.js +4 -3
- package/dist/cli/commands/users/passwd.js +5 -4
- package/dist/cli/load-extensions.js +4 -2
- package/dist/cli/utils/create-env/env-stub.liquid +1 -1
- package/dist/constants.d.ts +1 -1
- package/dist/constants.js +4 -1
- package/dist/controllers/assets.js +5 -3
- package/dist/controllers/auth.js +5 -4
- package/dist/controllers/extensions.js +18 -6
- package/dist/controllers/files.js +3 -3
- package/dist/controllers/permissions.js +11 -2
- package/dist/controllers/schema.js +3 -2
- package/dist/controllers/shares.js +3 -3
- package/dist/controllers/utils.js +13 -32
- package/dist/database/helpers/index.d.ts +1 -1
- package/dist/database/index.js +9 -2
- package/dist/database/migrations/20210518A-add-foreign-key-constraints.js +3 -1
- package/dist/database/migrations/20210519A-add-system-fk-triggers.js +3 -1
- package/dist/database/migrations/20210802A-replace-groups.js +2 -1
- package/dist/database/migrations/20230721A-require-shares-fields.js +2 -1
- package/dist/database/migrations/20231215A-add-focalpoints.d.ts +3 -0
- package/dist/database/migrations/20231215A-add-focalpoints.js +12 -0
- package/dist/database/migrations/run.js +2 -1
- package/dist/database/run-ast.js +5 -2
- package/dist/database/system-data/app-access-permissions/app-access-permissions.yaml +0 -7
- package/dist/database/system-data/fields/files.yaml +16 -0
- package/dist/emitter.js +3 -1
- package/dist/extensions/lib/get-extensions-path.d.ts +1 -1
- package/dist/extensions/lib/get-extensions-path.js +2 -1
- package/dist/extensions/lib/get-extensions.d.ts +1 -1
- package/dist/extensions/lib/get-extensions.js +32 -8
- package/dist/extensions/lib/get-shared-deps-mapping.js +6 -4
- package/dist/extensions/lib/sandbox/register/call-reference.js +4 -2
- package/dist/extensions/lib/sandbox/sdk/generators/log.js +2 -1
- package/dist/extensions/lib/sync-extensions.js +6 -4
- package/dist/extensions/manager.js +43 -19
- package/dist/flows.js +13 -7
- package/dist/logger.d.ts +7 -7
- package/dist/logger.js +116 -92
- package/dist/mailer.js +4 -2
- package/dist/middleware/cache.js +4 -2
- package/dist/middleware/check-ip.js +25 -6
- package/dist/middleware/cors.js +2 -1
- package/dist/middleware/error-handler.js +5 -5
- package/dist/middleware/rate-limiter-global.js +4 -2
- package/dist/middleware/rate-limiter-ip.js +2 -1
- package/dist/middleware/respond.js +5 -3
- package/dist/operations/log/index.js +2 -1
- package/dist/rate-limiter.d.ts +2 -1
- package/dist/rate-limiter.js +5 -2
- package/dist/redis/index.d.ts +3 -2
- package/dist/redis/index.js +3 -2
- package/dist/redis/{create-redis.js → lib/create-redis.js} +2 -2
- package/dist/redis/utils/redis-config-available.d.ts +4 -0
- package/dist/redis/utils/redis-config-available.js +8 -0
- package/dist/request/request-interceptor.js +7 -5
- package/dist/request/response-interceptor.js +2 -2
- package/dist/request/validate-ip.d.ts +1 -1
- package/dist/request/validate-ip.js +23 -7
- package/dist/server.js +11 -7
- package/dist/services/activity.js +5 -4
- package/dist/services/assets.d.ts +2 -0
- package/dist/services/assets.js +9 -6
- package/dist/services/authentication.js +17 -9
- package/dist/services/authorization.d.ts +1 -1
- package/dist/services/authorization.js +15 -3
- package/dist/services/collections.js +5 -4
- package/dist/services/extensions.d.ts +15 -9
- package/dist/services/extensions.js +74 -39
- package/dist/services/fields.js +9 -4
- package/dist/services/files.d.ts +2 -2
- package/dist/services/files.js +22 -14
- package/dist/services/graphql/index.js +46 -3
- package/dist/services/graphql/subscription.js +2 -2
- package/dist/services/graphql/types/bigint.js +16 -5
- package/dist/services/graphql/utils/process-error.d.ts +4 -1
- package/dist/services/graphql/utils/process-error.js +10 -8
- package/dist/services/{import-export/index.d.ts → import-export.d.ts} +1 -1
- package/dist/services/{import-export/index.js → import-export.js} +14 -12
- package/dist/services/index.d.ts +1 -1
- package/dist/services/index.js +1 -1
- package/dist/services/items.js +12 -8
- package/dist/services/mail/index.js +4 -2
- package/dist/services/notifications.js +7 -3
- package/dist/services/permissions.d.ts +3 -2
- package/dist/services/permissions.js +76 -1
- package/dist/services/relations.js +19 -10
- package/dist/services/roles.js +83 -15
- package/dist/services/server.js +7 -5
- package/dist/services/shares.js +3 -2
- package/dist/services/specifications.js +2 -1
- package/dist/services/users.js +20 -9
- package/dist/services/versions.js +6 -5
- package/dist/services/webhooks.d.ts +2 -2
- package/dist/services/webhooks.js +2 -2
- package/dist/services/websocket.d.ts +1 -1
- package/dist/services/websocket.js +4 -3
- package/dist/storage/register-drivers.js +2 -1
- package/dist/storage/register-locations.js +2 -1
- package/dist/synchronization.js +3 -1
- package/dist/telemetry/lib/get-report.js +1 -1
- package/dist/telemetry/lib/init-telemetry.js +2 -2
- package/dist/telemetry/lib/send-report.js +1 -1
- package/dist/telemetry/lib/track.js +2 -3
- package/dist/telemetry/utils/get-user-count.js +1 -1
- package/dist/types/assets.d.ts +2 -0
- package/dist/types/items.d.ts +4 -12
- package/dist/types/items.js +0 -4
- package/dist/utils/apply-diff.js +2 -1
- package/dist/utils/apply-query.js +0 -11
- package/dist/utils/delete-from-require-cache.js +2 -1
- package/dist/utils/get-accountability-for-token.js +3 -2
- package/dist/utils/get-auth-providers.js +2 -1
- package/dist/utils/get-cache-headers.js +5 -2
- package/dist/utils/get-config-from-env.js +2 -1
- package/dist/utils/get-default-value.js +4 -3
- package/dist/utils/get-ip-from-req.js +4 -2
- package/dist/utils/get-permissions.js +5 -3
- package/dist/utils/get-schema.js +5 -2
- package/dist/utils/get-snapshot-diff.js +7 -9
- package/dist/utils/get-snapshot.js +4 -4
- package/dist/utils/ip-in-networks.d.ts +6 -0
- package/dist/utils/ip-in-networks.js +13 -0
- package/dist/utils/is-url-allowed.js +2 -1
- package/dist/utils/job-queue.d.ts +1 -0
- package/dist/utils/job-queue.js +3 -0
- package/dist/utils/sanitize-query.js +7 -2
- package/dist/utils/sanitize-schema.d.ts +1 -1
- package/dist/utils/should-clear-cache.js +2 -1
- package/dist/utils/should-skip-cache.js +2 -1
- package/dist/utils/transformations.js +95 -12
- package/dist/utils/validate-env.js +4 -2
- package/dist/utils/validate-query.js +7 -3
- package/dist/utils/validate-storage.js +4 -2
- package/dist/webhooks.js +4 -3
- package/dist/websocket/controllers/base.js +12 -6
- package/dist/websocket/controllers/graphql.js +4 -2
- package/dist/websocket/controllers/hooks.js +3 -2
- package/dist/websocket/controllers/index.js +4 -2
- package/dist/websocket/controllers/rest.js +4 -2
- package/dist/websocket/errors.js +2 -1
- package/dist/websocket/handlers/heartbeat.js +4 -3
- package/dist/websocket/handlers/subscribe.d.ts +2 -2
- package/dist/websocket/handlers/subscribe.js +5 -4
- package/package.json +57 -57
- package/dist/__utils__/items-utils.d.ts +0 -2
- package/dist/__utils__/items-utils.js +0 -31
- package/dist/__utils__/mock-env.d.ts +0 -18
- package/dist/__utils__/mock-env.js +0 -41
- package/dist/__utils__/schemas.d.ts +0 -13
- package/dist/__utils__/schemas.js +0 -301
- package/dist/__utils__/snapshots.d.ts +0 -5
- package/dist/__utils__/snapshots.js +0 -903
- package/dist/env.d.ts +0 -14
- package/dist/env.js +0 -511
- package/dist/messenger.d.ts +0 -24
- package/dist/messenger.js +0 -64
- package/dist/services/import-export/import-worker.d.ts +0 -9
- package/dist/services/import-export/import-worker.js +0 -9
- package/dist/utils/to-boolean.d.ts +0 -4
- package/dist/utils/to-boolean.js +0 -6
- package/dist/worker-pool.d.ts +0 -2
- package/dist/worker-pool.js +0 -19
- /package/dist/redis/{create-redis.d.ts → lib/create-redis.d.ts} +0 -0
- /package/dist/redis/{use-redis.d.ts → lib/use-redis.d.ts} +0 -0
- /package/dist/redis/{use-redis.js → lib/use-redis.js} +0 -0
package/dist/controllers/auth.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useEnv } from '@directus/env';
|
|
2
|
+
import { ErrorCode, InvalidPayloadError, isDirectusError } from '@directus/errors';
|
|
2
3
|
import { Router } from 'express';
|
|
3
4
|
import { createLDAPAuthRouter, createLocalAuthRouter, createOAuth2AuthRouter, createOpenIDAuthRouter, createSAMLAuthRouter, } from '../auth/drivers/index.js';
|
|
4
5
|
import { COOKIE_OPTIONS, DEFAULT_AUTH_PROVIDER } from '../constants.js';
|
|
5
|
-
import
|
|
6
|
-
import { ErrorCode, InvalidPayloadError } from '@directus/errors';
|
|
7
|
-
import logger from '../logger.js';
|
|
6
|
+
import { useLogger } from '../logger.js';
|
|
8
7
|
import { respond } from '../middleware/respond.js';
|
|
9
8
|
import { AuthenticationService } from '../services/authentication.js';
|
|
10
9
|
import { UsersService } from '../services/users.js';
|
|
@@ -12,6 +11,8 @@ import asyncHandler from '../utils/async-handler.js';
|
|
|
12
11
|
import { getAuthProviders } from '../utils/get-auth-providers.js';
|
|
13
12
|
import { getIPFromReq } from '../utils/get-ip-from-req.js';
|
|
14
13
|
const router = Router();
|
|
14
|
+
const env = useEnv();
|
|
15
|
+
const logger = useLogger();
|
|
15
16
|
const authProviders = getAuthProviders();
|
|
16
17
|
for (const authProvider of authProviders) {
|
|
17
18
|
let authRouter;
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useEnv } from '@directus/env';
|
|
2
|
+
import { ErrorCode, ForbiddenError, RouteNotFoundError, isDirectusError } from '@directus/errors';
|
|
2
3
|
import express from 'express';
|
|
3
|
-
import env from '../env.js';
|
|
4
4
|
import { getExtensionManager } from '../extensions/index.js';
|
|
5
5
|
import { respond } from '../middleware/respond.js';
|
|
6
6
|
import useCollection from '../middleware/use-collection.js';
|
|
7
|
-
import { ExtensionsService } from '../services/extensions.js';
|
|
7
|
+
import { ExtensionReadError, ExtensionsService } from '../services/extensions.js';
|
|
8
8
|
import asyncHandler from '../utils/async-handler.js';
|
|
9
9
|
import { getCacheControlHeader } from '../utils/get-cache-headers.js';
|
|
10
10
|
import { getMilliseconds } from '../utils/get-milliseconds.js';
|
|
11
11
|
const router = express.Router();
|
|
12
|
+
const env = useEnv();
|
|
12
13
|
router.use(useCollection('directus_extensions'));
|
|
13
14
|
router.get('/', asyncHandler(async (req, res, next) => {
|
|
14
15
|
const service = new ExtensionsService({
|
|
@@ -29,9 +30,20 @@ router.patch('/:bundleOrName/:name?', asyncHandler(async (req, res, next) => {
|
|
|
29
30
|
if (bundle === undefined || !name) {
|
|
30
31
|
throw new ForbiddenError();
|
|
31
32
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
try {
|
|
34
|
+
const result = await service.updateOne(bundle, name, req.body);
|
|
35
|
+
res.locals['payload'] = { data: result || null };
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
let finalError = error;
|
|
39
|
+
if (error instanceof ExtensionReadError) {
|
|
40
|
+
finalError = error.originalError;
|
|
41
|
+
if (isDirectusError(finalError, ErrorCode.Forbidden)) {
|
|
42
|
+
return next();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
throw finalError;
|
|
46
|
+
}
|
|
35
47
|
return next();
|
|
36
48
|
}), respond);
|
|
37
49
|
router.get('/sources/:chunk', asyncHandler(async (req, res) => {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useEnv } from '@directus/env';
|
|
2
|
+
import { ErrorCode, InvalidPayloadError, isDirectusError } from '@directus/errors';
|
|
2
3
|
import formatTitle from '@directus/format-title';
|
|
3
4
|
import { toArray } from '@directus/utils';
|
|
4
5
|
import Busboy from 'busboy';
|
|
@@ -7,8 +8,6 @@ import express from 'express';
|
|
|
7
8
|
import Joi from 'joi';
|
|
8
9
|
import { minimatch } from 'minimatch';
|
|
9
10
|
import path from 'path';
|
|
10
|
-
import env from '../env.js';
|
|
11
|
-
import { ErrorCode, InvalidPayloadError } from '@directus/errors';
|
|
12
11
|
import { respond } from '../middleware/respond.js';
|
|
13
12
|
import useCollection from '../middleware/use-collection.js';
|
|
14
13
|
import { validateBatch } from '../middleware/validate-batch.js';
|
|
@@ -17,6 +16,7 @@ import { MetaService } from '../services/meta.js';
|
|
|
17
16
|
import asyncHandler from '../utils/async-handler.js';
|
|
18
17
|
import { sanitizeQuery } from '../utils/sanitize-query.js';
|
|
19
18
|
const router = express.Router();
|
|
19
|
+
const env = useEnv();
|
|
20
20
|
router.use(useCollection('directus_files'));
|
|
21
21
|
export const multipartHandler = (req, res, next) => {
|
|
22
22
|
if (req.is('multipart/form-data') === false)
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { isDirectusError } from '@directus/errors';
|
|
1
|
+
import { ErrorCode, isDirectusError } from '@directus/errors';
|
|
2
2
|
import express from 'express';
|
|
3
|
-
import { ErrorCode } from '@directus/errors';
|
|
4
3
|
import { respond } from '../middleware/respond.js';
|
|
5
4
|
import useCollection from '../middleware/use-collection.js';
|
|
6
5
|
import { validateBatch } from '../middleware/validate-batch.js';
|
|
@@ -152,4 +151,14 @@ router.delete('/:pk', asyncHandler(async (req, _res, next) => {
|
|
|
152
151
|
await service.deleteOne(req.params['pk']);
|
|
153
152
|
return next();
|
|
154
153
|
}), respond);
|
|
154
|
+
router.get('/me/:collection/:pk?', asyncHandler(async (req, res, next) => {
|
|
155
|
+
const { collection, pk } = req.params;
|
|
156
|
+
const service = new PermissionsService({
|
|
157
|
+
accountability: req.accountability,
|
|
158
|
+
schema: req.schema,
|
|
159
|
+
});
|
|
160
|
+
const itemPermissions = await service.getItemPermissions(collection, pk);
|
|
161
|
+
res.locals['payload'] = { data: itemPermissions };
|
|
162
|
+
return next();
|
|
163
|
+
}), respond);
|
|
155
164
|
export default router;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
+
import { InvalidPayloadError, UnsupportedMediaTypeError } from '@directus/errors';
|
|
1
2
|
import { parseJSON } from '@directus/utils';
|
|
2
3
|
import Busboy from 'busboy';
|
|
3
4
|
import express from 'express';
|
|
4
5
|
import { load as loadYaml } from 'js-yaml';
|
|
5
|
-
import {
|
|
6
|
-
import logger from '../logger.js';
|
|
6
|
+
import { useLogger } from '../logger.js';
|
|
7
7
|
import { respond } from '../middleware/respond.js';
|
|
8
8
|
import { SchemaService } from '../services/schema.js';
|
|
9
9
|
import asyncHandler from '../utils/async-handler.js';
|
|
@@ -36,6 +36,7 @@ const schemaMultipartHandler = (req, res, next) => {
|
|
|
36
36
|
let isFileIncluded = false;
|
|
37
37
|
let upload = null;
|
|
38
38
|
busboy.on('file', async (_, fileStream, { mimeType }) => {
|
|
39
|
+
const logger = useLogger();
|
|
39
40
|
if (isFileIncluded)
|
|
40
41
|
return next(new InvalidPayloadError({ reason: `More than one file was included in the body` }));
|
|
41
42
|
isFileIncluded = true;
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useEnv } from '@directus/env';
|
|
2
|
+
import { ErrorCode, InvalidPayloadError, isDirectusError } from '@directus/errors';
|
|
2
3
|
import express from 'express';
|
|
3
4
|
import Joi from 'joi';
|
|
4
5
|
import { COOKIE_OPTIONS, UUID_REGEX } from '../constants.js';
|
|
5
|
-
import env from '../env.js';
|
|
6
|
-
import { ErrorCode, InvalidPayloadError } from '@directus/errors';
|
|
7
6
|
import { respond } from '../middleware/respond.js';
|
|
8
7
|
import useCollection from '../middleware/use-collection.js';
|
|
9
8
|
import { validateBatch } from '../middleware/validate-batch.js';
|
|
@@ -11,6 +10,7 @@ import { SharesService } from '../services/shares.js';
|
|
|
11
10
|
import asyncHandler from '../utils/async-handler.js';
|
|
12
11
|
import { sanitizeQuery } from '../utils/sanitize-query.js';
|
|
13
12
|
const router = express.Router();
|
|
13
|
+
const env = useEnv();
|
|
14
14
|
router.use(useCollection('directus_shares'));
|
|
15
15
|
const sharedLoginSchema = Joi.object({
|
|
16
16
|
share: Joi.string().required(),
|
|
@@ -1,13 +1,11 @@
|
|
|
1
|
+
import { InvalidPayloadError, InvalidQueryError, UnsupportedMediaTypeError } from '@directus/errors';
|
|
1
2
|
import argon2 from 'argon2';
|
|
2
3
|
import Busboy from 'busboy';
|
|
3
4
|
import { Router } from 'express';
|
|
4
5
|
import Joi from 'joi';
|
|
5
|
-
import fs from 'node:fs';
|
|
6
|
-
import { createRequire } from 'node:module';
|
|
7
|
-
import { InvalidPayloadError, InvalidQueryError, UnsupportedMediaTypeError } from '@directus/errors';
|
|
8
6
|
import collectionExists from '../middleware/collection-exists.js';
|
|
9
7
|
import { respond } from '../middleware/respond.js';
|
|
10
|
-
import { ExportService } from '../services/import-export
|
|
8
|
+
import { ExportService, ImportService } from '../services/import-export.js';
|
|
11
9
|
import { RevisionsService } from '../services/revisions.js';
|
|
12
10
|
import { UtilsService } from '../services/utils.js';
|
|
13
11
|
import asyncHandler from '../utils/async-handler.js';
|
|
@@ -66,6 +64,10 @@ router.post('/import/:collection', collectionExists, asyncHandler(async (req, re
|
|
|
66
64
|
if (req.is('multipart/form-data') === false) {
|
|
67
65
|
throw new UnsupportedMediaTypeError({ mediaType: req.headers['content-type'], where: 'Content-Type header' });
|
|
68
66
|
}
|
|
67
|
+
const service = new ImportService({
|
|
68
|
+
accountability: req.accountability,
|
|
69
|
+
schema: req.schema,
|
|
70
|
+
});
|
|
69
71
|
let headers;
|
|
70
72
|
if (req.headers['content-type']) {
|
|
71
73
|
headers = req.headers;
|
|
@@ -78,34 +80,13 @@ router.post('/import/:collection', collectionExists, asyncHandler(async (req, re
|
|
|
78
80
|
}
|
|
79
81
|
const busboy = Busboy({ headers });
|
|
80
82
|
busboy.on('file', async (_fieldname, fileStream, { mimeType }) => {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
const workerPool = getWorkerPool();
|
|
89
|
-
const require = createRequire(import.meta.url);
|
|
90
|
-
const filename = require.resolve('../services/import-export/import-worker');
|
|
91
|
-
const workerData = {
|
|
92
|
-
collection: req.params['collection'],
|
|
93
|
-
mimeType,
|
|
94
|
-
filePath: tmpFile.path,
|
|
95
|
-
accountability: req.accountability,
|
|
96
|
-
schema: req.schema,
|
|
97
|
-
};
|
|
98
|
-
try {
|
|
99
|
-
await workerPool.run(workerData, { filename });
|
|
100
|
-
res.status(200).end();
|
|
101
|
-
}
|
|
102
|
-
catch (error) {
|
|
103
|
-
next(error);
|
|
104
|
-
}
|
|
105
|
-
finally {
|
|
106
|
-
await tmpFile.cleanup();
|
|
107
|
-
}
|
|
108
|
-
});
|
|
83
|
+
try {
|
|
84
|
+
await service.import(req.params['collection'], mimeType, fileStream);
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
return next(err);
|
|
88
|
+
}
|
|
89
|
+
return res.status(200).end();
|
|
109
90
|
});
|
|
110
91
|
busboy.on('error', (err) => next(err));
|
|
111
92
|
req.pipe(busboy);
|
|
@@ -6,7 +6,7 @@ import * as geometryHelpers from './geometry/index.js';
|
|
|
6
6
|
import * as schemaHelpers from './schema/index.js';
|
|
7
7
|
import * as sequenceHelpers from './sequence/index.js';
|
|
8
8
|
export declare function getHelpers(database: Knex): {
|
|
9
|
-
date: dateHelpers.
|
|
9
|
+
date: dateHelpers.postgres | dateHelpers.oracle | dateHelpers.mysql | dateHelpers.mssql | dateHelpers.sqlite;
|
|
10
10
|
st: geometryHelpers.mysql | geometryHelpers.postgres | geometryHelpers.mssql | geometryHelpers.sqlite | geometryHelpers.oracle | geometryHelpers.redshift;
|
|
11
11
|
schema: schemaHelpers.mysql | schemaHelpers.cockroachdb | schemaHelpers.mssql | schemaHelpers.postgres | schemaHelpers.sqlite | schemaHelpers.oracle;
|
|
12
12
|
sequence: sequenceHelpers.mysql | sequenceHelpers.postgres;
|
package/dist/database/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useEnv } from '@directus/env';
|
|
1
2
|
import { createInspector } from '@directus/schema';
|
|
2
3
|
import fse from 'fs-extra';
|
|
3
4
|
import knex from 'knex';
|
|
@@ -7,9 +8,8 @@ import { fileURLToPath } from 'node:url';
|
|
|
7
8
|
import path from 'path';
|
|
8
9
|
import { performance } from 'perf_hooks';
|
|
9
10
|
import { promisify } from 'util';
|
|
10
|
-
import env from '../env.js';
|
|
11
11
|
import { getExtensionsPath } from '../extensions/lib/get-extensions-path.js';
|
|
12
|
-
import
|
|
12
|
+
import { useLogger } from '../logger.js';
|
|
13
13
|
import { getConfigFromEnv } from '../utils/get-config-from-env.js';
|
|
14
14
|
import { validateEnv } from '../utils/validate-env.js';
|
|
15
15
|
import { getHelpers } from './helpers/index.js';
|
|
@@ -22,6 +22,8 @@ export function getDatabase() {
|
|
|
22
22
|
if (database) {
|
|
23
23
|
return database;
|
|
24
24
|
}
|
|
25
|
+
const env = useEnv();
|
|
26
|
+
const logger = useLogger();
|
|
25
27
|
const { client, version, searchPath, connectionString, pool: poolConfig = {}, ...connectionConfig } = getConfigFromEnv('DB_', ['DB_EXCLUDE_TABLES']);
|
|
26
28
|
const requiredEnvVars = ['DB_CLIENT'];
|
|
27
29
|
switch (client) {
|
|
@@ -165,6 +167,7 @@ export async function hasDatabaseConnection(database) {
|
|
|
165
167
|
}
|
|
166
168
|
export async function validateDatabaseConnection(database) {
|
|
167
169
|
database = database ?? getDatabase();
|
|
170
|
+
const logger = useLogger();
|
|
168
171
|
try {
|
|
169
172
|
if (getDatabaseClient(database) === 'oracle') {
|
|
170
173
|
await database.raw('select 1 from DUAL');
|
|
@@ -209,6 +212,7 @@ export async function isInstalled() {
|
|
|
209
212
|
}
|
|
210
213
|
export async function validateMigrations() {
|
|
211
214
|
const database = getDatabase();
|
|
215
|
+
const logger = useLogger();
|
|
212
216
|
try {
|
|
213
217
|
let migrationFiles = await fse.readdir(path.join(__dirname, 'migrations'));
|
|
214
218
|
const customMigrationsPath = path.resolve(getExtensionsPath(), 'migrations');
|
|
@@ -234,6 +238,7 @@ export async function validateDatabaseExtensions() {
|
|
|
234
238
|
const client = getDatabaseClient(database);
|
|
235
239
|
const helpers = getHelpers(database);
|
|
236
240
|
const geometrySupport = await helpers.st.supported();
|
|
241
|
+
const logger = useLogger();
|
|
237
242
|
if (!geometrySupport) {
|
|
238
243
|
switch (client) {
|
|
239
244
|
case 'postgres':
|
|
@@ -248,7 +253,9 @@ export async function validateDatabaseExtensions() {
|
|
|
248
253
|
}
|
|
249
254
|
}
|
|
250
255
|
async function validateDatabaseCharset(database) {
|
|
256
|
+
const env = useEnv();
|
|
251
257
|
database = database ?? getDatabase();
|
|
258
|
+
const logger = useLogger();
|
|
252
259
|
if (getDatabaseClient(database) === 'mysql') {
|
|
253
260
|
const { collation } = await database.select(database.raw(`@@collation_database as collation`)).first();
|
|
254
261
|
const tables = await database('information_schema.tables')
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { createInspector } from '@directus/schema';
|
|
2
|
-
import
|
|
2
|
+
import { useLogger } from '../../logger.js';
|
|
3
3
|
import { getDefaultIndexName } from '../../utils/get-default-index-name.js';
|
|
4
4
|
export async function up(knex) {
|
|
5
|
+
const logger = useLogger();
|
|
5
6
|
const inspector = createInspector(knex);
|
|
6
7
|
const foreignKeys = await inspector.foreignKeys();
|
|
7
8
|
const relations = await knex
|
|
@@ -87,6 +88,7 @@ export async function up(knex) {
|
|
|
87
88
|
}
|
|
88
89
|
}
|
|
89
90
|
export async function down(knex) {
|
|
91
|
+
const logger = useLogger();
|
|
90
92
|
const relations = await knex
|
|
91
93
|
.select('many_collection', 'many_field', 'one_collection')
|
|
92
94
|
.from('directus_relations');
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createInspector } from '@directus/schema';
|
|
2
|
-
import
|
|
2
|
+
import { useLogger } from '../../logger.js';
|
|
3
3
|
/**
|
|
4
4
|
* Things to keep in mind:
|
|
5
5
|
*
|
|
@@ -77,6 +77,7 @@ const updates = [
|
|
|
77
77
|
},
|
|
78
78
|
];
|
|
79
79
|
export async function up(knex) {
|
|
80
|
+
const logger = useLogger();
|
|
80
81
|
const inspector = createInspector(knex);
|
|
81
82
|
const foreignKeys = await inspector.foreignKeys();
|
|
82
83
|
for (const update of updates) {
|
|
@@ -123,6 +124,7 @@ export async function up(knex) {
|
|
|
123
124
|
}
|
|
124
125
|
}
|
|
125
126
|
export async function down(knex) {
|
|
127
|
+
const logger = useLogger();
|
|
126
128
|
for (const update of updates) {
|
|
127
129
|
for (const constraint of update.constraints) {
|
|
128
130
|
try {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { parseJSON } from '@directus/utils';
|
|
2
|
-
import
|
|
2
|
+
import { useLogger } from '../../logger.js';
|
|
3
3
|
export async function up(knex) {
|
|
4
|
+
const logger = useLogger();
|
|
4
5
|
const dividerGroups = await knex.select('*').from('directus_fields').where('interface', '=', 'group-divider');
|
|
5
6
|
for (const dividerGroup of dividerGroups) {
|
|
6
7
|
const newOptions = { showHeader: true };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createInspector } from '@directus/schema';
|
|
2
|
-
import
|
|
2
|
+
import { useLogger } from '../../logger.js';
|
|
3
3
|
import { getHelpers } from '../helpers/index.js';
|
|
4
4
|
export async function up(knex) {
|
|
5
5
|
const helper = getHelpers(knex).schema;
|
|
@@ -33,6 +33,7 @@ export async function down(knex) {
|
|
|
33
33
|
* Temporarily drop foreign key constraint for MySQL instances, see https://github.com/directus/directus/issues/19399
|
|
34
34
|
*/
|
|
35
35
|
async function dropConstraint(knex) {
|
|
36
|
+
const logger = useLogger();
|
|
36
37
|
const inspector = createInspector(knex);
|
|
37
38
|
const foreignKeys = await inspector.foreignKeys('directus_shares');
|
|
38
39
|
const collectionForeignKeys = foreignKeys.filter((fk) => fk.column === 'collection');
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export async function up(knex) {
|
|
2
|
+
await knex.schema.alterTable('directus_files', (table) => {
|
|
3
|
+
table.integer('focal_point_x').nullable();
|
|
4
|
+
table.integer('focal_point_y').nullable();
|
|
5
|
+
});
|
|
6
|
+
}
|
|
7
|
+
export async function down(knex) {
|
|
8
|
+
await knex.schema.alterTable('directus_files', (table) => {
|
|
9
|
+
table.dropColumn('focal_point_x');
|
|
10
|
+
table.dropColumn('focal_point_y');
|
|
11
|
+
});
|
|
12
|
+
}
|
|
@@ -6,10 +6,11 @@ import { fileURLToPath } from 'node:url';
|
|
|
6
6
|
import path from 'path';
|
|
7
7
|
import { flushCaches } from '../../cache.js';
|
|
8
8
|
import { getExtensionsPath } from '../../extensions/lib/get-extensions-path.js';
|
|
9
|
-
import
|
|
9
|
+
import { useLogger } from '../../logger.js';
|
|
10
10
|
import getModuleDefault from '../../utils/get-module-default.js';
|
|
11
11
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
12
12
|
export default async function run(database, direction, log = true) {
|
|
13
|
+
const logger = useLogger();
|
|
13
14
|
let migrationFiles = await fse.readdir(__dirname);
|
|
14
15
|
const customMigrationsPath = path.resolve(getExtensionsPath(), 'migrations');
|
|
15
16
|
let customMigrationFiles = ((await fse.pathExists(customMigrationsPath)) && (await fse.readdir(customMigrationsPath))) || [];
|
package/dist/database/run-ast.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
+
import { useEnv } from '@directus/env';
|
|
1
2
|
import { toArray } from '@directus/utils';
|
|
2
3
|
import { clone, cloneDeep, isNil, merge, pick, uniq } from 'lodash-es';
|
|
3
|
-
import { getHelpers } from './helpers/index.js';
|
|
4
|
-
import env from '../env.js';
|
|
5
4
|
import { PayloadService } from '../services/payload.js';
|
|
6
5
|
import { applyFunctionToColumnName } from '../utils/apply-function-to-column-name.js';
|
|
7
6
|
import applyQuery, { applyLimit, applySort, generateAlias } from '../utils/apply-query.js';
|
|
8
7
|
import { getCollectionFromAlias } from '../utils/get-collection-from-alias.js';
|
|
9
8
|
import { getColumn } from '../utils/get-column.js';
|
|
10
9
|
import { stripFunction } from '../utils/strip-function.js';
|
|
10
|
+
import { getHelpers } from './helpers/index.js';
|
|
11
11
|
import getDatabase from './index.js';
|
|
12
12
|
/**
|
|
13
13
|
* Execute a given AST using Knex. Returns array of items based on requested AST.
|
|
@@ -26,6 +26,7 @@ export default async function runAST(originalAST, schema, options) {
|
|
|
26
26
|
return await run(ast.name, ast.children, options?.query || ast.query);
|
|
27
27
|
}
|
|
28
28
|
async function run(collection, children, query) {
|
|
29
|
+
const env = useEnv();
|
|
29
30
|
// Retrieve the database columns to select in the current AST
|
|
30
31
|
const { fieldNodes, primaryKeyField, nestedCollectionNodes } = await parseCurrentLevel(schema, collection, children, query);
|
|
31
32
|
// The actual knex query builder instance. This is a promise that resolves with the raw items from the db
|
|
@@ -148,6 +149,7 @@ function getColumnPreprocessor(knex, schema, table) {
|
|
|
148
149
|
};
|
|
149
150
|
}
|
|
150
151
|
async function getDBQuery(schema, knex, table, fieldNodes, query) {
|
|
152
|
+
const env = useEnv();
|
|
151
153
|
const preProcess = getColumnPreprocessor(knex, schema, table);
|
|
152
154
|
const queryCopy = clone(query);
|
|
153
155
|
const helpers = getHelpers(knex);
|
|
@@ -296,6 +298,7 @@ function applyParentFilters(schema, nestedCollectionNodes, parentItem) {
|
|
|
296
298
|
return nestedCollectionNodes;
|
|
297
299
|
}
|
|
298
300
|
function mergeWithParentItems(schema, nestedItem, parentItem, nestedNode) {
|
|
301
|
+
const env = useEnv();
|
|
299
302
|
const nestedItems = toArray(nestedItem);
|
|
300
303
|
const parentItems = clone(toArray(parentItem));
|
|
301
304
|
if (nestedNode.type === 'm2o') {
|
|
@@ -102,13 +102,6 @@
|
|
|
102
102
|
- appearance
|
|
103
103
|
- theme_light
|
|
104
104
|
- theme_dark
|
|
105
|
-
- theme_light_overrides
|
|
106
|
-
- theme_dark_overrides
|
|
107
105
|
- tfa_secret
|
|
108
106
|
- status
|
|
109
107
|
- role
|
|
110
|
-
|
|
111
|
-
# This is a temporary allowed field to help people migrate from
|
|
112
|
-
# 10.6 to 10.7 and should be removed in 10.8
|
|
113
|
-
# @TODO remove
|
|
114
|
-
- theme
|
|
@@ -46,6 +46,22 @@ fields:
|
|
|
46
46
|
width: half
|
|
47
47
|
readonly: true
|
|
48
48
|
|
|
49
|
+
- field: focal_point_divider
|
|
50
|
+
interface: presentation-divider
|
|
51
|
+
options:
|
|
52
|
+
icon: image_search
|
|
53
|
+
title: $t:field_options.directus_files.focal_point_divider
|
|
54
|
+
special:
|
|
55
|
+
- alias
|
|
56
|
+
- no-data
|
|
57
|
+
width: full
|
|
58
|
+
|
|
59
|
+
- field: focal_point_x
|
|
60
|
+
width: half
|
|
61
|
+
|
|
62
|
+
- field: focal_point_y
|
|
63
|
+
width: half
|
|
64
|
+
|
|
49
65
|
- field: storage_divider
|
|
50
66
|
interface: presentation-divider
|
|
51
67
|
options:
|
package/dist/emitter.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import ee2 from 'eventemitter2';
|
|
2
2
|
import getDatabase from './database/index.js';
|
|
3
|
-
import
|
|
3
|
+
import { useLogger } from './logger.js';
|
|
4
4
|
export class Emitter {
|
|
5
5
|
filterEmitter;
|
|
6
6
|
actionEmitter;
|
|
@@ -42,6 +42,7 @@ export class Emitter {
|
|
|
42
42
|
return updatedPayload;
|
|
43
43
|
}
|
|
44
44
|
emitAction(event, meta, context = null) {
|
|
45
|
+
const logger = useLogger();
|
|
45
46
|
const events = Array.isArray(event) ? event : [event];
|
|
46
47
|
for (const event of events) {
|
|
47
48
|
this.actionEmitter.emitAsync(event, { event, ...meta }, context ?? this.getDefaultContext()).catch((err) => {
|
|
@@ -51,6 +52,7 @@ export class Emitter {
|
|
|
51
52
|
}
|
|
52
53
|
}
|
|
53
54
|
async emitInit(event, meta) {
|
|
55
|
+
const logger = useLogger();
|
|
54
56
|
try {
|
|
55
57
|
await this.initEmitter.emitAsync(event, { event, ...meta });
|
|
56
58
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const getExtensionsPath: () =>
|
|
1
|
+
export declare const getExtensionsPath: () => string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const getExtensions: () => Promise<
|
|
1
|
+
export declare const getExtensions: () => Promise<any[]>;
|
|
@@ -1,12 +1,36 @@
|
|
|
1
|
+
import { useEnv } from '@directus/env';
|
|
1
2
|
import { getLocalExtensions, getPackageExtensions, resolvePackageExtensions } from '@directus/extensions/node';
|
|
2
|
-
import
|
|
3
|
+
import { useLogger } from '../../logger.js';
|
|
3
4
|
import { getExtensionsPath } from './get-extensions-path.js';
|
|
4
5
|
export const getExtensions = async () => {
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
6
|
+
const env = useEnv();
|
|
7
|
+
const logger = useLogger();
|
|
8
|
+
const loadedExtensions = new Map();
|
|
9
|
+
const duplicateExtensions = [];
|
|
10
|
+
const filterDuplicates = (extension) => {
|
|
11
|
+
const isExistingExtension = loadedExtensions.has(extension.name);
|
|
12
|
+
if (isExistingExtension) {
|
|
13
|
+
duplicateExtensions.push(extension.name);
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
if (extension.type === 'bundle') {
|
|
17
|
+
const bundleEntryNames = new Set();
|
|
18
|
+
for (const entry of extension.entries) {
|
|
19
|
+
if (bundleEntryNames.has(entry.name)) {
|
|
20
|
+
// Do not load entire bundle if it has duplicated entries
|
|
21
|
+
duplicateExtensions.push(extension.name);
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
bundleEntryNames.add(entry.name);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
loadedExtensions.set(extension.name, extension);
|
|
28
|
+
};
|
|
29
|
+
(await getLocalExtensions(getExtensionsPath())).forEach(filterDuplicates);
|
|
30
|
+
(await resolvePackageExtensions(getExtensionsPath())).forEach(filterDuplicates);
|
|
31
|
+
(await getPackageExtensions(env['PACKAGE_FILE_LOCATION'])).forEach(filterDuplicates);
|
|
32
|
+
if (duplicateExtensions.length > 0) {
|
|
33
|
+
logger.warn(`Failed to load the following extensions because they have/contain duplicate names: ${duplicateExtensions.join(', ')}`);
|
|
34
|
+
}
|
|
35
|
+
return Array.from(loadedExtensions.values());
|
|
12
36
|
};
|
|
@@ -1,14 +1,16 @@
|
|
|
1
|
+
import { useEnv } from '@directus/env';
|
|
1
2
|
import { resolvePackage } from '@directus/utils/node';
|
|
2
3
|
import { escapeRegExp } from 'lodash-es';
|
|
3
4
|
import { readdir } from 'node:fs/promises';
|
|
4
|
-
import path from 'path';
|
|
5
|
-
import env from '../../env.js';
|
|
6
|
-
import logger from '../../logger.js';
|
|
7
|
-
import { Url } from '../../utils/url.js';
|
|
8
5
|
import { dirname } from 'node:path';
|
|
9
6
|
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import path from 'path';
|
|
8
|
+
import { useLogger } from '../../logger.js';
|
|
9
|
+
import { Url } from '../../utils/url.js';
|
|
10
10
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
11
11
|
export const getSharedDepsMapping = async (deps) => {
|
|
12
|
+
const env = useEnv();
|
|
13
|
+
const logger = useLogger();
|
|
12
14
|
const appDir = await readdir(path.join(resolvePackage('@directus/app', __dirname), 'dist', 'assets'));
|
|
13
15
|
const depsMapping = {};
|
|
14
16
|
for (const dep of deps) {
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import { useEnv } from '@directus/env';
|
|
2
|
+
import { useLogger } from '../../../../logger.js';
|
|
3
3
|
export async function callReference(fn, args) {
|
|
4
|
+
const env = useEnv();
|
|
5
|
+
const logger = useLogger();
|
|
4
6
|
const sandboxTimeout = Number(env['EXTENSIONS_SANDBOX_TIMEOUT']);
|
|
5
7
|
try {
|
|
6
8
|
return await fn.apply(undefined, args, {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { useLogger } from '../../../../../logger.js';
|
|
2
2
|
export function logGenerator(requestedScopes) {
|
|
3
|
+
const logger = useLogger();
|
|
3
4
|
return (message) => {
|
|
4
5
|
if (requestedScopes.log === undefined)
|
|
5
6
|
throw new Error('No permission to access "log"');
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useEnv } from '@directus/env';
|
|
1
2
|
import { NESTED_EXTENSION_TYPES } from '@directus/extensions';
|
|
2
3
|
import { ensureExtensionDirs } from '@directus/extensions/node';
|
|
3
4
|
import mid from 'node-machine-id';
|
|
@@ -6,19 +7,20 @@ import { mkdir } from 'node:fs/promises';
|
|
|
6
7
|
import { dirname, join, relative, resolve, sep } from 'node:path';
|
|
7
8
|
import { pipeline } from 'node:stream/promises';
|
|
8
9
|
import Queue from 'p-queue';
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
import { getMessenger } from '../../messenger.js';
|
|
10
|
+
import { useBus } from '../../bus/index.js';
|
|
11
|
+
import { useLogger } from '../../logger.js';
|
|
12
12
|
import { getStorage } from '../../storage/index.js';
|
|
13
13
|
import { getExtensionsPath } from './get-extensions-path.js';
|
|
14
14
|
import { SyncStatus, getSyncStatus, setSyncStatus } from './sync-status.js';
|
|
15
15
|
export const syncExtensions = async () => {
|
|
16
|
+
const env = useEnv();
|
|
17
|
+
const logger = useLogger();
|
|
16
18
|
const extensionsPath = getExtensionsPath();
|
|
17
19
|
if (!env['EXTENSIONS_LOCATION']) {
|
|
18
20
|
// Safe to run with multiple instances since dirs are created with `recursive: true`
|
|
19
21
|
return ensureExtensionDirs(extensionsPath, NESTED_EXTENSION_TYPES);
|
|
20
22
|
}
|
|
21
|
-
const messenger =
|
|
23
|
+
const messenger = useBus();
|
|
22
24
|
const isPrimaryProcess = String(process.env['NODE_APP_INSTANCE']) === '0' || process.env['NODE_APP_INSTANCE'] === undefined;
|
|
23
25
|
const id = await mid.machineId();
|
|
24
26
|
const message = `extensions-sync/${id}`;
|