@directus/api 14.1.2 → 16.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 (207) hide show
  1. package/dist/app.js +8 -6
  2. package/dist/auth/drivers/ldap.js +7 -4
  3. package/dist/auth/drivers/local.js +3 -2
  4. package/dist/auth/drivers/oauth2.js +11 -5
  5. package/dist/auth/drivers/openid.js +11 -5
  6. package/dist/auth/drivers/saml.js +6 -4
  7. package/dist/auth.js +7 -4
  8. package/dist/bus/index.d.ts +1 -0
  9. package/dist/bus/index.js +1 -0
  10. package/dist/bus/lib/use-bus.d.ts +9 -0
  11. package/dist/bus/lib/use-bus.js +21 -0
  12. package/dist/cache.js +9 -9
  13. package/dist/cli/commands/bootstrap/index.js +6 -2
  14. package/dist/cli/commands/count/index.js +2 -1
  15. package/dist/cli/commands/database/install.js +2 -1
  16. package/dist/cli/commands/database/migrate.js +2 -1
  17. package/dist/cli/commands/roles/create.js +2 -1
  18. package/dist/cli/commands/schema/apply.js +46 -34
  19. package/dist/cli/commands/schema/snapshot.js +6 -5
  20. package/dist/cli/commands/users/create.js +4 -3
  21. package/dist/cli/commands/users/passwd.js +5 -4
  22. package/dist/cli/index.js +2 -2
  23. package/dist/cli/load-extensions.js +4 -2
  24. package/dist/cli/utils/create-env/env-stub.liquid +1 -1
  25. package/dist/constants.d.ts +1 -1
  26. package/dist/constants.js +4 -1
  27. package/dist/controllers/assets.js +5 -3
  28. package/dist/controllers/auth.js +5 -4
  29. package/dist/controllers/extensions.js +18 -6
  30. package/dist/controllers/files.js +3 -3
  31. package/dist/controllers/schema.js +3 -2
  32. package/dist/controllers/shares.js +3 -3
  33. package/dist/database/helpers/index.d.ts +1 -1
  34. package/dist/database/index.d.ts +2 -1
  35. package/dist/database/index.js +11 -3
  36. package/dist/database/migrations/20210518A-add-foreign-key-constraints.js +3 -1
  37. package/dist/database/migrations/20210519A-add-system-fk-triggers.js +3 -1
  38. package/dist/database/migrations/20210802A-replace-groups.js +2 -1
  39. package/dist/database/migrations/20230721A-require-shares-fields.js +2 -1
  40. package/dist/database/migrations/20231215A-add-focalpoints.d.ts +3 -0
  41. package/dist/database/migrations/20231215A-add-focalpoints.js +12 -0
  42. package/dist/database/migrations/run.js +2 -1
  43. package/dist/database/run-ast.js +5 -2
  44. package/dist/database/system-data/app-access-permissions/app-access-permissions.yaml +0 -7
  45. package/dist/database/system-data/fields/files.yaml +16 -0
  46. package/dist/database/system-data/relations/relations.yaml +4 -0
  47. package/dist/emitter.d.ts +1 -0
  48. package/dist/emitter.js +4 -1
  49. package/dist/extensions/lib/get-extensions-path.d.ts +1 -1
  50. package/dist/extensions/lib/get-extensions-path.js +2 -1
  51. package/dist/extensions/lib/get-extensions.d.ts +1 -1
  52. package/dist/extensions/lib/get-extensions.js +32 -8
  53. package/dist/extensions/lib/get-shared-deps-mapping.js +7 -5
  54. package/dist/extensions/lib/sandbox/register/call-reference.js +4 -2
  55. package/dist/extensions/lib/sandbox/register/route.d.ts +1 -0
  56. package/dist/extensions/lib/sandbox/sdk/generators/log.js +2 -1
  57. package/dist/extensions/lib/sync-extensions.js +6 -4
  58. package/dist/extensions/manager.d.ts +5 -0
  59. package/dist/extensions/manager.js +84 -34
  60. package/dist/flows.js +13 -7
  61. package/dist/logger.d.ts +7 -6
  62. package/dist/logger.js +116 -91
  63. package/dist/mailer.js +4 -2
  64. package/dist/middleware/cache.js +4 -2
  65. package/dist/middleware/check-ip.js +25 -6
  66. package/dist/middleware/cors.js +2 -1
  67. package/dist/middleware/error-handler.js +5 -5
  68. package/dist/middleware/rate-limiter-global.js +4 -2
  69. package/dist/middleware/rate-limiter-ip.js +16 -12
  70. package/dist/middleware/respond.js +4 -2
  71. package/dist/operations/log/index.js +2 -1
  72. package/dist/rate-limiter.d.ts +2 -1
  73. package/dist/rate-limiter.js +5 -2
  74. package/dist/redis/index.d.ts +3 -0
  75. package/dist/redis/index.js +3 -0
  76. package/dist/redis/lib/create-redis.d.ts +7 -0
  77. package/dist/redis/lib/create-redis.js +12 -0
  78. package/dist/redis/lib/use-redis.d.ts +16 -0
  79. package/dist/redis/lib/use-redis.js +22 -0
  80. package/dist/redis/utils/redis-config-available.d.ts +4 -0
  81. package/dist/redis/utils/redis-config-available.js +8 -0
  82. package/dist/request/request-interceptor.js +7 -5
  83. package/dist/request/response-interceptor.js +2 -2
  84. package/dist/request/validate-ip.d.ts +1 -1
  85. package/dist/request/validate-ip.js +23 -7
  86. package/dist/server.d.ts +2 -0
  87. package/dist/server.js +11 -7
  88. package/dist/services/activity.js +5 -4
  89. package/dist/services/assets.d.ts +2 -0
  90. package/dist/services/assets.js +9 -4
  91. package/dist/services/authentication.js +17 -9
  92. package/dist/services/collections.js +5 -4
  93. package/dist/services/extensions.d.ts +15 -9
  94. package/dist/services/extensions.js +75 -40
  95. package/dist/services/fields.js +9 -4
  96. package/dist/services/files.d.ts +2 -2
  97. package/dist/services/files.js +22 -14
  98. package/dist/services/graphql/index.js +96 -18
  99. package/dist/services/graphql/subscription.js +2 -2
  100. package/dist/services/graphql/types/bigint.js +16 -5
  101. package/dist/services/graphql/utils/process-error.d.ts +4 -1
  102. package/dist/services/graphql/utils/process-error.js +10 -8
  103. package/dist/services/import-export/index.js +5 -3
  104. package/dist/services/items.js +12 -8
  105. package/dist/services/mail/index.js +4 -2
  106. package/dist/services/notifications.js +7 -3
  107. package/dist/services/payload.js +3 -3
  108. package/dist/services/relations.js +19 -10
  109. package/dist/services/server.js +7 -7
  110. package/dist/services/shares.js +3 -2
  111. package/dist/services/specifications.js +5 -4
  112. package/dist/services/users.js +24 -13
  113. package/dist/services/versions.js +6 -5
  114. package/dist/services/webhooks.d.ts +2 -2
  115. package/dist/services/webhooks.js +2 -2
  116. package/dist/services/websocket.d.ts +1 -1
  117. package/dist/services/websocket.js +4 -3
  118. package/dist/storage/register-drivers.js +2 -1
  119. package/dist/storage/register-locations.js +2 -1
  120. package/dist/synchronization.js +3 -1
  121. package/dist/telemetry/index.d.ts +4 -0
  122. package/dist/telemetry/index.js +4 -0
  123. package/dist/telemetry/lib/get-report.d.ts +5 -0
  124. package/dist/telemetry/lib/get-report.js +42 -0
  125. package/dist/telemetry/lib/init-telemetry.d.ts +11 -0
  126. package/dist/telemetry/lib/init-telemetry.js +30 -0
  127. package/dist/telemetry/lib/send-report.d.ts +5 -0
  128. package/dist/telemetry/lib/send-report.js +23 -0
  129. package/dist/telemetry/lib/track.d.ts +10 -0
  130. package/dist/telemetry/lib/track.js +30 -0
  131. package/dist/telemetry/types/report.d.ts +58 -0
  132. package/dist/telemetry/types/report.js +1 -0
  133. package/dist/telemetry/utils/get-item-count.d.ts +26 -0
  134. package/dist/telemetry/utils/get-item-count.js +36 -0
  135. package/dist/telemetry/utils/get-random-wait-time.d.ts +5 -0
  136. package/dist/telemetry/utils/get-random-wait-time.js +5 -0
  137. package/dist/telemetry/utils/get-user-count.d.ts +7 -0
  138. package/dist/telemetry/utils/get-user-count.js +30 -0
  139. package/dist/telemetry/utils/get-user-item-count.d.ts +13 -0
  140. package/dist/telemetry/utils/get-user-item-count.js +18 -0
  141. package/dist/types/assets.d.ts +2 -0
  142. package/dist/utils/apply-diff.js +2 -1
  143. package/dist/utils/apply-query.js +2 -2
  144. package/dist/utils/delete-from-require-cache.js +2 -1
  145. package/dist/utils/get-accountability-for-token.js +3 -2
  146. package/dist/utils/get-auth-providers.js +2 -1
  147. package/dist/utils/get-cache-headers.js +5 -2
  148. package/dist/utils/get-cache-key.js +1 -1
  149. package/dist/utils/get-config-from-env.js +2 -1
  150. package/dist/utils/get-default-value.js +4 -3
  151. package/dist/utils/get-ip-from-req.d.ts +1 -1
  152. package/dist/utils/get-ip-from-req.js +5 -3
  153. package/dist/utils/get-permissions.js +5 -3
  154. package/dist/utils/get-schema.js +5 -2
  155. package/dist/utils/get-snapshot-diff.js +7 -9
  156. package/dist/utils/get-snapshot.js +5 -5
  157. package/dist/utils/get-versioned-hash.js +1 -1
  158. package/dist/utils/ip-in-networks.d.ts +6 -0
  159. package/dist/utils/ip-in-networks.js +13 -0
  160. package/dist/utils/is-url-allowed.js +2 -1
  161. package/dist/utils/job-queue.d.ts +1 -0
  162. package/dist/utils/job-queue.js +3 -0
  163. package/dist/utils/md.d.ts +1 -1
  164. package/dist/utils/md.js +3 -2
  165. package/dist/utils/sanitize-query.js +7 -2
  166. package/dist/utils/sanitize-schema.d.ts +1 -1
  167. package/dist/utils/should-clear-cache.js +2 -1
  168. package/dist/utils/should-skip-cache.js +2 -1
  169. package/dist/utils/transformations.js +95 -12
  170. package/dist/utils/validate-env.js +4 -2
  171. package/dist/utils/validate-query.js +8 -3
  172. package/dist/utils/validate-snapshot.js +3 -3
  173. package/dist/utils/validate-storage.js +4 -2
  174. package/dist/webhooks.js +4 -3
  175. package/dist/websocket/controllers/base.d.ts +2 -0
  176. package/dist/websocket/controllers/base.js +12 -6
  177. package/dist/websocket/controllers/graphql.d.ts +2 -0
  178. package/dist/websocket/controllers/graphql.js +5 -3
  179. package/dist/websocket/controllers/hooks.js +3 -2
  180. package/dist/websocket/controllers/index.d.ts +2 -0
  181. package/dist/websocket/controllers/index.js +4 -2
  182. package/dist/websocket/controllers/rest.d.ts +2 -0
  183. package/dist/websocket/controllers/rest.js +4 -2
  184. package/dist/websocket/errors.js +2 -1
  185. package/dist/websocket/handlers/heartbeat.js +4 -3
  186. package/dist/websocket/handlers/subscribe.d.ts +2 -2
  187. package/dist/websocket/handlers/subscribe.js +5 -4
  188. package/dist/websocket/types.d.ts +3 -1
  189. package/package.json +114 -115
  190. package/dist/__utils__/items-utils.d.ts +0 -2
  191. package/dist/__utils__/items-utils.js +0 -31
  192. package/dist/__utils__/mock-env.d.ts +0 -18
  193. package/dist/__utils__/mock-env.js +0 -41
  194. package/dist/__utils__/schemas.d.ts +0 -13
  195. package/dist/__utils__/schemas.js +0 -301
  196. package/dist/__utils__/snapshots.d.ts +0 -5
  197. package/dist/__utils__/snapshots.js +0 -903
  198. package/dist/env.d.ts +0 -13
  199. package/dist/env.js +0 -505
  200. package/dist/messenger.d.ts +0 -24
  201. package/dist/messenger.js +0 -64
  202. package/dist/utils/package.d.ts +0 -2
  203. package/dist/utils/package.js +0 -6
  204. package/dist/utils/telemetry.d.ts +0 -1
  205. package/dist/utils/telemetry.js +0 -23
  206. package/dist/utils/to-boolean.d.ts +0 -4
  207. package/dist/utils/to-boolean.js +0 -6
package/dist/app.js CHANGED
@@ -1,3 +1,5 @@
1
+ import { useEnv } from '@directus/env';
2
+ import { InvalidPayloadError, ServiceUnavailableError } from '@directus/errors';
1
3
  import { handlePressure } from '@directus/pressure';
2
4
  import cookieParser from 'cookie-parser';
3
5
  import express from 'express';
@@ -39,11 +41,9 @@ import versionsRouter from './controllers/versions.js';
39
41
  import webhooksRouter from './controllers/webhooks.js';
40
42
  import { isInstalled, validateDatabaseConnection, validateDatabaseExtensions, validateMigrations, } from './database/index.js';
41
43
  import emitter from './emitter.js';
42
- import env from './env.js';
43
- import { InvalidPayloadError, ServiceUnavailableError } from '@directus/errors';
44
44
  import { getExtensionManager } from './extensions/index.js';
45
45
  import { getFlowManager } from './flows.js';
46
- import logger, { expressLogger } from './logger.js';
46
+ import { createExpressLogger, useLogger } from './logger.js';
47
47
  import authenticate from './middleware/authenticate.js';
48
48
  import cache from './middleware/cache.js';
49
49
  import { checkIP } from './middleware/check-ip.js';
@@ -55,14 +55,16 @@ import rateLimiterGlobal from './middleware/rate-limiter-global.js';
55
55
  import rateLimiter from './middleware/rate-limiter-ip.js';
56
56
  import sanitizeQuery from './middleware/sanitize-query.js';
57
57
  import schema from './middleware/schema.js';
58
+ import { initTelemetry } from './telemetry/index.js';
58
59
  import { getConfigFromEnv } from './utils/get-config-from-env.js';
59
- import { collectTelemetry } from './utils/telemetry.js';
60
60
  import { Url } from './utils/url.js';
61
61
  import { validateEnv } from './utils/validate-env.js';
62
62
  import { validateStorage } from './utils/validate-storage.js';
63
63
  import { init as initWebhooks } from './webhooks.js';
64
64
  const require = createRequire(import.meta.url);
65
65
  export default async function createApp() {
66
+ const env = useEnv();
67
+ const logger = useLogger();
66
68
  const helmet = await import('helmet');
67
69
  validateEnv(['KEY', 'SECRET']);
68
70
  if (!new Url(env['PUBLIC_URL']).isAbsolute()) {
@@ -124,7 +126,7 @@ export default async function createApp() {
124
126
  }
125
127
  await emitter.emitInit('app.before', { app });
126
128
  await emitter.emitInit('middlewares.before', { app });
127
- app.use(expressLogger);
129
+ app.use(createExpressLogger());
128
130
  app.use((_req, res, next) => {
129
131
  res.setHeader('X-Powered-By', 'Directus');
130
132
  next();
@@ -234,7 +236,7 @@ export default async function createApp() {
234
236
  await emitter.emitInit('routes.after', { app });
235
237
  // Register all webhooks
236
238
  await initWebhooks();
237
- collectTelemetry();
239
+ initTelemetry();
238
240
  await emitter.emitInit('app.after', { app });
239
241
  return app;
240
242
  }
@@ -1,12 +1,11 @@
1
- import { isDirectusError } from '@directus/errors';
1
+ import { useEnv } from '@directus/env';
2
+ import { ErrorCode, InvalidCredentialsError, InvalidPayloadError, InvalidProviderConfigError, InvalidProviderError, ServiceUnavailableError, UnexpectedResponseError, isDirectusError, } from '@directus/errors';
2
3
  import { Router } from 'express';
3
4
  import Joi from 'joi';
4
5
  import ldap from 'ldapjs';
5
6
  import getDatabase from '../../database/index.js';
6
7
  import emitter from '../../emitter.js';
7
- import env from '../../env.js';
8
- import { ErrorCode, InvalidCredentialsError, InvalidPayloadError, InvalidProviderError, InvalidProviderConfigError, ServiceUnavailableError, UnexpectedResponseError, } from '@directus/errors';
9
- import logger from '../../logger.js';
8
+ import { useLogger } from '../../logger.js';
10
9
  import { respond } from '../../middleware/respond.js';
11
10
  import { AuthenticationService } from '../../services/authentication.js';
12
11
  import { UsersService } from '../../services/users.js';
@@ -24,6 +23,7 @@ export class LDAPAuthDriver extends AuthDriver {
24
23
  config;
25
24
  constructor(options, config) {
26
25
  super(options, config);
26
+ const logger = useLogger();
27
27
  const { bindDn, bindPassword, userDn, provider, clientUrl } = config;
28
28
  if (bindDn === undefined ||
29
29
  bindPassword === undefined ||
@@ -42,6 +42,7 @@ export class LDAPAuthDriver extends AuthDriver {
42
42
  this.config = config;
43
43
  }
44
44
  async validateBindClient() {
45
+ const logger = useLogger();
45
46
  const { bindDn, bindPassword, provider } = this.config;
46
47
  return new Promise((resolve, reject) => {
47
48
  // Healthcheck bind user
@@ -168,6 +169,7 @@ export class LDAPAuthDriver extends AuthDriver {
168
169
  if (!payload['identifier']) {
169
170
  throw new InvalidCredentialsError();
170
171
  }
172
+ const logger = useLogger();
171
173
  await this.validateBindClient();
172
174
  const { userDn, userScope, userAttribute, groupDn, groupScope, groupAttribute, defaultRoleId } = this.config;
173
175
  const userInfo = await this.fetchUserInfo(userDn, new ldap.EqualityFilter({
@@ -292,6 +294,7 @@ export function createLDAPAuthRouter(provider) {
292
294
  otp: Joi.string(),
293
295
  }).unknown();
294
296
  router.post('/', asyncHandler(async (req, res, next) => {
297
+ const env = useEnv();
295
298
  const accountability = {
296
299
  ip: getIPFromReq(req),
297
300
  role: null,
@@ -1,10 +1,10 @@
1
+ import { InvalidCredentialsError, InvalidPayloadError } from '@directus/errors';
1
2
  import argon2 from 'argon2';
2
3
  import { Router } from 'express';
3
4
  import Joi from 'joi';
4
5
  import { performance } from 'perf_hooks';
5
6
  import { COOKIE_OPTIONS } from '../../constants.js';
6
- import env from '../../env.js';
7
- import { InvalidCredentialsError, InvalidPayloadError } from '@directus/errors';
7
+ import { useEnv } from '@directus/env';
8
8
  import { respond } from '../../middleware/respond.js';
9
9
  import { AuthenticationService } from '../../services/authentication.js';
10
10
  import asyncHandler from '../../utils/async-handler.js';
@@ -36,6 +36,7 @@ export class LocalAuthDriver extends AuthDriver {
36
36
  }
37
37
  }
38
38
  export function createLocalAuthRouter(provider) {
39
+ const env = useEnv();
39
40
  const router = Router();
40
41
  const userLoginSchema = Joi.object({
41
42
  email: Joi.string().email().required(),
@@ -1,15 +1,14 @@
1
- import { isDirectusError } from '@directus/errors';
1
+ import { useEnv } from '@directus/env';
2
+ import { ErrorCode, InvalidCredentialsError, InvalidProviderConfigError, InvalidProviderError, InvalidTokenError, isDirectusError, ServiceUnavailableError, } from '@directus/errors';
2
3
  import { parseJSON } from '@directus/utils';
3
4
  import express, { Router } from 'express';
4
- import flatten from 'flat';
5
+ import { flatten } from 'flat';
5
6
  import jwt from 'jsonwebtoken';
6
7
  import { errors, generators, Issuer } from 'openid-client';
7
8
  import { getAuthProvider } from '../../auth.js';
8
9
  import getDatabase from '../../database/index.js';
9
10
  import emitter from '../../emitter.js';
10
- import env from '../../env.js';
11
- import { ErrorCode, InvalidCredentialsError, InvalidProviderError, InvalidProviderConfigError, InvalidTokenError, ServiceUnavailableError, } from '@directus/errors';
12
- import logger from '../../logger.js';
11
+ import { useLogger } from '../../logger.js';
13
12
  import { respond } from '../../middleware/respond.js';
14
13
  import { AuthenticationService } from '../../services/authentication.js';
15
14
  import { UsersService } from '../../services/users.js';
@@ -26,6 +25,8 @@ export class OAuth2AuthDriver extends LocalAuthDriver {
26
25
  config;
27
26
  constructor(options, config) {
28
27
  super(options, config);
28
+ const env = useEnv();
29
+ const logger = useLogger();
29
30
  const { authorizeUrl, accessUrl, profileUrl, clientId, clientSecret, ...additionalConfig } = config;
30
31
  if (!authorizeUrl || !accessUrl || !profileUrl || !clientId || !clientSecret || !additionalConfig['provider']) {
31
32
  logger.error('Invalid provider config');
@@ -82,6 +83,7 @@ export class OAuth2AuthDriver extends LocalAuthDriver {
82
83
  return user?.id;
83
84
  }
84
85
  async getUserID(payload) {
86
+ const logger = useLogger();
85
87
  if (!payload['code'] || !payload['codeVerifier'] || !payload['state']) {
86
88
  logger.warn('[OAuth2] No code, codeVerifier or state in payload');
87
89
  throw new InvalidCredentialsError();
@@ -161,6 +163,7 @@ export class OAuth2AuthDriver extends LocalAuthDriver {
161
163
  return this.refresh(user);
162
164
  }
163
165
  async refresh(user) {
166
+ const logger = useLogger();
164
167
  let authData = user.auth_data;
165
168
  if (typeof authData === 'string') {
166
169
  try {
@@ -187,6 +190,7 @@ export class OAuth2AuthDriver extends LocalAuthDriver {
187
190
  }
188
191
  }
189
192
  const handleError = (e) => {
193
+ const logger = useLogger();
190
194
  if (e instanceof errors.OPError) {
191
195
  if (e.error === 'invalid_grant') {
192
196
  // Invalid token
@@ -210,6 +214,7 @@ const handleError = (e) => {
210
214
  };
211
215
  export function createOAuth2AuthRouter(providerName) {
212
216
  const router = Router();
217
+ const env = useEnv();
213
218
  router.get('/', (req, res) => {
214
219
  const provider = getAuthProvider(providerName);
215
220
  const codeVerifier = provider.generateCodeVerifier();
@@ -228,6 +233,7 @@ export function createOAuth2AuthRouter(providerName) {
228
233
  res.redirect(303, `./callback?${new URLSearchParams(req.body)}`);
229
234
  }, respond);
230
235
  router.get('/callback', asyncHandler(async (req, res, next) => {
236
+ const logger = useLogger();
231
237
  let tokenData;
232
238
  try {
233
239
  tokenData = jwt.verify(req.cookies[`oauth2.${providerName}`], env['SECRET'], {
@@ -1,15 +1,14 @@
1
- import { isDirectusError } from '@directus/errors';
1
+ import { useEnv } from '@directus/env';
2
+ import { ErrorCode, InvalidCredentialsError, InvalidProviderConfigError, InvalidProviderError, InvalidTokenError, isDirectusError, ServiceUnavailableError, } from '@directus/errors';
2
3
  import { parseJSON } from '@directus/utils';
3
4
  import express, { Router } from 'express';
4
- import flatten from 'flat';
5
+ import { flatten } from 'flat';
5
6
  import jwt from 'jsonwebtoken';
6
7
  import { errors, generators, Issuer } from 'openid-client';
7
8
  import { getAuthProvider } from '../../auth.js';
8
9
  import getDatabase from '../../database/index.js';
9
10
  import emitter from '../../emitter.js';
10
- import env from '../../env.js';
11
- import { ErrorCode, InvalidCredentialsError, InvalidProviderError, InvalidProviderConfigError, InvalidTokenError, ServiceUnavailableError, } from '@directus/errors';
12
- import logger from '../../logger.js';
11
+ import { useLogger } from '../../logger.js';
13
12
  import { respond } from '../../middleware/respond.js';
14
13
  import { AuthenticationService } from '../../services/authentication.js';
15
14
  import { UsersService } from '../../services/users.js';
@@ -26,6 +25,8 @@ export class OpenIDAuthDriver extends LocalAuthDriver {
26
25
  config;
27
26
  constructor(options, config) {
28
27
  super(options, config);
28
+ const env = useEnv();
29
+ const logger = useLogger();
29
30
  const { issuerUrl, clientId, clientSecret, ...additionalConfig } = config;
30
31
  if (!issuerUrl || !clientId || !clientSecret || !additionalConfig['provider']) {
31
32
  logger.error('Invalid provider config');
@@ -94,6 +95,7 @@ export class OpenIDAuthDriver extends LocalAuthDriver {
94
95
  return user?.id;
95
96
  }
96
97
  async getUserID(payload) {
98
+ const logger = useLogger();
97
99
  if (!payload['code'] || !payload['codeVerifier'] || !payload['state']) {
98
100
  logger.warn('[OpenID] No code, codeVerifier or state in payload');
99
101
  throw new InvalidCredentialsError();
@@ -181,6 +183,7 @@ export class OpenIDAuthDriver extends LocalAuthDriver {
181
183
  return this.refresh(user);
182
184
  }
183
185
  async refresh(user) {
186
+ const logger = useLogger();
184
187
  let authData = user.auth_data;
185
188
  if (typeof authData === 'string') {
186
189
  try {
@@ -208,6 +211,7 @@ export class OpenIDAuthDriver extends LocalAuthDriver {
208
211
  }
209
212
  }
210
213
  const handleError = (e) => {
214
+ const logger = useLogger();
211
215
  if (e instanceof errors.OPError) {
212
216
  if (e.error === 'invalid_grant') {
213
217
  // Invalid token
@@ -230,6 +234,7 @@ const handleError = (e) => {
230
234
  return e;
231
235
  };
232
236
  export function createOpenIDAuthRouter(providerName) {
237
+ const env = useEnv();
233
238
  const router = Router();
234
239
  router.get('/', asyncHandler(async (req, res) => {
235
240
  const provider = getAuthProvider(providerName);
@@ -249,6 +254,7 @@ export function createOpenIDAuthRouter(providerName) {
249
254
  res.redirect(303, `./callback?${new URLSearchParams(req.body)}`);
250
255
  }, respond);
251
256
  router.get('/callback', asyncHandler(async (req, res, next) => {
257
+ const logger = useLogger();
252
258
  let tokenData;
253
259
  try {
254
260
  tokenData = jwt.verify(req.cookies[`openid.${providerName}`], env['SECRET'], {
@@ -1,14 +1,13 @@
1
1
  import * as validator from '@authenio/samlify-node-xmllint';
2
- import { isDirectusError } from '@directus/errors';
2
+ import { useEnv } from '@directus/env';
3
+ import { ErrorCode, InvalidCredentialsError, InvalidProviderError, isDirectusError } from '@directus/errors';
3
4
  import express, { Router } from 'express';
4
5
  import * as samlify from 'samlify';
5
6
  import { getAuthProvider } from '../../auth.js';
6
7
  import { COOKIE_OPTIONS } from '../../constants.js';
7
8
  import getDatabase from '../../database/index.js';
8
9
  import emitter from '../../emitter.js';
9
- import env from '../../env.js';
10
- import { ErrorCode, InvalidCredentialsError, InvalidProviderError } from '@directus/errors';
11
- import logger from '../../logger.js';
10
+ import { useLogger } from '../../logger.js';
12
11
  import { respond } from '../../middleware/respond.js';
13
12
  import { AuthenticationService } from '../../services/authentication.js';
14
13
  import { UsersService } from '../../services/users.js';
@@ -38,6 +37,7 @@ export class SAMLAuthDriver extends LocalAuthDriver {
38
37
  return user?.id;
39
38
  }
40
39
  async getUserID(payload) {
40
+ const logger = useLogger();
41
41
  const { provider, emailKey, identifierKey, givenNameKey, familyNameKey, allowPublicRegistration } = this.config;
42
42
  const email = payload[emailKey ?? 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress'];
43
43
  const identifier = payload[identifierKey ?? 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier'];
@@ -79,6 +79,7 @@ export class SAMLAuthDriver extends LocalAuthDriver {
79
79
  }
80
80
  export function createSAMLAuthRouter(providerName) {
81
81
  const router = Router();
82
+ const env = useEnv();
82
83
  router.get('/metadata', asyncHandler(async (_req, res) => {
83
84
  const { sp } = getAuthProvider(providerName);
84
85
  return res.header('Content-Type', 'text/xml').send(sp.getMetadata());
@@ -106,6 +107,7 @@ export function createSAMLAuthRouter(providerName) {
106
107
  return res.redirect(context);
107
108
  }));
108
109
  router.post('/acs', express.urlencoded({ extended: false }), asyncHandler(async (req, res, next) => {
110
+ const logger = useLogger();
109
111
  const relayState = req.body?.RelayState;
110
112
  try {
111
113
  const { sp, idp } = getAuthProvider(providerName);
package/dist/auth.js CHANGED
@@ -1,15 +1,15 @@
1
+ import { useEnv } from '@directus/env';
2
+ import { InvalidProviderConfigError } from '@directus/errors';
1
3
  import { toArray } from '@directus/utils';
2
4
  import { LDAPAuthDriver, LocalAuthDriver, OAuth2AuthDriver, OpenIDAuthDriver, SAMLAuthDriver, } from './auth/drivers/index.js';
3
5
  import { DEFAULT_AUTH_PROVIDER } from './constants.js';
4
6
  import getDatabase from './database/index.js';
5
- import env from './env.js';
6
- import { InvalidProviderConfigError } from '@directus/errors';
7
- import logger from './logger.js';
7
+ import { useLogger } from './logger.js';
8
8
  import { getConfigFromEnv } from './utils/get-config-from-env.js';
9
9
  import { getSchema } from './utils/get-schema.js';
10
- const providerNames = toArray(env['AUTH_PROVIDERS']);
11
10
  const providers = new Map();
12
11
  export function getAuthProvider(provider) {
12
+ const logger = useLogger();
13
13
  if (!providers.has(provider)) {
14
14
  logger.error('Auth provider not configured');
15
15
  throw new InvalidProviderConfigError({ provider });
@@ -17,7 +17,10 @@ export function getAuthProvider(provider) {
17
17
  return providers.get(provider);
18
18
  }
19
19
  export async function registerAuthProviders() {
20
+ const env = useEnv();
21
+ const logger = useLogger();
20
22
  const options = { knex: getDatabase(), schema: await getSchema() };
23
+ const providerNames = toArray(env['AUTH_PROVIDERS']);
21
24
  // Register default provider if not disabled
22
25
  if (!env['AUTH_DISABLE_DEFAULT']) {
23
26
  const defaultProvider = getProviderInstance('local', options);
@@ -0,0 +1 @@
1
+ export { useBus } from './lib/use-bus.js';
@@ -0,0 +1 @@
1
+ export { useBus } from './lib/use-bus.js';
@@ -0,0 +1,9 @@
1
+ import { type Bus } from '@directus/memory';
2
+ export declare const _cache: {
3
+ bus: Bus | undefined;
4
+ };
5
+ /**
6
+ * Returns globally shared message bus. If Redis is available, will use a redis-driven pub/sub bus.
7
+ * Otherwise will default to a local-only bus.
8
+ */
9
+ export declare const useBus: () => Bus;
@@ -0,0 +1,21 @@
1
+ import { createBus } from '@directus/memory';
2
+ import { redisConfigAvailable, useRedis } from '../../redis/index.js';
3
+ export const _cache = {
4
+ bus: undefined,
5
+ };
6
+ /**
7
+ * Returns globally shared message bus. If Redis is available, will use a redis-driven pub/sub bus.
8
+ * Otherwise will default to a local-only bus.
9
+ */
10
+ export const useBus = () => {
11
+ if (_cache.bus) {
12
+ return _cache.bus;
13
+ }
14
+ if (redisConfigAvailable()) {
15
+ _cache.bus = createBus({ type: 'redis', redis: useRedis(), namespace: 'directus:bus' });
16
+ }
17
+ else {
18
+ _cache.bus = createBus({ type: 'local' });
19
+ }
20
+ return _cache.bus;
21
+ };
package/dist/cache.js CHANGED
@@ -1,13 +1,16 @@
1
+ import { useEnv } from '@directus/env';
1
2
  import { getSimpleHash } from '@directus/utils';
2
3
  import Keyv from 'keyv';
3
- import env from './env.js';
4
- import logger from './logger.js';
5
- import { getMessenger } from './messenger.js';
4
+ import { useBus } from './bus/index.js';
5
+ import { useLogger } from './logger.js';
6
+ import { redisConfigAvailable } from './redis/index.js';
6
7
  import { compress, decompress } from './utils/compress.js';
7
8
  import { getConfigFromEnv } from './utils/get-config-from-env.js';
8
9
  import { getMilliseconds } from './utils/get-milliseconds.js';
9
10
  import { validateEnv } from './utils/validate-env.js';
10
11
  import { createRequire } from 'node:module';
12
+ const logger = useLogger();
13
+ const env = useEnv();
11
14
  const require = createRequire(import.meta.url);
12
15
  let cache = null;
13
16
  let systemCache = null;
@@ -15,11 +18,8 @@ let localSchemaCache = null;
15
18
  let sharedSchemaCache = null;
16
19
  let lockCache = null;
17
20
  let messengerSubscribed = false;
18
- const messenger = getMessenger();
19
- if (env['MESSENGER_STORE'] === 'redis' &&
20
- env['CACHE_STORE'] === 'memory' &&
21
- env['CACHE_AUTO_PURGE'] &&
22
- !messengerSubscribed) {
21
+ const messenger = useBus();
22
+ if (redisConfigAvailable() && env['CACHE_STORE'] === 'memory' && env['CACHE_AUTO_PURGE'] && !messengerSubscribed) {
23
23
  messengerSubscribed = true;
24
24
  messenger.subscribe('schemaChanged', async (opts) => {
25
25
  if (cache && opts?.['autoPurgeCache'] !== false) {
@@ -122,7 +122,7 @@ function getConfig(store = 'memory', ttl, namespaceSuffix = '') {
122
122
  };
123
123
  if (store === 'redis') {
124
124
  const KeyvRedis = require('@keyv/redis');
125
- config.store = new KeyvRedis(env['REDIS'] || getConfigFromEnv('REDIS'));
125
+ config.store = new KeyvRedis(env['REDIS'] || getConfigFromEnv('REDIS'), { useRedisSets: false });
126
126
  }
127
127
  return config;
128
128
  }
@@ -1,15 +1,17 @@
1
+ import { useEnv } from '@directus/env';
1
2
  import getDatabase, { hasDatabaseConnection, isInstalled, validateDatabaseConnection, } from '../../../database/index.js';
2
3
  import runMigrations from '../../../database/migrations/run.js';
3
4
  import installDatabase from '../../../database/seeds/run.js';
4
- import env from '../../../env.js';
5
- import logger from '../../../logger.js';
5
+ import { useLogger } from '../../../logger.js';
6
6
  import { RolesService } from '../../../services/roles.js';
7
7
  import { SettingsService } from '../../../services/settings.js';
8
8
  import { UsersService } from '../../../services/users.js';
9
9
  import { getSchema } from '../../../utils/get-schema.js';
10
10
  import { defaultAdminRole, defaultAdminUser } from '../../utils/defaults.js';
11
11
  export default async function bootstrap({ skipAdminInit }) {
12
+ const logger = useLogger();
12
13
  logger.info('Initializing bootstrap...');
14
+ const env = useEnv();
13
15
  const database = getDatabase();
14
16
  await waitForDatabase(database);
15
17
  if ((await isInstalled()) === false) {
@@ -52,6 +54,8 @@ async function waitForDatabase(database) {
52
54
  return database;
53
55
  }
54
56
  async function createDefaultAdmin(schema) {
57
+ const logger = useLogger();
58
+ const env = useEnv();
55
59
  const { nanoid } = await import('nanoid');
56
60
  logger.info('Setting up first admin role...');
57
61
  const rolesService = new RolesService({ schema });
@@ -1,7 +1,8 @@
1
1
  import getDatabase from '../../../database/index.js';
2
- import logger from '../../../logger.js';
2
+ import { useLogger } from '../../../logger.js';
3
3
  export default async function count(collection) {
4
4
  const database = getDatabase();
5
+ const logger = useLogger();
5
6
  if (!collection) {
6
7
  logger.error('Collection is required');
7
8
  process.exit(1);
@@ -1,8 +1,9 @@
1
1
  import installSeeds from '../../../database/seeds/run.js';
2
2
  import getDatabase from '../../../database/index.js';
3
- import logger from '../../../logger.js';
3
+ import { useLogger } from '../../../logger.js';
4
4
  export default async function start() {
5
5
  const database = getDatabase();
6
+ const logger = useLogger();
6
7
  try {
7
8
  await installSeeds(database);
8
9
  database.destroy();
@@ -1,8 +1,9 @@
1
1
  import run from '../../../database/migrations/run.js';
2
2
  import getDatabase from '../../../database/index.js';
3
- import logger from '../../../logger.js';
3
+ import { useLogger } from '../../../logger.js';
4
4
  export default async function migrate(direction) {
5
5
  const database = getDatabase();
6
+ const logger = useLogger();
6
7
  try {
7
8
  logger.info('Running migrations...');
8
9
  await run(database, direction);
@@ -1,9 +1,10 @@
1
1
  import { getSchema } from '../../../utils/get-schema.js';
2
2
  import { RolesService } from '../../../services/roles.js';
3
3
  import getDatabase from '../../../database/index.js';
4
- import logger from '../../../logger.js';
4
+ import { useLogger } from '../../../logger.js';
5
5
  export default async function rolesCreate({ role: name, admin }) {
6
6
  const database = getDatabase();
7
+ const logger = useLogger();
7
8
  if (!name) {
8
9
  logger.error('Name is required');
9
10
  process.exit(1);