diff --git a/.eslintrc.js b/.eslintrc.js index b3761c4a2b..4f3aa37730 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -20,17 +20,11 @@ module.exports = { extends: ['eslint:recommended', 'prettier'], rules: defaultRules, parserOptions: { - ecmaVersion: 2020, + ecmaVersion: 2022, + sourceType: 'module', }, overrides: [ - // Parse config files as modules - { - files: ['rollup.config.js', 'vite?(st).config.js', 'api/globalSetup.js'], - parserOptions: { - sourceType: 'module', - }, - rules: defaultRules, - }, + // Jest { files: ['**/*.test.js'], env: { diff --git a/api/cli.js b/api/cli.js index 6c1cc9f5c0..c4799493e2 100755 --- a/api/cli.js +++ b/api/cli.js @@ -1,2 +1,2 @@ #!/usr/bin/env node -require('./dist/cli/run.js'); +import './dist/cli/run.js'; diff --git a/api/package.json b/api/package.json index 1b1b8576dd..4672a80aeb 100644 --- a/api/package.json +++ b/api/package.json @@ -2,6 +2,7 @@ "name": "directus", "version": "9.24.0", "description": "Directus is a real-time API and App dashboard for managing SQL database content", + "type": "module", "keywords": [ "directus", "realtime", @@ -65,8 +66,8 @@ ], "scripts": { "build": "tsc --build && copyfiles \"src/**/*.{yaml,liquid}\" -u 1 dist", - "cli": "NODE_ENV=development SERVE_APP=false ts-node --script-mode --transpile-only src/cli/run.ts", - "dev": "NODE_ENV=development SERVE_APP=false ts-node-dev --files --transpile-only --respawn --watch \".env\" --inspect=0 --exit-child -- src/start.ts", + "cli": "NODE_ENV=development SERVE_APP=false node --loader @esbuild-kit/esm-loader src/cli/run.ts", + "dev": "NODE_ENV=development SERVE_APP=false node --loader @esbuild-kit/esm-loader --watch --inspect=0 src/start.ts", "start": "node cli.js start", "test": "vitest run", "test:coverage": "vitest run --coverage", @@ -76,10 +77,11 @@ "@authenio/samlify-node-xmllint": "2.0.0", "@aws-sdk/client-ses": "3.292.0", "@directus/app": "workspace:*", + "@directus/constants": "workspace:*", + "@directus/exceptions": "workspace:*", "@directus/extensions-sdk": "workspace:*", - "@directus/format-title": "9.15.0", + "@directus/format-title": "10.0.0", "@directus/schema": "workspace:*", - "@directus/shared": "workspace:*", "@directus/specs": "workspace:*", "@directus/storage": "workspace:*", "@directus/storage-driver-azure": "workspace:*", @@ -87,6 +89,7 @@ "@directus/storage-driver-gcs": "workspace:*", "@directus/storage-driver-local": "workspace:*", "@directus/storage-driver-s3": "workspace:*", + "@directus/update-check": "workspace:*", "@directus/utils": "workspace:*", "@godaddy/terminus": "4.11.2", "@rollup/plugin-alias": "4.0.3", @@ -129,10 +132,9 @@ "jsonwebtoken": "9.0.0", "keyv": "4.5.2", "knex": "2.4.2", - "knex-schema-inspector": "3.0.1", "ldapjs": "2.3.3", "liquidjs": "10.6.1", - "lodash": "4.17.21", + "lodash-es": "4.17.21", "marked": "4.2.12", "micromustache": "8.0.3", "mime-types": "2.1.35", @@ -160,13 +162,15 @@ "stream-json": "1.7.5", "strip-bom-stream": "4.0.0", "tmp-promise": "3.0.3", - "update-check": "1.5.4", "uuid": "9.0.0", "uuid-validate": "0.0.3", "vm2": "3.9.14", "wellknown": "0.5.0" }, "devDependencies": { + "@directus/tsconfig": "0.0.6", + "@directus/types": "workspace:*", + "@esbuild-kit/esm-loader": "2.5.5", "@ngneat/falso": "6.4.0", "@types/async": "3.2.18", "@types/busboy": "1.5.0", @@ -188,7 +192,7 @@ "@types/jsonwebtoken": "9.0.1", "@types/keyv": "3.1.4", "@types/ldapjs": "2.2.5", - "@types/lodash": "4.14.191", + "@types/lodash-es": "4.17.7", "@types/marked": "4.0.8", "@types/mime-types": "2.1.1", "@types/ms": "0.7.31", @@ -207,8 +211,6 @@ "copyfiles": "2.4.1", "form-data": "4.0.0", "knex-mock-client": "2.0.0", - "ts-node": "10.9.1", - "ts-node-dev": "2.0.0", "typescript": "4.9.5", "vitest": "0.29.3" }, diff --git a/api/src/__utils__/schemas.ts b/api/src/__utils__/schemas.ts index c66549c6fc..384b62fcc6 100644 --- a/api/src/__utils__/schemas.ts +++ b/api/src/__utils__/schemas.ts @@ -1,4 +1,4 @@ -import type { CollectionsOverview, Relation } from '@directus/shared/types'; +import type { CollectionsOverview, Relation } from '@directus/types'; export const systemSchema = { collections: { diff --git a/api/src/__utils__/snapshots.ts b/api/src/__utils__/snapshots.ts index 90e080a101..33698e6387 100644 --- a/api/src/__utils__/snapshots.ts +++ b/api/src/__utils__/snapshots.ts @@ -1,4 +1,4 @@ -import type { Snapshot, SnapshotField, SnapshotRelation } from '../types'; +import type { Snapshot, SnapshotField, SnapshotRelation } from '../types/index.js'; export const snapshotBeforeCreateCollection: Snapshot = { version: 1, diff --git a/api/src/app.test.ts b/api/src/app.test.ts index 407e71d4c2..d68fbf6be2 100644 --- a/api/src/app.test.ts +++ b/api/src/app.test.ts @@ -1,8 +1,7 @@ import { Router } from 'express'; import request from 'supertest'; import { describe, expect, test, vi } from 'vitest'; - -import createApp from './app'; +import createApp from './app.js'; vi.mock('./database', () => ({ default: vi.fn(), diff --git a/api/src/app.ts b/api/src/app.ts index c69a38bb91..68e117aeb2 100644 --- a/api/src/app.ts +++ b/api/src/app.ts @@ -1,65 +1,72 @@ import cookieParser from 'cookie-parser'; import express, { Request, RequestHandler, Response } from 'express'; -import fse from 'fs-extra'; import type { ServerResponse } from 'http'; +import { merge } from 'lodash-es'; +import { readFile } from 'node:fs/promises'; +import { createRequire } from 'node:module'; import path from 'path'; import qs from 'qs'; -import activityRouter from './controllers/activity'; -import assetsRouter from './controllers/assets'; -import authRouter from './controllers/auth'; -import collectionsRouter from './controllers/collections'; -import dashboardsRouter from './controllers/dashboards'; -import extensionsRouter from './controllers/extensions'; -import fieldsRouter from './controllers/fields'; -import filesRouter from './controllers/files'; -import flowsRouter from './controllers/flows'; -import foldersRouter from './controllers/folders'; -import graphqlRouter from './controllers/graphql'; -import itemsRouter from './controllers/items'; -import notFoundHandler from './controllers/not-found'; -import notificationsRouter from './controllers/notifications'; -import operationsRouter from './controllers/operations'; -import panelsRouter from './controllers/panels'; -import permissionsRouter from './controllers/permissions'; -import presetsRouter from './controllers/presets'; -import relationsRouter from './controllers/relations'; -import revisionsRouter from './controllers/revisions'; -import rolesRouter from './controllers/roles'; -import schemaRouter from './controllers/schema'; -import serverRouter from './controllers/server'; -import settingsRouter from './controllers/settings'; -import sharesRouter from './controllers/shares'; -import usersRouter from './controllers/users'; -import utilsRouter from './controllers/utils'; -import webhooksRouter from './controllers/webhooks'; -import { isInstalled, validateDatabaseConnection, validateDatabaseExtensions, validateMigrations } from './database'; -import emitter from './emitter'; -import env from './env'; -import { InvalidPayloadException } from './exceptions'; -import { getExtensionManager } from './extensions'; -import { getFlowManager } from './flows'; -import logger, { expressLogger } from './logger'; -import authenticate from './middleware/authenticate'; -import cache from './middleware/cache'; -import { checkIP } from './middleware/check-ip'; -import cors from './middleware/cors'; -import errorHandler from './middleware/error-handler'; -import extractToken from './middleware/extract-token'; -import getPermissions from './middleware/get-permissions'; -import rateLimiterGlobal from './middleware/rate-limiter-global'; -import rateLimiter from './middleware/rate-limiter-ip'; -import sanitizeQuery from './middleware/sanitize-query'; -import schema from './middleware/schema'; +import { registerAuthProviders } from './auth.js'; +import { flushCaches } from './cache.js'; +import activityRouter from './controllers/activity.js'; +import assetsRouter from './controllers/assets.js'; +import authRouter from './controllers/auth.js'; +import collectionsRouter from './controllers/collections.js'; +import dashboardsRouter from './controllers/dashboards.js'; +import extensionsRouter from './controllers/extensions.js'; +import fieldsRouter from './controllers/fields.js'; +import filesRouter from './controllers/files.js'; +import flowsRouter from './controllers/flows.js'; +import foldersRouter from './controllers/folders.js'; +import graphqlRouter from './controllers/graphql.js'; +import itemsRouter from './controllers/items.js'; +import notFoundHandler from './controllers/not-found.js'; +import notificationsRouter from './controllers/notifications.js'; +import operationsRouter from './controllers/operations.js'; +import panelsRouter from './controllers/panels.js'; +import permissionsRouter from './controllers/permissions.js'; +import presetsRouter from './controllers/presets.js'; +import relationsRouter from './controllers/relations.js'; +import revisionsRouter from './controllers/revisions.js'; +import rolesRouter from './controllers/roles.js'; +import schemaRouter from './controllers/schema.js'; +import serverRouter from './controllers/server.js'; +import settingsRouter from './controllers/settings.js'; +import sharesRouter from './controllers/shares.js'; +import usersRouter from './controllers/users.js'; +import utilsRouter from './controllers/utils.js'; +import webhooksRouter from './controllers/webhooks.js'; +import { + isInstalled, + validateDatabaseConnection, + validateDatabaseExtensions, + validateMigrations, +} from './database/index.js'; +import emitter from './emitter.js'; +import env from './env.js'; +import { InvalidPayloadException } from './exceptions/invalid-payload.js'; +import { getExtensionManager } from './extensions.js'; +import { getFlowManager } from './flows.js'; +import logger, { expressLogger } from './logger.js'; +import authenticate from './middleware/authenticate.js'; +import cache from './middleware/cache.js'; +import { checkIP } from './middleware/check-ip.js'; +import cors from './middleware/cors.js'; +import errorHandler from './middleware/error-handler.js'; +import extractToken from './middleware/extract-token.js'; +import getPermissions from './middleware/get-permissions.js'; +import rateLimiterGlobal from './middleware/rate-limiter-global.js'; +import rateLimiter from './middleware/rate-limiter-ip.js'; +import sanitizeQuery from './middleware/sanitize-query.js'; +import schema from './middleware/schema.js'; +import { getConfigFromEnv } from './utils/get-config-from-env.js'; +import { collectTelemetry } from './utils/telemetry.js'; +import { Url } from './utils/url.js'; +import { validateEnv } from './utils/validate-env.js'; +import { validateStorage } from './utils/validate-storage.js'; +import { init as initWebhooks } from './webhooks.js'; -import { merge } from 'lodash'; -import { registerAuthProviders } from './auth'; -import { flushCaches } from './cache'; -import { getConfigFromEnv } from './utils/get-config-from-env'; -import { collectTelemetry } from './utils/telemetry'; -import { Url } from './utils/url'; -import { validateEnv } from './utils/validate-env'; -import { validateStorage } from './utils/validate-storage'; -import { init as initWebhooks } from './webhooks'; +const require = createRequire(import.meta.url); export default async function createApp(): Promise { const helmet = await import('helmet'); @@ -186,7 +193,7 @@ export default async function createApp(): Promise { const embeds = extensionManager.getEmbeds(); // Set the App's base path according to the APIs public URL - const html = await fse.readFile(adminPath, 'utf8'); + const html = await readFile(adminPath, 'utf8'); const htmlWithVars = html .replace(//, ``) .replace(//, embeds.head) diff --git a/api/src/auth.ts b/api/src/auth.ts index 18b6fc560f..e4c2d81da7 100644 --- a/api/src/auth.ts +++ b/api/src/auth.ts @@ -1,14 +1,20 @@ -import { toArray } from '@directus/shared/utils'; -import type { AuthDriver } from './auth/auth'; -import { LDAPAuthDriver, LocalAuthDriver, OAuth2AuthDriver, OpenIDAuthDriver, SAMLAuthDriver } from './auth/drivers'; -import { DEFAULT_AUTH_PROVIDER } from './constants'; -import getDatabase from './database'; -import env from './env'; -import { InvalidConfigException } from './exceptions'; -import logger from './logger'; -import type { AuthDriverOptions } from './types'; -import { getConfigFromEnv } from './utils/get-config-from-env'; -import { getSchema } from './utils/get-schema'; +import { toArray } from '@directus/utils'; +import type { AuthDriver } from './auth/auth.js'; +import { + LDAPAuthDriver, + LocalAuthDriver, + OAuth2AuthDriver, + OpenIDAuthDriver, + SAMLAuthDriver, +} from './auth/drivers/index.js'; +import { DEFAULT_AUTH_PROVIDER } from './constants.js'; +import getDatabase from './database/index.js'; +import env from './env.js'; +import { InvalidConfigException } from './exceptions/invalid-config.js'; +import logger from './logger.js'; +import type { AuthDriverOptions } from './types/index.js'; +import { getConfigFromEnv } from './utils/get-config-from-env.js'; +import { getSchema } from './utils/get-schema.js'; const providerNames = toArray(env['AUTH_PROVIDERS']); diff --git a/api/src/auth/auth.ts b/api/src/auth/auth.ts index f16c38d03a..72315a545d 100644 --- a/api/src/auth/auth.ts +++ b/api/src/auth/auth.ts @@ -1,6 +1,6 @@ -import type { SchemaOverview } from '@directus/shared/types'; +import type { SchemaOverview } from '@directus/types'; import type { Knex } from 'knex'; -import type { AuthDriverOptions, User } from '../types'; +import type { AuthDriverOptions, User } from '../types/index.js'; export abstract class AuthDriver { knex: Knex; diff --git a/api/src/auth/drivers/index.ts b/api/src/auth/drivers/index.ts index e204e61673..e71b8cb123 100644 --- a/api/src/auth/drivers/index.ts +++ b/api/src/auth/drivers/index.ts @@ -1,5 +1,5 @@ -export * from './local'; -export * from './oauth2'; -export * from './openid'; -export * from './ldap'; -export * from './saml'; +export * from './local.js'; +export * from './oauth2.js'; +export * from './openid.js'; +export * from './ldap.js'; +export * from './saml.js'; diff --git a/api/src/auth/drivers/ldap.ts b/api/src/auth/drivers/ldap.ts index 139abe27fc..ddae2a14a9 100644 --- a/api/src/auth/drivers/ldap.ts +++ b/api/src/auth/drivers/ldap.ts @@ -1,18 +1,10 @@ -import type { Accountability } from '@directus/shared/types'; +import type { Accountability } from '@directus/types'; import { Router } from 'express'; import Joi from 'joi'; -import ldap, { - Client, - EqualityFilter, - Error, - InappropriateAuthenticationError, - InsufficientAccessRightsError, - InvalidCredentialsError, - LDAPResult, - SearchCallbackResponse, - SearchEntry, -} from 'ldapjs'; -import env from '../../env'; +import type { Client, Error, LDAPResult, SearchCallbackResponse, SearchEntry } from 'ldapjs'; +import ldap from 'ldapjs'; +import env from '../../env.js'; +import { RecordNotUniqueException } from '../../exceptions/database/record-not-unique.js'; import { InvalidConfigException, InvalidCredentialsException, @@ -20,16 +12,16 @@ import { InvalidProviderException, ServiceUnavailableException, UnexpectedResponseException, -} from '../../exceptions'; -import { RecordNotUniqueException } from '../../exceptions/database/record-not-unique'; -import logger from '../../logger'; -import { respond } from '../../middleware/respond'; -import { AuthenticationService, UsersService } from '../../services'; -import type { AuthDriverOptions, User } from '../../types'; -import asyncHandler from '../../utils/async-handler'; -import { getIPFromReq } from '../../utils/get-ip-from-req'; -import { getMilliseconds } from '../../utils/get-milliseconds'; -import { AuthDriver } from '../auth'; +} from '../../exceptions/index.js'; +import logger from '../../logger.js'; +import { respond } from '../../middleware/respond.js'; +import { AuthenticationService } from '../../services/authentication.js'; +import { UsersService } from '../../services/users.js'; +import type { AuthDriverOptions, User } from '../../types/index.js'; +import asyncHandler from '../../utils/async-handler.js'; +import { getIPFromReq } from '../../utils/get-ip-from-req.js'; +import { getMilliseconds } from '../../utils/get-milliseconds.js'; +import { AuthDriver } from '../auth.js'; interface UserInfo { dn: string; @@ -121,7 +113,7 @@ export class LDAPAuthDriver extends AuthDriver { private async fetchUserInfo( baseDn: string, - filter?: EqualityFilter, + filter?: ldap.EqualityFilter, scope?: SearchScope ): Promise { let { firstNameAttribute, lastNameAttribute, mailAttribute } = this.config; @@ -178,7 +170,7 @@ export class LDAPAuthDriver extends AuthDriver { }); } - private async fetchUserGroups(baseDn: string, filter?: EqualityFilter, scope?: SearchScope): Promise { + private async fetchUserGroups(baseDn: string, filter?: ldap.EqualityFilter, scope?: SearchScope): Promise { return new Promise((resolve, reject) => { let userGroups: string[] = []; @@ -237,7 +229,7 @@ export class LDAPAuthDriver extends AuthDriver { const userInfo = await this.fetchUserInfo( userDn, - new EqualityFilter({ + new ldap.EqualityFilter({ attribute: userAttribute ?? 'cn', value: payload['identifier'], }), @@ -253,7 +245,7 @@ export class LDAPAuthDriver extends AuthDriver { if (groupDn) { const userGroups = await this.fetchUserGroups( groupDn, - new EqualityFilter({ + new ldap.EqualityFilter({ attribute: groupAttribute ?? 'member', value: groupAttribute?.toLowerCase() === 'memberuid' && userInfo.uid ? userInfo.uid : userInfo.dn, }), @@ -351,9 +343,9 @@ export class LDAPAuthDriver extends AuthDriver { const handleError = (e: Error) => { if ( - e instanceof InappropriateAuthenticationError || - e instanceof InvalidCredentialsError || - e instanceof InsufficientAccessRightsError + e instanceof ldap.InappropriateAuthenticationError || + e instanceof ldap.InvalidCredentialsError || + e instanceof ldap.InsufficientAccessRightsError ) { return new InvalidCredentialsException(); } diff --git a/api/src/auth/drivers/local.ts b/api/src/auth/drivers/local.ts index 4882d63701..c4b21b7fdb 100644 --- a/api/src/auth/drivers/local.ts +++ b/api/src/auth/drivers/local.ts @@ -1,18 +1,18 @@ -import type { Accountability } from '@directus/shared/types'; +import type { Accountability } from '@directus/types'; import argon2 from 'argon2'; import { Router } from 'express'; import Joi from 'joi'; import { performance } from 'perf_hooks'; -import { COOKIE_OPTIONS } from '../../constants'; -import env from '../../env'; -import { InvalidCredentialsException, InvalidPayloadException } from '../../exceptions'; -import { respond } from '../../middleware/respond'; -import { AuthenticationService } from '../../services'; -import type { User } from '../../types'; -import asyncHandler from '../../utils/async-handler'; -import { getIPFromReq } from '../../utils/get-ip-from-req'; -import { stall } from '../../utils/stall'; -import { AuthDriver } from '../auth'; +import { COOKIE_OPTIONS } from '../../constants.js'; +import env from '../../env.js'; +import { InvalidCredentialsException, InvalidPayloadException } from '../../exceptions/index.js'; +import { respond } from '../../middleware/respond.js'; +import { AuthenticationService } from '../../services/authentication.js'; +import type { User } from '../../types/index.js'; +import asyncHandler from '../../utils/async-handler.js'; +import { getIPFromReq } from '../../utils/get-ip-from-req.js'; +import { stall } from '../../utils/stall.js'; +import { AuthDriver } from '../auth.js'; export class LocalAuthDriver extends AuthDriver { async getUserID(payload: Record): Promise { diff --git a/api/src/auth/drivers/oauth2.ts b/api/src/auth/drivers/oauth2.ts index edcb224507..8171fc081d 100644 --- a/api/src/auth/drivers/oauth2.ts +++ b/api/src/auth/drivers/oauth2.ts @@ -1,30 +1,31 @@ -import { BaseException } from '@directus/shared/exceptions'; -import type { Accountability } from '@directus/shared/types'; -import { parseJSON } from '@directus/shared/utils'; +import { BaseException } from '@directus/exceptions'; +import type { Accountability } from '@directus/types'; +import { parseJSON } from '@directus/utils'; import express, { Router } from 'express'; import flatten from 'flat'; import jwt from 'jsonwebtoken'; import { Client, errors, generators, Issuer } from 'openid-client'; -import { getAuthProvider } from '../../auth'; -import env from '../../env'; +import { getAuthProvider } from '../../auth.js'; +import env from '../../env.js'; +import { RecordNotUniqueException } from '../../exceptions/database/record-not-unique.js'; import { InvalidConfigException, InvalidCredentialsException, InvalidProviderException, InvalidTokenException, ServiceUnavailableException, -} from '../../exceptions'; -import { RecordNotUniqueException } from '../../exceptions/database/record-not-unique'; -import logger from '../../logger'; -import { respond } from '../../middleware/respond'; -import { AuthenticationService, UsersService } from '../../services'; -import type { AuthData, AuthDriverOptions, User } from '../../types'; -import asyncHandler from '../../utils/async-handler'; -import { getConfigFromEnv } from '../../utils/get-config-from-env'; -import { getIPFromReq } from '../../utils/get-ip-from-req'; -import { getMilliseconds } from '../../utils/get-milliseconds'; -import { Url } from '../../utils/url'; -import { LocalAuthDriver } from './local'; +} from '../../exceptions/index.js'; +import logger from '../../logger.js'; +import { respond } from '../../middleware/respond.js'; +import { AuthenticationService } from '../../services/authentication.js'; +import { UsersService } from '../../services/users.js'; +import type { AuthData, AuthDriverOptions, User } from '../../types/index.js'; +import asyncHandler from '../../utils/async-handler.js'; +import { getConfigFromEnv } from '../../utils/get-config-from-env.js'; +import { getIPFromReq } from '../../utils/get-ip-from-req.js'; +import { getMilliseconds } from '../../utils/get-milliseconds.js'; +import { Url } from '../../utils/url.js'; +import { LocalAuthDriver } from './local.js'; export class OAuth2AuthDriver extends LocalAuthDriver { client: Client; diff --git a/api/src/auth/drivers/openid.ts b/api/src/auth/drivers/openid.ts index 7acfba5976..4c75a9025d 100644 --- a/api/src/auth/drivers/openid.ts +++ b/api/src/auth/drivers/openid.ts @@ -1,30 +1,31 @@ -import { BaseException } from '@directus/shared/exceptions'; -import type { Accountability } from '@directus/shared/types'; -import { parseJSON } from '@directus/shared/utils'; +import { BaseException } from '@directus/exceptions'; +import type { Accountability } from '@directus/types'; +import { parseJSON } from '@directus/utils'; import express, { Router } from 'express'; import flatten from 'flat'; import jwt from 'jsonwebtoken'; import { Client, errors, generators, Issuer } from 'openid-client'; -import { getAuthProvider } from '../../auth'; -import env from '../../env'; +import { getAuthProvider } from '../../auth.js'; +import env from '../../env.js'; +import { RecordNotUniqueException } from '../../exceptions/database/record-not-unique.js'; import { InvalidConfigException, InvalidCredentialsException, InvalidProviderException, InvalidTokenException, ServiceUnavailableException, -} from '../../exceptions'; -import { RecordNotUniqueException } from '../../exceptions/database/record-not-unique'; -import logger from '../../logger'; -import { respond } from '../../middleware/respond'; -import { AuthenticationService, UsersService } from '../../services'; -import type { AuthData, AuthDriverOptions, User } from '../../types'; -import asyncHandler from '../../utils/async-handler'; -import { getConfigFromEnv } from '../../utils/get-config-from-env'; -import { getIPFromReq } from '../../utils/get-ip-from-req'; -import { getMilliseconds } from '../../utils/get-milliseconds'; -import { Url } from '../../utils/url'; -import { LocalAuthDriver } from './local'; +} from '../../exceptions/index.js'; +import logger from '../../logger.js'; +import { respond } from '../../middleware/respond.js'; +import { AuthenticationService } from '../../services/authentication.js'; +import { UsersService } from '../../services/users.js'; +import type { AuthData, AuthDriverOptions, User } from '../../types/index.js'; +import asyncHandler from '../../utils/async-handler.js'; +import { getConfigFromEnv } from '../../utils/get-config-from-env.js'; +import { getIPFromReq } from '../../utils/get-ip-from-req.js'; +import { getMilliseconds } from '../../utils/get-milliseconds.js'; +import { Url } from '../../utils/url.js'; +import { LocalAuthDriver } from './local.js'; export class OpenIDAuthDriver extends LocalAuthDriver { client: Promise; diff --git a/api/src/auth/drivers/saml.ts b/api/src/auth/drivers/saml.ts index 1ddd3ad6ad..c2da550cda 100644 --- a/api/src/auth/drivers/saml.ts +++ b/api/src/auth/drivers/saml.ts @@ -1,19 +1,20 @@ import * as validator from '@authenio/samlify-node-xmllint'; -import { BaseException } from '@directus/shared/exceptions'; +import { BaseException } from '@directus/exceptions'; import express, { Router } from 'express'; import * as samlify from 'samlify'; -import { getAuthProvider } from '../../auth'; -import { COOKIE_OPTIONS } from '../../constants'; -import env from '../../env'; -import { InvalidCredentialsException, InvalidProviderException } from '../../exceptions'; -import { RecordNotUniqueException } from '../../exceptions/database/record-not-unique'; -import logger from '../../logger'; -import { respond } from '../../middleware/respond'; -import { AuthenticationService, UsersService } from '../../services'; -import type { AuthDriverOptions, User } from '../../types'; -import asyncHandler from '../../utils/async-handler'; -import { getConfigFromEnv } from '../../utils/get-config-from-env'; -import { LocalAuthDriver } from './local'; +import { getAuthProvider } from '../../auth.js'; +import { COOKIE_OPTIONS } from '../../constants.js'; +import env from '../../env.js'; +import { RecordNotUniqueException } from '../../exceptions/database/record-not-unique.js'; +import { InvalidCredentialsException, InvalidProviderException } from '../../exceptions/index.js'; +import logger from '../../logger.js'; +import { respond } from '../../middleware/respond.js'; +import { AuthenticationService } from '../../services/authentication.js'; +import { UsersService } from '../../services/users.js'; +import type { AuthDriverOptions, User } from '../../types/index.js'; +import asyncHandler from '../../utils/async-handler.js'; +import { getConfigFromEnv } from '../../utils/get-config-from-env.js'; +import { LocalAuthDriver } from './local.js'; // tell samlify to use validator... samlify.setSchemaValidator(validator); diff --git a/api/src/cache.ts b/api/src/cache.ts index bffaba8496..7e56169f29 100644 --- a/api/src/cache.ts +++ b/api/src/cache.ts @@ -1,13 +1,16 @@ +import type { SchemaOverview } from '@directus/types'; +import { getSimpleHash } from '@directus/utils'; import Keyv, { Options } from 'keyv'; -import env from './env'; -import logger from './logger'; -import { compress, decompress } from './utils/compress'; -import { getConfigFromEnv } from './utils/get-config-from-env'; -import { getMilliseconds } from './utils/get-milliseconds'; -import { validateEnv } from './utils/validate-env'; -import { getMessenger } from './messenger'; -import { getSimpleHash } from '@directus/shared/utils'; -import type { SchemaOverview } from '@directus/shared/types'; +import env from './env.js'; +import logger from './logger.js'; +import { getMessenger } from './messenger.js'; +import { compress, decompress } from './utils/compress.js'; +import { getConfigFromEnv } from './utils/get-config-from-env.js'; +import { getMilliseconds } from './utils/get-milliseconds.js'; +import { validateEnv } from './utils/validate-env.js'; + +import { createRequire } from 'node:module'; +const require = createRequire(import.meta.url); let cache: Keyv | null = null; let systemCache: Keyv | null = null; @@ -167,7 +170,6 @@ function getConfig(store: Store = 'memory', ttl: number | undefined, namespaceSu if (store === 'redis') { const KeyvRedis = require('@keyv/redis'); - config.store = new KeyvRedis(env['CACHE_REDIS'] || getConfigFromEnv('CACHE_REDIS_')); } diff --git a/api/src/cli/commands/bootstrap/index.ts b/api/src/cli/commands/bootstrap/index.ts index 544bd4f50c..30e0612926 100644 --- a/api/src/cli/commands/bootstrap/index.ts +++ b/api/src/cli/commands/bootstrap/index.ts @@ -1,13 +1,19 @@ -import type { SchemaOverview } from '@directus/shared/types'; +import type { SchemaOverview } from '@directus/types'; import type { Knex } from 'knex'; -import getDatabase, { hasDatabaseConnection, isInstalled, validateDatabaseConnection } from '../../../database'; -import runMigrations from '../../../database/migrations/run'; -import installDatabase from '../../../database/seeds/run'; -import env from '../../../env'; -import logger from '../../../logger'; -import { RolesService, SettingsService, UsersService } from '../../../services'; -import { getSchema } from '../../../utils/get-schema'; -import { defaultAdminRole, defaultAdminUser } from '../../utils/defaults'; +import getDatabase, { + hasDatabaseConnection, + isInstalled, + validateDatabaseConnection, +} from '../../../database/index.js'; +import runMigrations from '../../../database/migrations/run.js'; +import installDatabase from '../../../database/seeds/run.js'; +import env from '../../../env.js'; +import logger from '../../../logger.js'; +import { RolesService } from '../../../services/roles.js'; +import { SettingsService } from '../../../services/settings.js'; +import { UsersService } from '../../../services/users.js'; +import { getSchema } from '../../../utils/get-schema.js'; +import { defaultAdminRole, defaultAdminUser } from '../../utils/defaults.js'; export default async function bootstrap({ skipAdminInit }: { skipAdminInit?: boolean }): Promise { logger.info('Initializing bootstrap...'); diff --git a/api/src/cli/commands/count/index.ts b/api/src/cli/commands/count/index.ts index 1e35d3d7a0..f99898b766 100644 --- a/api/src/cli/commands/count/index.ts +++ b/api/src/cli/commands/count/index.ts @@ -1,5 +1,5 @@ -import getDatabase from '../../../database'; -import logger from '../../../logger'; +import getDatabase from '../../../database/index.js'; +import logger from '../../../logger.js'; export default async function count(collection: string): Promise { const database = getDatabase(); diff --git a/api/src/cli/commands/database/install.ts b/api/src/cli/commands/database/install.ts index 147d47f501..0c71d76804 100644 --- a/api/src/cli/commands/database/install.ts +++ b/api/src/cli/commands/database/install.ts @@ -1,6 +1,6 @@ -import installSeeds from '../../../database/seeds/run'; -import getDatabase from '../../../database'; -import logger from '../../../logger'; +import installSeeds from '../../../database/seeds/run.js'; +import getDatabase from '../../../database/index.js'; +import logger from '../../../logger.js'; export default async function start(): Promise { const database = getDatabase(); diff --git a/api/src/cli/commands/database/migrate.ts b/api/src/cli/commands/database/migrate.ts index caae05408d..5026db72b9 100644 --- a/api/src/cli/commands/database/migrate.ts +++ b/api/src/cli/commands/database/migrate.ts @@ -1,6 +1,6 @@ -import run from '../../../database/migrations/run'; -import getDatabase from '../../../database'; -import logger from '../../../logger'; +import run from '../../../database/migrations/run.js'; +import getDatabase from '../../../database/index.js'; +import logger from '../../../logger.js'; export default async function migrate(direction: 'latest' | 'up' | 'down'): Promise { const database = getDatabase(); diff --git a/api/src/cli/commands/init/index.ts b/api/src/cli/commands/init/index.ts index d94daddf0c..532a899173 100644 --- a/api/src/cli/commands/init/index.ts +++ b/api/src/cli/commands/init/index.ts @@ -5,14 +5,14 @@ import Joi from 'joi'; import type { Knex } from 'knex'; import ora from 'ora'; import { v4 as uuid } from 'uuid'; -import runMigrations from '../../../database/migrations/run'; -import runSeed from '../../../database/seeds/run'; -import { generateHash } from '../../../utils/generate-hash'; -import createDBConnection, { Credentials } from '../../utils/create-db-connection'; -import createEnv from '../../utils/create-env'; -import { defaultAdminRole, defaultAdminUser } from '../../utils/defaults'; -import { drivers, getDriverForClient } from '../../utils/drivers'; -import { databaseQuestions } from './questions'; +import runMigrations from '../../../database/migrations/run.js'; +import runSeed from '../../../database/seeds/run.js'; +import { generateHash } from '../../../utils/generate-hash.js'; +import createDBConnection, { Credentials } from '../../utils/create-db-connection.js'; +import createEnv from '../../utils/create-env/index.js'; +import { defaultAdminRole, defaultAdminUser } from '../../utils/defaults.js'; +import { drivers, getDriverForClient } from '../../utils/drivers.js'; +import { databaseQuestions } from './questions.js'; export default async function init(): Promise { const rootPath = process.cwd(); diff --git a/api/src/cli/commands/roles/create.ts b/api/src/cli/commands/roles/create.ts index 1e301add25..038506cef9 100644 --- a/api/src/cli/commands/roles/create.ts +++ b/api/src/cli/commands/roles/create.ts @@ -1,7 +1,7 @@ -import { getSchema } from '../../../utils/get-schema'; -import { RolesService } from '../../../services'; -import getDatabase from '../../../database'; -import logger from '../../../logger'; +import { getSchema } from '../../../utils/get-schema.js'; +import { RolesService } from '../../../services/roles.js'; +import getDatabase from '../../../database/index.js'; +import logger from '../../../logger.js'; export default async function rolesCreate({ role: name, admin }: { role: string; admin: boolean }): Promise { const database = getDatabase(); diff --git a/api/src/cli/commands/schema/apply.ts b/api/src/cli/commands/schema/apply.ts index 15795396b5..618f3d8852 100644 --- a/api/src/cli/commands/schema/apply.ts +++ b/api/src/cli/commands/schema/apply.ts @@ -1,16 +1,16 @@ -import { parseJSON } from '@directus/shared/utils'; +import { parseJSON } from '@directus/utils'; import chalk from 'chalk'; import { promises as fs } from 'fs'; import inquirer from 'inquirer'; import { load as loadYaml } from 'js-yaml'; import path from 'path'; -import getDatabase, { isInstalled, validateDatabaseConnection } from '../../../database'; -import logger from '../../../logger'; -import { DiffKind, Snapshot } from '../../../types'; -import { isNestedMetaUpdate } from '../../../utils/apply-diff'; -import { applySnapshot } from '../../../utils/apply-snapshot'; -import { getSnapshot } from '../../../utils/get-snapshot'; -import { getSnapshotDiff } from '../../../utils/get-snapshot-diff'; +import getDatabase, { isInstalled, validateDatabaseConnection } from '../../../database/index.js'; +import logger from '../../../logger.js'; +import { DiffKind, Snapshot } from '../../../types/index.js'; +import { isNestedMetaUpdate } from '../../../utils/apply-diff.js'; +import { applySnapshot } from '../../../utils/apply-snapshot.js'; +import { getSnapshot } from '../../../utils/get-snapshot.js'; +import { getSnapshotDiff } from '../../../utils/get-snapshot-diff.js'; export async function apply(snapshotPath: string, options?: { yes: boolean; dryRun: boolean }): Promise { const filename = path.resolve(process.cwd(), snapshotPath); diff --git a/api/src/cli/commands/schema/snapshot.ts b/api/src/cli/commands/schema/snapshot.ts index 14899681a3..6990acf954 100644 --- a/api/src/cli/commands/schema/snapshot.ts +++ b/api/src/cli/commands/schema/snapshot.ts @@ -1,6 +1,6 @@ -import getDatabase from '../../../database'; -import logger from '../../../logger'; -import { getSnapshot } from '../../../utils/get-snapshot'; +import getDatabase from '../../../database/index.js'; +import logger from '../../../logger.js'; +import { getSnapshot } from '../../../utils/get-snapshot.js'; import { constants as fsConstants, promises as fs } from 'fs'; import path from 'path'; import inquirer from 'inquirer'; diff --git a/api/src/cli/commands/users/create.ts b/api/src/cli/commands/users/create.ts index b07d4080c6..b400a77907 100644 --- a/api/src/cli/commands/users/create.ts +++ b/api/src/cli/commands/users/create.ts @@ -1,7 +1,7 @@ -import { getSchema } from '../../../utils/get-schema'; -import { UsersService } from '../../../services'; -import getDatabase from '../../../database'; -import logger from '../../../logger'; +import { getSchema } from '../../../utils/get-schema.js'; +import { UsersService } from '../../../services/users.js'; +import getDatabase from '../../../database/index.js'; +import logger from '../../../logger.js'; export default async function usersCreate({ email, diff --git a/api/src/cli/commands/users/passwd.ts b/api/src/cli/commands/users/passwd.ts index 3d30401bed..d1dbba1eaf 100644 --- a/api/src/cli/commands/users/passwd.ts +++ b/api/src/cli/commands/users/passwd.ts @@ -1,8 +1,8 @@ -import { getSchema } from '../../../utils/get-schema'; -import { generateHash } from '../../../utils/generate-hash'; -import { UsersService } from '../../../services'; -import getDatabase from '../../../database'; -import logger from '../../../logger'; +import { getSchema } from '../../../utils/get-schema.js'; +import { generateHash } from '../../../utils/generate-hash.js'; +import { UsersService } from '../../../services/users.js'; +import getDatabase from '../../../database/index.js'; +import logger from '../../../logger.js'; export default async function usersPasswd({ email, password }: { email?: string; password?: string }): Promise { const database = getDatabase(); diff --git a/api/src/cli/index.test.ts b/api/src/cli/index.test.ts deleted file mode 100644 index 3ddaa9f99e..0000000000 --- a/api/src/cli/index.test.ts +++ /dev/null @@ -1,90 +0,0 @@ -import type { Extension, HookConfig } from '@directus/shared/types'; -import type { Command } from 'commander'; -import path from 'path'; -import { beforeEach, describe, expect, test, vi } from 'vitest'; -import { createCli } from './index'; - -vi.mock('../../src/env', async () => { - const actual = (await vi.importActual('../../src/env')) as { default: Record }; - const MOCK_ENV = { - ...actual.default, - EXTENSIONS_PATH: '', - SERVE_APP: false, - DB_CLIENT: 'pg', - DB_HOST: 'localhost', - DB_PORT: 5432, - DB_DATABASE: 'directus', - DB_USER: 'postgres', - DB_PASSWORD: 'psql1234', - }; - return { - default: MOCK_ENV, - getEnv: () => MOCK_ENV, - }; -}); - -vi.mock('@directus/shared/utils/node', async () => { - const actual = await vi.importActual('@directus/shared/utils/node'); - - const customCliExtension: Extension = { - path: '/hooks/custom-cli', - name: 'custom-cli', - type: 'hook', - entrypoint: 'index.js', - local: true, - }; - - return { - ...(actual as object), - getPackageExtensions: vi.fn(() => Promise.resolve([])), - getLocalExtensions: vi.fn(() => Promise.resolve([customCliExtension])), - }; -}); - -const beforeHook = vi.fn(); -const afterAction = vi.fn(); -const afterHook = vi.fn(({ program }) => { - (program as Command).command('custom').action(afterAction); -}); - -const customCliHook: HookConfig = ({ init }) => { - init('cli.before', beforeHook); - init('cli.after', afterHook); -}; - -vi.mock(path.resolve('/hooks/custom-cli', 'index.js'), () => ({ - default: customCliHook, -})); - -const writeOut = vi.fn(); -const writeErr = vi.fn(); - -const setup = async () => { - const program = await createCli(); - program.exitOverride(); - program.configureOutput({ writeOut, writeErr }); - return program; -}; - -beforeEach(() => { - vi.clearAllMocks(); -}); - -describe('cli hooks', () => { - test('should call hooks before and after creating the cli', async () => { - const program = await setup(); - - expect(beforeHook).toHaveBeenCalledTimes(1); - expect(beforeHook).toHaveBeenCalledWith({ event: 'cli.before', program }); - - expect(afterHook).toHaveBeenCalledTimes(1); - expect(afterHook).toHaveBeenCalledWith({ event: 'cli.after', program }); - }); - - test('should be able to add a custom cli command', async () => { - const program = await setup(); - program.parseAsync(['custom'], { from: 'user' }); - - expect(afterAction).toHaveBeenCalledTimes(1); - }); -}); diff --git a/api/src/cli/index.ts b/api/src/cli/index.ts index 6abdec92cc..ba40bfddd2 100644 --- a/api/src/cli/index.ts +++ b/api/src/cli/index.ts @@ -1,21 +1,20 @@ import { Command, Option } from 'commander'; -import { startServer } from '../server'; -import emitter from '../emitter'; -import { getExtensionManager } from '../extensions'; -import bootstrap from './commands/bootstrap'; -import count from './commands/count'; -import dbInstall from './commands/database/install'; -import dbMigrate from './commands/database/migrate'; -import init from './commands/init'; -import keyGenerate from './commands/security/key'; -import secretGenerate from './commands/security/secret'; -import rolesCreate from './commands/roles/create'; -import usersCreate from './commands/users/create'; -import usersPasswd from './commands/users/passwd'; -import { snapshot } from './commands/schema/snapshot'; -import { apply } from './commands/schema/apply'; - -const pkg = require('../../package.json'); +import emitter from '../emitter.js'; +import { getExtensionManager } from '../extensions.js'; +import { startServer } from '../server.js'; +import bootstrap from './commands/bootstrap/index.js'; +import count from './commands/count/index.js'; +import dbInstall from './commands/database/install.js'; +import dbMigrate from './commands/database/migrate.js'; +import init from './commands/init/index.js'; +import rolesCreate from './commands/roles/create.js'; +import { apply } from './commands/schema/apply.js'; +import { snapshot } from './commands/schema/snapshot.js'; +import keyGenerate from './commands/security/key.js'; +import secretGenerate from './commands/security/secret.js'; +import usersCreate from './commands/users/create.js'; +import usersPasswd from './commands/users/passwd.js'; +import * as pkg from '../utils/package.js'; export async function createCli(): Promise { const program = new Command(); diff --git a/api/src/cli/run.ts b/api/src/cli/run.ts index 5bbf0fd1ea..9bf5b3a613 100644 --- a/api/src/cli/run.ts +++ b/api/src/cli/run.ts @@ -1,4 +1,4 @@ -import { createCli } from './index'; +import { createCli } from './index.js'; createCli() .then((program) => program.parseAsync(process.argv)) diff --git a/api/src/cli/utils/create-db-connection.ts b/api/src/cli/utils/create-db-connection.ts index a31651cc0c..90824cb587 100644 --- a/api/src/cli/utils/create-db-connection.ts +++ b/api/src/cli/utils/create-db-connection.ts @@ -1,7 +1,12 @@ -import { knex, Knex } from 'knex'; +import knex from 'knex'; +import type { Knex } from 'knex'; +import { dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; import path from 'path'; import { promisify } from 'util'; -import type { Driver } from '../../types'; +import type { Driver } from '../../types/index.js'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); export type Credentials = { filename?: string; @@ -73,6 +78,6 @@ export default function createDBConnection(client: Driver, credentials: Credenti }; } - const db = knex(knexConfig); + const db = knex.default(knexConfig); return db; } diff --git a/api/src/cli/utils/create-env/index.ts b/api/src/cli/utils/create-env/index.ts index 8a56c3e9b6..81364fef1a 100644 --- a/api/src/cli/utils/create-env/index.ts +++ b/api/src/cli/utils/create-env/index.ts @@ -1,10 +1,14 @@ import fs from 'fs'; import { Liquid } from 'liquidjs'; +import { dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; import path from 'path'; import { promisify } from 'util'; import { v4 as uuid } from 'uuid'; -import type { Credentials } from '../create-db-connection'; -import type { drivers } from '../drivers'; +import type { Credentials } from '../create-db-connection.js'; +import type { drivers } from '../drivers.js'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); const readFile = promisify(fs.readFile); const writeFile = promisify(fs.writeFile); diff --git a/api/src/cli/utils/drivers.ts b/api/src/cli/utils/drivers.ts index 12ebf1cd0c..67c72c93fc 100644 --- a/api/src/cli/utils/drivers.ts +++ b/api/src/cli/utils/drivers.ts @@ -1,4 +1,4 @@ -import type { Driver } from '../../types'; +import type { Driver } from '../../types/index.js'; export const drivers: Record = { pg: 'PostgreSQL / Redshift', diff --git a/api/src/constants.ts b/api/src/constants.ts index 20bc21c0ac..b935c9bbae 100644 --- a/api/src/constants.ts +++ b/api/src/constants.ts @@ -1,7 +1,7 @@ import type { CookieOptions } from 'express'; -import env from './env'; -import type { TransformationParams } from './types'; -import { getMilliseconds } from './utils/get-milliseconds'; +import env from './env.js'; +import type { TransformationParams } from './types/index.js'; +import { getMilliseconds } from './utils/get-milliseconds.js'; export const SYSTEM_ASSET_ALLOW_LIST: TransformationParams[] = [ { diff --git a/api/src/controllers/activity.ts b/api/src/controllers/activity.ts index 4650153890..ecd647f309 100644 --- a/api/src/controllers/activity.ts +++ b/api/src/controllers/activity.ts @@ -1,13 +1,14 @@ -import { Action } from '@directus/shared/types'; +import { Action } from '@directus/types'; import express from 'express'; import Joi from 'joi'; -import { ForbiddenException, InvalidPayloadException } from '../exceptions'; -import { respond } from '../middleware/respond'; -import useCollection from '../middleware/use-collection'; -import { validateBatch } from '../middleware/validate-batch'; -import { ActivityService, MetaService } from '../services'; -import asyncHandler from '../utils/async-handler'; -import { getIPFromReq } from '../utils/get-ip-from-req'; +import { ForbiddenException, InvalidPayloadException } from '../exceptions/index.js'; +import { respond } from '../middleware/respond.js'; +import useCollection from '../middleware/use-collection.js'; +import { validateBatch } from '../middleware/validate-batch.js'; +import { ActivityService } from '../services/activity.js'; +import { MetaService } from '../services/meta.js'; +import asyncHandler from '../utils/async-handler.js'; +import { getIPFromReq } from '../utils/get-ip-from-req.js'; const router = express.Router(); diff --git a/api/src/controllers/assets.ts b/api/src/controllers/assets.ts index 0e227e1f31..e6d5bbccea 100644 --- a/api/src/controllers/assets.ts +++ b/api/src/controllers/assets.ts @@ -1,21 +1,20 @@ -// @ts-expect-error https://github.com/microsoft/TypeScript/issues/49721 import type { Range } from '@directus/storage'; - -import { parseJSON } from '@directus/shared/utils'; +import { parseJSON } from '@directus/utils'; import { Router } from 'express'; -import { merge, pick } from 'lodash'; -import { ASSET_TRANSFORM_QUERY_KEYS, SYSTEM_ASSET_ALLOW_LIST } from '../constants'; -import getDatabase from '../database'; -import env from '../env'; -import { InvalidQueryException, RangeNotSatisfiableException } from '../exceptions'; -import logger from '../logger'; -import useCollection from '../middleware/use-collection'; -import { AssetsService, PayloadService } from '../services'; -import { TransformationMethods, TransformationParams, TransformationPreset } from '../types/assets'; -import asyncHandler from '../utils/async-handler'; -import { getCacheControlHeader } from '../utils/get-cache-headers'; -import { getConfigFromEnv } from '../utils/get-config-from-env'; -import { getMilliseconds } from '../utils/get-milliseconds'; +import { merge, pick } from 'lodash-es'; +import { ASSET_TRANSFORM_QUERY_KEYS, SYSTEM_ASSET_ALLOW_LIST } from '../constants.js'; +import getDatabase from '../database/index.js'; +import env from '../env.js'; +import { InvalidQueryException, RangeNotSatisfiableException } from '../exceptions/index.js'; +import logger from '../logger.js'; +import useCollection from '../middleware/use-collection.js'; +import { AssetsService } from '../services/assets.js'; +import { PayloadService } from '../services/payload.js'; +import { TransformationMethods, TransformationParams, TransformationPreset } from '../types/assets.js'; +import asyncHandler from '../utils/async-handler.js'; +import { getCacheControlHeader } from '../utils/get-cache-headers.js'; +import { getConfigFromEnv } from '../utils/get-config-from-env.js'; +import { getMilliseconds } from '../utils/get-milliseconds.js'; const router = Router(); diff --git a/api/src/controllers/auth.ts b/api/src/controllers/auth.ts index de1c5e34d9..e7f3ec8080 100644 --- a/api/src/controllers/auth.ts +++ b/api/src/controllers/auth.ts @@ -1,4 +1,4 @@ -import type { Accountability } from '@directus/shared/types'; +import type { Accountability } from '@directus/types'; import { Router } from 'express'; import { createLDAPAuthRouter, @@ -6,16 +6,17 @@ import { createOAuth2AuthRouter, createOpenIDAuthRouter, createSAMLAuthRouter, -} from '../auth/drivers'; -import { COOKIE_OPTIONS, DEFAULT_AUTH_PROVIDER } from '../constants'; -import env from '../env'; -import { InvalidPayloadException } from '../exceptions'; -import logger from '../logger'; -import { respond } from '../middleware/respond'; -import { AuthenticationService, UsersService } from '../services'; -import asyncHandler from '../utils/async-handler'; -import { getAuthProviders } from '../utils/get-auth-providers'; -import { getIPFromReq } from '../utils/get-ip-from-req'; +} from '../auth/drivers/index.js'; +import { COOKIE_OPTIONS, DEFAULT_AUTH_PROVIDER } from '../constants.js'; +import env from '../env.js'; +import { InvalidPayloadException } from '../exceptions/index.js'; +import logger from '../logger.js'; +import { respond } from '../middleware/respond.js'; +import { AuthenticationService } from '../services/authentication.js'; +import { UsersService } from '../services/users.js'; +import asyncHandler from '../utils/async-handler.js'; +import { getAuthProviders } from '../utils/get-auth-providers.js'; +import { getIPFromReq } from '../utils/get-ip-from-req.js'; const router = Router(); diff --git a/api/src/controllers/collections.ts b/api/src/controllers/collections.ts index 9de6f87f53..3523b480f5 100644 --- a/api/src/controllers/collections.ts +++ b/api/src/controllers/collections.ts @@ -1,10 +1,11 @@ import { Router } from 'express'; -import { ForbiddenException } from '../exceptions'; -import { respond } from '../middleware/respond'; -import { validateBatch } from '../middleware/validate-batch'; -import { CollectionsService, MetaService } from '../services'; -import type { Item } from '../types'; -import asyncHandler from '../utils/async-handler'; +import { ForbiddenException } from '../exceptions/index.js'; +import { respond } from '../middleware/respond.js'; +import { validateBatch } from '../middleware/validate-batch.js'; +import { CollectionsService } from '../services/collections.js'; +import { MetaService } from '../services/meta.js'; +import type { Item } from '../types/index.js'; +import asyncHandler from '../utils/async-handler.js'; const router = Router(); diff --git a/api/src/controllers/dashboards.ts b/api/src/controllers/dashboards.ts index 0cf07c0d7e..eb89d30aba 100644 --- a/api/src/controllers/dashboards.ts +++ b/api/src/controllers/dashboards.ts @@ -1,12 +1,13 @@ import express from 'express'; -import { ForbiddenException } from '../exceptions'; -import { respond } from '../middleware/respond'; -import useCollection from '../middleware/use-collection'; -import { validateBatch } from '../middleware/validate-batch'; -import { DashboardsService, MetaService } from '../services'; -import type { PrimaryKey } from '../types'; -import asyncHandler from '../utils/async-handler'; -import { sanitizeQuery } from '../utils/sanitize-query'; +import { ForbiddenException } from '../exceptions/index.js'; +import { respond } from '../middleware/respond.js'; +import useCollection from '../middleware/use-collection.js'; +import { validateBatch } from '../middleware/validate-batch.js'; +import { DashboardsService } from '../services/dashboards.js'; +import { MetaService } from '../services/meta.js'; +import type { PrimaryKey } from '../types/index.js'; +import asyncHandler from '../utils/async-handler.js'; +import { sanitizeQuery } from '../utils/sanitize-query.js'; const router = express.Router(); diff --git a/api/src/controllers/extensions.ts b/api/src/controllers/extensions.ts index 60065c8891..16cc6e2593 100644 --- a/api/src/controllers/extensions.ts +++ b/api/src/controllers/extensions.ts @@ -1,14 +1,14 @@ -import { EXTENSION_TYPES } from '@directus/shared/constants'; -import type { Plural } from '@directus/shared/types'; -import { depluralize, isIn } from '@directus/shared/utils'; +import { EXTENSION_TYPES } from '@directus/constants'; +import type { Plural } from '@directus/types'; +import { depluralize, isIn } from '@directus/utils'; import { Router } from 'express'; -import env from '../env'; -import { RouteNotFoundException } from '../exceptions'; -import { getExtensionManager } from '../extensions'; -import { respond } from '../middleware/respond'; -import asyncHandler from '../utils/async-handler'; -import { getCacheControlHeader } from '../utils/get-cache-headers'; -import { getMilliseconds } from '../utils/get-milliseconds'; +import env from '../env.js'; +import { RouteNotFoundException } from '../exceptions/index.js'; +import { getExtensionManager } from '../extensions.js'; +import { respond } from '../middleware/respond.js'; +import asyncHandler from '../utils/async-handler.js'; +import { getCacheControlHeader } from '../utils/get-cache-headers.js'; +import { getMilliseconds } from '../utils/get-milliseconds.js'; const router = Router(); diff --git a/api/src/controllers/fields.ts b/api/src/controllers/fields.ts index efa2fd2242..a080d68e82 100644 --- a/api/src/controllers/fields.ts +++ b/api/src/controllers/fields.ts @@ -1,14 +1,14 @@ -import { TYPES } from '@directus/shared/constants'; -import type { Field, Type } from '@directus/shared/types'; +import { TYPES } from '@directus/constants'; +import type { Field, Type } from '@directus/types'; import { Router } from 'express'; import Joi from 'joi'; -import { ALIAS_TYPES } from '../constants'; -import { ForbiddenException, InvalidPayloadException } from '../exceptions'; -import validateCollection from '../middleware/collection-exists'; -import { respond } from '../middleware/respond'; -import useCollection from '../middleware/use-collection'; -import { FieldsService } from '../services/fields'; -import asyncHandler from '../utils/async-handler'; +import { ALIAS_TYPES } from '../constants.js'; +import { ForbiddenException, InvalidPayloadException } from '../exceptions/index.js'; +import validateCollection from '../middleware/collection-exists.js'; +import { respond } from '../middleware/respond.js'; +import useCollection from '../middleware/use-collection.js'; +import { FieldsService } from '../services/fields.js'; +import asyncHandler from '../utils/async-handler.js'; const router = Router(); diff --git a/api/src/controllers/files.test.ts b/api/src/controllers/files.test.ts index 5de36b420c..b89e5f8c54 100644 --- a/api/src/controllers/files.test.ts +++ b/api/src/controllers/files.test.ts @@ -2,8 +2,8 @@ import type { Request, Response } from 'express'; import FormData from 'form-data'; import { PassThrough } from 'stream'; import { describe, expect, it, vi } from 'vitest'; -import { InvalidPayloadException } from '../exceptions/invalid-payload'; -import { multipartHandler } from './files'; +import { InvalidPayloadException } from '../exceptions/invalid-payload.js'; +import { multipartHandler } from './files.js'; vi.mock('../../src/database'); diff --git a/api/src/controllers/files.ts b/api/src/controllers/files.ts index 1975d0b61c..614b7219a4 100644 --- a/api/src/controllers/files.ts +++ b/api/src/controllers/files.ts @@ -1,20 +1,19 @@ -import { toArray } from '@directus/shared/utils'; +import formatTitle from '@directus/format-title'; +import { toArray } from '@directus/utils'; import Busboy from 'busboy'; import express, { RequestHandler } from 'express'; import Joi from 'joi'; import path from 'path'; -import env from '../env'; -import { ForbiddenException, InvalidPayloadException } from '../exceptions'; -import { respond } from '../middleware/respond'; -import useCollection from '../middleware/use-collection'; -import { validateBatch } from '../middleware/validate-batch'; -import { FilesService, MetaService } from '../services'; -import type { PrimaryKey } from '../types'; -import asyncHandler from '../utils/async-handler'; - -// @ts-ignore -import formatTitle from '@directus/format-title'; -import { sanitizeQuery } from '../utils/sanitize-query'; +import env from '../env.js'; +import { ForbiddenException, InvalidPayloadException } from '../exceptions/index.js'; +import { respond } from '../middleware/respond.js'; +import useCollection from '../middleware/use-collection.js'; +import { validateBatch } from '../middleware/validate-batch.js'; +import { FilesService } from '../services/files.js'; +import { MetaService } from '../services/meta.js'; +import type { PrimaryKey } from '../types/index.js'; +import asyncHandler from '../utils/async-handler.js'; +import { sanitizeQuery } from '../utils/sanitize-query.js'; const router = express.Router(); diff --git a/api/src/controllers/flows.ts b/api/src/controllers/flows.ts index ba21b2dc7c..86e7a27a48 100644 --- a/api/src/controllers/flows.ts +++ b/api/src/controllers/flows.ts @@ -1,14 +1,15 @@ import express from 'express'; -import { UUID_REGEX } from '../constants'; -import { ForbiddenException } from '../exceptions'; -import { getFlowManager } from '../flows'; -import { respond } from '../middleware/respond'; -import useCollection from '../middleware/use-collection'; -import { validateBatch } from '../middleware/validate-batch'; -import { FlowsService, MetaService } from '../services'; -import type { PrimaryKey } from '../types'; -import asyncHandler from '../utils/async-handler'; -import { sanitizeQuery } from '../utils/sanitize-query'; +import { UUID_REGEX } from '../constants.js'; +import { ForbiddenException } from '../exceptions/index.js'; +import { getFlowManager } from '../flows.js'; +import { respond } from '../middleware/respond.js'; +import useCollection from '../middleware/use-collection.js'; +import { validateBatch } from '../middleware/validate-batch.js'; +import { FlowsService } from '../services/flows.js'; +import { MetaService } from '../services/meta.js'; +import type { PrimaryKey } from '../types/index.js'; +import asyncHandler from '../utils/async-handler.js'; +import { sanitizeQuery } from '../utils/sanitize-query.js'; const router = express.Router(); diff --git a/api/src/controllers/folders.ts b/api/src/controllers/folders.ts index a18875887d..eeb20d5e4f 100644 --- a/api/src/controllers/folders.ts +++ b/api/src/controllers/folders.ts @@ -1,12 +1,13 @@ import express from 'express'; -import { ForbiddenException } from '../exceptions'; -import { respond } from '../middleware/respond'; -import useCollection from '../middleware/use-collection'; -import { validateBatch } from '../middleware/validate-batch'; -import { FoldersService, MetaService } from '../services'; -import type { PrimaryKey } from '../types'; -import asyncHandler from '../utils/async-handler'; -import { sanitizeQuery } from '../utils/sanitize-query'; +import { ForbiddenException } from '../exceptions/index.js'; +import { respond } from '../middleware/respond.js'; +import useCollection from '../middleware/use-collection.js'; +import { validateBatch } from '../middleware/validate-batch.js'; +import { FoldersService } from '../services/folders.js'; +import { MetaService } from '../services/meta.js'; +import type { PrimaryKey } from '../types/index.js'; +import asyncHandler from '../utils/async-handler.js'; +import { sanitizeQuery } from '../utils/sanitize-query.js'; const router = express.Router(); diff --git a/api/src/controllers/graphql.ts b/api/src/controllers/graphql.ts index 312c2c7816..40d251a948 100644 --- a/api/src/controllers/graphql.ts +++ b/api/src/controllers/graphql.ts @@ -1,8 +1,8 @@ import { Router } from 'express'; -import { parseGraphQL } from '../middleware/graphql'; -import { respond } from '../middleware/respond'; -import { GraphQLService } from '../services'; -import asyncHandler from '../utils/async-handler'; +import { parseGraphQL } from '../middleware/graphql.js'; +import { respond } from '../middleware/respond.js'; +import { GraphQLService } from '../services/graphql/index.js'; +import asyncHandler from '../utils/async-handler.js'; const router = Router(); diff --git a/api/src/controllers/items.ts b/api/src/controllers/items.ts index bc622a1a1a..fce1140891 100644 --- a/api/src/controllers/items.ts +++ b/api/src/controllers/items.ts @@ -1,12 +1,13 @@ import express from 'express'; -import { ForbiddenException, RouteNotFoundException } from '../exceptions'; -import collectionExists from '../middleware/collection-exists'; -import { respond } from '../middleware/respond'; -import { validateBatch } from '../middleware/validate-batch'; -import { ItemsService, MetaService } from '../services'; -import type { PrimaryKey } from '../types'; -import asyncHandler from '../utils/async-handler'; -import { sanitizeQuery } from '../utils/sanitize-query'; +import { ForbiddenException, RouteNotFoundException } from '../exceptions/index.js'; +import collectionExists from '../middleware/collection-exists.js'; +import { respond } from '../middleware/respond.js'; +import { validateBatch } from '../middleware/validate-batch.js'; +import { ItemsService } from '../services/items.js'; +import { MetaService } from '../services/meta.js'; +import type { PrimaryKey } from '../types/index.js'; +import asyncHandler from '../utils/async-handler.js'; +import { sanitizeQuery } from '../utils/sanitize-query.js'; const router = express.Router(); diff --git a/api/src/controllers/not-found.ts b/api/src/controllers/not-found.ts index 7ada826222..3aed6deff1 100644 --- a/api/src/controllers/not-found.ts +++ b/api/src/controllers/not-found.ts @@ -1,7 +1,7 @@ import type { RequestHandler } from 'express'; -import getDatabase from '../database'; -import emitter from '../emitter'; -import { RouteNotFoundException } from '../exceptions'; +import getDatabase from '../database/index.js'; +import emitter from '../emitter.js'; +import { RouteNotFoundException } from '../exceptions/index.js'; /** * Handles not found routes. diff --git a/api/src/controllers/notifications.ts b/api/src/controllers/notifications.ts index 14b8478a45..69579caee2 100644 --- a/api/src/controllers/notifications.ts +++ b/api/src/controllers/notifications.ts @@ -1,12 +1,13 @@ import express from 'express'; -import { ForbiddenException } from '../exceptions'; -import { respond } from '../middleware/respond'; -import useCollection from '../middleware/use-collection'; -import { validateBatch } from '../middleware/validate-batch'; -import { MetaService, NotificationsService } from '../services'; -import type { PrimaryKey } from '../types'; -import asyncHandler from '../utils/async-handler'; -import { sanitizeQuery } from '../utils/sanitize-query'; +import { ForbiddenException } from '../exceptions/index.js'; +import { respond } from '../middleware/respond.js'; +import useCollection from '../middleware/use-collection.js'; +import { validateBatch } from '../middleware/validate-batch.js'; +import { MetaService } from '../services/meta.js'; +import { NotificationsService } from '../services/notifications.js'; +import type { PrimaryKey } from '../types/index.js'; +import asyncHandler from '../utils/async-handler.js'; +import { sanitizeQuery } from '../utils/sanitize-query.js'; const router = express.Router(); diff --git a/api/src/controllers/operations.ts b/api/src/controllers/operations.ts index b859e608d2..f1ce31ce84 100644 --- a/api/src/controllers/operations.ts +++ b/api/src/controllers/operations.ts @@ -1,12 +1,13 @@ import express from 'express'; -import { ForbiddenException } from '../exceptions'; -import { respond } from '../middleware/respond'; -import useCollection from '../middleware/use-collection'; -import { validateBatch } from '../middleware/validate-batch'; -import { MetaService, OperationsService } from '../services'; -import type { PrimaryKey } from '../types'; -import asyncHandler from '../utils/async-handler'; -import { sanitizeQuery } from '../utils/sanitize-query'; +import { ForbiddenException } from '../exceptions/index.js'; +import { respond } from '../middleware/respond.js'; +import useCollection from '../middleware/use-collection.js'; +import { validateBatch } from '../middleware/validate-batch.js'; +import { MetaService } from '../services/meta.js'; +import { OperationsService } from '../services/operations.js'; +import type { PrimaryKey } from '../types/index.js'; +import asyncHandler from '../utils/async-handler.js'; +import { sanitizeQuery } from '../utils/sanitize-query.js'; const router = express.Router(); diff --git a/api/src/controllers/panels.ts b/api/src/controllers/panels.ts index dd9e6a31be..7740f8b7df 100644 --- a/api/src/controllers/panels.ts +++ b/api/src/controllers/panels.ts @@ -1,12 +1,13 @@ import express from 'express'; -import { ForbiddenException } from '../exceptions'; -import { respond } from '../middleware/respond'; -import useCollection from '../middleware/use-collection'; -import { validateBatch } from '../middleware/validate-batch'; -import { MetaService, PanelsService } from '../services'; -import type { PrimaryKey } from '../types'; -import asyncHandler from '../utils/async-handler'; -import { sanitizeQuery } from '../utils/sanitize-query'; +import { ForbiddenException } from '../exceptions/index.js'; +import { respond } from '../middleware/respond.js'; +import useCollection from '../middleware/use-collection.js'; +import { validateBatch } from '../middleware/validate-batch.js'; +import { MetaService } from '../services/meta.js'; +import { PanelsService } from '../services/panels.js'; +import type { PrimaryKey } from '../types/index.js'; +import asyncHandler from '../utils/async-handler.js'; +import { sanitizeQuery } from '../utils/sanitize-query.js'; const router = express.Router(); diff --git a/api/src/controllers/permissions.ts b/api/src/controllers/permissions.ts index 53a83dd191..c8f5f0e12f 100644 --- a/api/src/controllers/permissions.ts +++ b/api/src/controllers/permissions.ts @@ -1,12 +1,13 @@ import express from 'express'; -import { ForbiddenException } from '../exceptions'; -import { respond } from '../middleware/respond'; -import useCollection from '../middleware/use-collection'; -import { validateBatch } from '../middleware/validate-batch'; -import { MetaService, PermissionsService } from '../services'; -import type { PrimaryKey } from '../types'; -import asyncHandler from '../utils/async-handler'; -import { sanitizeQuery } from '../utils/sanitize-query'; +import { ForbiddenException } from '../exceptions/index.js'; +import { respond } from '../middleware/respond.js'; +import useCollection from '../middleware/use-collection.js'; +import { validateBatch } from '../middleware/validate-batch.js'; +import { MetaService } from '../services/meta.js'; +import { PermissionsService } from '../services/permissions.js'; +import type { PrimaryKey } from '../types/index.js'; +import asyncHandler from '../utils/async-handler.js'; +import { sanitizeQuery } from '../utils/sanitize-query.js'; const router = express.Router(); diff --git a/api/src/controllers/presets.ts b/api/src/controllers/presets.ts index 8f041c3a48..00fa5f9d74 100644 --- a/api/src/controllers/presets.ts +++ b/api/src/controllers/presets.ts @@ -1,12 +1,13 @@ import express from 'express'; -import { ForbiddenException } from '../exceptions'; -import { respond } from '../middleware/respond'; -import useCollection from '../middleware/use-collection'; -import { validateBatch } from '../middleware/validate-batch'; -import { MetaService, PresetsService } from '../services'; -import type { PrimaryKey } from '../types'; -import asyncHandler from '../utils/async-handler'; -import { sanitizeQuery } from '../utils/sanitize-query'; +import { ForbiddenException } from '../exceptions/index.js'; +import { respond } from '../middleware/respond.js'; +import useCollection from '../middleware/use-collection.js'; +import { validateBatch } from '../middleware/validate-batch.js'; +import { MetaService } from '../services/meta.js'; +import { PresetsService } from '../services/presets.js'; +import type { PrimaryKey } from '../types/index.js'; +import asyncHandler from '../utils/async-handler.js'; +import { sanitizeQuery } from '../utils/sanitize-query.js'; const router = express.Router(); diff --git a/api/src/controllers/relations.ts b/api/src/controllers/relations.ts index 8e7bf54d25..b8be681f78 100644 --- a/api/src/controllers/relations.ts +++ b/api/src/controllers/relations.ts @@ -1,11 +1,11 @@ import express from 'express'; -import { ForbiddenException, InvalidPayloadException } from '../exceptions'; -import { respond } from '../middleware/respond'; -import useCollection from '../middleware/use-collection'; -import { RelationsService } from '../services'; -import asyncHandler from '../utils/async-handler'; -import validateCollection from '../middleware/collection-exists'; import Joi from 'joi'; +import { ForbiddenException, InvalidPayloadException } from '../exceptions/index.js'; +import validateCollection from '../middleware/collection-exists.js'; +import { respond } from '../middleware/respond.js'; +import useCollection from '../middleware/use-collection.js'; +import { RelationsService } from '../services/relations.js'; +import asyncHandler from '../utils/async-handler.js'; const router = express.Router(); diff --git a/api/src/controllers/revisions.ts b/api/src/controllers/revisions.ts index 0df8170a11..805fca5bb1 100644 --- a/api/src/controllers/revisions.ts +++ b/api/src/controllers/revisions.ts @@ -1,9 +1,10 @@ import express from 'express'; -import { respond } from '../middleware/respond'; -import useCollection from '../middleware/use-collection'; -import { validateBatch } from '../middleware/validate-batch'; -import { MetaService, RevisionsService } from '../services'; -import asyncHandler from '../utils/async-handler'; +import { respond } from '../middleware/respond.js'; +import useCollection from '../middleware/use-collection.js'; +import { validateBatch } from '../middleware/validate-batch.js'; +import { MetaService } from '../services/meta.js'; +import { RevisionsService } from '../services/revisions.js'; +import asyncHandler from '../utils/async-handler.js'; const router = express.Router(); diff --git a/api/src/controllers/roles.ts b/api/src/controllers/roles.ts index 7c4feae95a..98914186ec 100644 --- a/api/src/controllers/roles.ts +++ b/api/src/controllers/roles.ts @@ -1,12 +1,13 @@ import express from 'express'; -import { ForbiddenException } from '../exceptions'; -import { respond } from '../middleware/respond'; -import useCollection from '../middleware/use-collection'; -import { validateBatch } from '../middleware/validate-batch'; -import { MetaService, RolesService } from '../services'; -import type { PrimaryKey } from '../types'; -import asyncHandler from '../utils/async-handler'; -import { sanitizeQuery } from '../utils/sanitize-query'; +import { ForbiddenException } from '../exceptions/index.js'; +import { respond } from '../middleware/respond.js'; +import useCollection from '../middleware/use-collection.js'; +import { validateBatch } from '../middleware/validate-batch.js'; +import { MetaService } from '../services/meta.js'; +import { RolesService } from '../services/roles.js'; +import type { PrimaryKey } from '../types/index.js'; +import asyncHandler from '../utils/async-handler.js'; +import { sanitizeQuery } from '../utils/sanitize-query.js'; const router = express.Router(); diff --git a/api/src/controllers/schema.ts b/api/src/controllers/schema.ts index 9109aab406..f4775b2537 100644 --- a/api/src/controllers/schema.ts +++ b/api/src/controllers/schema.ts @@ -1,14 +1,14 @@ -import { parseJSON } from '@directus/shared/utils'; +import { parseJSON } from '@directus/utils'; import Busboy from 'busboy'; import express, { RequestHandler } from 'express'; import { load as loadYaml } from 'js-yaml'; -import { InvalidPayloadException, UnsupportedMediaTypeException } from '../exceptions'; -import logger from '../logger'; -import { respond } from '../middleware/respond'; -import { SchemaService } from '../services/schema'; -import type { Snapshot } from '../types'; -import asyncHandler from '../utils/async-handler'; -import { getVersionedHash } from '../utils/get-versioned-hash'; +import { InvalidPayloadException, UnsupportedMediaTypeException } from '../exceptions/index.js'; +import logger from '../logger.js'; +import { respond } from '../middleware/respond.js'; +import { SchemaService } from '../services/schema.js'; +import type { Snapshot } from '../types/index.js'; +import asyncHandler from '../utils/async-handler.js'; +import { getVersionedHash } from '../utils/get-versioned-hash.js'; const router = express.Router(); diff --git a/api/src/controllers/server.ts b/api/src/controllers/server.ts index acf2a47b5c..c8d65be90e 100644 --- a/api/src/controllers/server.ts +++ b/api/src/controllers/server.ts @@ -1,9 +1,10 @@ import { format } from 'date-fns'; import { Router } from 'express'; -import { RouteNotFoundException } from '../exceptions'; -import { respond } from '../middleware/respond'; -import { ServerService, SpecificationService } from '../services'; -import asyncHandler from '../utils/async-handler'; +import { RouteNotFoundException } from '../exceptions/index.js'; +import { respond } from '../middleware/respond.js'; +import { ServerService } from '../services/server.js'; +import { SpecificationService } from '../services/specifications.js'; +import asyncHandler from '../utils/async-handler.js'; const router = Router(); diff --git a/api/src/controllers/settings.ts b/api/src/controllers/settings.ts index f89fd59d3f..6ab77754c1 100644 --- a/api/src/controllers/settings.ts +++ b/api/src/controllers/settings.ts @@ -1,9 +1,9 @@ import express from 'express'; -import { ForbiddenException } from '../exceptions'; -import { respond } from '../middleware/respond'; -import useCollection from '../middleware/use-collection'; -import { SettingsService } from '../services'; -import asyncHandler from '../utils/async-handler'; +import { ForbiddenException } from '../exceptions/index.js'; +import { respond } from '../middleware/respond.js'; +import useCollection from '../middleware/use-collection.js'; +import { SettingsService } from '../services/settings.js'; +import asyncHandler from '../utils/async-handler.js'; const router = express.Router(); diff --git a/api/src/controllers/shares.ts b/api/src/controllers/shares.ts index a14690b043..a3d5f836b4 100644 --- a/api/src/controllers/shares.ts +++ b/api/src/controllers/shares.ts @@ -1,15 +1,15 @@ import express from 'express'; import Joi from 'joi'; -import { COOKIE_OPTIONS, UUID_REGEX } from '../constants'; -import env from '../env'; -import { ForbiddenException, InvalidPayloadException } from '../exceptions'; -import { respond } from '../middleware/respond'; -import useCollection from '../middleware/use-collection'; -import { validateBatch } from '../middleware/validate-batch'; -import { SharesService } from '../services'; -import type { PrimaryKey } from '../types'; -import asyncHandler from '../utils/async-handler'; -import { sanitizeQuery } from '../utils/sanitize-query'; +import { COOKIE_OPTIONS, UUID_REGEX } from '../constants.js'; +import env from '../env.js'; +import { ForbiddenException, InvalidPayloadException } from '../exceptions/index.js'; +import { respond } from '../middleware/respond.js'; +import useCollection from '../middleware/use-collection.js'; +import { validateBatch } from '../middleware/validate-batch.js'; +import { SharesService } from '../services/shares.js'; +import type { PrimaryKey } from '../types/index.js'; +import asyncHandler from '../utils/async-handler.js'; +import { sanitizeQuery } from '../utils/sanitize-query.js'; const router = express.Router(); diff --git a/api/src/controllers/users.ts b/api/src/controllers/users.ts index fb0bad66c2..d61895aa10 100644 --- a/api/src/controllers/users.ts +++ b/api/src/controllers/users.ts @@ -1,14 +1,18 @@ -import type { Role } from '@directus/shared/types'; +import type { Role } from '@directus/types'; import express from 'express'; import Joi from 'joi'; -import { ForbiddenException, InvalidCredentialsException, InvalidPayloadException } from '../exceptions'; -import { respond } from '../middleware/respond'; -import useCollection from '../middleware/use-collection'; -import { validateBatch } from '../middleware/validate-batch'; -import { AuthenticationService, MetaService, RolesService, TFAService, UsersService } from '../services'; -import type { PrimaryKey } from '../types'; -import asyncHandler from '../utils/async-handler'; -import { sanitizeQuery } from '../utils/sanitize-query'; +import { ForbiddenException, InvalidCredentialsException, InvalidPayloadException } from '../exceptions/index.js'; +import { respond } from '../middleware/respond.js'; +import useCollection from '../middleware/use-collection.js'; +import { validateBatch } from '../middleware/validate-batch.js'; +import { AuthenticationService } from '../services/authentication.js'; +import { MetaService } from '../services/meta.js'; +import { RolesService } from '../services/roles.js'; +import { TFAService } from '../services/tfa.js'; +import { UsersService } from '../services/users.js'; +import type { PrimaryKey } from '../types/index.js'; +import asyncHandler from '../utils/async-handler.js'; +import { sanitizeQuery } from '../utils/sanitize-query.js'; const router = express.Router(); diff --git a/api/src/controllers/utils.ts b/api/src/controllers/utils.ts index 63fc5cef5b..53540e9643 100644 --- a/api/src/controllers/utils.ts +++ b/api/src/controllers/utils.ts @@ -1,20 +1,22 @@ import argon2 from 'argon2'; +import Busboy from 'busboy'; import { Router } from 'express'; import Joi from 'joi'; +import { flushCaches } from '../cache.js'; import { ForbiddenException, InvalidPayloadException, InvalidQueryException, UnsupportedMediaTypeException, -} from '../exceptions'; -import collectionExists from '../middleware/collection-exists'; -import { respond } from '../middleware/respond'; -import { RevisionsService, UtilsService, ImportService, ExportService } from '../services'; -import asyncHandler from '../utils/async-handler'; -import Busboy from 'busboy'; -import { flushCaches } from '../cache'; -import { generateHash } from '../utils/generate-hash'; -import { sanitizeQuery } from '../utils/sanitize-query'; +} from '../exceptions/index.js'; +import collectionExists from '../middleware/collection-exists.js'; +import { respond } from '../middleware/respond.js'; +import { ExportService, ImportService } from '../services/import-export.js'; +import { RevisionsService } from '../services/revisions.js'; +import { UtilsService } from '../services/utils.js'; +import asyncHandler from '../utils/async-handler.js'; +import { generateHash } from '../utils/generate-hash.js'; +import { sanitizeQuery } from '../utils/sanitize-query.js'; const router = Router(); diff --git a/api/src/controllers/webhooks.ts b/api/src/controllers/webhooks.ts index da793b4fa8..b4157f44ad 100644 --- a/api/src/controllers/webhooks.ts +++ b/api/src/controllers/webhooks.ts @@ -1,12 +1,13 @@ import express from 'express'; -import { ForbiddenException } from '../exceptions'; -import { respond } from '../middleware/respond'; -import useCollection from '../middleware/use-collection'; -import { validateBatch } from '../middleware/validate-batch'; -import { MetaService, WebhooksService } from '../services'; -import type { PrimaryKey } from '../types'; -import asyncHandler from '../utils/async-handler'; -import { sanitizeQuery } from '../utils/sanitize-query'; +import { ForbiddenException } from '../exceptions/index.js'; +import { respond } from '../middleware/respond.js'; +import useCollection from '../middleware/use-collection.js'; +import { validateBatch } from '../middleware/validate-batch.js'; +import { MetaService } from '../services/meta.js'; +import { WebhooksService } from '../services/webhooks.js'; +import type { PrimaryKey } from '../types/index.js'; +import asyncHandler from '../utils/async-handler.js'; +import { sanitizeQuery } from '../utils/sanitize-query.js'; const router = express.Router(); diff --git a/api/src/database/helpers/date/dialects/default.ts b/api/src/database/helpers/date/dialects/default.ts index 840c229ad3..ce1e30a935 100644 --- a/api/src/database/helpers/date/dialects/default.ts +++ b/api/src/database/helpers/date/dialects/default.ts @@ -1,3 +1,3 @@ -import { DateHelper } from '../types'; +import { DateHelper } from '../types.js'; export class DateHelperDefault extends DateHelper {} diff --git a/api/src/database/helpers/date/dialects/mssql.ts b/api/src/database/helpers/date/dialects/mssql.ts index 2186e4bfc8..59e87303fa 100644 --- a/api/src/database/helpers/date/dialects/mssql.ts +++ b/api/src/database/helpers/date/dialects/mssql.ts @@ -1,4 +1,4 @@ -import { DateHelper } from '../types'; +import { DateHelper } from '../types.js'; import { parseISO } from 'date-fns'; export class DateHelperMSSQL extends DateHelper { diff --git a/api/src/database/helpers/date/dialects/mysql.ts b/api/src/database/helpers/date/dialects/mysql.ts index a056a2e26b..d183367c93 100644 --- a/api/src/database/helpers/date/dialects/mysql.ts +++ b/api/src/database/helpers/date/dialects/mysql.ts @@ -1,4 +1,4 @@ -import { DateHelper } from '../types'; +import { DateHelper } from '../types.js'; import { parseISO } from 'date-fns'; export class DateHelperMySQL extends DateHelper { diff --git a/api/src/database/helpers/date/dialects/oracle.ts b/api/src/database/helpers/date/dialects/oracle.ts index f786082074..d33093427a 100644 --- a/api/src/database/helpers/date/dialects/oracle.ts +++ b/api/src/database/helpers/date/dialects/oracle.ts @@ -1,4 +1,4 @@ -import { DateHelper } from '../types'; +import { DateHelper } from '../types.js'; export class DateHelperOracle extends DateHelper { override fieldFlagForField(fieldType: string): string { diff --git a/api/src/database/helpers/date/dialects/sqlite.ts b/api/src/database/helpers/date/dialects/sqlite.ts index d7e01e9a48..80ac3e700d 100644 --- a/api/src/database/helpers/date/dialects/sqlite.ts +++ b/api/src/database/helpers/date/dialects/sqlite.ts @@ -1,4 +1,4 @@ -import { DateHelper } from '../types'; +import { DateHelper } from '../types.js'; export class DateHelperSQLite extends DateHelper { override parse(date: string | Date): string { diff --git a/api/src/database/helpers/date/index.ts b/api/src/database/helpers/date/index.ts index da009b733d..3a0ecee429 100644 --- a/api/src/database/helpers/date/index.ts +++ b/api/src/database/helpers/date/index.ts @@ -1,7 +1,7 @@ -export { DateHelperDefault as postgres } from './dialects/default'; -export { DateHelperDefault as redshift } from './dialects/default'; -export { DateHelperDefault as cockroachdb } from './dialects/default'; -export { DateHelperOracle as oracle } from './dialects/oracle'; -export { DateHelperMySQL as mysql } from './dialects/mysql'; -export { DateHelperMSSQL as mssql } from './dialects/mssql'; -export { DateHelperSQLite as sqlite } from './dialects/sqlite'; +export { DateHelperDefault as postgres } from './dialects/default.js'; +export { DateHelperDefault as redshift } from './dialects/default.js'; +export { DateHelperDefault as cockroachdb } from './dialects/default.js'; +export { DateHelperOracle as oracle } from './dialects/oracle.js'; +export { DateHelperMySQL as mysql } from './dialects/mysql.js'; +export { DateHelperMSSQL as mssql } from './dialects/mssql.js'; +export { DateHelperSQLite as sqlite } from './dialects/sqlite.js'; diff --git a/api/src/database/helpers/date/types.ts b/api/src/database/helpers/date/types.ts index 2edf38a8e9..3a2e88dd2b 100644 --- a/api/src/database/helpers/date/types.ts +++ b/api/src/database/helpers/date/types.ts @@ -1,4 +1,4 @@ -import { DatabaseHelper } from '../types'; +import { DatabaseHelper } from '../types.js'; import { parseISO } from 'date-fns'; export abstract class DateHelper extends DatabaseHelper { diff --git a/api/src/database/helpers/fn/dialects/mssql.ts b/api/src/database/helpers/fn/dialects/mssql.ts index eb0bb3e664..781543e7f2 100644 --- a/api/src/database/helpers/fn/dialects/mssql.ts +++ b/api/src/database/helpers/fn/dialects/mssql.ts @@ -1,5 +1,5 @@ import type { Knex } from 'knex'; -import { FnHelper, FnHelperOptions } from '../types'; +import { FnHelper, FnHelperOptions } from '../types.js'; const parseLocaltime = (columnType?: string) => { if (columnType === 'timestamp') { diff --git a/api/src/database/helpers/fn/dialects/mysql.ts b/api/src/database/helpers/fn/dialects/mysql.ts index e89ff3b967..cee885da1e 100644 --- a/api/src/database/helpers/fn/dialects/mysql.ts +++ b/api/src/database/helpers/fn/dialects/mysql.ts @@ -1,5 +1,5 @@ import type { Knex } from 'knex'; -import { FnHelper, FnHelperOptions } from '../types'; +import { FnHelper, FnHelperOptions } from '../types.js'; export class FnHelperMySQL extends FnHelper { year(table: string, column: string): Knex.Raw { diff --git a/api/src/database/helpers/fn/dialects/oracle.ts b/api/src/database/helpers/fn/dialects/oracle.ts index 3b6eb542d4..53393419c2 100644 --- a/api/src/database/helpers/fn/dialects/oracle.ts +++ b/api/src/database/helpers/fn/dialects/oracle.ts @@ -1,5 +1,5 @@ import type { Knex } from 'knex'; -import { FnHelper, FnHelperOptions } from '../types'; +import { FnHelper, FnHelperOptions } from '../types.js'; const parseLocaltime = (columnType?: string) => { if (columnType === 'timestamp') { diff --git a/api/src/database/helpers/fn/dialects/postgres.ts b/api/src/database/helpers/fn/dialects/postgres.ts index b3c80b07d1..fea2215765 100644 --- a/api/src/database/helpers/fn/dialects/postgres.ts +++ b/api/src/database/helpers/fn/dialects/postgres.ts @@ -1,5 +1,5 @@ import type { Knex } from 'knex'; -import { FnHelper, FnHelperOptions } from '../types'; +import { FnHelper, FnHelperOptions } from '../types.js'; const parseLocaltime = (columnType?: string) => { if (columnType === 'timestamp') { diff --git a/api/src/database/helpers/fn/dialects/sqlite.ts b/api/src/database/helpers/fn/dialects/sqlite.ts index 370ee1c731..a6cf61f6f3 100644 --- a/api/src/database/helpers/fn/dialects/sqlite.ts +++ b/api/src/database/helpers/fn/dialects/sqlite.ts @@ -1,5 +1,5 @@ import type { Knex } from 'knex'; -import { FnHelper, FnHelperOptions } from '../types'; +import { FnHelper, FnHelperOptions } from '../types.js'; const parseLocaltime = (columnType?: string) => { if (columnType === 'timestamp') { diff --git a/api/src/database/helpers/fn/index.ts b/api/src/database/helpers/fn/index.ts index b3337d7504..d1c7f86702 100644 --- a/api/src/database/helpers/fn/index.ts +++ b/api/src/database/helpers/fn/index.ts @@ -1,7 +1,7 @@ -export { FnHelperPostgres as postgres } from './dialects/postgres'; -export { FnHelperPostgres as redshift } from './dialects/postgres'; -export { FnHelperPostgres as cockroachdb } from './dialects/postgres'; -export { FnHelperOracle as oracle } from './dialects/oracle'; -export { FnHelperSQLite as sqlite } from './dialects/sqlite'; -export { FnHelperMySQL as mysql } from './dialects/mysql'; -export { FnHelperMSSQL as mssql } from './dialects/mssql'; +export { FnHelperPostgres as postgres } from './dialects/postgres.js'; +export { FnHelperPostgres as redshift } from './dialects/postgres.js'; +export { FnHelperPostgres as cockroachdb } from './dialects/postgres.js'; +export { FnHelperOracle as oracle } from './dialects/oracle.js'; +export { FnHelperSQLite as sqlite } from './dialects/sqlite.js'; +export { FnHelperMySQL as mysql } from './dialects/mysql.js'; +export { FnHelperMSSQL as mssql } from './dialects/mssql.js'; diff --git a/api/src/database/helpers/fn/types.ts b/api/src/database/helpers/fn/types.ts index de56fd6977..efae3cda1f 100644 --- a/api/src/database/helpers/fn/types.ts +++ b/api/src/database/helpers/fn/types.ts @@ -1,7 +1,7 @@ -import type { Query, SchemaOverview } from '@directus/shared/types'; +import type { Query, SchemaOverview } from '@directus/types'; import type { Knex } from 'knex'; -import { applyFilter } from '../../../utils/apply-query'; -import { DatabaseHelper } from '../types'; +import { applyFilter } from '../../../utils/apply-query.js'; +import { DatabaseHelper } from '../types.js'; export type FnHelperOptions = { type: string | undefined; diff --git a/api/src/database/helpers/geometry/dialects/mssql.ts b/api/src/database/helpers/geometry/dialects/mssql.ts index f58eb01951..8d71f9100f 100644 --- a/api/src/database/helpers/geometry/dialects/mssql.ts +++ b/api/src/database/helpers/geometry/dialects/mssql.ts @@ -1,7 +1,7 @@ -import type { Field, RawField } from '@directus/shared/types'; +import type { Field, RawField } from '@directus/types'; import type { Knex } from 'knex'; import type { GeoJSONGeometry } from 'wellknown'; -import { GeometryHelper } from '../types'; +import { GeometryHelper } from '../types.js'; export class GeometryHelperMSSQL extends GeometryHelper { override isTrue(expression: Knex.Raw) { diff --git a/api/src/database/helpers/geometry/dialects/mysql.ts b/api/src/database/helpers/geometry/dialects/mysql.ts index e288c7ffb3..578b4ae7df 100644 --- a/api/src/database/helpers/geometry/dialects/mysql.ts +++ b/api/src/database/helpers/geometry/dialects/mysql.ts @@ -1,5 +1,5 @@ import type { Knex } from 'knex'; -import { GeometryHelper } from '../types'; +import { GeometryHelper } from '../types.js'; export class GeometryHelperMySQL extends GeometryHelper { override collect(table: string, column: string): Knex.Raw { diff --git a/api/src/database/helpers/geometry/dialects/oracle.ts b/api/src/database/helpers/geometry/dialects/oracle.ts index 77ca252e57..3dea82509f 100644 --- a/api/src/database/helpers/geometry/dialects/oracle.ts +++ b/api/src/database/helpers/geometry/dialects/oracle.ts @@ -1,7 +1,7 @@ -import type { Field, RawField } from '@directus/shared/types'; +import type { Field, RawField } from '@directus/types'; import type { Knex } from 'knex'; import type { GeoJSONGeometry } from 'wellknown'; -import { GeometryHelper } from '../types'; +import { GeometryHelper } from '../types.js'; export class GeometryHelperOracle extends GeometryHelper { override isTrue(expression: Knex.Raw) { diff --git a/api/src/database/helpers/geometry/dialects/postgres.ts b/api/src/database/helpers/geometry/dialects/postgres.ts index f446e88e3b..13c73c48ec 100644 --- a/api/src/database/helpers/geometry/dialects/postgres.ts +++ b/api/src/database/helpers/geometry/dialects/postgres.ts @@ -1,7 +1,7 @@ -import type { Field, RawField } from '@directus/shared/types'; +import type { Field, RawField } from '@directus/types'; import type { Knex } from 'knex'; import type { GeoJSONGeometry } from 'wellknown'; -import { GeometryHelper } from '../types'; +import { GeometryHelper } from '../types.js'; export class GeometryHelperPostgres extends GeometryHelper { override async supported() { diff --git a/api/src/database/helpers/geometry/dialects/redshift.ts b/api/src/database/helpers/geometry/dialects/redshift.ts index 1c65bd56c4..44e2eabcbf 100644 --- a/api/src/database/helpers/geometry/dialects/redshift.ts +++ b/api/src/database/helpers/geometry/dialects/redshift.ts @@ -1,6 +1,6 @@ -import type { Field, RawField } from '@directus/shared/types'; +import type { Field, RawField } from '@directus/types'; import type { Knex } from 'knex'; -import { GeometryHelper } from '../types'; +import { GeometryHelper } from '../types.js'; export class GeometryHelperRedshift extends GeometryHelper { override createColumn(table: Knex.CreateTableBuilder, field: RawField | Field) { diff --git a/api/src/database/helpers/geometry/dialects/sqlite.ts b/api/src/database/helpers/geometry/dialects/sqlite.ts index 1a5cb97c06..9bfaf68149 100644 --- a/api/src/database/helpers/geometry/dialects/sqlite.ts +++ b/api/src/database/helpers/geometry/dialects/sqlite.ts @@ -1,5 +1,5 @@ import type { Knex } from 'knex'; -import { GeometryHelper } from '../types'; +import { GeometryHelper } from '../types.js'; export class GeometryHelperSQLite extends GeometryHelper { override async supported() { diff --git a/api/src/database/helpers/geometry/index.ts b/api/src/database/helpers/geometry/index.ts index 475eb4d564..6af8dc9709 100644 --- a/api/src/database/helpers/geometry/index.ts +++ b/api/src/database/helpers/geometry/index.ts @@ -1,7 +1,7 @@ -export { GeometryHelperPostgres as postgres } from './dialects/postgres'; -export { GeometryHelperPostgres as cockroachdb } from './dialects/postgres'; -export { GeometryHelperRedshift as redshift } from './dialects/redshift'; -export { GeometryHelperOracle as oracle } from './dialects/oracle'; -export { GeometryHelperSQLite as sqlite } from './dialects/sqlite'; -export { GeometryHelperMySQL as mysql } from './dialects/mysql'; -export { GeometryHelperMSSQL as mssql } from './dialects/mssql'; +export { GeometryHelperPostgres as postgres } from './dialects/postgres.js'; +export { GeometryHelperPostgres as cockroachdb } from './dialects/postgres.js'; +export { GeometryHelperRedshift as redshift } from './dialects/redshift.js'; +export { GeometryHelperOracle as oracle } from './dialects/oracle.js'; +export { GeometryHelperSQLite as sqlite } from './dialects/sqlite.js'; +export { GeometryHelperMySQL as mysql } from './dialects/mysql.js'; +export { GeometryHelperMSSQL as mssql } from './dialects/mssql.js'; diff --git a/api/src/database/helpers/geometry/types.ts b/api/src/database/helpers/geometry/types.ts index 034fd06a43..296e892107 100644 --- a/api/src/database/helpers/geometry/types.ts +++ b/api/src/database/helpers/geometry/types.ts @@ -1,7 +1,7 @@ -import type { Field, RawField } from '@directus/shared/types'; +import type { Field, RawField } from '@directus/types'; import type { Knex } from 'knex'; import { GeoJSONGeometry, stringify as geojsonToWKT } from 'wellknown'; -import { DatabaseHelper } from '../types'; +import { DatabaseHelper } from '../types.js'; export abstract class GeometryHelper extends DatabaseHelper { supported(): boolean | Promise { diff --git a/api/src/database/helpers/index.ts b/api/src/database/helpers/index.ts index 9828c865a1..d52a370f57 100644 --- a/api/src/database/helpers/index.ts +++ b/api/src/database/helpers/index.ts @@ -1,11 +1,11 @@ -import type { SchemaOverview } from '@directus/shared/types'; +import type { SchemaOverview } from '@directus/types'; import type { Knex } from 'knex'; -import { getDatabaseClient } from '..'; +import { getDatabaseClient } from '../index.js'; -import * as dateHelpers from './date'; -import * as fnHelpers from './fn'; -import * as geometryHelpers from './geometry'; -import * as schemaHelpers from './schema'; +import * as dateHelpers from './date/index.js'; +import * as fnHelpers from './fn/index.js'; +import * as geometryHelpers from './geometry/index.js'; +import * as schemaHelpers from './schema/index.js'; export function getHelpers(database: Knex) { const client = getDatabaseClient(database); diff --git a/api/src/database/helpers/schema/dialects/cockroachdb.ts b/api/src/database/helpers/schema/dialects/cockroachdb.ts index b544a2a77c..07a8df2b84 100644 --- a/api/src/database/helpers/schema/dialects/cockroachdb.ts +++ b/api/src/database/helpers/schema/dialects/cockroachdb.ts @@ -1,5 +1,5 @@ -import type { KNEX_TYPES } from '@directus/shared/constants'; -import { Options, SchemaHelper } from '../types'; +import type { KNEX_TYPES } from '@directus/constants'; +import { Options, SchemaHelper } from '../types.js'; export class SchemaHelperCockroachDb extends SchemaHelper { override async changeToType( diff --git a/api/src/database/helpers/schema/dialects/default.ts b/api/src/database/helpers/schema/dialects/default.ts index b6a19f2092..96f4b3ea28 100644 --- a/api/src/database/helpers/schema/dialects/default.ts +++ b/api/src/database/helpers/schema/dialects/default.ts @@ -1,3 +1,3 @@ -import { SchemaHelper } from '../types'; +import { SchemaHelper } from '../types.js'; export class SchemaHelperDefault extends SchemaHelper {} diff --git a/api/src/database/helpers/schema/dialects/mssql.ts b/api/src/database/helpers/schema/dialects/mssql.ts index aab9f419e3..72d8676519 100644 --- a/api/src/database/helpers/schema/dialects/mssql.ts +++ b/api/src/database/helpers/schema/dialects/mssql.ts @@ -1,5 +1,5 @@ import type { Knex } from 'knex'; -import { SchemaHelper } from '../types'; +import { SchemaHelper } from '../types.js'; export class SchemaHelperMSSQL extends SchemaHelper { override applyLimit(rootQuery: Knex.QueryBuilder, limit: number): void { diff --git a/api/src/database/helpers/schema/dialects/mysql.ts b/api/src/database/helpers/schema/dialects/mysql.ts index 4eeeacc819..e5339f4baa 100644 --- a/api/src/database/helpers/schema/dialects/mysql.ts +++ b/api/src/database/helpers/schema/dialects/mysql.ts @@ -1,6 +1,6 @@ import type { Knex } from 'knex'; -import { getDatabaseVersion } from '../../../../database'; -import { SchemaHelper } from '../types'; +import { getDatabaseVersion } from '../../../../database/index.js'; +import { SchemaHelper } from '../types.js'; export class SchemaHelperMySQL extends SchemaHelper { override applyMultiRelationalSort( diff --git a/api/src/database/helpers/schema/dialects/oracle.ts b/api/src/database/helpers/schema/dialects/oracle.ts index ea07c2333b..1b6c412223 100644 --- a/api/src/database/helpers/schema/dialects/oracle.ts +++ b/api/src/database/helpers/schema/dialects/oracle.ts @@ -1,6 +1,6 @@ -import type { KNEX_TYPES } from '@directus/shared/constants'; -import type { Field, Relation, Type } from '@directus/shared/types'; -import { Options, SchemaHelper } from '../types'; +import type { KNEX_TYPES } from '@directus/constants'; +import type { Field, Relation, Type } from '@directus/types'; +import { Options, SchemaHelper } from '../types.js'; export class SchemaHelperOracle extends SchemaHelper { override async changeToType( diff --git a/api/src/database/helpers/schema/dialects/sqlite.ts b/api/src/database/helpers/schema/dialects/sqlite.ts index cbe1b6d5c9..6f5539b988 100644 --- a/api/src/database/helpers/schema/dialects/sqlite.ts +++ b/api/src/database/helpers/schema/dialects/sqlite.ts @@ -1,4 +1,4 @@ -import { SchemaHelper } from '../types'; +import { SchemaHelper } from '../types.js'; export class SchemaHelperSQLite extends SchemaHelper { override async preColumnChange(): Promise { diff --git a/api/src/database/helpers/schema/index.ts b/api/src/database/helpers/schema/index.ts index df528ec4f0..04e9a73f3d 100644 --- a/api/src/database/helpers/schema/index.ts +++ b/api/src/database/helpers/schema/index.ts @@ -1,7 +1,7 @@ -export { SchemaHelperDefault as postgres } from './dialects/default'; -export { SchemaHelperCockroachDb as cockroachdb } from './dialects/cockroachdb'; -export { SchemaHelperDefault as redshift } from './dialects/default'; -export { SchemaHelperOracle as oracle } from './dialects/oracle'; -export { SchemaHelperSQLite as sqlite } from './dialects/sqlite'; -export { SchemaHelperMySQL as mysql } from './dialects/mysql'; -export { SchemaHelperMSSQL as mssql } from './dialects/mssql'; +export { SchemaHelperDefault as postgres } from './dialects/default.js'; +export { SchemaHelperCockroachDb as cockroachdb } from './dialects/cockroachdb.js'; +export { SchemaHelperDefault as redshift } from './dialects/default.js'; +export { SchemaHelperOracle as oracle } from './dialects/oracle.js'; +export { SchemaHelperSQLite as sqlite } from './dialects/sqlite.js'; +export { SchemaHelperMySQL as mysql } from './dialects/mysql.js'; +export { SchemaHelperMSSQL as mssql } from './dialects/mssql.js'; diff --git a/api/src/database/helpers/schema/types.ts b/api/src/database/helpers/schema/types.ts index bd7f5beab4..b19bd6aac5 100644 --- a/api/src/database/helpers/schema/types.ts +++ b/api/src/database/helpers/schema/types.ts @@ -1,9 +1,9 @@ -import type { KNEX_TYPES } from '@directus/shared/constants'; -import type { Field, Relation, Type } from '@directus/shared/types'; +import type { KNEX_TYPES } from '@directus/constants'; +import type { Field, Relation, Type } from '@directus/types'; import type { Knex } from 'knex'; -import type { DatabaseClient } from '../../../types'; -import { getDatabaseClient } from '../../index'; -import { DatabaseHelper } from '../types'; +import type { DatabaseClient } from '../../../types/index.js'; +import { getDatabaseClient } from '../../index.js'; +import { DatabaseHelper } from '../types.js'; export type Options = { nullable?: boolean; default?: any; length?: number }; diff --git a/api/src/database/index.ts b/api/src/database/index.ts index 03ed674bec..fe67aa6528 100644 --- a/api/src/database/index.ts +++ b/api/src/database/index.ts @@ -1,21 +1,27 @@ -import SchemaInspector from '@directus/schema'; +import { createInspector } from '@directus/schema'; +import type { SchemaInspector } from '@directus/schema'; import fse from 'fs-extra'; -import { knex, Knex } from 'knex'; -import { merge } from 'lodash'; +import type { Knex } from 'knex'; +import knex from 'knex'; +import { merge } from 'lodash-es'; +import { dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; import path from 'path'; import { performance } from 'perf_hooks'; import { promisify } from 'util'; -import env from '../env'; -import logger from '../logger'; -import type { DatabaseClient } from '../types'; -import { getConfigFromEnv } from '../utils/get-config-from-env'; -import { validateEnv } from '../utils/validate-env'; -import { getHelpers } from './helpers'; +import env from '../env.js'; +import logger from '../logger.js'; +import type { DatabaseClient } from '../types/index.js'; +import { getConfigFromEnv } from '../utils/get-config-from-env.js'; +import { validateEnv } from '../utils/validate-env.js'; +import { getHelpers } from './helpers/index.js'; let database: Knex | null = null; -let inspector: ReturnType | null = null; +let inspector: SchemaInspector | null = null; let databaseVersion: string | null = null; +const __dirname = dirname(fileURLToPath(import.meta.url)); + export default function getDatabase(): Knex { if (database) { return database; @@ -131,7 +137,7 @@ export default function getDatabase(): Knex { merge(knexConfig, { connection: { options: { useUTC: false } } }); } - database = knex(knexConfig); + database = knex.default(knexConfig); validateDatabaseCharset(database); const times: Record = {}; @@ -149,14 +155,14 @@ export default function getDatabase(): Knex { return database; } -export function getSchemaInspector(): ReturnType { +export function getSchemaInspector(): SchemaInspector { if (inspector) { return inspector; } const database = getDatabase(); - inspector = SchemaInspector(database); + inspector = createInspector(database); return inspector; } diff --git a/api/src/database/migrations/20201029A-remove-system-relations.ts b/api/src/database/migrations/20201029A-remove-system-relations.ts index 12f81e9464..bdd52c093b 100644 --- a/api/src/database/migrations/20201029A-remove-system-relations.ts +++ b/api/src/database/migrations/20201029A-remove-system-relations.ts @@ -1,5 +1,5 @@ import type { Knex } from 'knex'; -import { merge } from 'lodash'; +import { merge } from 'lodash-es'; export async function up(knex: Knex): Promise { await knex('directus_relations') diff --git a/api/src/database/migrations/20201029B-remove-system-collections.ts b/api/src/database/migrations/20201029B-remove-system-collections.ts index 65c7011fe0..edac8414af 100644 --- a/api/src/database/migrations/20201029B-remove-system-collections.ts +++ b/api/src/database/migrations/20201029B-remove-system-collections.ts @@ -1,5 +1,5 @@ import type { Knex } from 'knex'; -import { merge } from 'lodash'; +import { merge } from 'lodash-es'; export async function up(knex: Knex): Promise { await knex('directus_collections').delete().where('collection', 'like', 'directus_%'); diff --git a/api/src/database/migrations/20201029C-remove-system-fields.ts b/api/src/database/migrations/20201029C-remove-system-fields.ts index c3cf4b81f9..8b894f0b81 100644 --- a/api/src/database/migrations/20201029C-remove-system-fields.ts +++ b/api/src/database/migrations/20201029C-remove-system-fields.ts @@ -1,5 +1,5 @@ import type { Knex } from 'knex'; -import { merge, uniq } from 'lodash'; +import { merge, uniq } from 'lodash-es'; const defaults = { collection: null, diff --git a/api/src/database/migrations/20201105B-change-webhook-url-type.ts b/api/src/database/migrations/20201105B-change-webhook-url-type.ts index ab4a182040..1ec1e7bb7a 100644 --- a/api/src/database/migrations/20201105B-change-webhook-url-type.ts +++ b/api/src/database/migrations/20201105B-change-webhook-url-type.ts @@ -1,5 +1,5 @@ import type { Knex } from 'knex'; -import { getHelpers } from '../helpers'; +import { getHelpers } from '../helpers/index.js'; export async function up(knex: Knex): Promise { const helper = getHelpers(knex).schema; diff --git a/api/src/database/migrations/20210225A-add-relations-sort-field.ts b/api/src/database/migrations/20210225A-add-relations-sort-field.ts index 3979fe5b22..a20178917a 100644 --- a/api/src/database/migrations/20210225A-add-relations-sort-field.ts +++ b/api/src/database/migrations/20210225A-add-relations-sort-field.ts @@ -1,4 +1,4 @@ -import { parseJSON } from '@directus/shared/utils'; +import { parseJSON } from '@directus/utils'; import type { Knex } from 'knex'; export async function up(knex: Knex): Promise { diff --git a/api/src/database/migrations/20210312A-webhooks-collections-text.ts b/api/src/database/migrations/20210312A-webhooks-collections-text.ts index fa7be61680..8e7d94f649 100644 --- a/api/src/database/migrations/20210312A-webhooks-collections-text.ts +++ b/api/src/database/migrations/20210312A-webhooks-collections-text.ts @@ -1,5 +1,5 @@ import type { Knex } from 'knex'; -import { getHelpers } from '../helpers'; +import { getHelpers } from '../helpers/index.js'; export async function up(knex: Knex): Promise { const helper = getHelpers(knex).schema; diff --git a/api/src/database/migrations/20210415A-make-filesize-nullable.ts b/api/src/database/migrations/20210415A-make-filesize-nullable.ts index 9df3fffe7a..87d560ad93 100644 --- a/api/src/database/migrations/20210415A-make-filesize-nullable.ts +++ b/api/src/database/migrations/20210415A-make-filesize-nullable.ts @@ -1,5 +1,5 @@ import type { Knex } from 'knex'; -import { getHelpers } from '../helpers'; +import { getHelpers } from '../helpers/index.js'; export async function up(knex: Knex): Promise { const helper = getHelpers(knex).schema; diff --git a/api/src/database/migrations/20210506A-rename-interfaces.ts b/api/src/database/migrations/20210506A-rename-interfaces.ts index 928141a52c..59ecce4a49 100644 --- a/api/src/database/migrations/20210506A-rename-interfaces.ts +++ b/api/src/database/migrations/20210506A-rename-interfaces.ts @@ -1,4 +1,4 @@ -import { parseJSON } from '@directus/shared/utils'; +import { parseJSON } from '@directus/utils'; import type { Knex } from 'knex'; // [before, after, after-option additions] diff --git a/api/src/database/migrations/20210510A-restructure-relations.ts b/api/src/database/migrations/20210510A-restructure-relations.ts index 8fbfa1a298..ceff45d620 100644 --- a/api/src/database/migrations/20210510A-restructure-relations.ts +++ b/api/src/database/migrations/20210510A-restructure-relations.ts @@ -1,5 +1,5 @@ import type { Knex } from 'knex'; -import { getHelpers } from '../helpers'; +import { getHelpers } from '../helpers/index.js'; export async function up(knex: Knex): Promise { const helper = getHelpers(knex).schema; diff --git a/api/src/database/migrations/20210518A-add-foreign-key-constraints.ts b/api/src/database/migrations/20210518A-add-foreign-key-constraints.ts index 6d458907f5..2f3c3f16f0 100644 --- a/api/src/database/migrations/20210518A-add-foreign-key-constraints.ts +++ b/api/src/database/migrations/20210518A-add-foreign-key-constraints.ts @@ -1,11 +1,11 @@ -import type { RelationMeta } from '@directus/shared/types'; +import type { RelationMeta } from '@directus/types'; import type { Knex } from 'knex'; -import SchemaInspector from 'knex-schema-inspector'; -import logger from '../../logger'; -import { getDefaultIndexName } from '../../utils/get-default-index-name'; +import { createInspector } from '@directus/schema'; +import logger from '../../logger.js'; +import { getDefaultIndexName } from '../../utils/get-default-index-name.js'; export async function up(knex: Knex): Promise { - const inspector = SchemaInspector(knex); + const inspector = createInspector(knex); const foreignKeys = await inspector.foreignKeys(); const relations = await knex diff --git a/api/src/database/migrations/20210519A-add-system-fk-triggers.ts b/api/src/database/migrations/20210519A-add-system-fk-triggers.ts index 1d152272f2..db0d2de068 100644 --- a/api/src/database/migrations/20210519A-add-system-fk-triggers.ts +++ b/api/src/database/migrations/20210519A-add-system-fk-triggers.ts @@ -1,6 +1,6 @@ import type { Knex } from 'knex'; -import SchemaInspector from 'knex-schema-inspector'; -import logger from '../../logger'; +import { createInspector } from '@directus/schema'; +import logger from '../../logger.js'; /** * Things to keep in mind: @@ -81,14 +81,14 @@ const updates = [ ]; export async function up(knex: Knex): Promise { - const inspector = SchemaInspector(knex); + const inspector = createInspector(knex); const foreignKeys = await inspector.foreignKeys(); for (const update of updates) { for (const constraint of update.constraints) { const existingForeignKey = foreignKeys.find( - (fk) => + (fk: any) => fk.table === update.table && fk.column === constraint.column && fk.foreign_key_table === constraint.references.split('.')[0] && diff --git a/api/src/database/migrations/20210626A-change-filesize-bigint.ts b/api/src/database/migrations/20210626A-change-filesize-bigint.ts index 4691b47327..5db64c2bbd 100644 --- a/api/src/database/migrations/20210626A-change-filesize-bigint.ts +++ b/api/src/database/migrations/20210626A-change-filesize-bigint.ts @@ -1,5 +1,5 @@ import type { Knex } from 'knex'; -import { getHelpers } from '../helpers'; +import { getHelpers } from '../helpers/index.js'; export async function up(knex: Knex): Promise { const helper = getHelpers(knex).schema; diff --git a/api/src/database/migrations/20210721A-add-default-folder.ts b/api/src/database/migrations/20210721A-add-default-folder.ts index 606a286a2a..43a931c1ee 100644 --- a/api/src/database/migrations/20210721A-add-default-folder.ts +++ b/api/src/database/migrations/20210721A-add-default-folder.ts @@ -1,5 +1,5 @@ import type { Knex } from 'knex'; -import { getDefaultIndexName } from '../../utils/get-default-index-name'; +import { getDefaultIndexName } from '../../utils/get-default-index-name.js'; const indexName = getDefaultIndexName('foreign', 'directus_settings', 'storage_default_folder'); diff --git a/api/src/database/migrations/20210802A-replace-groups.ts b/api/src/database/migrations/20210802A-replace-groups.ts index 626084a7b3..9bd379c8d9 100644 --- a/api/src/database/migrations/20210802A-replace-groups.ts +++ b/api/src/database/migrations/20210802A-replace-groups.ts @@ -1,6 +1,6 @@ -import { parseJSON } from '@directus/shared/utils'; +import { parseJSON } from '@directus/utils'; import type { Knex } from 'knex'; -import logger from '../../logger'; +import logger from '../../logger.js'; export async function up(knex: Knex): Promise { const dividerGroups = await knex.select('*').from('directus_fields').where('interface', '=', 'group-divider'); diff --git a/api/src/database/migrations/20210805A-update-groups.ts b/api/src/database/migrations/20210805A-update-groups.ts index 5bc0ca9748..c285fdfded 100644 --- a/api/src/database/migrations/20210805A-update-groups.ts +++ b/api/src/database/migrations/20210805A-update-groups.ts @@ -1,4 +1,4 @@ -import { parseJSON } from '@directus/shared/utils'; +import { parseJSON } from '@directus/utils'; import type { Knex } from 'knex'; export async function up(knex: Knex): Promise { diff --git a/api/src/database/migrations/20210805B-change-image-metadata-structure.ts b/api/src/database/migrations/20210805B-change-image-metadata-structure.ts index 3cf6be7441..a97efc07f8 100644 --- a/api/src/database/migrations/20210805B-change-image-metadata-structure.ts +++ b/api/src/database/migrations/20210805B-change-image-metadata-structure.ts @@ -1,4 +1,4 @@ -import { parseJSON } from '@directus/shared/utils'; +import { parseJSON } from '@directus/utils'; import type { Knex } from 'knex'; // Change image metadata structure to match the output from 'exifr' diff --git a/api/src/database/migrations/20210903A-add-auth-provider.ts b/api/src/database/migrations/20210903A-add-auth-provider.ts index abc532f1a5..e10873202d 100644 --- a/api/src/database/migrations/20210903A-add-auth-provider.ts +++ b/api/src/database/migrations/20210903A-add-auth-provider.ts @@ -1,5 +1,5 @@ import type { Knex } from 'knex'; -import { getHelpers } from '../helpers'; +import { getHelpers } from '../helpers/index.js'; export async function up(knex: Knex): Promise { const helper = getHelpers(knex).schema; diff --git a/api/src/database/migrations/20210907A-webhooks-collections-not-null.ts b/api/src/database/migrations/20210907A-webhooks-collections-not-null.ts index 7dcd06082e..dbef445222 100644 --- a/api/src/database/migrations/20210907A-webhooks-collections-not-null.ts +++ b/api/src/database/migrations/20210907A-webhooks-collections-not-null.ts @@ -1,5 +1,5 @@ import type { Knex } from 'knex'; -import { getHelpers } from '../helpers'; +import { getHelpers } from '../helpers/index.js'; export async function up(knex: Knex): Promise { const helper = getHelpers(knex).schema; diff --git a/api/src/database/migrations/20210920A-webhooks-url-not-null.ts b/api/src/database/migrations/20210920A-webhooks-url-not-null.ts index b290c4ab64..82741a648c 100644 --- a/api/src/database/migrations/20210920A-webhooks-url-not-null.ts +++ b/api/src/database/migrations/20210920A-webhooks-url-not-null.ts @@ -1,5 +1,5 @@ import type { Knex } from 'knex'; -import { getHelpers } from '../helpers'; +import { getHelpers } from '../helpers/index.js'; export async function up(knex: Knex): Promise { const helper = getHelpers(knex).schema; diff --git a/api/src/database/migrations/20210927A-replace-fields-group.ts b/api/src/database/migrations/20210927A-replace-fields-group.ts index 88cc2bc9a6..3bd3478384 100644 --- a/api/src/database/migrations/20210927A-replace-fields-group.ts +++ b/api/src/database/migrations/20210927A-replace-fields-group.ts @@ -1,5 +1,5 @@ import type { Knex } from 'knex'; -import { uniq } from 'lodash'; +import { uniq } from 'lodash-es'; export async function up(knex: Knex): Promise { const groupsInUse = await knex.select('id', 'group').from('directus_fields').whereNotNull('group'); diff --git a/api/src/database/migrations/20211007A-update-presets.ts b/api/src/database/migrations/20211007A-update-presets.ts index 5dffb7b48b..fdedb05222 100644 --- a/api/src/database/migrations/20211007A-update-presets.ts +++ b/api/src/database/migrations/20211007A-update-presets.ts @@ -1,5 +1,5 @@ -import type { Filter, LogicalFilterAND } from '@directus/shared/types'; -import { parseJSON } from '@directus/shared/utils'; +import type { Filter, LogicalFilterAND } from '@directus/types'; +import { parseJSON } from '@directus/utils'; import type { Knex } from 'knex'; type OldFilter = { diff --git a/api/src/database/migrations/20220303A-remove-default-project-color.ts b/api/src/database/migrations/20220303A-remove-default-project-color.ts index d2cba3a1e9..88a5d4ba3b 100644 --- a/api/src/database/migrations/20220303A-remove-default-project-color.ts +++ b/api/src/database/migrations/20220303A-remove-default-project-color.ts @@ -1,5 +1,5 @@ import type { Knex } from 'knex'; -import { getHelpers } from '../helpers'; +import { getHelpers } from '../helpers/index.js'; export async function up(knex: Knex): Promise { const helper = getHelpers(knex).schema; diff --git a/api/src/database/migrations/20220322A-rename-field-typecast-flags.ts b/api/src/database/migrations/20220322A-rename-field-typecast-flags.ts index 8203304133..7fb92616ed 100644 --- a/api/src/database/migrations/20220322A-rename-field-typecast-flags.ts +++ b/api/src/database/migrations/20220322A-rename-field-typecast-flags.ts @@ -1,6 +1,6 @@ -import { toArray } from '@directus/shared/utils'; +import { toArray } from '@directus/utils'; import type { Knex } from 'knex'; -import { isArray } from 'lodash'; +import { isArray } from 'lodash-es'; export async function up(knex: Knex): Promise { const fields = await knex diff --git a/api/src/database/migrations/20220325A-fix-typecast-flags.ts b/api/src/database/migrations/20220325A-fix-typecast-flags.ts index 0815e7f6a6..c63d040c04 100644 --- a/api/src/database/migrations/20220325A-fix-typecast-flags.ts +++ b/api/src/database/migrations/20220325A-fix-typecast-flags.ts @@ -1,6 +1,6 @@ -import { toArray } from '@directus/shared/utils'; +import { toArray } from '@directus/utils'; import type { Knex } from 'knex'; -import { isArray } from 'lodash'; +import { isArray } from 'lodash-es'; export async function up(knex: Knex): Promise { const fields = await knex diff --git a/api/src/database/migrations/20220325B-add-default-language.ts b/api/src/database/migrations/20220325B-add-default-language.ts index b7fc515c84..40eceb199c 100644 --- a/api/src/database/migrations/20220325B-add-default-language.ts +++ b/api/src/database/migrations/20220325B-add-default-language.ts @@ -1,5 +1,5 @@ import type { Knex } from 'knex'; -import { getHelpers } from '../helpers'; +import { getHelpers } from '../helpers/index.js'; export async function up(knex: Knex): Promise { const helper = getHelpers(knex).schema; diff --git a/api/src/database/migrations/20220402A-remove-default-value-panel-icon.ts b/api/src/database/migrations/20220402A-remove-default-value-panel-icon.ts index c1c39c872c..d1c3f32d87 100644 --- a/api/src/database/migrations/20220402A-remove-default-value-panel-icon.ts +++ b/api/src/database/migrations/20220402A-remove-default-value-panel-icon.ts @@ -1,5 +1,5 @@ import type { Knex } from 'knex'; -import { getHelpers } from '../helpers'; +import { getHelpers } from '../helpers/index.js'; export async function up(knex: Knex): Promise { const helper = getHelpers(knex).schema; diff --git a/api/src/database/migrations/20220429A-add-flows.ts b/api/src/database/migrations/20220429A-add-flows.ts index 7ef6016782..87ace11975 100644 --- a/api/src/database/migrations/20220429A-add-flows.ts +++ b/api/src/database/migrations/20220429A-add-flows.ts @@ -1,4 +1,4 @@ -import { parseJSON, toArray } from '@directus/shared/utils'; +import { parseJSON, toArray } from '@directus/utils'; import type { Knex } from 'knex'; import { v4 as uuid } from 'uuid'; diff --git a/api/src/database/migrations/20220801A-update-notifications-timestamp-column.ts b/api/src/database/migrations/20220801A-update-notifications-timestamp-column.ts index 28a4205c33..ae53f840bf 100644 --- a/api/src/database/migrations/20220801A-update-notifications-timestamp-column.ts +++ b/api/src/database/migrations/20220801A-update-notifications-timestamp-column.ts @@ -1,5 +1,5 @@ import type { Knex } from 'knex'; -import { getHelpers } from '../helpers'; +import { getHelpers } from '../helpers/index.js'; export async function up(knex: Knex): Promise { const helper = getHelpers(knex).schema; diff --git a/api/src/database/migrations/run.test.ts b/api/src/database/migrations/run.test.ts index b020b5ff71..db93afc970 100644 --- a/api/src/database/migrations/run.test.ts +++ b/api/src/database/migrations/run.test.ts @@ -1,6 +1,7 @@ -import knex, { Knex } from 'knex'; +import knex from 'knex'; +import type { Knex } from 'knex'; import { createTracker, MockClient, Tracker } from 'knex-mock-client'; -import run from './run'; +import run from './run.js'; import { describe, beforeAll, afterEach, it, expect, MockedFunction, vi } from 'vitest'; describe('run', () => { @@ -8,7 +9,7 @@ describe('run', () => { let tracker: Tracker; beforeAll(() => { - db = vi.mocked(knex({ client: MockClient })); + db = vi.mocked(knex.default({ client: MockClient })); tracker = createTracker(db); }); diff --git a/api/src/database/migrations/run.ts b/api/src/database/migrations/run.ts index d32e6aed03..a67c69bfe7 100644 --- a/api/src/database/migrations/run.ts +++ b/api/src/database/migrations/run.ts @@ -1,14 +1,15 @@ +import formatTitle from '@directus/format-title'; import fse from 'fs-extra'; import type { Knex } from 'knex'; -import { orderBy } from 'lodash'; +import { orderBy } from 'lodash-es'; +import { dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; import path from 'path'; -import env from '../../env'; -import logger from '../../logger'; -import type { Migration } from '../../types'; -import { dynamicImport } from '../../utils/dynamic-import'; +import env from '../../env.js'; +import logger from '../../logger.js'; +import type { Migration } from '../../types/index.js'; -// @ts-ignore -import formatTitle from '@directus/format-title'; +const __dirname = dirname(fileURLToPath(import.meta.url)); export default async function run(database: Knex, direction: 'up' | 'down' | 'latest', log = true): Promise { let migrationFiles = await fse.readdir(__dirname); @@ -34,7 +35,7 @@ export default async function run(database: Knex, direction: 'up' | 'down' | 'la function parseFilePath(filePath: string, custom = false) { const version = filePath.split('-')[0]; - const name = formatTitle(filePath.split('-').slice(1).join('_').split('.')[0]); + const name = formatTitle(filePath.split('-').slice(1).join('_').split('.')[0]!); const completed = !!completedMigrations.find((migration) => migration.version === version); return { @@ -66,7 +67,7 @@ export default async function run(database: Knex, direction: 'up' | 'down' | 'la throw Error('Nothing to upgrade'); } - const { up } = await dynamicImport(nextVersion.file); + const { up } = await import(nextVersion.file); if (log) { logger.info(`Applying ${nextVersion.name}...`); @@ -89,7 +90,7 @@ export default async function run(database: Knex, direction: 'up' | 'down' | 'la throw new Error("Couldn't find migration"); } - const { down } = await dynamicImport(migration.file); + const { down } = await import(migration.file); if (log) { logger.info(`Undoing ${migration.name}...`); @@ -102,7 +103,7 @@ export default async function run(database: Knex, direction: 'up' | 'down' | 'la async function latest() { for (const migration of migrations) { if (migration.completed === false) { - const { up } = await dynamicImport(migration.file); + const { up } = await import(migration.file); if (log) { logger.info(`Applying ${migration.name}...`); diff --git a/api/src/database/run-ast.ts b/api/src/database/run-ast.ts index f67f71f2d0..63f973128d 100644 --- a/api/src/database/run-ast.ts +++ b/api/src/database/run-ast.ts @@ -1,18 +1,18 @@ -import type { Item, Query, SchemaOverview } from '@directus/shared/types'; -import { toArray } from '@directus/shared/utils'; +import type { Item, Query, SchemaOverview } from '@directus/types'; +import { toArray } from '@directus/utils'; import type { Knex } from 'knex'; -import { clone, cloneDeep, isNil, merge, pick, uniq } from 'lodash'; -import getDatabase from '.'; -import { getHelpers } from '../database/helpers'; -import env from '../env'; -import { PayloadService } from '../services/payload'; -import type { AST, FieldNode, FunctionFieldNode, M2ONode, NestedCollectionNode } from '../types/ast'; -import { applyFunctionToColumnName } from '../utils/apply-function-to-column-name'; -import applyQuery, { applyLimit, applySort, ColumnSortRecord, generateAlias } from '../utils/apply-query'; -import { getCollectionFromAlias } from '../utils/get-collection-from-alias'; -import { getColumn } from '../utils/get-column'; -import type { AliasMap } from '../utils/get-column-path'; -import { stripFunction } from '../utils/strip-function'; +import { clone, cloneDeep, isNil, merge, pick, uniq } from 'lodash-es'; +import { getHelpers } from '../database/helpers/index.js'; +import env from '../env.js'; +import { PayloadService } from '../services/payload.js'; +import type { AST, FieldNode, FunctionFieldNode, M2ONode, NestedCollectionNode } from '../types/ast.js'; +import { applyFunctionToColumnName } from '../utils/apply-function-to-column-name.js'; +import applyQuery, { applyLimit, applySort, ColumnSortRecord, generateAlias } from '../utils/apply-query.js'; +import { getCollectionFromAlias } from '../utils/get-collection-from-alias.js'; +import type { AliasMap } from '../utils/get-column-path.js'; +import { getColumn } from '../utils/get-column.js'; +import { stripFunction } from '../utils/strip-function.js'; +import getDatabase from './index.js'; type RunASTOptions = { /** diff --git a/api/src/database/seeds/run.ts b/api/src/database/seeds/run.ts index b158157e63..5162db25ba 100644 --- a/api/src/database/seeds/run.ts +++ b/api/src/database/seeds/run.ts @@ -1,10 +1,14 @@ -import type { Field, Type } from '@directus/shared/types'; +import type { Field, Type } from '@directus/types'; import fse from 'fs-extra'; import yaml from 'js-yaml'; import type { Knex } from 'knex'; -import { isObject } from 'lodash'; +import { isObject } from 'lodash-es'; +import { dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; import path from 'path'; -import { getHelpers } from '../helpers'; +import { getHelpers } from '../helpers/index.js'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); type TableSeed = { table: string; diff --git a/api/src/database/system-data/app-access-permissions/index.ts b/api/src/database/system-data/app-access-permissions/index.ts index 8e0a39ba36..93b5097c53 100644 --- a/api/src/database/system-data/app-access-permissions/index.ts +++ b/api/src/database/system-data/app-access-permissions/index.ts @@ -1,6 +1,8 @@ -import type { Permission } from '@directus/shared/types'; -import { merge } from 'lodash'; -import { requireYAML } from '../../../utils/require-yaml'; +import type { Permission } from '@directus/types'; +import { merge } from 'lodash-es'; +import path, { dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { requireYAML } from '../../../utils/require-yaml.js'; const defaults: Partial = { role: null, @@ -11,8 +13,10 @@ const defaults: Partial = { system: true, }; -const schemaPermissionsRaw = requireYAML(require.resolve('./schema-access-permissions.yaml')) as Permission[]; -const permissions = requireYAML(require.resolve('./app-access-permissions.yaml')) as Permission[]; +const __dirname = dirname(fileURLToPath(import.meta.url)); + +const schemaPermissionsRaw = requireYAML(path.resolve(__dirname, './schema-access-permissions.yaml')) as Permission[]; +const permissions = requireYAML(path.resolve(__dirname, './app-access-permissions.yaml')) as Permission[]; export const schemaPermissions: Permission[] = schemaPermissionsRaw.map((row) => merge({}, defaults, row)); export const appAccessMinimalPermissions: Permission[] = [...schemaPermissions, ...permissions].map((row) => diff --git a/api/src/database/system-data/collections/index.ts b/api/src/database/system-data/collections/index.ts index 2ef25f92d0..d68492aad4 100644 --- a/api/src/database/system-data/collections/index.ts +++ b/api/src/database/system-data/collections/index.ts @@ -1,8 +1,12 @@ -import { merge } from 'lodash'; -import type { CollectionMeta } from '../../../types'; -import { requireYAML } from '../../../utils/require-yaml'; +import { merge } from 'lodash-es'; +import type { CollectionMeta } from '../../../types/index.js'; +import { requireYAML } from '../../../utils/require-yaml.js'; +import { dirname, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; -const systemData = requireYAML(require.resolve('./collections.yaml')); +const __dirname = dirname(fileURLToPath(import.meta.url)); + +const systemData = requireYAML(resolve(__dirname, './collections.yaml')); export const systemCollectionRows: CollectionMeta[] = systemData['data'].map((row: Record) => { return merge({ system: true }, systemData['defaults'], row); diff --git a/api/src/database/system-data/fields/index.ts b/api/src/database/system-data/fields/index.ts index 36f50f45e5..33ae6a1ffa 100644 --- a/api/src/database/system-data/fields/index.ts +++ b/api/src/database/system-data/fields/index.ts @@ -1,14 +1,16 @@ -import type { FieldMeta } from '@directus/shared/types'; +import type { FieldMeta } from '@directus/types'; import fse from 'fs-extra'; -import { merge } from 'lodash'; +import { merge } from 'lodash-es'; import path from 'path'; -import { getAuthProviders } from '../../../utils/get-auth-providers'; -import { requireYAML } from '../../../utils/require-yaml'; - -// @ts-ignore +import { getAuthProviders } from '../../../utils/get-auth-providers.js'; +import { requireYAML } from '../../../utils/require-yaml.js'; import formatTitle from '@directus/format-title'; +import { fileURLToPath } from 'url'; -const defaults = requireYAML(require.resolve('./_defaults.yaml')); +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +const defaults = requireYAML(path.join(__dirname, './_defaults.yaml')); const fieldData = fse.readdirSync(path.resolve(__dirname)); export const systemFieldRows: FieldMeta[] = []; diff --git a/api/src/database/system-data/relations/index.ts b/api/src/database/system-data/relations/index.ts index 5eb16e1129..8d112c087c 100644 --- a/api/src/database/system-data/relations/index.ts +++ b/api/src/database/system-data/relations/index.ts @@ -1,8 +1,12 @@ -import type { RelationMeta } from '@directus/shared/types'; -import { merge } from 'lodash'; -import { requireYAML } from '../../../utils/require-yaml'; +import type { RelationMeta } from '@directus/types'; +import { merge } from 'lodash-es'; +import { requireYAML } from '../../../utils/require-yaml.js'; +import { dirname, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; -const systemData = requireYAML(require.resolve('./relations.yaml')) as { +const __dirname = dirname(fileURLToPath(import.meta.url)); + +const systemData = requireYAML(resolve(__dirname, './relations.yaml')) as { data: RelationMeta[]; defaults: Partial; }; diff --git a/api/src/emitter.ts b/api/src/emitter.ts index 0d0942f179..d4bf26a12c 100644 --- a/api/src/emitter.ts +++ b/api/src/emitter.ts @@ -1,6 +1,6 @@ -import type { ActionHandler, EventContext, FilterHandler, InitHandler } from '@directus/shared/types'; -import { EventEmitter2 } from 'eventemitter2'; -import logger from './logger'; +import type { ActionHandler, EventContext, FilterHandler, InitHandler } from '@directus/types'; +import ee2 from 'eventemitter2'; +import logger from './logger.js'; export class Emitter { private filterEmitter; @@ -17,9 +17,9 @@ export class Emitter { ignoreErrors: true, }; - this.filterEmitter = new EventEmitter2(emitterOptions); - this.actionEmitter = new EventEmitter2(emitterOptions); - this.initEmitter = new EventEmitter2(emitterOptions); + this.filterEmitter = new ee2.EventEmitter2(emitterOptions); + this.actionEmitter = new ee2.EventEmitter2(emitterOptions); + this.initEmitter = new ee2.EventEmitter2(emitterOptions); } public async emitFilter( diff --git a/api/src/env.ts b/api/src/env.ts index 20f962a6b9..552862023e 100644 --- a/api/src/env.ts +++ b/api/src/env.ts @@ -3,12 +3,15 @@ * For all possible keys, see: https://docs.directus.io/self-hosted/config-options/ */ +import { parseJSON, toArray } from '@directus/utils'; import dotenv from 'dotenv'; import fs from 'fs'; -import { clone, toNumber, toString } from 'lodash'; +import { clone, toNumber, toString } from 'lodash-es'; import path from 'path'; -import { requireYAML } from './utils/require-yaml'; -import { toArray, parseJSON } from '@directus/shared/utils'; +import { requireYAML } from './utils/require-yaml.js'; + +import { createRequire } from 'node:module'; +const require = createRequire(import.meta.url); // keeping this here for now to prevent a circular import to constants.ts const allowedEnvironmentVars = [ diff --git a/api/src/exceptions/database/contains-null-values.ts b/api/src/exceptions/database/contains-null-values.ts index a1456e291e..b1005fb666 100644 --- a/api/src/exceptions/database/contains-null-values.ts +++ b/api/src/exceptions/database/contains-null-values.ts @@ -1,4 +1,4 @@ -import { BaseException } from '@directus/shared/exceptions'; +import { BaseException } from '@directus/exceptions'; type Exceptions = { collection: string; diff --git a/api/src/exceptions/database/dialects/mssql.ts b/api/src/exceptions/database/dialects/mssql.ts index 3ccf775b18..0b1c552b14 100644 --- a/api/src/exceptions/database/dialects/mssql.ts +++ b/api/src/exceptions/database/dialects/mssql.ts @@ -1,11 +1,11 @@ -import getDatabase from '../../../database'; -import { ContainsNullValuesException } from '../contains-null-values'; -import { InvalidForeignKeyException } from '../invalid-foreign-key'; -import { NotNullViolationException } from '../not-null-violation'; -import { RecordNotUniqueException } from '../record-not-unique'; -import { ValueOutOfRangeException } from '../value-out-of-range'; -import { ValueTooLongException } from '../value-too-long'; -import type { MSSQLError } from './types'; +import getDatabase from '../../../database/index.js'; +import { ContainsNullValuesException } from '../contains-null-values.js'; +import { InvalidForeignKeyException } from '../invalid-foreign-key.js'; +import { NotNullViolationException } from '../not-null-violation.js'; +import { RecordNotUniqueException } from '../record-not-unique.js'; +import { ValueOutOfRangeException } from '../value-out-of-range.js'; +import { ValueTooLongException } from '../value-too-long.js'; +import type { MSSQLError } from './types.js'; enum MSSQLErrorCodes { FOREIGN_KEY_VIOLATION = 547, diff --git a/api/src/exceptions/database/dialects/mysql.ts b/api/src/exceptions/database/dialects/mysql.ts index ebf8b70930..9407522411 100644 --- a/api/src/exceptions/database/dialects/mysql.ts +++ b/api/src/exceptions/database/dialects/mysql.ts @@ -1,10 +1,10 @@ -import { ContainsNullValuesException } from '../contains-null-values'; -import { InvalidForeignKeyException } from '../invalid-foreign-key'; -import { NotNullViolationException } from '../not-null-violation'; -import { RecordNotUniqueException } from '../record-not-unique'; -import { ValueOutOfRangeException } from '../value-out-of-range'; -import { ValueTooLongException } from '../value-too-long'; -import type { MySQLError } from './types'; +import { ContainsNullValuesException } from '../contains-null-values.js'; +import { InvalidForeignKeyException } from '../invalid-foreign-key.js'; +import { NotNullViolationException } from '../not-null-violation.js'; +import { RecordNotUniqueException } from '../record-not-unique.js'; +import { ValueOutOfRangeException } from '../value-out-of-range.js'; +import { ValueTooLongException } from '../value-too-long.js'; +import type { MySQLError } from './types.js'; enum MySQLErrorCodes { UNIQUE_VIOLATION = 'ER_DUP_ENTRY', diff --git a/api/src/exceptions/database/dialects/oracle.ts b/api/src/exceptions/database/dialects/oracle.ts index 48f55bf59d..0673243d5b 100644 --- a/api/src/exceptions/database/dialects/oracle.ts +++ b/api/src/exceptions/database/dialects/oracle.ts @@ -1,5 +1,5 @@ -import { ContainsNullValuesException } from '../contains-null-values'; -import type { OracleError } from './types'; +import { ContainsNullValuesException } from '../contains-null-values.js'; +import type { OracleError } from './types.js'; enum OracleErrorCodes { 'CONTAINS_NULL_VALUES' = 2296, diff --git a/api/src/exceptions/database/dialects/postgres.ts b/api/src/exceptions/database/dialects/postgres.ts index 06e7f5a109..d09640e032 100644 --- a/api/src/exceptions/database/dialects/postgres.ts +++ b/api/src/exceptions/database/dialects/postgres.ts @@ -1,10 +1,10 @@ -import { ContainsNullValuesException } from '../contains-null-values'; -import { InvalidForeignKeyException } from '../invalid-foreign-key'; -import { NotNullViolationException } from '../not-null-violation'; -import { RecordNotUniqueException } from '../record-not-unique'; -import { ValueOutOfRangeException } from '../value-out-of-range'; -import { ValueTooLongException } from '../value-too-long'; -import type { PostgresError } from './types'; +import { ContainsNullValuesException } from '../contains-null-values.js'; +import { InvalidForeignKeyException } from '../invalid-foreign-key.js'; +import { NotNullViolationException } from '../not-null-violation.js'; +import { RecordNotUniqueException } from '../record-not-unique.js'; +import { ValueOutOfRangeException } from '../value-out-of-range.js'; +import { ValueTooLongException } from '../value-too-long.js'; +import type { PostgresError } from './types.js'; enum PostgresErrorCodes { FOREIGN_KEY_VIOLATION = '23503', diff --git a/api/src/exceptions/database/dialects/sqlite.ts b/api/src/exceptions/database/dialects/sqlite.ts index fbb5b4e17d..59f00c3ed8 100644 --- a/api/src/exceptions/database/dialects/sqlite.ts +++ b/api/src/exceptions/database/dialects/sqlite.ts @@ -1,8 +1,8 @@ -import { ContainsNullValuesException } from '../contains-null-values'; -import { InvalidForeignKeyException } from '../invalid-foreign-key'; -import { NotNullViolationException } from '../not-null-violation'; -import { RecordNotUniqueException } from '../record-not-unique'; -import type { SQLiteError } from './types'; +import { ContainsNullValuesException } from '../contains-null-values.js'; +import { InvalidForeignKeyException } from '../invalid-foreign-key.js'; +import { NotNullViolationException } from '../not-null-violation.js'; +import { RecordNotUniqueException } from '../record-not-unique.js'; +import type { SQLiteError } from './types.js'; // NOTE: // - Sqlite doesn't have varchar with length support, so no ValueTooLongException diff --git a/api/src/exceptions/database/invalid-foreign-key.ts b/api/src/exceptions/database/invalid-foreign-key.ts index f95750b3d3..99f4b3b0c1 100644 --- a/api/src/exceptions/database/invalid-foreign-key.ts +++ b/api/src/exceptions/database/invalid-foreign-key.ts @@ -1,4 +1,4 @@ -import { BaseException } from '@directus/shared/exceptions'; +import { BaseException } from '@directus/exceptions'; type Extensions = { collection: string; diff --git a/api/src/exceptions/database/not-null-violation.ts b/api/src/exceptions/database/not-null-violation.ts index 154eda3d57..db54c952be 100644 --- a/api/src/exceptions/database/not-null-violation.ts +++ b/api/src/exceptions/database/not-null-violation.ts @@ -1,4 +1,4 @@ -import { BaseException } from '@directus/shared/exceptions'; +import { BaseException } from '@directus/exceptions'; type Exceptions = { collection: string; diff --git a/api/src/exceptions/database/record-not-unique.ts b/api/src/exceptions/database/record-not-unique.ts index 9348ac01e5..11de05bf81 100644 --- a/api/src/exceptions/database/record-not-unique.ts +++ b/api/src/exceptions/database/record-not-unique.ts @@ -1,4 +1,4 @@ -import { BaseException } from '@directus/shared/exceptions'; +import { BaseException } from '@directus/exceptions'; type Extensions = { collection: string; diff --git a/api/src/exceptions/database/translate.ts b/api/src/exceptions/database/translate.ts index 405e4de8c4..fc5f4231a8 100644 --- a/api/src/exceptions/database/translate.ts +++ b/api/src/exceptions/database/translate.ts @@ -1,11 +1,11 @@ -import getDatabase, { getDatabaseClient } from '../../database'; -import emitter from '../../emitter'; -import { extractError as mssql } from './dialects/mssql'; -import { extractError as mysql } from './dialects/mysql'; -import { extractError as oracle } from './dialects/oracle'; -import { extractError as postgres } from './dialects/postgres'; -import { extractError as sqlite } from './dialects/sqlite'; -import type { SQLError } from './dialects/types'; +import getDatabase, { getDatabaseClient } from '../../database/index.js'; +import emitter from '../../emitter.js'; +import { extractError as mssql } from './dialects/mssql.js'; +import { extractError as mysql } from './dialects/mysql.js'; +import { extractError as oracle } from './dialects/oracle.js'; +import { extractError as postgres } from './dialects/postgres.js'; +import { extractError as sqlite } from './dialects/sqlite.js'; +import type { SQLError } from './dialects/types.js'; /** * Translates an error thrown by any of the databases into a pre-defined Exception. Currently diff --git a/api/src/exceptions/database/value-out-of-range.ts b/api/src/exceptions/database/value-out-of-range.ts index 48f42de9f5..eb801bb780 100644 --- a/api/src/exceptions/database/value-out-of-range.ts +++ b/api/src/exceptions/database/value-out-of-range.ts @@ -1,4 +1,4 @@ -import { BaseException } from '@directus/shared/exceptions'; +import { BaseException } from '@directus/exceptions'; type Exceptions = { collection: string; diff --git a/api/src/exceptions/database/value-too-long.ts b/api/src/exceptions/database/value-too-long.ts index 0c0bfabf49..2e6ed9a6de 100644 --- a/api/src/exceptions/database/value-too-long.ts +++ b/api/src/exceptions/database/value-too-long.ts @@ -1,4 +1,4 @@ -import { BaseException } from '@directus/shared/exceptions'; +import { BaseException } from '@directus/exceptions'; type Extensions = { collection: string; diff --git a/api/src/exceptions/forbidden.ts b/api/src/exceptions/forbidden.ts index fd969abb05..cb6610dedd 100644 --- a/api/src/exceptions/forbidden.ts +++ b/api/src/exceptions/forbidden.ts @@ -1,4 +1,5 @@ -import { BaseException } from '@directus/shared/exceptions'; +import * as exceptions from '@directus/exceptions'; +const { BaseException } = exceptions; export class ForbiddenException extends BaseException { constructor() { diff --git a/api/src/exceptions/graphql-validation.ts b/api/src/exceptions/graphql-validation.ts index dc193b9db9..a46a4e54f4 100644 --- a/api/src/exceptions/graphql-validation.ts +++ b/api/src/exceptions/graphql-validation.ts @@ -1,6 +1,6 @@ -import { BaseException } from '@directus/shared/exceptions'; +import * as sharedExceptions from '@directus/exceptions'; -export class GraphQLValidationException extends BaseException { +export class GraphQLValidationException extends sharedExceptions.BaseException { constructor(extensions: Record) { super('GraphQL validation error.', 400, 'GRAPHQL_VALIDATION_EXCEPTION', extensions); } diff --git a/api/src/exceptions/hit-rate-limit.ts b/api/src/exceptions/hit-rate-limit.ts index 077f5c0193..0134a374c1 100644 --- a/api/src/exceptions/hit-rate-limit.ts +++ b/api/src/exceptions/hit-rate-limit.ts @@ -1,4 +1,4 @@ -import { BaseException } from '@directus/shared/exceptions'; +import { BaseException } from '@directus/exceptions'; type Extensions = { limit: number; diff --git a/api/src/exceptions/illegal-asset-transformation.ts b/api/src/exceptions/illegal-asset-transformation.ts index 0dbc174354..4a9966d63a 100644 --- a/api/src/exceptions/illegal-asset-transformation.ts +++ b/api/src/exceptions/illegal-asset-transformation.ts @@ -1,4 +1,4 @@ -import { BaseException } from '@directus/shared/exceptions'; +import { BaseException } from '@directus/exceptions'; export class IllegalAssetTransformation extends BaseException { constructor(message: string) { diff --git a/api/src/exceptions/index.ts b/api/src/exceptions/index.ts index b8c83b2038..dfe3ad99be 100644 --- a/api/src/exceptions/index.ts +++ b/api/src/exceptions/index.ts @@ -1,21 +1,21 @@ -export * from './forbidden'; -export * from './graphql-validation'; -export * from './hit-rate-limit'; -export * from './illegal-asset-transformation'; -export * from './invalid-config'; -export * from './invalid-credentials'; -export * from './invalid-ip'; -export * from './invalid-otp'; -export * from './invalid-payload'; -export * from './invalid-provider'; -export * from './invalid-query'; -export * from './invalid-token'; -export * from './method-not-allowed'; -export * from './range-not-satisfiable'; -export * from './route-not-found'; -export * from './service-unavailable'; -export * from './token-expired'; -export * from './unprocessable-entity'; -export * from './unsupported-media-type'; -export * from './user-suspended'; -export * from './unexpected-response'; +export * from './forbidden.js'; +export * from './graphql-validation.js'; +export * from './hit-rate-limit.js'; +export * from './illegal-asset-transformation.js'; +export * from './invalid-config.js'; +export * from './invalid-credentials.js'; +export * from './invalid-ip.js'; +export * from './invalid-otp.js'; +export * from './invalid-payload.js'; +export * from './invalid-provider.js'; +export * from './invalid-query.js'; +export * from './invalid-token.js'; +export * from './method-not-allowed.js'; +export * from './range-not-satisfiable.js'; +export * from './route-not-found.js'; +export * from './service-unavailable.js'; +export * from './token-expired.js'; +export * from './unprocessable-entity.js'; +export * from './unsupported-media-type.js'; +export * from './user-suspended.js'; +export * from './unexpected-response.js'; diff --git a/api/src/exceptions/invalid-config.ts b/api/src/exceptions/invalid-config.ts index c47426160b..4523a5dafd 100644 --- a/api/src/exceptions/invalid-config.ts +++ b/api/src/exceptions/invalid-config.ts @@ -1,4 +1,4 @@ -import { BaseException } from '@directus/shared/exceptions'; +import { BaseException } from '@directus/exceptions'; export class InvalidConfigException extends BaseException { constructor(message = 'Invalid config', extensions?: Record) { diff --git a/api/src/exceptions/invalid-credentials.ts b/api/src/exceptions/invalid-credentials.ts index cfdfc258b0..c1c930f40c 100644 --- a/api/src/exceptions/invalid-credentials.ts +++ b/api/src/exceptions/invalid-credentials.ts @@ -1,4 +1,4 @@ -import { BaseException } from '@directus/shared/exceptions'; +import { BaseException } from '@directus/exceptions'; export class InvalidCredentialsException extends BaseException { constructor(message = 'Invalid user credentials.') { diff --git a/api/src/exceptions/invalid-ip.ts b/api/src/exceptions/invalid-ip.ts index 73ca7d068d..6fe8146ee3 100644 --- a/api/src/exceptions/invalid-ip.ts +++ b/api/src/exceptions/invalid-ip.ts @@ -1,4 +1,4 @@ -import { BaseException } from '@directus/shared/exceptions'; +import { BaseException } from '@directus/exceptions'; export class InvalidIPException extends BaseException { constructor(message = 'Invalid IP address.') { diff --git a/api/src/exceptions/invalid-otp.ts b/api/src/exceptions/invalid-otp.ts index 13e2db07f8..9d8443f60f 100644 --- a/api/src/exceptions/invalid-otp.ts +++ b/api/src/exceptions/invalid-otp.ts @@ -1,4 +1,4 @@ -import { BaseException } from '@directus/shared/exceptions'; +import { BaseException } from '@directus/exceptions'; export class InvalidOTPException extends BaseException { constructor(message = 'Invalid user OTP.') { diff --git a/api/src/exceptions/invalid-payload.ts b/api/src/exceptions/invalid-payload.ts index d40382f87b..5c616fc7e2 100644 --- a/api/src/exceptions/invalid-payload.ts +++ b/api/src/exceptions/invalid-payload.ts @@ -1,4 +1,4 @@ -import { BaseException } from '@directus/shared/exceptions'; +import { BaseException } from '@directus/exceptions'; export class InvalidPayloadException extends BaseException { constructor(message: string, extensions?: Record) { diff --git a/api/src/exceptions/invalid-provider.ts b/api/src/exceptions/invalid-provider.ts index f8071fc118..ed654f692b 100644 --- a/api/src/exceptions/invalid-provider.ts +++ b/api/src/exceptions/invalid-provider.ts @@ -1,4 +1,4 @@ -import { BaseException } from '@directus/shared/exceptions'; +import { BaseException } from '@directus/exceptions'; export class InvalidProviderException extends BaseException { constructor(message = 'Invalid provider.') { diff --git a/api/src/exceptions/invalid-query.ts b/api/src/exceptions/invalid-query.ts index fd7ed5f134..909205a949 100644 --- a/api/src/exceptions/invalid-query.ts +++ b/api/src/exceptions/invalid-query.ts @@ -1,4 +1,4 @@ -import { BaseException } from '@directus/shared/exceptions'; +import { BaseException } from '@directus/exceptions'; export class InvalidQueryException extends BaseException { constructor(message: string) { diff --git a/api/src/exceptions/invalid-token.ts b/api/src/exceptions/invalid-token.ts index 223fff4ccc..edd95dbae6 100644 --- a/api/src/exceptions/invalid-token.ts +++ b/api/src/exceptions/invalid-token.ts @@ -1,4 +1,4 @@ -import { BaseException } from '@directus/shared/exceptions'; +import { BaseException } from '@directus/exceptions'; export class InvalidTokenException extends BaseException { constructor(message = 'Invalid token') { diff --git a/api/src/exceptions/method-not-allowed.ts b/api/src/exceptions/method-not-allowed.ts index 656d92d43b..7794fe4080 100644 --- a/api/src/exceptions/method-not-allowed.ts +++ b/api/src/exceptions/method-not-allowed.ts @@ -1,4 +1,4 @@ -import { BaseException } from '@directus/shared/exceptions'; +import { BaseException } from '@directus/exceptions'; type Extensions = { allow: string[]; diff --git a/api/src/exceptions/range-not-satisfiable.ts b/api/src/exceptions/range-not-satisfiable.ts index 9a39beddf9..4ce456f0f3 100644 --- a/api/src/exceptions/range-not-satisfiable.ts +++ b/api/src/exceptions/range-not-satisfiable.ts @@ -1,6 +1,4 @@ -import { BaseException } from '@directus/shared/exceptions'; - -// @ts-expect-error https://github.com/microsoft/TypeScript/issues/49721 +import { BaseException } from '@directus/exceptions'; import type { Range } from '@directus/storage'; export class RangeNotSatisfiableException extends BaseException { diff --git a/api/src/exceptions/route-not-found.ts b/api/src/exceptions/route-not-found.ts index d225dba10b..0f9bf5b33e 100644 --- a/api/src/exceptions/route-not-found.ts +++ b/api/src/exceptions/route-not-found.ts @@ -1,4 +1,4 @@ -import { BaseException } from '@directus/shared/exceptions'; +import { BaseException } from '@directus/exceptions'; export class RouteNotFoundException extends BaseException { constructor(path: string) { diff --git a/api/src/exceptions/service-unavailable.ts b/api/src/exceptions/service-unavailable.ts index cd8a39860e..40a5b0fde2 100644 --- a/api/src/exceptions/service-unavailable.ts +++ b/api/src/exceptions/service-unavailable.ts @@ -1,4 +1,4 @@ -import { BaseException } from '@directus/shared/exceptions'; +import { BaseException } from '@directus/exceptions'; type Extensions = { service: string; diff --git a/api/src/exceptions/token-expired.ts b/api/src/exceptions/token-expired.ts index 6a3d0809d3..a3a9824cbc 100644 --- a/api/src/exceptions/token-expired.ts +++ b/api/src/exceptions/token-expired.ts @@ -1,4 +1,4 @@ -import { BaseException } from '@directus/shared/exceptions'; +import { BaseException } from '@directus/exceptions'; export class TokenExpiredException extends BaseException { constructor(message = 'Token expired.') { diff --git a/api/src/exceptions/unexpected-response.ts b/api/src/exceptions/unexpected-response.ts index ff7ba28b16..30f952e474 100644 --- a/api/src/exceptions/unexpected-response.ts +++ b/api/src/exceptions/unexpected-response.ts @@ -1,4 +1,4 @@ -import { BaseException } from '@directus/shared/exceptions'; +import { BaseException } from '@directus/exceptions'; export class UnexpectedResponseException extends BaseException { constructor(message: string) { diff --git a/api/src/exceptions/unprocessable-entity.ts b/api/src/exceptions/unprocessable-entity.ts index 5a6dc25f30..3d02cf69b3 100644 --- a/api/src/exceptions/unprocessable-entity.ts +++ b/api/src/exceptions/unprocessable-entity.ts @@ -1,4 +1,4 @@ -import { BaseException } from '@directus/shared/exceptions'; +import { BaseException } from '@directus/exceptions'; export class UnprocessableEntityException extends BaseException { constructor(message: string) { diff --git a/api/src/exceptions/unsupported-media-type.ts b/api/src/exceptions/unsupported-media-type.ts index 26031cb96f..1323221edc 100644 --- a/api/src/exceptions/unsupported-media-type.ts +++ b/api/src/exceptions/unsupported-media-type.ts @@ -1,4 +1,4 @@ -import { BaseException } from '@directus/shared/exceptions'; +import { BaseException } from '@directus/exceptions'; export class UnsupportedMediaTypeException extends BaseException { constructor(message: string, extensions?: Record) { diff --git a/api/src/exceptions/user-suspended.ts b/api/src/exceptions/user-suspended.ts index 9bd5ae6d89..ce7ee0193e 100644 --- a/api/src/exceptions/user-suspended.ts +++ b/api/src/exceptions/user-suspended.ts @@ -1,4 +1,4 @@ -import { BaseException } from '@directus/shared/exceptions'; +import { BaseException } from '@directus/exceptions'; export class UserSuspendedException extends BaseException { constructor(message = 'User suspended.') { diff --git a/api/src/extensions.ts b/api/src/extensions.ts index 3237817afb..b0011795db 100644 --- a/api/src/extensions.ts +++ b/api/src/extensions.ts @@ -3,8 +3,8 @@ import { APP_SHARED_DEPS, HYBRID_EXTENSION_TYPES, NESTED_EXTENSION_TYPES, -} from '@directus/shared/constants'; -import * as sharedExceptions from '@directus/shared/exceptions'; +} from '@directus/constants'; +import * as sharedExceptions from '@directus/exceptions'; import type { ActionHandler, ApiExtension, @@ -21,8 +21,8 @@ import type { NestedExtensionType, OperationApiConfig, ScheduleHandler, -} from '@directus/shared/types'; -import { isIn, isTypeIn, pluralize } from '@directus/shared/utils'; +} from '@directus/types'; +import { isIn, isTypeIn, pluralize } from '@directus/utils'; import { ensureExtensionDirs, generateExtensionsEntrypoint, @@ -31,30 +31,39 @@ import { pathToRelativeUrl, resolvePackage, resolvePackageExtensions, -} from '@directus/shared/utils/node'; -import alias from '@rollup/plugin-alias'; -import virtual from '@rollup/plugin-virtual'; +} from '@directus/utils/node'; +import aliasDefault from '@rollup/plugin-alias'; +import virtualDefault from '@rollup/plugin-virtual'; import chokidar, { FSWatcher } from 'chokidar'; import express, { Router } from 'express'; -import fse from 'fs-extra'; import globby from 'globby'; -import { clone, escapeRegExp } from 'lodash'; +import { clone, escapeRegExp } from 'lodash-es'; import { schedule, validate } from 'node-cron'; +import { readdir } from 'node:fs/promises'; +import { createRequire } from 'node:module'; +import { dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; import path from 'path'; import { rollup } from 'rollup'; -import getDatabase from './database'; -import emitter, { Emitter } from './emitter'; -import env from './env'; -import * as exceptions from './exceptions'; -import { getFlowManager } from './flows'; -import logger from './logger'; -import * as services from './services'; -import type { EventHandler } from './types'; -import { dynamicImport } from './utils/dynamic-import'; -import getModuleDefault from './utils/get-module-default'; -import { getSchema } from './utils/get-schema'; -import { JobQueue } from './utils/job-queue'; -import { Url } from './utils/url'; +import getDatabase from './database/index.js'; +import emitter, { Emitter } from './emitter.js'; +import env from './env.js'; +import * as exceptions from './exceptions/index.js'; +import { getFlowManager } from './flows.js'; +import logger from './logger.js'; +import * as services from './services/index.js'; +import type { EventHandler } from './types/index.js'; +import getModuleDefault from './utils/get-module-default.js'; +import { getSchema } from './utils/get-schema.js'; +import { JobQueue } from './utils/job-queue.js'; +import { Url } from './utils/url.js'; + +// Workaround for https://github.com/rollup/plugins/issues/1329 +const virtual = virtualDefault as unknown as typeof virtualDefault.default; +const alias = aliasDefault as unknown as typeof aliasDefault.default; + +const require = createRequire(import.meta.url); +const __dirname = dirname(fileURLToPath(import.meta.url)); let extensionManager: ExtensionManager | undefined; @@ -362,7 +371,7 @@ class ExtensionManager { } private async getSharedDepsMapping(deps: string[]): Promise> { - const appDir = await fse.readdir(path.join(resolvePackage('@directus/app', __dirname), 'dist', 'assets')); + const appDir = await readdir(path.join(resolvePackage('@directus/app', __dirname), 'dist', 'assets')); const depsMapping: Record = {}; for (const dep of deps) { @@ -386,7 +395,7 @@ class ExtensionManager { for (const hook of hooks) { try { const hookPath = path.resolve(hook.path, hook.entrypoint); - const hookInstance: HookConfig | { default: HookConfig } = await dynamicImport(hookPath); + const hookInstance: HookConfig | { default: HookConfig } = await import(`file://${hookPath}`); const config = getModuleDefault(hookInstance); @@ -406,7 +415,7 @@ class ExtensionManager { for (const endpoint of endpoints) { try { const endpointPath = path.resolve(endpoint.path, endpoint.entrypoint); - const endpointInstance: EndpointConfig | { default: EndpointConfig } = require(endpointPath); + const endpointInstance: EndpointConfig | { default: EndpointConfig } = await import(`file://${endpointPath}`); const config = getModuleDefault(endpointInstance); @@ -440,7 +449,9 @@ class ExtensionManager { for (const operation of [...internalOperations, ...operations]) { try { const operationPath = path.resolve(operation.path, operation.entrypoint.api!); - const operationInstance: OperationApiConfig | { default: OperationApiConfig } = require(operationPath); + const operationInstance: OperationApiConfig | { default: OperationApiConfig } = await import( + `file://${operationPath}` + ); const config = getModuleDefault(operationInstance); @@ -460,7 +471,7 @@ class ExtensionManager { for (const bundle of bundles) { try { const bundlePath = path.resolve(bundle.path, bundle.entrypoint.api); - const bundleInstances: BundleConfig | { default: BundleConfig } = require(bundlePath); + const bundleInstances: BundleConfig | { default: BundleConfig } = await import(`file://${bundlePath}`); const configs = getModuleDefault(bundleInstances); diff --git a/api/src/flows.ts b/api/src/flows.ts index 79963a905e..2ae244ba69 100644 --- a/api/src/flows.ts +++ b/api/src/flows.ts @@ -1,4 +1,4 @@ -import * as sharedExceptions from '@directus/shared/exceptions'; +import * as sharedExceptions from '@directus/exceptions'; import { Accountability, Action, @@ -8,28 +8,28 @@ import { Operation, OperationHandler, SchemaOverview, -} from '@directus/shared/types'; -import { applyOptionsData, isValidJSON, parseJSON, toArray } from '@directus/shared/utils'; +} from '@directus/types'; +import { applyOptionsData, isValidJSON, parseJSON, toArray } from '@directus/utils'; import fastRedact from 'fast-redact'; import type { Knex } from 'knex'; -import { omit, pick } from 'lodash'; +import { omit, pick } from 'lodash-es'; import { get } from 'micromustache'; import { schedule, validate } from 'node-cron'; -import getDatabase from './database'; -import emitter from './emitter'; -import env from './env'; -import * as exceptions from './exceptions'; -import logger from './logger'; -import { getMessenger } from './messenger'; -import * as services from './services'; -import { FlowsService } from './services'; -import { ActivityService } from './services/activity'; -import { RevisionsService } from './services/revisions'; -import type { EventHandler } from './types'; -import { constructFlowTree } from './utils/construct-flow-tree'; -import { getSchema } from './utils/get-schema'; -import { JobQueue } from './utils/job-queue'; -import { mapValuesDeep } from './utils/map-values-deep'; +import getDatabase from './database/index.js'; +import emitter from './emitter.js'; +import env from './env.js'; +import * as exceptions from './exceptions/index.js'; +import logger from './logger.js'; +import { getMessenger } from './messenger.js'; +import { ActivityService } from './services/activity.js'; +import * as services from './services/index.js'; +import { FlowsService } from './services/flows.js'; +import { RevisionsService } from './services/revisions.js'; +import type { EventHandler } from './types/index.js'; +import { constructFlowTree } from './utils/construct-flow-tree.js'; +import { getSchema } from './utils/get-schema.js'; +import { JobQueue } from './utils/job-queue.js'; +import { mapValuesDeep } from './utils/map-values-deep.js'; let flowManager: FlowManager | undefined; diff --git a/api/src/index.ts b/api/src/index.ts index 2ca39bc31c..51a14945aa 100644 --- a/api/src/index.ts +++ b/api/src/index.ts @@ -1,3 +1,3 @@ -export { default as createApp } from './app'; -export * from './services'; -export * from './exceptions'; +export { default as createApp } from './app.js'; +export * from './services/index.js'; +export * from './exceptions/index.js'; diff --git a/api/src/logger.test.ts b/api/src/logger.test.ts index a2beb95caf..17ca5121a5 100644 --- a/api/src/logger.test.ts +++ b/api/src/logger.test.ts @@ -18,9 +18,9 @@ vi.mock('./env', async () => { }); import { Writable } from 'node:stream'; -import pino from 'pino'; -import { REDACT_TEXT } from './constants'; -import { httpLoggerOptions } from './logger'; +import { pino } from 'pino'; +import { REDACT_TEXT } from './constants.js'; +import { httpLoggerOptions } from './logger.js'; const logOutput = vi.fn(); diff --git a/api/src/logger.ts b/api/src/logger.ts index f1199e22a3..99276fb4cc 100644 --- a/api/src/logger.ts +++ b/api/src/logger.ts @@ -1,12 +1,13 @@ -import { toArray } from '@directus/shared/utils'; -import { merge } from 'lodash'; -import pino, { LoggerOptions } from 'pino'; +import { toArray } from '@directus/utils'; +import { merge } from 'lodash-es'; +import { pino } from 'pino'; +import type { LoggerOptions } from 'pino'; import type { Request, RequestHandler } from 'express'; -import pinoHTTP, { stdSerializers } from 'pino-http'; +import { pinoHttp, stdSerializers } from 'pino-http'; import { URL } from 'url'; -import env from './env'; -import { REDACT_TEXT } from './constants'; -import { getConfigFromEnv } from './utils/get-config-from-env'; +import env from './env.js'; +import { REDACT_TEXT } from './constants.js'; +import { getConfigFromEnv } from './utils/get-config-from-env.js'; const pinoOptions: LoggerOptions = { level: env['LOG_LEVEL'] || 'info', @@ -95,7 +96,7 @@ const logger = pino(merge(pinoOptions, loggerEnvConfig)); const httpLoggerEnvConfig = getConfigFromEnv('LOGGER_HTTP', ['LOGGER_HTTP_LOGGER']); -export const expressLogger = pinoHTTP({ +export const expressLogger = pinoHttp({ logger: pino(merge(httpLoggerOptions, loggerEnvConfig)), ...httpLoggerEnvConfig, serializers: { diff --git a/api/src/mailer.ts b/api/src/mailer.ts index 7559606fe8..dd113e6cfe 100644 --- a/api/src/mailer.ts +++ b/api/src/mailer.ts @@ -1,7 +1,10 @@ import nodemailer, { Transporter } from 'nodemailer'; -import env from './env'; -import logger from './logger'; -import { getConfigFromEnv } from './utils/get-config-from-env'; +import env from './env.js'; +import logger from './logger.js'; +import { getConfigFromEnv } from './utils/get-config-from-env.js'; + +import { createRequire } from 'node:module'; +const require = createRequire(import.meta.url); let transporter: Transporter; diff --git a/api/src/messenger.ts b/api/src/messenger.ts index 9cb09d5b4f..bd0ae88949 100644 --- a/api/src/messenger.ts +++ b/api/src/messenger.ts @@ -1,8 +1,7 @@ -import { parseJSON } from '@directus/shared/utils'; -import IORedis from 'ioredis'; -import type { Redis } from 'ioredis'; -import env from './env'; -import { getConfigFromEnv } from './utils/get-config-from-env'; +import { parseJSON } from '@directus/utils'; +import { Redis } from 'ioredis'; +import env from './env.js'; +import { getConfigFromEnv } from './utils/get-config-from-env.js'; export type MessengerSubscriptionCallback = (payload: Record) => void; @@ -40,8 +39,8 @@ export class MessengerRedis implements Messenger { constructor() { const config = getConfigFromEnv('MESSENGER_REDIS'); - this.pub = new IORedis(env['MESSENGER_REDIS'] ?? config); - this.sub = new IORedis(env['MESSENGER_REDIS'] ?? config); + this.pub = new Redis(env['MESSENGER_REDIS'] ?? config); + this.sub = new Redis(env['MESSENGER_REDIS'] ?? config); this.namespace = env['MESSENGER_NAMESPACE'] ?? 'directus'; } diff --git a/api/src/middleware/authenticate.test.ts b/api/src/middleware/authenticate.test.ts index ed8e5c4f1c..713904b785 100644 --- a/api/src/middleware/authenticate.test.ts +++ b/api/src/middleware/authenticate.test.ts @@ -3,11 +3,11 @@ import jwt from 'jsonwebtoken'; import type { Knex } from 'knex'; import { afterEach, expect, test, vi } from 'vitest'; import '../../src/types/express.d.ts'; -import getDatabase from '../database'; -import emitter from '../emitter'; -import env from '../env'; -import { InvalidCredentialsException } from '../exceptions'; -import { handler } from './authenticate'; +import getDatabase from '../database/index.js'; +import emitter from '../emitter.js'; +import env from '../env.js'; +import { InvalidCredentialsException } from '../exceptions/invalid-credentials.js'; +import { handler } from './authenticate.js'; vi.mock('../../src/database'); vi.mock('../../src/env', () => { diff --git a/api/src/middleware/authenticate.ts b/api/src/middleware/authenticate.ts index 1abbc8543a..242d465154 100644 --- a/api/src/middleware/authenticate.ts +++ b/api/src/middleware/authenticate.ts @@ -1,14 +1,14 @@ -import type { Accountability } from '@directus/shared/types'; +import type { Accountability } from '@directus/types'; import type { NextFunction, Request, Response } from 'express'; -import { isEqual } from 'lodash'; -import getDatabase from '../database'; -import emitter from '../emitter'; -import env from '../env'; -import { InvalidCredentialsException } from '../exceptions'; -import asyncHandler from '../utils/async-handler'; -import { getIPFromReq } from '../utils/get-ip-from-req'; -import isDirectusJWT from '../utils/is-directus-jwt'; -import { verifyAccessJWT } from '../utils/jwt'; +import { isEqual } from 'lodash-es'; +import getDatabase from '../database/index.js'; +import emitter from '../emitter.js'; +import env from '../env.js'; +import { InvalidCredentialsException } from '../exceptions/index.js'; +import asyncHandler from '../utils/async-handler.js'; +import { getIPFromReq } from '../utils/get-ip-from-req.js'; +import isDirectusJWT from '../utils/is-directus-jwt.js'; +import { verifyAccessJWT } from '../utils/jwt.js'; /** * Verify the passed JWT and assign the user ID and role to `req` diff --git a/api/src/middleware/cache.ts b/api/src/middleware/cache.ts index 2cdf86a508..e289646b58 100644 --- a/api/src/middleware/cache.ts +++ b/api/src/middleware/cache.ts @@ -1,11 +1,11 @@ import type { RequestHandler } from 'express'; -import { getCache, getCacheValue } from '../cache'; -import env from '../env'; -import logger from '../logger'; -import asyncHandler from '../utils/async-handler'; -import { getCacheControlHeader } from '../utils/get-cache-headers'; -import { getCacheKey } from '../utils/get-cache-key'; -import { shouldSkipCache } from '../utils/should-skip-cache'; +import { getCache, getCacheValue } from '../cache.js'; +import env from '../env.js'; +import logger from '../logger.js'; +import asyncHandler from '../utils/async-handler.js'; +import { getCacheControlHeader } from '../utils/get-cache-headers.js'; +import { getCacheKey } from '../utils/get-cache-key.js'; +import { shouldSkipCache } from '../utils/should-skip-cache.js'; const checkCacheMiddleware: RequestHandler = asyncHandler(async (req, res, next) => { const { cache } = getCache(); diff --git a/api/src/middleware/check-ip.ts b/api/src/middleware/check-ip.ts index f0129e4388..505257e93d 100644 --- a/api/src/middleware/check-ip.ts +++ b/api/src/middleware/check-ip.ts @@ -1,7 +1,7 @@ import type { RequestHandler } from 'express'; -import getDatabase from '../database'; -import { InvalidIPException } from '../exceptions'; -import asyncHandler from '../utils/async-handler'; +import getDatabase from '../database/index.js'; +import { InvalidIPException } from '../exceptions/index.js'; +import asyncHandler from '../utils/async-handler.js'; export const checkIP: RequestHandler = asyncHandler(async (req, _res, next) => { const database = getDatabase(); diff --git a/api/src/middleware/collection-exists.ts b/api/src/middleware/collection-exists.ts index 675cb3a772..3a6bdb87b8 100644 --- a/api/src/middleware/collection-exists.ts +++ b/api/src/middleware/collection-exists.ts @@ -3,9 +3,9 @@ */ import type { RequestHandler } from 'express'; -import { systemCollectionRows } from '../database/system-data/collections'; -import { ForbiddenException } from '../exceptions'; -import asyncHandler from '../utils/async-handler'; +import { systemCollectionRows } from '../database/system-data/collections/index.js'; +import { ForbiddenException } from '../exceptions/index.js'; +import asyncHandler from '../utils/async-handler.js'; const collectionExists: RequestHandler = asyncHandler(async (req, _res, next) => { if (!req.params['collection']) return next(); @@ -23,7 +23,7 @@ const collectionExists: RequestHandler = asyncHandler(async (req, _res, next) => req.singleton = !!systemRow?.singleton; } else { - req.singleton = req.schema.collections[req.collection].singleton; + req.singleton = req.schema.collections[req.collection]?.singleton ?? false; } return next(); diff --git a/api/src/middleware/cors.ts b/api/src/middleware/cors.ts index a47938b214..7b0f1bc21d 100644 --- a/api/src/middleware/cors.ts +++ b/api/src/middleware/cors.ts @@ -1,6 +1,6 @@ import cors from 'cors'; import type { RequestHandler } from 'express'; -import env from '../env'; +import env from '../env.js'; let corsMiddleware: RequestHandler = (_req, _res, next) => next(); diff --git a/api/src/middleware/error-handler.ts b/api/src/middleware/error-handler.ts index ad5d63691e..26408b8b56 100644 --- a/api/src/middleware/error-handler.ts +++ b/api/src/middleware/error-handler.ts @@ -1,11 +1,11 @@ -import { BaseException } from '@directus/shared/exceptions'; -import { toArray } from '@directus/shared/utils'; +import { BaseException } from '@directus/exceptions'; +import { toArray } from '@directus/utils'; import type { ErrorRequestHandler } from 'express'; -import getDatabase from '../database'; -import emitter from '../emitter'; -import env from '../env'; -import { MethodNotAllowedException } from '../exceptions'; -import logger from '../logger'; +import getDatabase from '../database/index.js'; +import emitter from '../emitter.js'; +import env from '../env.js'; +import { MethodNotAllowedException } from '../exceptions/index.js'; +import logger from '../logger.js'; // Note: keep all 4 parameters here. That's how Express recognizes it's the error handler, even if // we don't use next diff --git a/api/src/middleware/extract-token.test.ts b/api/src/middleware/extract-token.test.ts index 2ba37b0de2..48d114c9d6 100644 --- a/api/src/middleware/extract-token.test.ts +++ b/api/src/middleware/extract-token.test.ts @@ -1,6 +1,6 @@ import type { Request, Response } from 'express'; import { beforeEach, expect, test, vi } from 'vitest'; -import extractToken from '../../src/middleware/extract-token'; +import extractToken from '../../src/middleware/extract-token.js'; import '../../src/types/express.d.ts'; let mockRequest: Partial; diff --git a/api/src/middleware/get-permissions.ts b/api/src/middleware/get-permissions.ts index 0511bb5a8f..97267b6988 100644 --- a/api/src/middleware/get-permissions.ts +++ b/api/src/middleware/get-permissions.ts @@ -1,6 +1,6 @@ import type { RequestHandler } from 'express'; -import asyncHandler from '../utils/async-handler'; -import { getPermissions as getPermissionsUtil } from '../utils/get-permissions'; +import asyncHandler from '../utils/async-handler.js'; +import { getPermissions as getPermissionsUtil } from '../utils/get-permissions.js'; const getPermissions: RequestHandler = asyncHandler(async (req, _res, next) => { if (!req.accountability) { diff --git a/api/src/middleware/graphql.ts b/api/src/middleware/graphql.ts index 64209977ed..5dc2e72a0a 100644 --- a/api/src/middleware/graphql.ts +++ b/api/src/middleware/graphql.ts @@ -1,9 +1,9 @@ -import { parseJSON } from '@directus/shared/utils'; +import { parseJSON } from '@directus/utils'; import type { RequestHandler } from 'express'; import { DocumentNode, getOperationAST, parse, Source } from 'graphql'; -import { InvalidPayloadException, InvalidQueryException, MethodNotAllowedException } from '../exceptions'; -import type { GraphQLParams } from '../types'; -import asyncHandler from '../utils/async-handler'; +import { InvalidPayloadException, InvalidQueryException, MethodNotAllowedException } from '../exceptions/index.js'; +import type { GraphQLParams } from '../types/index.js'; +import asyncHandler from '../utils/async-handler.js'; export const parseGraphQL: RequestHandler = asyncHandler(async (req, res, next) => { if (req.method !== 'GET' && req.method !== 'POST') { diff --git a/api/src/middleware/rate-limiter-global.ts b/api/src/middleware/rate-limiter-global.ts index a36840a7b3..0b32c69be5 100644 --- a/api/src/middleware/rate-limiter-global.ts +++ b/api/src/middleware/rate-limiter-global.ts @@ -1,12 +1,12 @@ import type { RequestHandler } from 'express'; import ms from 'ms'; import type { RateLimiterMemcache, RateLimiterMemory, RateLimiterRedis } from 'rate-limiter-flexible'; -import env from '../env'; -import { HitRateLimitException } from '../exceptions/index'; -import logger from '../logger'; -import { createRateLimiter } from '../rate-limiter'; -import asyncHandler from '../utils/async-handler'; -import { validateEnv } from '../utils/validate-env'; +import env from '../env.js'; +import { HitRateLimitException } from '../exceptions/index.js'; +import logger from '../logger.js'; +import { createRateLimiter } from '../rate-limiter.js'; +import asyncHandler from '../utils/async-handler.js'; +import { validateEnv } from '../utils/validate-env.js'; const RATE_LIMITER_GLOBAL_KEY = 'global-rate-limit'; diff --git a/api/src/middleware/rate-limiter-ip.ts b/api/src/middleware/rate-limiter-ip.ts index 11a557dc40..7e9d91d2b3 100644 --- a/api/src/middleware/rate-limiter-ip.ts +++ b/api/src/middleware/rate-limiter-ip.ts @@ -1,12 +1,12 @@ import type { RequestHandler } from 'express'; import ms from 'ms'; import type { RateLimiterMemcache, RateLimiterMemory, RateLimiterRedis } from 'rate-limiter-flexible'; -import env from '../env'; -import { HitRateLimitException } from '../exceptions'; -import { createRateLimiter } from '../rate-limiter'; -import asyncHandler from '../utils/async-handler'; -import { getIPFromReq } from '../utils/get-ip-from-req'; -import { validateEnv } from '../utils/validate-env'; +import env from '../env.js'; +import { HitRateLimitException } from '../exceptions/index.js'; +import { createRateLimiter } from '../rate-limiter.js'; +import asyncHandler from '../utils/async-handler.js'; +import { getIPFromReq } from '../utils/get-ip-from-req.js'; +import { validateEnv } from '../utils/validate-env.js'; let checkRateLimit: RequestHandler = (_req, _res, next) => next(); export let rateLimiter: RateLimiterRedis | RateLimiterMemcache | RateLimiterMemory; diff --git a/api/src/middleware/respond.ts b/api/src/middleware/respond.ts index 66ff75a45b..68da8f8770 100644 --- a/api/src/middleware/respond.ts +++ b/api/src/middleware/respond.ts @@ -1,15 +1,15 @@ import { parse as parseBytesConfiguration } from 'bytes'; import type { RequestHandler } from 'express'; -import { getCache, setCacheValue } from '../cache'; -import env from '../env'; -import logger from '../logger'; -import { ExportService } from '../services'; -import asyncHandler from '../utils/async-handler'; -import { getCacheControlHeader } from '../utils/get-cache-headers'; -import { getCacheKey } from '../utils/get-cache-key'; -import { getDateFormatted } from '../utils/get-date-formatted'; -import { getMilliseconds } from '../utils/get-milliseconds'; -import { stringByteSize } from '../utils/get-string-byte-size'; +import { getCache, setCacheValue } from '../cache.js'; +import env from '../env.js'; +import logger from '../logger.js'; +import { ExportService } from '../services/import-export.js'; +import asyncHandler from '../utils/async-handler.js'; +import { getCacheControlHeader } from '../utils/get-cache-headers.js'; +import { getCacheKey } from '../utils/get-cache-key.js'; +import { getDateFormatted } from '../utils/get-date-formatted.js'; +import { getMilliseconds } from '../utils/get-milliseconds.js'; +import { stringByteSize } from '../utils/get-string-byte-size.js'; export const respond: RequestHandler = asyncHandler(async (req, res) => { const { cache } = getCache(); diff --git a/api/src/middleware/sanitize-query.ts b/api/src/middleware/sanitize-query.ts index 8fe69f5392..291afe350a 100644 --- a/api/src/middleware/sanitize-query.ts +++ b/api/src/middleware/sanitize-query.ts @@ -4,8 +4,8 @@ */ import type { RequestHandler } from 'express'; -import { sanitizeQuery } from '../utils/sanitize-query'; -import { validateQuery } from '../utils/validate-query'; +import { sanitizeQuery } from '../utils/sanitize-query.js'; +import { validateQuery } from '../utils/validate-query.js'; const sanitizeQueryMiddleware: RequestHandler = (req, _res, next) => { req.sanitizedQuery = {}; diff --git a/api/src/middleware/schema.ts b/api/src/middleware/schema.ts index a69f9b3dde..b984ef6870 100644 --- a/api/src/middleware/schema.ts +++ b/api/src/middleware/schema.ts @@ -1,6 +1,6 @@ import type { RequestHandler } from 'express'; -import asyncHandler from '../utils/async-handler'; -import { getSchema } from '../utils/get-schema'; +import asyncHandler from '../utils/async-handler.js'; +import { getSchema } from '../utils/get-schema.js'; const schema: RequestHandler = asyncHandler(async (req, _res, next) => { req.schema = await getSchema(); diff --git a/api/src/middleware/use-collection.ts b/api/src/middleware/use-collection.ts index 3b0ea4765a..a73c615682 100644 --- a/api/src/middleware/use-collection.ts +++ b/api/src/middleware/use-collection.ts @@ -3,7 +3,7 @@ * system collections */ import type { RequestHandler } from 'express'; -import asyncHandler from '../utils/async-handler'; +import asyncHandler from '../utils/async-handler.js'; const useCollection = (collection: string): RequestHandler => asyncHandler(async (req, _res, next) => { diff --git a/api/src/middleware/validate-batch.test.ts b/api/src/middleware/validate-batch.test.ts index eec034950a..b2c85fc6b2 100644 --- a/api/src/middleware/validate-batch.test.ts +++ b/api/src/middleware/validate-batch.test.ts @@ -1,8 +1,8 @@ import type { Request, Response } from 'express'; -import { validateBatch } from './validate-batch'; +import { validateBatch } from './validate-batch.js'; import '../../src/types/express.d.ts'; -import { InvalidPayloadException } from '../exceptions'; -import { FailedValidationException } from '@directus/shared/exceptions'; +import { InvalidPayloadException } from '../exceptions/invalid-payload.js'; +import { FailedValidationException } from '@directus/exceptions'; import { vi, beforeEach, test, expect } from 'vitest'; let mockRequest: Partial; diff --git a/api/src/middleware/validate-batch.ts b/api/src/middleware/validate-batch.ts index 641b5eb917..49dbc37952 100644 --- a/api/src/middleware/validate-batch.ts +++ b/api/src/middleware/validate-batch.ts @@ -1,8 +1,8 @@ +import { FailedValidationException } from '@directus/exceptions'; import Joi from 'joi'; -import { InvalidPayloadException } from '../exceptions'; -import { FailedValidationException } from '@directus/shared/exceptions'; -import asyncHandler from '../utils/async-handler'; -import { sanitizeQuery } from '../utils/sanitize-query'; +import { InvalidPayloadException } from '../exceptions/index.js'; +import asyncHandler from '../utils/async-handler.js'; +import { sanitizeQuery } from '../utils/sanitize-query.js'; export const validateBatch = (scope: 'read' | 'update' | 'delete') => asyncHandler(async (req, _res, next) => { diff --git a/api/src/operations/condition/index.test.ts b/api/src/operations/condition/index.test.ts index 75255d2794..ce4e1f39a2 100644 --- a/api/src/operations/condition/index.test.ts +++ b/api/src/operations/condition/index.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from 'vitest'; -import config from './index'; +import config from './index.js'; describe('Operations / Condition', () => { test('returns null when condition passes', () => { diff --git a/api/src/operations/condition/index.ts b/api/src/operations/condition/index.ts index 050f2a32a5..42d51e177e 100644 --- a/api/src/operations/condition/index.ts +++ b/api/src/operations/condition/index.ts @@ -1,5 +1,5 @@ -import type { Filter } from '@directus/shared/types'; -import { defineOperationApi, validatePayload } from '@directus/shared/utils'; +import type { Filter } from '@directus/types'; +import { defineOperationApi, validatePayload } from '@directus/utils'; type Options = { filter: Filter; diff --git a/api/src/operations/exec/index.test.ts b/api/src/operations/exec/index.test.ts index 97f151f137..9cb97c6367 100644 --- a/api/src/operations/exec/index.test.ts +++ b/api/src/operations/exec/index.test.ts @@ -1,7 +1,7 @@ import { VMError } from 'vm2'; import { test, expect } from 'vitest'; -import config from './index'; +import config from './index.js'; test('Rejects when modules are used without modules being allowed', async () => { const testCode = ` diff --git a/api/src/operations/exec/index.ts b/api/src/operations/exec/index.ts index 6069b76922..8aeff598de 100644 --- a/api/src/operations/exec/index.ts +++ b/api/src/operations/exec/index.ts @@ -1,4 +1,4 @@ -import { defineOperationApi, toArray } from '@directus/shared/utils'; +import { defineOperationApi, toArray } from '@directus/utils'; import { NodeVM, NodeVMOptions, VMScript } from 'vm2'; import { isBuiltin } from 'node:module'; diff --git a/api/src/operations/item-create/index.test.ts b/api/src/operations/item-create/index.test.ts index e50a12521e..5a71470d85 100644 --- a/api/src/operations/item-create/index.test.ts +++ b/api/src/operations/item-create/index.test.ts @@ -1,17 +1,17 @@ import { afterEach, expect, test, vi } from 'vitest'; -vi.mock('../../services', () => { +vi.mock('../../services/items.js', () => { const ItemsService = vi.fn(); ItemsService.prototype.createMany = vi.fn(); return { ItemsService }; }); -vi.mock('../../utils/get-accountability-for-role', () => ({ +vi.mock('../../utils/get-accountability-for-role.js', () => ({ getAccountabilityForRole: vi.fn((role: string | null, _context) => Promise.resolve(role)), })); -import { ItemsService } from '../../services'; -import config from './index'; +import { ItemsService } from '../../services/items.js'; +import config from './index.js'; const testCollection = 'test'; const testId = '00000000-0000-0000-0000-000000000000'; diff --git a/api/src/operations/item-create/index.ts b/api/src/operations/item-create/index.ts index 16e26d5188..9f068cecae 100644 --- a/api/src/operations/item-create/index.ts +++ b/api/src/operations/item-create/index.ts @@ -1,8 +1,8 @@ -import type { Accountability, PrimaryKey } from '@directus/shared/types'; -import { defineOperationApi, optionToObject, toArray } from '@directus/shared/utils'; -import { ItemsService } from '../../services'; -import type { Item } from '../../types'; -import { getAccountabilityForRole } from '../../utils/get-accountability-for-role'; +import type { Accountability, PrimaryKey } from '@directus/types'; +import { defineOperationApi, optionToObject, toArray } from '@directus/utils'; +import { ItemsService } from '../../services/items.js'; +import type { Item } from '../../types/index.js'; +import { getAccountabilityForRole } from '../../utils/get-accountability-for-role.js'; type Options = { collection: string; diff --git a/api/src/operations/item-delete/index.test.ts b/api/src/operations/item-delete/index.test.ts index 5fa4c7bc4f..605a249803 100644 --- a/api/src/operations/item-delete/index.test.ts +++ b/api/src/operations/item-delete/index.test.ts @@ -1,9 +1,9 @@ import { afterEach, describe, expect, test, vi } from 'vitest'; -import { ItemsService } from '../../services'; -import config from './index'; +import { ItemsService } from '../../services/items.js'; +import config from './index.js'; -vi.mock('../../services', () => { +vi.mock('../../services/items.js', () => { const ItemsService = vi.fn(); ItemsService.prototype.deleteByQuery = vi.fn(); ItemsService.prototype.deleteOne = vi.fn(); @@ -13,7 +13,7 @@ vi.mock('../../services', () => { const getSchema = vi.fn().mockResolvedValue({}); -vi.mock('../../utils/get-accountability-for-role', () => ({ +vi.mock('../../utils/get-accountability-for-role.js', () => ({ getAccountabilityForRole: vi.fn((role: string | null, _context) => Promise.resolve(role)), })); diff --git a/api/src/operations/item-delete/index.ts b/api/src/operations/item-delete/index.ts index b52ec1596f..a78245834d 100644 --- a/api/src/operations/item-delete/index.ts +++ b/api/src/operations/item-delete/index.ts @@ -1,8 +1,8 @@ -import type { Accountability, PrimaryKey } from '@directus/shared/types'; -import { defineOperationApi, optionToObject, toArray } from '@directus/shared/utils'; -import { ItemsService } from '../../services'; -import { getAccountabilityForRole } from '../../utils/get-accountability-for-role'; -import { sanitizeQuery } from '../../utils/sanitize-query'; +import type { Accountability, PrimaryKey } from '@directus/types'; +import { defineOperationApi, optionToObject, toArray } from '@directus/utils'; +import { ItemsService } from '../../services/items.js'; +import { getAccountabilityForRole } from '../../utils/get-accountability-for-role.js'; +import { sanitizeQuery } from '../../utils/sanitize-query.js'; type Options = { collection: string; diff --git a/api/src/operations/item-read/index.test.ts b/api/src/operations/item-read/index.test.ts index f9e51bfdb3..30a97dd84d 100644 --- a/api/src/operations/item-read/index.test.ts +++ b/api/src/operations/item-read/index.test.ts @@ -1,9 +1,9 @@ import { afterEach, describe, expect, test, vi } from 'vitest'; -import { ItemsService } from '../../services'; -import config from './index'; +import { ItemsService } from '../../services/index.js'; +import config from './index.js'; -vi.mock('../../services', () => { +vi.mock('../../services/items.js', () => { const ItemsService = vi.fn(); ItemsService.prototype.readByQuery = vi.fn(); ItemsService.prototype.readOne = vi.fn(); @@ -13,7 +13,7 @@ vi.mock('../../services', () => { const getSchema = vi.fn().mockResolvedValue({}); -vi.mock('../../utils/get-accountability-for-role', () => ({ +vi.mock('../../utils/get-accountability-for-role.js', () => ({ getAccountabilityForRole: vi.fn((role: string | null, _context) => Promise.resolve(role)), })); diff --git a/api/src/operations/item-read/index.ts b/api/src/operations/item-read/index.ts index 468c1b7727..82ef75141f 100644 --- a/api/src/operations/item-read/index.ts +++ b/api/src/operations/item-read/index.ts @@ -1,9 +1,9 @@ -import type { Accountability, PrimaryKey } from '@directus/shared/types'; -import { defineOperationApi, optionToObject, toArray } from '@directus/shared/utils'; -import { ItemsService } from '../../services'; -import type { Item } from '../../types'; -import { getAccountabilityForRole } from '../../utils/get-accountability-for-role'; -import { sanitizeQuery } from '../../utils/sanitize-query'; +import type { Accountability, PrimaryKey } from '@directus/types'; +import { defineOperationApi, optionToObject, toArray } from '@directus/utils'; +import { ItemsService } from '../../services/items.js'; +import type { Item } from '../../types/index.js'; +import { getAccountabilityForRole } from '../../utils/get-accountability-for-role.js'; +import { sanitizeQuery } from '../../utils/sanitize-query.js'; type Options = { collection: string; diff --git a/api/src/operations/item-update/index.test.ts b/api/src/operations/item-update/index.test.ts index 8e3cef139d..dae4c35935 100644 --- a/api/src/operations/item-update/index.test.ts +++ b/api/src/operations/item-update/index.test.ts @@ -1,6 +1,6 @@ import { afterEach, describe, expect, test, vi } from 'vitest'; -vi.mock('../../services', () => { +vi.mock('../../services/items.js', () => { const ItemsService = vi.fn(); ItemsService.prototype.updateByQuery = vi.fn(); ItemsService.prototype.updateOne = vi.fn(); @@ -8,12 +8,12 @@ vi.mock('../../services', () => { return { ItemsService }; }); -vi.mock('../../utils/get-accountability-for-role', () => ({ +vi.mock('../../utils/get-accountability-for-role.js', () => ({ getAccountabilityForRole: vi.fn((role: string | null, _context) => Promise.resolve(role)), })); -import { ItemsService } from '../../services'; -import config from './index'; +import { ItemsService } from '../../services/items.js'; +import config from './index.js'; const testCollection = 'test'; const testPayload = {}; diff --git a/api/src/operations/item-update/index.ts b/api/src/operations/item-update/index.ts index 7d4d51fb6e..c6442f0d0d 100644 --- a/api/src/operations/item-update/index.ts +++ b/api/src/operations/item-update/index.ts @@ -1,9 +1,9 @@ -import type { Accountability, PrimaryKey } from '@directus/shared/types'; -import { defineOperationApi, optionToObject, toArray } from '@directus/shared/utils'; -import { ItemsService } from '../../services'; -import type { Item } from '../../types'; -import { getAccountabilityForRole } from '../../utils/get-accountability-for-role'; -import { sanitizeQuery } from '../../utils/sanitize-query'; +import type { Accountability, PrimaryKey } from '@directus/types'; +import { defineOperationApi, optionToObject, toArray } from '@directus/utils'; +import { ItemsService } from '../../services/items.js'; +import type { Item } from '../../types/index.js'; +import { getAccountabilityForRole } from '../../utils/get-accountability-for-role.js'; +import { sanitizeQuery } from '../../utils/sanitize-query.js'; type Options = { collection: string; diff --git a/api/src/operations/log/index.test.ts b/api/src/operations/log/index.test.ts index a22d72f491..63092e8598 100644 --- a/api/src/operations/log/index.test.ts +++ b/api/src/operations/log/index.test.ts @@ -8,7 +8,7 @@ vi.mock('../../logger', () => ({ }, })); -import config from './index'; +import config from './index.js'; afterEach(() => { vi.clearAllMocks(); diff --git a/api/src/operations/log/index.ts b/api/src/operations/log/index.ts index db49fba373..3a2b5d55fd 100644 --- a/api/src/operations/log/index.ts +++ b/api/src/operations/log/index.ts @@ -1,5 +1,5 @@ -import { defineOperationApi, optionToString } from '@directus/shared/utils'; -import logger from '../../logger'; +import { defineOperationApi, optionToString } from '@directus/utils'; +import logger from '../../logger.js'; type Options = { message: unknown; diff --git a/api/src/operations/mail/index.ts b/api/src/operations/mail/index.ts index f957eca666..4b57bad6b2 100644 --- a/api/src/operations/mail/index.ts +++ b/api/src/operations/mail/index.ts @@ -1,6 +1,6 @@ -import { defineOperationApi } from '@directus/shared/utils'; -import { MailService } from '../../services'; -import { md } from '../../utils/md'; +import { defineOperationApi } from '@directus/utils'; +import { MailService } from '../../services/mail/index.js'; +import { md } from '../../utils/md.js'; type Options = { body: string; diff --git a/api/src/operations/notification/index.test.ts b/api/src/operations/notification/index.test.ts index 5e8b091617..24f313bd41 100644 --- a/api/src/operations/notification/index.test.ts +++ b/api/src/operations/notification/index.test.ts @@ -1,18 +1,17 @@ import { afterEach, expect, test, vi } from 'vitest'; -vi.mock('../../services', () => { +vi.mock('../../services/notifications.js', () => { const NotificationsService = vi.fn(); NotificationsService.prototype.createMany = vi.fn(); return { NotificationsService }; }); -vi.mock('../../utils/get-accountability-for-role', () => ({ +vi.mock('../../utils/get-accountability-for-role.js', () => ({ getAccountabilityForRole: vi.fn((role: string | null, _context) => Promise.resolve(role)), })); -import { NotificationsService } from '../../services'; - -import config from './index'; +import { NotificationsService } from '../../services/notifications.js'; +import config from './index.js'; const testId = '00000000-0000-0000-0000-000000000000'; diff --git a/api/src/operations/notification/index.ts b/api/src/operations/notification/index.ts index f20b9fec91..7d98329c6e 100644 --- a/api/src/operations/notification/index.ts +++ b/api/src/operations/notification/index.ts @@ -1,7 +1,7 @@ -import type { Accountability } from '@directus/shared/types'; -import { defineOperationApi, optionToString, toArray } from '@directus/shared/utils'; -import { NotificationsService } from '../../services'; -import { getAccountabilityForRole } from '../../utils/get-accountability-for-role'; +import type { Accountability } from '@directus/types'; +import { defineOperationApi, optionToString, toArray } from '@directus/utils'; +import { NotificationsService } from '../../services/notifications.js'; +import { getAccountabilityForRole } from '../../utils/get-accountability-for-role.js'; type Options = { recipient: string; diff --git a/api/src/operations/request/index.test.ts b/api/src/operations/request/index.test.ts index c7f77020d0..24fcd448eb 100644 --- a/api/src/operations/request/index.test.ts +++ b/api/src/operations/request/index.test.ts @@ -2,7 +2,7 @@ import { afterEach, expect, test, vi } from 'vitest'; const axiosDefault = vi.fn(); -vi.mock('../../request', () => ({ +vi.mock('../../request/index.js', () => ({ getAxios: () => axiosDefault.mockResolvedValue({ status: 200, @@ -15,7 +15,7 @@ vi.mock('../../request', () => ({ const url = '/'; const method = 'POST'; -import config from './index'; +import config from './index.js'; afterEach(() => { vi.clearAllMocks(); diff --git a/api/src/operations/request/index.ts b/api/src/operations/request/index.ts index 3f75ae04c6..cfaaa0638b 100644 --- a/api/src/operations/request/index.ts +++ b/api/src/operations/request/index.ts @@ -1,6 +1,6 @@ -import { defineOperationApi, isValidJSON } from '@directus/shared/utils'; +import { defineOperationApi, isValidJSON } from '@directus/utils'; import encodeUrl from 'encodeurl'; -import { getAxios } from '../../request/index'; +import { getAxios } from '../../request/index.js'; type Options = { url: string; diff --git a/api/src/operations/sleep/index.test.ts b/api/src/operations/sleep/index.test.ts index 0bd7e1898b..410dab30d0 100644 --- a/api/src/operations/sleep/index.test.ts +++ b/api/src/operations/sleep/index.test.ts @@ -1,6 +1,6 @@ import { afterEach, beforeEach, expect, test, vi } from 'vitest'; -import config from './index'; +import config from './index.js'; beforeEach(() => { vi.useFakeTimers(); diff --git a/api/src/operations/sleep/index.ts b/api/src/operations/sleep/index.ts index 74c54cf9a9..dc26004e79 100644 --- a/api/src/operations/sleep/index.ts +++ b/api/src/operations/sleep/index.ts @@ -1,4 +1,4 @@ -import { defineOperationApi } from '@directus/shared/utils'; +import { defineOperationApi } from '@directus/utils'; type Options = { milliseconds: string | number; diff --git a/api/src/operations/transform/index.test.ts b/api/src/operations/transform/index.test.ts index 742a9e0866..4cac780f19 100644 --- a/api/src/operations/transform/index.test.ts +++ b/api/src/operations/transform/index.test.ts @@ -1,6 +1,6 @@ import { expect, test } from 'vitest'; -import config from './index'; +import config from './index.js'; test('runs the same object as the input', async () => { const json = { test: 'item' }; diff --git a/api/src/operations/transform/index.ts b/api/src/operations/transform/index.ts index 806c607b9e..a50823cfae 100644 --- a/api/src/operations/transform/index.ts +++ b/api/src/operations/transform/index.ts @@ -1,4 +1,4 @@ -import { defineOperationApi, optionToObject } from '@directus/shared/utils'; +import { defineOperationApi, optionToObject } from '@directus/utils'; type Options = { json: string | Record; diff --git a/api/src/operations/trigger/index.test.ts b/api/src/operations/trigger/index.test.ts index fcf8082bf0..b89a898fcf 100644 --- a/api/src/operations/trigger/index.test.ts +++ b/api/src/operations/trigger/index.test.ts @@ -2,13 +2,13 @@ import { afterEach, expect, test, vi } from 'vitest'; const runOperationFlow = vi.fn(); -vi.mock('../../flows', () => ({ +vi.mock('../../flows.js', () => ({ getFlowManager: vi.fn().mockReturnValue({ runOperationFlow, }), })); -import config from './index'; +import config from './index.js'; const testFlowId = '00000000-0000-0000-0000-000000000000'; diff --git a/api/src/operations/trigger/index.ts b/api/src/operations/trigger/index.ts index 3dfcb822af..b263cc6e5b 100644 --- a/api/src/operations/trigger/index.ts +++ b/api/src/operations/trigger/index.ts @@ -1,6 +1,6 @@ -import { defineOperationApi, optionToObject } from '@directus/shared/utils'; -import { omit } from 'lodash'; -import { getFlowManager } from '../../flows'; +import { defineOperationApi, optionToObject } from '@directus/utils'; +import { omit } from 'lodash-es'; +import { getFlowManager } from '../../flows.js'; type Options = { flow: string; diff --git a/api/src/rate-limiter.ts b/api/src/rate-limiter.ts index aef1b4aad7..bc8705e1d8 100644 --- a/api/src/rate-limiter.ts +++ b/api/src/rate-limiter.ts @@ -1,4 +1,4 @@ -import { merge } from 'lodash'; +import { merge } from 'lodash-es'; import { IRateLimiterOptions, IRateLimiterStoreOptions, @@ -7,8 +7,11 @@ import { RateLimiterMemory, RateLimiterRedis, } from 'rate-limiter-flexible'; -import env from './env'; -import { getConfigFromEnv } from './utils/get-config-from-env'; +import env from './env.js'; +import { getConfigFromEnv } from './utils/get-config-from-env.js'; + +import { createRequire } from 'node:module'; +const require = createRequire(import.meta.url); type IRateLimiterOptionsOverrides = Partial | Partial; diff --git a/api/src/request/index.test.ts b/api/src/request/index.test.ts index 540f2ae95f..9629c05708 100644 --- a/api/src/request/index.test.ts +++ b/api/src/request/index.test.ts @@ -1,5 +1,5 @@ import { test, vi, afterEach, beforeEach, expect } from 'vitest'; -import { getAxios, _cache } from './index'; +import { getAxios, _cache } from './index.js'; import axios from 'axios'; import type { AxiosInstance } from 'axios'; diff --git a/api/src/request/index.ts b/api/src/request/index.ts index e51266be57..967eaece51 100644 --- a/api/src/request/index.ts +++ b/api/src/request/index.ts @@ -1,6 +1,6 @@ import type { AxiosInstance } from 'axios'; -import { requestInterceptor } from './request-interceptor'; -import { responseInterceptor } from './response-interceptor'; +import { requestInterceptor } from './request-interceptor.js'; +import { responseInterceptor } from './response-interceptor.js'; export const _cache: { axiosInstance: AxiosInstance | null } = { axiosInstance: null, diff --git a/api/src/request/request-interceptor.test.ts b/api/src/request/request-interceptor.test.ts index 9c6515d527..9a66b673b3 100644 --- a/api/src/request/request-interceptor.test.ts +++ b/api/src/request/request-interceptor.test.ts @@ -6,9 +6,9 @@ import { lookup } from 'node:dns/promises'; import { isIP } from 'node:net'; import { URL } from 'node:url'; import { afterEach, beforeEach, expect, test, vi } from 'vitest'; -import logger from '../logger'; -import { requestInterceptor } from './request-interceptor'; -import { validateIP } from './validate-ip'; +import logger from '../logger.js'; +import { requestInterceptor } from './request-interceptor.js'; +import { validateIP } from './validate-ip.js'; vi.mock('axios'); vi.mock('node:net'); diff --git a/api/src/request/request-interceptor.ts b/api/src/request/request-interceptor.ts index 90c6b1a069..4a3eca8d17 100644 --- a/api/src/request/request-interceptor.ts +++ b/api/src/request/request-interceptor.ts @@ -3,8 +3,8 @@ import axios from 'axios'; import { lookup } from 'node:dns/promises'; import { isIP } from 'node:net'; import { URL } from 'node:url'; -import logger from '../logger'; -import { validateIP } from './validate-ip'; +import logger from '../logger.js'; +import { validateIP } from './validate-ip.js'; export const requestInterceptor = async (config: InternalAxiosRequestConfig) => { const uri = axios.getUri(config); diff --git a/api/src/request/response-interceptor.test.ts b/api/src/request/response-interceptor.test.ts index bda433ee6c..4536978a61 100644 --- a/api/src/request/response-interceptor.test.ts +++ b/api/src/request/response-interceptor.test.ts @@ -1,8 +1,8 @@ import { randIp, randUrl } from '@ngneat/falso'; import type { AxiosResponse } from 'axios'; import { afterEach, beforeEach, expect, test, vi } from 'vitest'; -import { responseInterceptor } from './response-interceptor'; -import { validateIP } from './validate-ip'; +import { responseInterceptor } from './response-interceptor.js'; +import { validateIP } from './validate-ip.js'; vi.mock('./validate-ip'); diff --git a/api/src/request/response-interceptor.ts b/api/src/request/response-interceptor.ts index bfad826fa0..8d8479186a 100644 --- a/api/src/request/response-interceptor.ts +++ b/api/src/request/response-interceptor.ts @@ -1,5 +1,5 @@ import type { AxiosResponse } from 'axios'; -import { validateIP } from './validate-ip'; +import { validateIP } from './validate-ip.js'; export const responseInterceptor = async (config: AxiosResponse) => { await validateIP(config.request.socket.remoteAddress, config.request.url); diff --git a/api/src/request/validate-ip.test.ts b/api/src/request/validate-ip.test.ts index 4cf3982ad4..5043e58f7c 100644 --- a/api/src/request/validate-ip.test.ts +++ b/api/src/request/validate-ip.test.ts @@ -1,8 +1,8 @@ import { randIp, randUrl } from '@ngneat/falso'; import os from 'node:os'; import { afterEach, beforeEach, expect, test, vi } from 'vitest'; -import { getEnv } from '../env'; -import { validateIP } from './validate-ip'; +import { getEnv } from '../env.js'; +import { validateIP } from './validate-ip.js'; vi.mock('../env'); vi.mock('node:os'); diff --git a/api/src/request/validate-ip.ts b/api/src/request/validate-ip.ts index 4f1da15e92..f8f5567c4f 100644 --- a/api/src/request/validate-ip.ts +++ b/api/src/request/validate-ip.ts @@ -1,5 +1,5 @@ import os from 'node:os'; -import { getEnv } from '../env'; +import { getEnv } from '../env.js'; export const validateIP = async (ip: string, url: string) => { const env = getEnv(); diff --git a/api/src/server.ts b/api/src/server.ts index 9fc818a643..3582e82946 100644 --- a/api/src/server.ts +++ b/api/src/server.ts @@ -2,17 +2,17 @@ import { createTerminus, TerminusOptions } from '@godaddy/terminus'; import type { Request } from 'express'; import * as http from 'http'; import * as https from 'https'; -import { once } from 'lodash'; +import { once } from 'lodash-es'; import qs from 'qs'; -import checkForUpdate from 'update-check'; +import { isUpToDate } from '@directus/update-check'; import url from 'url'; -import pkg from '../package.json'; -import createApp from './app'; -import getDatabase from './database'; -import emitter from './emitter'; -import env from './env'; -import logger from './logger'; -import { getConfigFromEnv } from './utils/get-config-from-env'; +import * as pkg from './utils/package.js'; +import createApp from './app.js'; +import getDatabase from './database/index.js'; +import emitter from './emitter.js'; +import env from './env.js'; +import logger from './logger.js'; +import { getConfigFromEnv } from './utils/get-config-from-env.js'; export async function createServer(): Promise { const server = http.createServer(await createApp()); @@ -131,10 +131,10 @@ export async function startServer(): Promise { server .listen(port, host, () => { - checkForUpdate(pkg) + isUpToDate(pkg.name, pkg.version) .then((update) => { if (update) { - logger.warn(`Update available: ${pkg.version} -> ${update.latest}`); + logger.warn(`Update available: ${pkg.version} -> ${update}`); } }) .catch(() => { diff --git a/api/src/services/activity.ts b/api/src/services/activity.ts index faaadaf919..beff2682b5 100644 --- a/api/src/services/activity.ts +++ b/api/src/services/activity.ts @@ -1,17 +1,17 @@ -import { Accountability, Action } from '@directus/shared/types'; -import { uniq } from 'lodash'; +import { Accountability, Action } from '@directus/types'; +import { uniq } from 'lodash-es'; import validateUUID from 'uuid-validate'; -import env from '../env'; -import { ForbiddenException } from '../exceptions/forbidden'; -import logger from '../logger'; -import type { AbstractServiceOptions, Item, MutationOptions, PrimaryKey } from '../types'; -import { getPermissions } from '../utils/get-permissions'; -import { Url } from '../utils/url'; -import { userName } from '../utils/user-name'; -import { AuthorizationService } from './authorization'; -import { ItemsService } from './items'; -import { NotificationsService } from './notifications'; -import { UsersService } from './users'; +import env from '../env.js'; +import { ForbiddenException } from '../exceptions/forbidden.js'; +import logger from '../logger.js'; +import type { AbstractServiceOptions, Item, MutationOptions, PrimaryKey } from '../types/index.js'; +import { getPermissions } from '../utils/get-permissions.js'; +import { Url } from '../utils/url.js'; +import { userName } from '../utils/user-name.js'; +import { AuthorizationService } from './authorization.js'; +import { ItemsService } from './items.js'; +import { NotificationsService } from './notifications.js'; +import { UsersService } from './users.js'; export class ActivityService extends ItemsService { notificationsService: NotificationsService; diff --git a/api/src/services/assets.ts b/api/src/services/assets.ts index 2c62195825..add4d3a191 100644 --- a/api/src/services/assets.ts +++ b/api/src/services/assets.ts @@ -1,31 +1,29 @@ -// @ts-expect-error https://github.com/microsoft/TypeScript/issues/49721 import type { Range, Stat } from '@directus/storage'; - -import type { Accountability } from '@directus/shared/types'; +import type { Accountability } from '@directus/types'; import type { Knex } from 'knex'; -import { clamp } from 'lodash'; +import { clamp } from 'lodash-es'; import { contentType } from 'mime-types'; import type { Readable } from 'node:stream'; import hash from 'object-hash'; import path from 'path'; import sharp from 'sharp'; import validateUUID from 'uuid-validate'; -import getDatabase from '../database'; -import env from '../env'; -import { ForbiddenException, IllegalAssetTransformation, RangeNotSatisfiableException } from '../exceptions'; -import { ServiceUnavailableException } from '../exceptions/service-unavailable'; -import logger from '../logger'; -import { getStorage } from '../storage'; +import getDatabase from '../database/index.js'; +import env from '../env.js'; +import { ForbiddenException, IllegalAssetTransformation, RangeNotSatisfiableException } from '../exceptions/index.js'; +import { ServiceUnavailableException } from '../exceptions/service-unavailable.js'; +import logger from '../logger.js'; +import { getStorage } from '../storage/index.js'; import type { AbstractServiceOptions, File, Transformation, TransformationParams, TransformationPreset, -} from '../types'; -import { getMilliseconds } from '../utils/get-milliseconds'; -import * as TransformationUtils from '../utils/transformations'; -import { AuthorizationService } from './authorization'; +} from '../types/index.js'; +import { getMilliseconds } from '../utils/get-milliseconds.js'; +import * as TransformationUtils from '../utils/transformations.js'; +import { AuthorizationService } from './authorization.js'; export class AssetsService { knex: Knex; diff --git a/api/src/services/authentication.ts b/api/src/services/authentication.ts index 3643839b06..bf389ba214 100644 --- a/api/src/services/authentication.ts +++ b/api/src/services/authentication.ts @@ -1,26 +1,26 @@ -import { Accountability, Action, SchemaOverview } from '@directus/shared/types'; +import { Accountability, Action, SchemaOverview } from '@directus/types'; import jwt from 'jsonwebtoken'; import type { Knex } from 'knex'; -import { clone, cloneDeep } from 'lodash'; +import { clone, cloneDeep } from 'lodash-es'; import { performance } from 'perf_hooks'; -import { getAuthProvider } from '../auth'; -import { DEFAULT_AUTH_PROVIDER } from '../constants'; -import getDatabase from '../database'; -import emitter from '../emitter'; -import env from '../env'; +import { getAuthProvider } from '../auth.js'; +import { DEFAULT_AUTH_PROVIDER } from '../constants.js'; +import getDatabase from '../database/index.js'; +import emitter from '../emitter.js'; +import env from '../env.js'; import { InvalidCredentialsException, InvalidOTPException, InvalidProviderException, UserSuspendedException, -} from '../exceptions'; -import { createRateLimiter } from '../rate-limiter'; -import type { AbstractServiceOptions, DirectusTokenPayload, LoginResult, Session, User } from '../types'; -import { getMilliseconds } from '../utils/get-milliseconds'; -import { stall } from '../utils/stall'; -import { ActivityService } from './activity'; -import { SettingsService } from './settings'; -import { TFAService } from './tfa'; +} from '../exceptions/index.js'; +import { createRateLimiter } from '../rate-limiter.js'; +import type { AbstractServiceOptions, DirectusTokenPayload, LoginResult, Session, User } from '../types/index.js'; +import { getMilliseconds } from '../utils/get-milliseconds.js'; +import { stall } from '../utils/stall.js'; +import { ActivityService } from './activity.js'; +import { SettingsService } from './settings.js'; +import { TFAService } from './tfa.js'; const loginAttemptsLimiter = createRateLimiter('RATE_LIMITER', { duration: 0 }); diff --git a/api/src/services/authorization.ts b/api/src/services/authorization.ts index 12e88aac96..ff9c040d5f 100644 --- a/api/src/services/authorization.ts +++ b/api/src/services/authorization.ts @@ -1,4 +1,4 @@ -import { FailedValidationException } from '@directus/shared/exceptions'; +import { FailedValidationException } from '@directus/exceptions'; import type { Accountability, Aggregate, @@ -7,13 +7,13 @@ import type { PermissionsAction, Query, SchemaOverview, -} from '@directus/shared/types'; -import { validatePayload } from '@directus/shared/utils'; +} from '@directus/types'; +import { validatePayload } from '@directus/utils'; import type { Knex } from 'knex'; -import { cloneDeep, flatten, isArray, isNil, merge, reduce, uniq, uniqWith } from 'lodash'; -import { GENERATE_SPECIAL } from '../constants'; -import getDatabase from '../database'; -import { ForbiddenException } from '../exceptions'; +import { cloneDeep, flatten, isArray, isNil, merge, reduce, uniq, uniqWith } from 'lodash-es'; +import { GENERATE_SPECIAL } from '../constants.js'; +import getDatabase from '../database/index.js'; +import { ForbiddenException } from '../exceptions/index.js'; import type { AbstractServiceOptions, AST, @@ -22,11 +22,11 @@ import type { Item, NestedCollectionNode, PrimaryKey, -} from '../types'; -import { getRelationInfo } from '../utils/get-relation-info'; -import { stripFunction } from '../utils/strip-function'; -import { ItemsService } from './items'; -import { PayloadService } from './payload'; +} from '../types/index.js'; +import { getRelationInfo } from '../utils/get-relation-info.js'; +import { stripFunction } from '../utils/strip-function.js'; +import { ItemsService } from './items.js'; +import { PayloadService } from './payload.js'; export class AuthorizationService { knex: Knex; diff --git a/api/src/services/collections.ts b/api/src/services/collections.ts index 60afa3d783..0b723df703 100644 --- a/api/src/services/collections.ts +++ b/api/src/services/collections.ts @@ -1,22 +1,28 @@ -import SchemaInspector from '@directus/schema'; -import type { Accountability, FieldMeta, RawField, SchemaOverview } from '@directus/shared/types'; -import { addFieldFlag } from '@directus/shared/utils'; +import { createInspector } from '@directus/schema'; +import type { Accountability, FieldMeta, RawField, SchemaOverview } from '@directus/types'; +import { addFieldFlag } from '@directus/utils'; import type Keyv from 'keyv'; import type { Knex } from 'knex'; -import type { Table } from 'knex-schema-inspector/dist/types/table'; -import { omit } from 'lodash'; -import { clearSystemCache, getCache } from '../cache'; -import { ALIAS_TYPES } from '../constants'; -import getDatabase, { getSchemaInspector } from '../database'; -import { getHelpers, Helpers } from '../database/helpers'; -import { systemCollectionRows } from '../database/system-data/collections'; -import emitter from '../emitter'; -import env from '../env'; -import { ForbiddenException, InvalidPayloadException } from '../exceptions'; -import { FieldsService } from '../services/fields'; -import { ItemsService } from '../services/items'; -import type { AbstractServiceOptions, ActionEventParams, Collection, CollectionMeta, MutationOptions } from '../types'; -import { getSchema } from '../utils/get-schema'; +import type { Table, SchemaInspector } from '@directus/schema'; +import { omit } from 'lodash-es'; +import { clearSystemCache, getCache } from '../cache.js'; +import { ALIAS_TYPES } from '../constants.js'; +import getDatabase, { getSchemaInspector } from '../database/index.js'; +import { getHelpers, Helpers } from '../database/helpers/index.js'; +import { systemCollectionRows } from '../database/system-data/collections/index.js'; +import emitter from '../emitter.js'; +import env from '../env.js'; +import { ForbiddenException, InvalidPayloadException } from '../exceptions/index.js'; +import { FieldsService } from '../services/fields.js'; +import { ItemsService } from '../services/items.js'; +import type { + AbstractServiceOptions, + ActionEventParams, + Collection, + CollectionMeta, + MutationOptions, +} from '../types/index.js'; +import { getSchema } from '../utils/get-schema.js'; export type RawCollection = { collection: string; @@ -29,7 +35,7 @@ export class CollectionsService { knex: Knex; helpers: Helpers; accountability: Accountability | null; - schemaInspector: ReturnType; + schemaInspector: SchemaInspector; schema: SchemaOverview; cache: Keyv | null; systemCache: Keyv; @@ -38,7 +44,7 @@ export class CollectionsService { this.knex = options.knex || getDatabase(); this.helpers = getHelpers(this.knex); this.accountability = options.accountability || null; - this.schemaInspector = options.knex ? SchemaInspector(options.knex) : getSchemaInspector(); + this.schemaInspector = options.knex ? createInspector(options.knex) : getSchemaInspector(); this.schema = options.schema; const { cache, systemCache } = getCache(); diff --git a/api/src/services/dashboards.ts b/api/src/services/dashboards.ts index 8f6b4a358f..241e64057e 100644 --- a/api/src/services/dashboards.ts +++ b/api/src/services/dashboards.ts @@ -1,5 +1,5 @@ -import type { AbstractServiceOptions } from '../types'; -import { ItemsService } from './items'; +import type { AbstractServiceOptions } from '../types/index.js'; +import { ItemsService } from './items.js'; export class DashboardsService extends ItemsService { constructor(options: AbstractServiceOptions) { diff --git a/api/src/services/fields.test.ts b/api/src/services/fields.test.ts deleted file mode 100644 index 2bb2426d96..0000000000 --- a/api/src/services/fields.test.ts +++ /dev/null @@ -1,354 +0,0 @@ -import type { Field } from '@directus/shared/types'; -import knex, { Knex } from 'knex'; -import { createTracker, MockClient, Tracker } from 'knex-mock-client'; -import { afterEach, beforeAll, beforeEach, describe, expect, it, MockedFunction, SpyInstance, vi } from 'vitest'; -import { FieldsService } from '.'; -import { InvalidPayloadException } from '../exceptions'; - -vi.mock('../../src/database/index', () => ({ - default: vi.fn(), - getDatabaseClient: vi.fn().mockReturnValue('postgres'), - getSchemaInspector: vi.fn(), -})); - -describe('Integration Tests', () => { - let db: MockedFunction; - let tracker: Tracker; - - beforeAll(() => { - db = vi.mocked(knex({ client: MockClient })); - tracker = createTracker(db); - }); - - afterEach(() => { - tracker.reset(); - }); - - describe('Services / Fields', () => { - let service: FieldsService; - - beforeEach(() => { - service = new FieldsService({ - schema: { collections: {}, relations: [] }, - }); - }); - - afterEach(() => { - vi.clearAllMocks(); - }); - - describe('addColumnToTable', () => { - let knexCreateTableBuilderSpy: SpyInstance; - - it.each(['alias', 'unknown'])('%s fields should be skipped', async (type) => { - const testCollection = 'test_collection'; - const testField = 'test_field'; - - const promise = db.schema.alterTable(testCollection, (table) => { - service.addColumnToTable(table, { - collection: testCollection, - field: testField, - type, - schema: { - name: testField, - table: testCollection, - data_type: type, - }, - meta: {}, - } as Field); - }); - - await expect(promise).resolves.not.toThrow(); - }); - - it('illegal fields should be throw InvalidPayloadException', async () => { - const testCollection = 'test_collection'; - const testField = 'test_field'; - const type = 'mystery'; - - expect.assertions(2); // to ensure both assertions in the catch block are reached - - try { - await db.schema.alterTable(testCollection, (table) => { - service.addColumnToTable(table, { - collection: testCollection, - field: testField, - type, - schema: { - name: testField, - table: testCollection, - data_type: type, - }, - meta: {}, - } as any); - }); - } catch (err: any) { - expect(err.message).toBe(`Illegal type passed: "${type}"`); - expect(err).toBeInstanceOf(InvalidPayloadException); - } - }); - - it.each([ - { type: 'integer', method: 'increments' }, - { type: 'bigInteger', method: 'bigIncrements' }, - ])('auto increment $type fields should use $method()', async ({ type, method }) => { - const testCollection = 'test_collection'; - const testField = 'test_field'; - - const regex = new RegExp(`alter table "${testCollection}" add column "${testField}" .*`); - tracker.on.any(regex).response({}); - - await db.schema.alterTable(testCollection, (table) => { - knexCreateTableBuilderSpy = vi.spyOn(table, method as keyof Knex.CreateTableBuilder); - - service.addColumnToTable(table, { - collection: testCollection, - field: testField, - type, - schema: { - name: testField, - table: testCollection, - data_type: type, - has_auto_increment: true, - }, - meta: {}, - } as Field); - }); - - expect(knexCreateTableBuilderSpy).toHaveBeenCalledWith(testField); - }); - - it.each([10, undefined])('string fields should use string() with %j max length', async (maxLength) => { - const testCollection = 'test_collection'; - const testField = 'test_field'; - const type = 'string'; - - const regex = new RegExp(`alter table "${testCollection}" add column "${testField}" .*`); - tracker.on.any(regex).response({}); - - await db.schema.alterTable(testCollection, (table) => { - knexCreateTableBuilderSpy = vi.spyOn(table, type as keyof Knex.CreateTableBuilder); - - service.addColumnToTable(table, { - collection: testCollection, - field: testField, - type, - schema: { - name: testField, - table: testCollection, - data_type: type, - max_length: maxLength, - }, - meta: {}, - } as Field); - }); - - expect(knexCreateTableBuilderSpy).toHaveBeenCalledWith(testField, maxLength); - }); - - it.each(['float', 'decimal'])( - 'precision and scale for %s fields should fallback to default value', - async (type) => { - const testCollection = 'test_collection'; - const testField = 'test_field'; - - const regex = new RegExp(`alter table "${testCollection}" add column "${testField}" ${type}.*`); - tracker.on.any(regex).response({}); - - await db.schema.alterTable(testCollection, (table) => { - knexCreateTableBuilderSpy = vi.spyOn(table, type as keyof Knex.CreateTableBuilder); - - service.addColumnToTable(table, { - collection: testCollection, - field: testField, - type, - schema: { - name: testField, - table: testCollection, - data_type: type, - }, - meta: {}, - } as Field); - }); - - expect(knexCreateTableBuilderSpy).toHaveBeenCalledWith(testField, 10, 5); - } - ); - - it.each(['float', 'decimal'])( - 'zero precision or scale for %s fields should not fallback to default value', - async (type) => { - const testCollection = 'test_collection'; - const testField = 'test_field'; - - const regex = new RegExp(`alter table "${testCollection}" add column "${testField}" ${type}.*`); - tracker.on.any(regex).response({}); - - await db.schema.alterTable('test_collection', (table) => { - knexCreateTableBuilderSpy = vi.spyOn(table, type as keyof Knex.CreateTableBuilder); - - service.addColumnToTable(table, { - collection: testCollection, - field: testField, - type, - schema: { - name: testField, - table: testCollection, - data_type: type, - numeric_precision: 0, - numeric_scale: 0, - }, - meta: {}, - } as Field); - }); - - expect(knexCreateTableBuilderSpy).toHaveBeenCalledWith(testField, 0, 0); - } - ); - - it('csv fields should use string()', async () => { - const testCollection = 'test_collection'; - const testField = 'test_field'; - const type = 'csv'; - - const regex = new RegExp(`alter table "${testCollection}" add column "${testField}" .*`); - tracker.on.any(regex).response({}); - - await db.schema.alterTable(testCollection, (table) => { - knexCreateTableBuilderSpy = vi.spyOn(table, 'string'); - - service.addColumnToTable(table, { - collection: testCollection, - field: testField, - type, - schema: { - name: testField, - table: testCollection, - data_type: type, - }, - meta: {}, - } as Field); - }); - - expect(knexCreateTableBuilderSpy).toHaveBeenCalledWith(testField); - }); - - it('hash fields should use string() with length 255', async () => { - const testCollection = 'test_collection'; - const testField = 'test_field'; - const type = 'hash'; - - const regex = new RegExp(`alter table "${testCollection}" add column "${testField}" .*`); - tracker.on.any(regex).response({}); - - await db.schema.alterTable(testCollection, (table) => { - knexCreateTableBuilderSpy = vi.spyOn(table, 'string'); - - service.addColumnToTable(table, { - collection: testCollection, - field: testField, - type, - schema: { - name: testField, - table: testCollection, - data_type: type, - }, - meta: {}, - } as Field); - }); - - expect(knexCreateTableBuilderSpy).toHaveBeenCalledWith(testField, 255); - }); - - it.each([ - { type: 'dateTime', useTz: false }, - { type: 'timestamp', useTz: true }, - ])('$type fields should use $type() with { useTz: $useTz } option', async ({ type, useTz }) => { - const testCollection = 'test_collection'; - const testField = 'test_field'; - - const regex = new RegExp(`alter table "${testCollection}" add column "${testField}" .*`); - tracker.on.any(regex).response({}); - - await db.schema.alterTable(testCollection, (table) => { - knexCreateTableBuilderSpy = vi.spyOn(table, type as keyof Knex.CreateTableBuilder); - - service.addColumnToTable(table, { - collection: testCollection, - field: testField, - type, - schema: { - name: testField, - table: testCollection, - data_type: type, - }, - meta: {}, - } as Field); - }); - - expect(knexCreateTableBuilderSpy).toHaveBeenCalledWith(testField, { useTz }); - }); - - it.each(['geometry', 'geometry.Point'])('%s fields should use this.helpers.st.createColumn()', async (type) => { - const testCollection = 'test_collection'; - const testField = 'test_field'; - - const regex = new RegExp(`alter table "${testCollection}" add column "${testField}" .*`); - tracker.on.any(regex).response({}); - - const thisHelpersStCreateColumnSpy = vi.spyOn(service.helpers.st, 'createColumn'); - - await db.schema.alterTable(testCollection, (table) => { - service.addColumnToTable(table, { - collection: testCollection, - field: testField, - type, - schema: { - name: testField, - table: testCollection, - data_type: type, - }, - meta: {}, - } as Field); - }); - - expect(thisHelpersStCreateColumnSpy).toHaveBeenCalled(); - }); - - // the rest of KNEX_TYPES except the ones above - it.each([ - { type: 'boolean' }, - { type: 'date' }, - { type: 'json' }, - { type: 'text' }, - { type: 'time' }, - { type: 'binary' }, - { type: 'uuid' }, - ])('$type fields should use $type()', async ({ type }) => { - const testCollection = 'test_collection'; - const testField = 'test_field'; - - const regex = new RegExp(`alter table "${testCollection}" add column "${testField}" .*`); - tracker.on.any(regex).response({}); - - await db.schema.alterTable(testCollection, (table) => { - knexCreateTableBuilderSpy = vi.spyOn(table, type as keyof Knex.CreateTableBuilder); - - service.addColumnToTable(table, { - collection: testCollection, - field: testField, - type, - schema: { - name: testField, - table: testCollection, - data_type: type, - }, - meta: {}, - } as Field); - }); - - expect(knexCreateTableBuilderSpy).toHaveBeenCalledWith(testField); - }); - }); - }); -}); diff --git a/api/src/services/fields.ts b/api/src/services/fields.ts index 04c5c5f980..f7425f1d10 100644 --- a/api/src/services/fields.ts +++ b/api/src/services/fields.ts @@ -1,27 +1,27 @@ -import SchemaInspector from '@directus/schema'; -import { KNEX_TYPES, REGEX_BETWEEN_PARENS } from '@directus/shared/constants'; -import type { Accountability, Field, FieldMeta, RawField, SchemaOverview, Type } from '@directus/shared/types'; -import { addFieldFlag, toArray } from '@directus/shared/utils'; +import type { Column, SchemaInspector } from '@directus/schema'; +import { createInspector } from '@directus/schema'; +import { KNEX_TYPES, REGEX_BETWEEN_PARENS } from '@directus/constants'; +import type { Accountability, Field, FieldMeta, RawField, SchemaOverview, Type } from '@directus/types'; +import { addFieldFlag, toArray } from '@directus/utils'; import type Keyv from 'keyv'; import type { Knex } from 'knex'; -import type { Column } from 'knex-schema-inspector/dist/types/column'; -import { isEqual, isNil } from 'lodash'; -import { clearSystemCache, getCache } from '../cache'; -import { ALIAS_TYPES } from '../constants'; -import getDatabase, { getSchemaInspector } from '../database'; -import { getHelpers, Helpers } from '../database/helpers'; -import { systemFieldRows } from '../database/system-data/fields/'; -import emitter from '../emitter'; -import env from '../env'; -import { ForbiddenException, InvalidPayloadException } from '../exceptions'; -import { translateDatabaseError } from '../exceptions/database/translate'; -import { ItemsService } from '../services/items'; -import { PayloadService } from '../services/payload'; -import type { AbstractServiceOptions, ActionEventParams, MutationOptions } from '../types'; -import getDefaultValue from '../utils/get-default-value'; -import getLocalType from '../utils/get-local-type'; -import { getSchema } from '../utils/get-schema'; -import { RelationsService } from './relations'; +import { isEqual, isNil } from 'lodash-es'; +import { clearSystemCache, getCache } from '../cache.js'; +import { ALIAS_TYPES } from '../constants.js'; +import { getHelpers, Helpers } from '../database/helpers/index.js'; +import getDatabase, { getSchemaInspector } from '../database/index.js'; +import { systemFieldRows } from '../database/system-data/fields/index.js'; +import emitter from '../emitter.js'; +import env from '../env.js'; +import { translateDatabaseError } from '../exceptions/database/translate.js'; +import { ForbiddenException, InvalidPayloadException } from '../exceptions/index.js'; +import { ItemsService } from '../services/items.js'; +import { PayloadService } from '../services/payload.js'; +import type { AbstractServiceOptions, ActionEventParams, MutationOptions } from '../types/index.js'; +import getDefaultValue from '../utils/get-default-value.js'; +import getLocalType from '../utils/get-local-type.js'; +import { getSchema } from '../utils/get-schema.js'; +import { RelationsService } from './relations.js'; export class FieldsService { knex: Knex; @@ -29,7 +29,7 @@ export class FieldsService { accountability: Accountability | null; itemsService: ItemsService; payloadService: PayloadService; - schemaInspector: ReturnType; + schemaInspector: SchemaInspector; schema: SchemaOverview; cache: Keyv | null; systemCache: Keyv; @@ -37,7 +37,7 @@ export class FieldsService { constructor(options: AbstractServiceOptions) { this.knex = options.knex || getDatabase(); this.helpers = getHelpers(this.knex); - this.schemaInspector = options.knex ? SchemaInspector(options.knex) : getSchemaInspector(); + this.schemaInspector = options.knex ? createInspector(options.knex) : getSchemaInspector(); this.accountability = options.accountability || null; this.itemsService = new ItemsService('directus_fields', options); this.payloadService = new PayloadService('directus_fields', options); diff --git a/api/src/services/files.test.ts b/api/src/services/files.test.ts index aa3e344e2f..6418cd196d 100644 --- a/api/src/services/files.test.ts +++ b/api/src/services/files.test.ts @@ -1,15 +1,16 @@ -import knex, { Knex } from 'knex'; +import type { Knex } from 'knex'; +import knex from 'knex'; import { createTracker, MockClient, Tracker } from 'knex-mock-client'; import { afterEach, beforeAll, beforeEach, describe, expect, it, MockedFunction, SpyInstance, vi } from 'vitest'; -import { FilesService, ItemsService } from '.'; -import { InvalidPayloadException } from '../exceptions'; +import { InvalidPayloadException } from '../exceptions/index.js'; +import { FilesService, ItemsService } from './index.js'; describe('Integration Tests', () => { let db: MockedFunction; let tracker: Tracker; beforeAll(() => { - db = vi.mocked(knex({ client: MockClient })); + db = vi.mocked(knex.default({ client: MockClient })); tracker = createTracker(db); }); diff --git a/api/src/services/files.ts b/api/src/services/files.ts index 01efa4f70b..efd4cca8b8 100644 --- a/api/src/services/files.ts +++ b/api/src/services/files.ts @@ -1,25 +1,23 @@ -import { toArray } from '@directus/shared/utils'; +import { toArray } from '@directus/utils'; import encodeURL from 'encodeurl'; import exif from 'exif-reader'; import { parse as parseIcc } from 'icc'; -import { clone, pick } from 'lodash'; +import { clone, pick } from 'lodash-es'; import { extension } from 'mime-types'; import type { Readable } from 'node:stream'; import { pipeline } from 'node:stream/promises'; import path from 'path'; import sharp from 'sharp'; import url from 'url'; -import emitter from '../emitter'; -import env from '../env'; -import { ForbiddenException, InvalidPayloadException, ServiceUnavailableException } from '../exceptions'; -import logger from '../logger'; -import { getAxios } from '../request/index'; -import { getStorage } from '../storage'; -import type { AbstractServiceOptions, File, Metadata, MutationOptions, PrimaryKey } from '../types'; -import { parseIptc, parseXmp } from '../utils/parse-image-metadata'; -import { ItemsService } from './items'; - -// @ts-ignore +import emitter from '../emitter.js'; +import env from '../env.js'; +import { ForbiddenException, InvalidPayloadException, ServiceUnavailableException } from '../exceptions/index.js'; +import logger from '../logger.js'; +import { getAxios } from '../request/index.js'; +import { getStorage } from '../storage/index.js'; +import type { AbstractServiceOptions, File, Metadata, MutationOptions, PrimaryKey } from '../types/index.js'; +import { parseIptc, parseXmp } from '../utils/parse-image-metadata.js'; +import { ItemsService } from './items.js'; import formatTitle from '@directus/format-title'; export class FilesService extends ItemsService { diff --git a/api/src/services/flows.test.ts b/api/src/services/flows.test.ts deleted file mode 100644 index 6076bb6310..0000000000 --- a/api/src/services/flows.test.ts +++ /dev/null @@ -1,138 +0,0 @@ -import knex, { Knex } from 'knex'; -import { createTracker, MockClient, Tracker } from 'knex-mock-client'; -import { afterEach, beforeAll, beforeEach, describe, expect, it, SpyInstance, vi } from 'vitest'; -import { FlowsService } from '.'; -import { getFlowManager } from '../flows'; - -vi.mock('../../src/database/index', () => { - return { __esModule: true, default: vi.fn(), getDatabaseClient: vi.fn().mockReturnValue('postgres') }; -}); - -vi.mock('../flows', () => { - return { getFlowManager: vi.fn().mockReturnValue({ reload: vi.fn() }) }; -}); - -describe('Integration Tests', () => { - let db: Knex; - let tracker: Tracker; - - beforeAll(async () => { - db = knex({ client: MockClient }); - tracker = createTracker(db); - }); - - beforeEach(() => { - tracker.on.any('directus_flows').response({}); - tracker.on.update('directus_operations').response({}); - }); - - afterEach(() => { - tracker.reset(); - }); - - describe('Services / Flows', () => { - let service: FlowsService; - let flowManagerReloadSpy: SpyInstance; - - beforeEach(() => { - service = new FlowsService({ - knex: db, - schema: { - collections: { - directus_flows: { - collection: 'directus_flows', - primary: 'id', - singleton: false, - sortField: null, - note: null, - accountability: null, - fields: { - id: { - field: 'id', - defaultValue: null, - nullable: false, - generated: true, - type: 'integer', - dbType: 'integer', - precision: null, - scale: null, - special: [], - note: null, - validation: null, - alias: false, - }, - }, - }, - }, - relations: [], - }, - }); - flowManagerReloadSpy = vi.spyOn(getFlowManager(), 'reload'); - }); - - afterEach(() => { - flowManagerReloadSpy.mockClear(); - }); - - describe('createOne', () => { - it('should reload flows once', async () => { - await service.createOne({}); - expect(flowManagerReloadSpy).toBeCalledTimes(1); - }); - }); - - describe('createMany', () => { - it('should reload flows once', async () => { - await service.createMany([{}]); - expect(flowManagerReloadSpy).toBeCalledTimes(1); - }); - }); - - describe('updateOne', () => { - it('should reload flows once', async () => { - await service.updateOne(1, {}); - expect(flowManagerReloadSpy).toBeCalledTimes(1); - }); - }); - - describe('updateBatch', () => { - it('should reload flows once', async () => { - await service.updateBatch([{ id: 1 }]); - expect(flowManagerReloadSpy).toBeCalledTimes(1); - }); - }); - - describe('updateMany', () => { - it('should reload flows once', async () => { - await service.updateMany([1], {}); - expect(flowManagerReloadSpy).toBeCalledTimes(1); - }); - }); - - describe('deleteOne', () => { - it('should update operations once and reload flows once', async () => { - await service.deleteOne(1); - - const updateOperationsCalls = tracker.history.update.filter((query) => - query.sql.includes(`update "directus_operations" set "resolve" = ?, "reject" = ? where "flow"`) - ).length; - - expect(updateOperationsCalls).toBe(1); - expect(flowManagerReloadSpy).toBeCalledTimes(1); - }); - }); - - describe('deleteMany', () => { - it('should update operations once and reload flows once', async () => { - await service.deleteMany([1]); - - const updateOperationsCalls = tracker.history.update.filter((query) => - query.sql.includes(`update "directus_operations" set "resolve" = ?, "reject" = ? where "flow"`) - ).length; - - expect(updateOperationsCalls).toBe(1); - expect(flowManagerReloadSpy).toBeCalledTimes(1); - }); - }); - }); -}); diff --git a/api/src/services/flows.ts b/api/src/services/flows.ts index d07abe1398..230cb9ba13 100644 --- a/api/src/services/flows.ts +++ b/api/src/services/flows.ts @@ -1,7 +1,7 @@ -import type { FlowRaw } from '@directus/shared/types'; -import { getFlowManager } from '../flows'; -import type { AbstractServiceOptions, Item, MutationOptions, PrimaryKey } from '../types'; -import { ItemsService } from './items'; +import type { FlowRaw } from '@directus/types'; +import { getFlowManager } from '../flows.js'; +import type { AbstractServiceOptions, Item, MutationOptions, PrimaryKey } from '../types/index.js'; +import { ItemsService } from './items.js'; export class FlowsService extends ItemsService { constructor(options: AbstractServiceOptions) { diff --git a/api/src/services/folders.ts b/api/src/services/folders.ts index dece381c9d..7925ceddf4 100644 --- a/api/src/services/folders.ts +++ b/api/src/services/folders.ts @@ -1,5 +1,5 @@ -import type { AbstractServiceOptions } from '../types'; -import { ItemsService } from './items'; +import type { AbstractServiceOptions } from '../types/index.js'; +import { ItemsService } from './items.js'; export class FoldersService extends ItemsService { constructor(options: AbstractServiceOptions) { diff --git a/api/src/services/graphql/index.ts b/api/src/services/graphql/index.ts index 550be9c9bf..eb2366736c 100644 --- a/api/src/services/graphql/index.ts +++ b/api/src/services/graphql/index.ts @@ -1,7 +1,7 @@ -import { FUNCTIONS } from '@directus/shared/constants'; -import type { BaseException } from '@directus/shared/exceptions'; -import { Accountability, Action, Aggregate, Filter, PrimaryKey, Query, SchemaOverview } from '@directus/shared/types'; -import { parseFilterFunctionPath } from '@directus/shared/utils'; +import { FUNCTIONS } from '@directus/constants'; +import type { BaseException } from '@directus/exceptions'; +import { Accountability, Action, Aggregate, Filter, PrimaryKey, Query, SchemaOverview } from '@directus/types'; +import { parseFilterFunctionPath } from '@directus/utils'; import argon2 from 'argon2'; import { ArgumentNode, @@ -45,51 +45,51 @@ import { toInputObjectType, } from 'graphql-compose'; import type { Knex } from 'knex'; -import { flatten, get, mapKeys, merge, omit, pick, set, transform, uniq } from 'lodash'; -import { clearSystemCache, getCache } from '../../cache'; -import { DEFAULT_AUTH_PROVIDER, GENERATE_SPECIAL } from '../../constants'; -import getDatabase from '../../database'; -import env from '../../env'; -import { ForbiddenException, GraphQLValidationException, InvalidPayloadException } from '../../exceptions'; -import { getExtensionManager } from '../../extensions'; -import type { AbstractServiceOptions, GraphQLParams, Item } from '../../types'; -import { generateHash } from '../../utils/generate-hash'; -import { getGraphQLType } from '../../utils/get-graphql-type'; -import { getMilliseconds } from '../../utils/get-milliseconds'; -import { reduceSchema } from '../../utils/reduce-schema'; -import { sanitizeQuery } from '../../utils/sanitize-query'; -import { validateQuery } from '../../utils/validate-query'; -import { ActivityService } from '../activity'; -import { AuthenticationService } from '../authentication'; -import { CollectionsService } from '../collections'; -import { FieldsService } from '../fields'; -import { FilesService } from '../files'; -import { FlowsService } from '../flows'; -import { FoldersService } from '../folders'; -import { ItemsService } from '../items'; -import { NotificationsService } from '../notifications'; -import { OperationsService } from '../operations'; -import { PermissionsService } from '../permissions'; -import { PresetsService } from '../presets'; -import { RelationsService } from '../relations'; -import { RevisionsService } from '../revisions'; -import { RolesService } from '../roles'; -import { ServerService } from '../server'; -import { SettingsService } from '../settings'; -import { SharesService } from '../shares'; -import { SpecificationService } from '../specifications'; -import { TFAService } from '../tfa'; -import { UsersService } from '../users'; -import { UtilsService } from '../utils'; -import { WebhooksService } from '../webhooks'; -import { GraphQLBigInt } from './types/bigint'; -import { GraphQLDate } from './types/date'; -import { GraphQLGeoJSON } from './types/geojson'; -import { GraphQLHash } from './types/hash'; -import { GraphQLStringOrFloat } from './types/string-or-float'; -import { GraphQLVoid } from './types/void'; -import { addPathToValidationError } from './utils/add-path-to-validation-error'; -import processError from './utils/process-error'; +import { flatten, get, mapKeys, merge, omit, pick, set, transform, uniq } from 'lodash-es'; +import { clearSystemCache, getCache } from '../../cache.js'; +import { DEFAULT_AUTH_PROVIDER, GENERATE_SPECIAL } from '../../constants.js'; +import getDatabase from '../../database/index.js'; +import env from '../../env.js'; +import { ForbiddenException, GraphQLValidationException, InvalidPayloadException } from '../../exceptions/index.js'; +import { getExtensionManager } from '../../extensions.js'; +import type { AbstractServiceOptions, GraphQLParams, Item } from '../../types/index.js'; +import { generateHash } from '../../utils/generate-hash.js'; +import { getGraphQLType } from '../../utils/get-graphql-type.js'; +import { getMilliseconds } from '../../utils/get-milliseconds.js'; +import { reduceSchema } from '../../utils/reduce-schema.js'; +import { sanitizeQuery } from '../../utils/sanitize-query.js'; +import { validateQuery } from '../../utils/validate-query.js'; +import { ActivityService } from '../activity.js'; +import { AuthenticationService } from '../authentication.js'; +import { CollectionsService } from '../collections.js'; +import { FieldsService } from '../fields.js'; +import { FilesService } from '../files.js'; +import { FlowsService } from '../flows.js'; +import { FoldersService } from '../folders.js'; +import { ItemsService } from '../items.js'; +import { NotificationsService } from '../notifications.js'; +import { OperationsService } from '../operations.js'; +import { PermissionsService } from '../permissions.js'; +import { PresetsService } from '../presets.js'; +import { RelationsService } from '../relations.js'; +import { RevisionsService } from '../revisions.js'; +import { RolesService } from '../roles.js'; +import { ServerService } from '../server.js'; +import { SettingsService } from '../settings.js'; +import { SharesService } from '../shares.js'; +import { SpecificationService } from '../specifications.js'; +import { TFAService } from '../tfa.js'; +import { UsersService } from '../users.js'; +import { UtilsService } from '../utils.js'; +import { WebhooksService } from '../webhooks.js'; +import { GraphQLBigInt } from './types/bigint.js'; +import { GraphQLDate } from './types/date.js'; +import { GraphQLGeoJSON } from './types/geojson.js'; +import { GraphQLHash } from './types/hash.js'; +import { GraphQLStringOrFloat } from './types/string-or-float.js'; +import { GraphQLVoid } from './types/void.js'; +import { addPathToValidationError } from './utils/add-path-to-validation-error.js'; +import processError from './utils/process-error.js'; const validationRules = Array.from(specifiedRules); diff --git a/api/src/services/graphql/utils/process-error.test.ts b/api/src/services/graphql/utils/process-error.test.ts index a62fbb754a..dd8d341c0f 100644 --- a/api/src/services/graphql/utils/process-error.test.ts +++ b/api/src/services/graphql/utils/process-error.test.ts @@ -1,6 +1,6 @@ import { GraphQLError } from 'graphql'; import { describe, expect, test } from 'vitest'; -import processError from './process-error'; +import processError from './process-error.js'; describe('GraphQL processError util', () => { const sampleError = new GraphQLError('An error message', { path: ['test_collection'] }); diff --git a/api/src/services/graphql/utils/process-error.ts b/api/src/services/graphql/utils/process-error.ts index 678bd251dc..46280ab1e9 100644 --- a/api/src/services/graphql/utils/process-error.ts +++ b/api/src/services/graphql/utils/process-error.ts @@ -1,7 +1,7 @@ -import { BaseException } from '@directus/shared/exceptions'; -import type { Accountability } from '@directus/shared/types'; +import { BaseException } from '@directus/exceptions'; +import type { Accountability } from '@directus/types'; import type { GraphQLError, GraphQLFormattedError } from 'graphql'; -import logger from '../../../logger'; +import logger from '../../../logger.js'; const processError = (accountability: Accountability | null, error: Readonly): GraphQLFormattedError => { logger.error(error); diff --git a/api/src/services/import-export.test.ts b/api/src/services/import-export.test.ts deleted file mode 100644 index 145c99df21..0000000000 --- a/api/src/services/import-export.test.ts +++ /dev/null @@ -1,175 +0,0 @@ -import { parse } from 'json2csv'; -import knex, { Knex } from 'knex'; -import { createTracker, MockClient, Tracker } from 'knex-mock-client'; -import { EOL } from 'node:os'; -import { Readable } from 'stream'; -import { afterEach, beforeAll, beforeEach, describe, expect, it, MockedFunction, vi } from 'vitest'; -import { ExportService, ImportService } from '.'; -import { ServiceUnavailableException } from '..'; -import emitter from '../emitter'; - -vi.mock('../../src/database/index', () => ({ - default: vi.fn(), - getDatabaseClient: vi.fn().mockReturnValue('postgres'), -})); - -describe('Integration Tests', () => { - let db: MockedFunction; - let tracker: Tracker; - - beforeAll(async () => { - db = vi.mocked(knex({ client: MockClient })); - tracker = createTracker(db); - }); - - afterEach(() => { - tracker.reset(); - }); - - describe('Services / ImportService', () => { - let service: ImportService; - let insertedId = 1; - const collection = 'test_coll'; - - beforeEach(() => { - service = new ImportService({ - knex: db, - schema: { - collections: { - [collection]: { - collection, - primary: 'id', - singleton: false, - sortField: null, - note: null, - accountability: null, - fields: { - id: { - field: 'id', - defaultValue: null, - nullable: false, - generated: true, - type: 'integer', - dbType: 'integer', - precision: null, - scale: null, - special: [], - note: null, - validation: null, - alias: false, - }, - name: { - field: 'name', - defaultValue: null, - nullable: true, - generated: false, - type: 'string', - dbType: 'string', - precision: null, - scale: null, - special: [], - note: null, - validation: null, - alias: false, - }, - }, - }, - }, - relations: [], - }, - }); - - insertedId = 1; - }); - - describe('importJSON', () => { - it('Emits action for correct number of times', async () => { - const emitActionSpy = vi.spyOn(emitter, 'emitAction'); - const data = [{ name: 'aaa' }, { name: 'bbb' }, { name: 'ccc' }]; - const stream = new Readable({ - read() { - this.push(JSON.stringify(data)); - this.push(null); - }, - }); - tracker.on.insert(collection).response(() => [insertedId++]); - - await service.importJSON(collection, stream); - - expect(emitActionSpy).toBeCalledTimes(insertedId - 1); - }); - }); - - describe('importCSV', () => { - it('Emits action for correct number of times', async () => { - const emitActionSpy = vi.spyOn(emitter, 'emitAction'); - const data = [{ name: 'ddd' }, { name: 'eee' }, { name: 'fff' }]; - const stream = new Readable({ - read() { - this.push(parse(data)); - this.push(null); - }, - }); - tracker.on.insert(collection).response(() => [insertedId++]); - - await service.importCSV(collection, stream); - - expect(emitActionSpy).toBeCalledTimes(insertedId - 1); - }); - }); - }); - - describe('Services / ExportService', () => { - describe('transform', () => { - it('should return json string with header and footer', () => { - const input = [{ key: 'value' }]; - - const service = new ExportService({ knex: db, schema: { collections: {}, relations: [] } }); - - expect(service.transform(input, 'json')).toBe(`[\n\t{\n\t\t"key": "value"\n\t}\n]`); - }); - - it('should return xml string with header and footer', () => { - const input = [{ key: 'value' }]; - - const service = new ExportService({ knex: db, schema: { collections: {}, relations: [] } }); - - expect(service.transform(input, 'xml')).toBe( - `\n\n \n value\n \n` - ); - }); - - it('should return csv string with header', () => { - const input = [{ key: 'value' }]; - - const service = new ExportService({ knex: db, schema: { collections: {}, relations: [] } }); - - expect(service.transform(input, 'csv')).toBe(`"key"${EOL}"value"`); - }); - - it('should return csv string without header', () => { - const input = [{ key: 'value' }]; - - const service = new ExportService({ knex: db, schema: { collections: {}, relations: [] } }); - - expect(service.transform(input, 'csv', { includeHeader: false })).toBe('\n"value"'); - }); - - it('should return yaml string', () => { - const input = [{ key: 'value' }]; - - const service = new ExportService({ knex: db, schema: { collections: {}, relations: [] } }); - - expect(service.transform(input, 'yaml')).toBe('- key: value\n'); - }); - - it('should throw ServiceUnavailableException error when using a non-existent export type', () => { - const input = [{ key: 'value' }]; - - const service = new ExportService({ knex: db, schema: { collections: {}, relations: [] } }); - - expect(() => service.transform(input, 'invalid-format' as any)).toThrowError(ServiceUnavailableException); - }); - }); - }); -}); diff --git a/api/src/services/import-export.ts b/api/src/services/import-export.ts index 81c080a433..41125586ca 100644 --- a/api/src/services/import-export.ts +++ b/api/src/services/import-export.ts @@ -1,33 +1,34 @@ -import type { Accountability, Query, SchemaOverview } from '@directus/shared/types'; -import { parseJSON, toArray } from '@directus/shared/utils'; +import type { Accountability, Query, SchemaOverview } from '@directus/types'; +import { parseJSON, toArray } from '@directus/utils'; import { queue } from 'async'; import csv from 'csv-parser'; import destroyStream from 'destroy'; -import { appendFile, createReadStream } from 'fs-extra'; import { dump as toYAML } from 'js-yaml'; import { parse as toXML } from 'js2xmlparser'; import { Parser as CSVParser, transforms as CSVTransforms } from 'json2csv'; import type { Knex } from 'knex'; -import { set, transform } from 'lodash'; +import { set, transform } from 'lodash-es'; +import { createReadStream } from 'node:fs'; +import { appendFile } from 'node:fs/promises'; import type { Readable } from 'node:stream'; -import StreamArray from 'stream-json/streamers/StreamArray'; +import StreamArray from 'stream-json/streamers/StreamArray.js'; import stripBomStream from 'strip-bom-stream'; import { file as createTmpFile } from 'tmp-promise'; -import getDatabase from '../database'; -import emitter from '../emitter'; -import env from '../env'; +import getDatabase from '../database/index.js'; +import emitter from '../emitter.js'; +import env from '../env.js'; import { ForbiddenException, InvalidPayloadException, ServiceUnavailableException, UnsupportedMediaTypeException, -} from '../exceptions'; -import logger from '../logger'; -import type { AbstractServiceOptions, ActionEventParams, File } from '../types'; -import { getDateFormatted } from '../utils/get-date-formatted'; -import { FilesService } from './files'; -import { ItemsService } from './items'; -import { NotificationsService } from './notifications'; +} from '../exceptions/index.js'; +import logger from '../logger.js'; +import type { AbstractServiceOptions, ActionEventParams, File } from '../types/index.js'; +import { getDateFormatted } from '../utils/get-date-formatted.js'; +import { FilesService } from './files.js'; +import { ItemsService } from './items.js'; +import { NotificationsService } from './notifications.js'; type ExportFormat = 'csv' | 'json' | 'xml' | 'yaml'; diff --git a/api/src/services/index.ts b/api/src/services/index.ts index 1bb8115dfe..4d3c0ac48f 100644 --- a/api/src/services/index.ts +++ b/api/src/services/index.ts @@ -1,34 +1,33 @@ -// Note: "items" must kept at the top to prevent circular dependencies issues between ItemsService <-> ActivityService / RevisionsService -export * from './items'; -export * from './activity'; -export * from './assets'; -export * from './authentication'; -export * from './authorization'; -export * from './collections'; -export * from './dashboards'; -export * from './fields'; -export * from './files'; -export * from './flows'; -export * from './folders'; -export * from './graphql'; -export * from './import-export'; -export * from './mail'; -export * from './meta'; -export * from './notifications'; -export * from './operations'; -export * from './panels'; -export * from './payload'; -export * from './permissions'; -export * from './presets'; -export * from './relations'; -export * from './revisions'; -export * from './roles'; -export * from './schema'; -export * from './server'; -export * from './settings'; -export * from './specifications'; -export * from './tfa'; -export * from './users'; -export * from './utils'; -export * from './webhooks'; -export * from './shares'; +export * from './activity.js'; +export * from './assets.js'; +export * from './authentication.js'; +export * from './authorization.js'; +export * from './collections.js'; +export * from './dashboards.js'; +export * from './fields.js'; +export * from './files.js'; +export * from './flows.js'; +export * from './folders.js'; +export * from './graphql/index.js'; +export * from './import-export.js'; +export * from './items.js'; +export * from './mail/index.js'; +export * from './meta.js'; +export * from './notifications.js'; +export * from './operations.js'; +export * from './panels.js'; +export * from './payload.js'; +export * from './permissions.js'; +export * from './presets.js'; +export * from './relations.js'; +export * from './revisions.js'; +export * from './roles.js'; +export * from './schema.js'; +export * from './server.js'; +export * from './settings.js'; +export * from './shares.js'; +export * from './specifications.js'; +export * from './tfa.js'; +export * from './users.js'; +export * from './utils.js'; +export * from './webhooks.js'; diff --git a/api/src/services/items.test.ts b/api/src/services/items.test.ts index a744605fd4..4699a23ac7 100644 --- a/api/src/services/items.test.ts +++ b/api/src/services/items.test.ts @@ -1,13 +1,14 @@ -import type { NestedDeepQuery } from '@directus/shared/types'; -import knex, { Knex } from 'knex'; +import type { NestedDeepQuery } from '@directus/types'; +import knex from 'knex'; +import type { Knex } from 'knex'; import { createTracker, MockClient, Tracker } from 'knex-mock-client'; -import { cloneDeep } from 'lodash'; +import { cloneDeep } from 'lodash-es'; import { afterEach, beforeAll, beforeEach, describe, expect, it, MockedFunction, vi } from 'vitest'; -import { getDatabaseClient } from '../../src/database/index'; -import { ItemsService } from '../../src/services'; -import { InvalidPayloadException } from '../exceptions'; -import { sqlFieldFormatter, sqlFieldList } from '../__utils__/items-utils'; -import { systemSchema, userSchema } from '../__utils__/schemas'; +import { getDatabaseClient } from '../../src/database/index.js'; +import { ItemsService } from '../../src/services/index.js'; +import { InvalidPayloadException } from '../exceptions/index.js'; +import { sqlFieldFormatter, sqlFieldList } from '../__utils__/items-utils.js'; +import { systemSchema, userSchema } from '../__utils__/schemas.js'; vi.mock('../env', async () => { const actual = (await vi.importActual('../env')) as { default: Record }; @@ -47,7 +48,7 @@ describe('Integration Tests', () => { }; beforeAll(() => { - db = vi.mocked(knex({ client: MockClient })); + db = vi.mocked(knex.default({ client: MockClient })); tracker = createTracker(db); }); diff --git a/api/src/services/items.ts b/api/src/services/items.ts index 307763c7e6..b0cfe75bef 100644 --- a/api/src/services/items.ts +++ b/api/src/services/items.ts @@ -1,15 +1,15 @@ -import { Accountability, Action, PermissionsAction, Query, SchemaOverview } from '@directus/shared/types'; +import { Accountability, Action, PermissionsAction, Query, SchemaOverview } from '@directus/types'; import type Keyv from 'keyv'; import type { Knex } from 'knex'; -import { assign, clone, cloneDeep, omit, pick, without } from 'lodash'; -import { getCache } from '../cache'; -import getDatabase from '../database'; -import { getHelpers } from '../database/helpers'; -import runAST from '../database/run-ast'; -import emitter from '../emitter'; -import env from '../env'; -import { ForbiddenException, InvalidPayloadException } from '../exceptions'; -import { translateDatabaseError } from '../exceptions/database/translate'; +import { assign, clone, cloneDeep, omit, pick, without } from 'lodash-es'; +import { getCache } from '../cache.js'; +import { getHelpers } from '../database/helpers/index.js'; +import getDatabase from '../database/index.js'; +import runAST from '../database/run-ast.js'; +import emitter from '../emitter.js'; +import env from '../env.js'; +import { translateDatabaseError } from '../exceptions/database/translate.js'; +import { ForbiddenException, InvalidPayloadException } from '../exceptions/index.js'; import type { AbstractService, AbstractServiceOptions, @@ -17,12 +17,11 @@ import type { Item as AnyItem, MutationOptions, PrimaryKey, -} from '../types'; -import getASTFromQuery from '../utils/get-ast-from-query'; -import { validateKeys } from '../utils/validate-keys'; -import { AuthorizationService } from './authorization'; -import { ActivityService, RevisionsService } from './index'; -import { PayloadService } from './payload'; +} from '../types/index.js'; +import getASTFromQuery from '../utils/get-ast-from-query.js'; +import { validateKeys } from '../utils/validate-keys.js'; +import { AuthorizationService } from './authorization.js'; +import { PayloadService } from './payload.js'; export type QueryOptions = { stripNonRequested?: boolean; @@ -70,6 +69,9 @@ export class ItemsService implements AbstractSer * Create a single new item. */ async createOne(data: Partial, opts?: MutationOptions): Promise { + const { ActivityService } = await import('./activity.js'); + const { RevisionsService } = await import('./revisions.js'); + const primaryKeyField = this.schema.collections[this.collection]!.primary; const fields = Object.keys(this.schema.collections[this.collection]!.fields); const aliases = Object.values(this.schema.collections[this.collection]!.fields) @@ -118,7 +120,7 @@ export class ItemsService implements AbstractSer : payload; const payloadWithPresets = this.accountability - ? await authorizationService.validatePayload('create', this.collection, payloadAfterHooks) + ? authorizationService.validatePayload('create', this.collection, payloadAfterHooks) : payloadAfterHooks; if (opts?.preMutationException) { @@ -503,6 +505,9 @@ export class ItemsService implements AbstractSer * Update many items by primary key, setting all items to the same change */ async updateMany(keys: PrimaryKey[], data: Partial, opts?: MutationOptions): Promise { + const { ActivityService } = await import('./activity.js'); + const { RevisionsService } = await import('./revisions.js'); + const primaryKeyField = this.schema.collections[this.collection]!.primary; validateKeys(this.schema, this.collection, primaryKeyField, keys); @@ -549,7 +554,7 @@ export class ItemsService implements AbstractSer } const payloadWithPresets = this.accountability - ? await authorizationService.validatePayload('update', this.collection, payloadAfterHooks) + ? authorizationService.validatePayload('update', this.collection, payloadAfterHooks) : payloadAfterHooks; if (opts?.preMutationException) { @@ -789,6 +794,8 @@ export class ItemsService implements AbstractSer * Delete multiple items by primary key */ async deleteMany(keys: PrimaryKey[], opts?: MutationOptions): Promise { + const { ActivityService } = await import('./activity.js'); + const primaryKeyField = this.schema.collections[this.collection]!.primary; validateKeys(this.schema, this.collection, primaryKeyField, keys); diff --git a/api/src/services/mail/index.ts b/api/src/services/mail/index.ts index ad603bdaf4..3db35fb088 100644 --- a/api/src/services/mail/index.ts +++ b/api/src/services/mail/index.ts @@ -1,16 +1,19 @@ -import type { Accountability, SchemaOverview } from '@directus/shared/types'; +import type { Accountability, SchemaOverview } from '@directus/types'; import fse from 'fs-extra'; import type { Knex } from 'knex'; import { Liquid } from 'liquidjs'; import type { SendMailOptions, Transporter } from 'nodemailer'; import path from 'path'; -import getDatabase from '../../database'; -import env from '../../env'; -import { InvalidPayloadException } from '../../exceptions'; -import logger from '../../logger'; -import getMailer from '../../mailer'; -import type { AbstractServiceOptions } from '../../types'; -import { Url } from '../../utils/url'; +import getDatabase from '../../database/index.js'; +import env from '../../env.js'; +import { InvalidPayloadException } from '../../exceptions/index.js'; +import logger from '../../logger.js'; +import getMailer from '../../mailer.js'; +import type { AbstractServiceOptions } from '../../types/index.js'; +import { Url } from '../../utils/url.js'; +import { fileURLToPath } from 'url'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); const liquidEngine = new Liquid({ root: [path.resolve(env['EXTENSIONS_PATH'], 'templates'), path.resolve(__dirname, 'templates')], diff --git a/api/src/services/meta.ts b/api/src/services/meta.ts index 47948296e2..c2ce34771f 100644 --- a/api/src/services/meta.ts +++ b/api/src/services/meta.ts @@ -1,9 +1,9 @@ -import type { Accountability, Query, SchemaOverview } from '@directus/shared/types'; +import type { Accountability, Query, SchemaOverview } from '@directus/types'; import type { Knex } from 'knex'; -import getDatabase from '../database'; -import { ForbiddenException } from '../exceptions'; -import type { AbstractServiceOptions } from '../types'; -import { applyFilter, applySearch } from '../utils/apply-query'; +import getDatabase from '../database/index.js'; +import { ForbiddenException } from '../exceptions/index.js'; +import type { AbstractServiceOptions } from '../types/index.js'; +import { applyFilter, applySearch } from '../utils/apply-query.js'; export class MetaService { knex: Knex; diff --git a/api/src/services/notifications.test.ts b/api/src/services/notifications.test.ts deleted file mode 100644 index 3617adaf76..0000000000 --- a/api/src/services/notifications.test.ts +++ /dev/null @@ -1,224 +0,0 @@ -import { afterEach, beforeEach, describe, expect, it, SpyInstance, vi } from 'vitest'; -import { ItemsService, NotificationsService } from '.'; - -vi.mock('../env', async () => { - const actual = (await vi.importActual('../env')) as { default: Record }; - const MOCK_ENV = { - ...actual.default, - PUBLIC_URL: '/', - }; - return { - default: MOCK_ENV, - getEnv: () => MOCK_ENV, - }; -}); - -vi.mock('../../src/database/index', () => ({ - default: vi.fn(), - getDatabaseClient: vi.fn().mockReturnValue('postgres'), -})); - -describe('Integration Tests', () => { - describe('Services / Notifications', () => { - let service: NotificationsService; - - beforeEach(() => { - service = new NotificationsService({ - schema: { collections: {}, relations: [] }, - }); - }); - - afterEach(() => { - vi.restoreAllMocks(); - }); - - describe('createOne', () => { - let superCreateOneSpy: SpyInstance; - let thisSendEmailSpy: SpyInstance; - - beforeEach(() => { - superCreateOneSpy = vi.spyOn(ItemsService.prototype, 'createOne').mockResolvedValue(0); - thisSendEmailSpy = vi.spyOn(NotificationsService.prototype, 'sendEmail').mockResolvedValue(); - }); - - it('create a notification and send email', async () => { - const data = { - recipient: '5aa7ffb5-bd54-46ab-8654-6dfead39694d', - sender: null, - subject: 'Notification Subject', - message: 'Notification Message', - }; - await service.createOne(data); - - expect(superCreateOneSpy).toHaveBeenCalled(); - expect(superCreateOneSpy).toBeCalledWith(data, undefined); - expect(thisSendEmailSpy).toHaveBeenCalled(); - expect(thisSendEmailSpy).toBeCalledWith(data); - }); - }); - - describe('createMany', () => { - let superCreateManySpy: SpyInstance; - let thisSendEmailSpy: SpyInstance; - - beforeEach(() => { - superCreateManySpy = vi.spyOn(ItemsService.prototype, 'createMany').mockResolvedValue([]); - thisSendEmailSpy = vi.spyOn(NotificationsService.prototype, 'sendEmail').mockResolvedValue(); - }); - - it('create many notifications and send email for notification', async () => { - const data = [ - { - recipient: '5aa7ffb5-bd54-46ab-8654-6dfead39694d', - sender: null, - subject: 'Notification Subject', - message: 'Notification Message', - }, - { - recipient: '51260c36-e944-4b0a-a370-dc83070d9d2b', - sender: null, - subject: 'Notification Subject', - message: 'Notification Message', - }, - ]; - await service.createMany(data); - - expect(superCreateManySpy).toBeCalledTimes(1); - expect(superCreateManySpy).toBeCalledWith(data, undefined); - expect(thisSendEmailSpy).toBeCalledTimes(data.length); - }); - }); - - describe('sendEmail', () => { - let usersServiceReadOneSpy: SpyInstance; - let mailServiceSendSpy: SpyInstance; - - beforeEach(() => { - usersServiceReadOneSpy = vi.spyOn(service.usersService, 'readOne').mockResolvedValue({}); - mailServiceSendSpy = vi.spyOn(service.mailService, 'send').mockResolvedValue(0); - }); - - it('do nothing when there is no recipient', async () => { - await service.sendEmail({ - sender: null, - subject: 'Notification Subject', - message: 'Notification Message', - }); - - expect(usersServiceReadOneSpy).not.toHaveBeenCalled(); - }); - - it('read recipient detail from userService when there is recipient', async () => { - usersServiceReadOneSpy.mockReturnValue(Promise.resolve({ id: '5aa7ffb5-bd54-46ab-8654-6dfead39694d' })); - - await service.sendEmail({ - recipient: '5aa7ffb5-bd54-46ab-8654-6dfead39694d', - sender: null, - subject: 'Notification Subject', - message: 'Notification Message', - }); - - expect(usersServiceReadOneSpy).toHaveBeenCalled(); - }); - - it('do not send email when user does not have email', async () => { - usersServiceReadOneSpy.mockReturnValue(Promise.resolve({ id: '5aa7ffb5-bd54-46ab-8654-6dfead39694d' })); - - await service.sendEmail({ - recipient: '5aa7ffb5-bd54-46ab-8654-6dfead39694d', - sender: null, - subject: 'Notification Subject', - message: 'Notification Message', - }); - - expect(usersServiceReadOneSpy).toHaveBeenCalled(); - expect(mailServiceSendSpy).not.toHaveBeenCalled(); - }); - - it('do not send email when user have email but disabled email notification', async () => { - usersServiceReadOneSpy.mockReturnValue( - Promise.resolve({ - id: '5aa7ffb5-bd54-46ab-8654-6dfead39694d', - email: 'user@example.com', - email_notifications: false, - }) - ); - - await service.sendEmail({ - recipient: '5aa7ffb5-bd54-46ab-8654-6dfead39694d', - sender: null, - subject: 'Notification Subject', - message: 'Notification Message', - }); - - expect(usersServiceReadOneSpy).toHaveBeenCalled(); - expect(mailServiceSendSpy).not.toHaveBeenCalled(); - }); - - it('send email without url when user role does not have app access', async () => { - const userDetail = { - id: '5aa7ffb5-bd54-46ab-8654-6dfead39694d', - email: 'user@example.com', - email_notifications: true, - role: { - app_access: false, - }, - }; - usersServiceReadOneSpy.mockReturnValue(Promise.resolve(userDetail)); - - const notificationDetail = { - recipient: '5aa7ffb5-bd54-46ab-8654-6dfead39694d', - sender: null, - subject: 'Notification Subject', - message: 'Notification Message', - }; - await service.sendEmail(notificationDetail); - - expect(usersServiceReadOneSpy).toHaveBeenCalled(); - expect(mailServiceSendSpy).toHaveBeenCalled(); - expect(mailServiceSendSpy).toHaveBeenCalledWith({ - template: { - name: 'base', - data: { html: `

${notificationDetail.message}

\n` }, - }, - to: userDetail.email, - subject: notificationDetail.subject, - }); - }); - - it('send email with url when user role have app access', async () => { - const userDetail = { - id: '5aa7ffb5-bd54-46ab-8654-6dfead39694d', - email: 'user@example.com', - email_notifications: true, - role: { - app_access: true, - }, - }; - usersServiceReadOneSpy.mockReturnValue(Promise.resolve(userDetail)); - - const notificationDetail = { - recipient: '5aa7ffb5-bd54-46ab-8654-6dfead39694d', - sender: null, - subject: 'Notification Subject', - message: 'Notification Message', - }; - await service.sendEmail(notificationDetail); - - expect(usersServiceReadOneSpy).toHaveBeenCalled(); - expect(mailServiceSendSpy).toHaveBeenCalled(); - expect(mailServiceSendSpy).toHaveBeenCalledWith({ - template: { - name: 'base', - data: { - url: `/admin/users/${userDetail.id}`, - html: `

${notificationDetail.message}

\n`, - }, - }, - to: userDetail.email, - subject: notificationDetail.subject, - }); - }); - }); - }); -}); diff --git a/api/src/services/notifications.ts b/api/src/services/notifications.ts index b057a6b1d5..cbd1a7f9dc 100644 --- a/api/src/services/notifications.ts +++ b/api/src/services/notifications.ts @@ -1,12 +1,12 @@ -import type { Notification } from '@directus/shared/types'; -import env from '../env'; -import logger from '../logger'; -import type { AbstractServiceOptions, MutationOptions, PrimaryKey } from '../types'; -import { md } from '../utils/md'; -import { Url } from '../utils/url'; -import { ItemsService } from './items'; -import { MailService } from './mail'; -import { UsersService } from './users'; +import type { Notification } from '@directus/types'; +import env from '../env.js'; +import logger from '../logger.js'; +import type { AbstractServiceOptions, MutationOptions, PrimaryKey } from '../types/index.js'; +import { md } from '../utils/md.js'; +import { Url } from '../utils/url.js'; +import { ItemsService } from './items.js'; +import { MailService } from './mail/index.js'; +import { UsersService } from './users.js'; export class NotificationsService extends ItemsService { usersService: UsersService; diff --git a/api/src/services/operations.test.ts b/api/src/services/operations.test.ts deleted file mode 100644 index 9be235eae2..0000000000 --- a/api/src/services/operations.test.ts +++ /dev/null @@ -1,125 +0,0 @@ -import knex, { Knex } from 'knex'; -import { createTracker, MockClient, Tracker } from 'knex-mock-client'; -import { afterEach, beforeAll, beforeEach, describe, expect, it, SpyInstance, vi } from 'vitest'; -import { OperationsService } from '.'; -import { getFlowManager } from '../flows'; - -vi.mock('../../src/database/index', () => { - return { __esModule: true, default: vi.fn(), getDatabaseClient: vi.fn().mockReturnValue('postgres') }; -}); - -vi.mock('../flows', () => { - return { getFlowManager: vi.fn().mockReturnValue({ reload: vi.fn() }) }; -}); - -describe('Integration Tests', () => { - let db: Knex; - let tracker: Tracker; - - beforeAll(async () => { - db = knex({ client: MockClient }); - tracker = createTracker(db); - }); - - beforeEach(() => { - tracker.on.any('directus_operations').response({}); - }); - - afterEach(() => { - tracker.reset(); - }); - - describe('Services / Operations', () => { - let service: OperationsService; - let flowManagerReloadSpy: SpyInstance; - - beforeEach(() => { - service = new OperationsService({ - knex: db, - schema: { - collections: { - directus_operations: { - collection: 'directus_operations', - primary: 'id', - singleton: false, - sortField: null, - note: null, - accountability: null, - fields: { - id: { - field: 'id', - defaultValue: null, - nullable: false, - generated: true, - type: 'integer', - dbType: 'integer', - precision: null, - scale: null, - special: [], - note: null, - validation: null, - alias: false, - }, - }, - }, - }, - relations: [], - }, - }); - flowManagerReloadSpy = vi.spyOn(getFlowManager(), 'reload'); - }); - - afterEach(() => { - flowManagerReloadSpy.mockClear(); - }); - - describe('createOne', () => { - it('should reload flows once', async () => { - await service.createOne({}); - expect(flowManagerReloadSpy).toBeCalledTimes(1); - }); - }); - - describe('createMany', () => { - it('should reload flows once', async () => { - await service.createMany([{}]); - expect(flowManagerReloadSpy).toBeCalledTimes(1); - }); - }); - - describe('updateOne', () => { - it('should reload flows once', async () => { - await service.updateOne(1, {}); - expect(flowManagerReloadSpy).toBeCalledTimes(1); - }); - }); - - describe('updateBatch', () => { - it('should reload flows once', async () => { - await service.updateBatch([{ id: 1 }]); - expect(flowManagerReloadSpy).toBeCalledTimes(1); - }); - }); - - describe('updateMany', () => { - it('should reload flows once', async () => { - await service.updateMany([1], {}); - expect(flowManagerReloadSpy).toBeCalledTimes(1); - }); - }); - - describe('deleteOne', () => { - it('should reload flows once', async () => { - await service.deleteOne(1); - expect(flowManagerReloadSpy).toBeCalledTimes(1); - }); - }); - - describe('deleteMany', () => { - it('should reload flows once', async () => { - await service.deleteMany([1]); - expect(flowManagerReloadSpy).toBeCalledTimes(1); - }); - }); - }); -}); diff --git a/api/src/services/operations.ts b/api/src/services/operations.ts index 097ef2ca9b..48a2906d0d 100644 --- a/api/src/services/operations.ts +++ b/api/src/services/operations.ts @@ -1,7 +1,7 @@ -import type { OperationRaw } from '@directus/shared/types'; -import { getFlowManager } from '../flows'; -import type { AbstractServiceOptions, Item, MutationOptions, PrimaryKey } from '../types'; -import { ItemsService } from './items'; +import type { OperationRaw } from '@directus/types'; +import { getFlowManager } from '../flows.js'; +import type { AbstractServiceOptions, Item, MutationOptions, PrimaryKey } from '../types/index.js'; +import { ItemsService } from './items.js'; export class OperationsService extends ItemsService { constructor(options: AbstractServiceOptions) { diff --git a/api/src/services/panels.ts b/api/src/services/panels.ts index da9cca9f4b..9b113c2f66 100644 --- a/api/src/services/panels.ts +++ b/api/src/services/panels.ts @@ -1,5 +1,5 @@ -import type { AbstractServiceOptions } from '../types'; -import { ItemsService } from './items'; +import type { AbstractServiceOptions } from '../types/index.js'; +import { ItemsService } from './items.js'; export class PanelsService extends ItemsService { constructor(options: AbstractServiceOptions) { diff --git a/api/src/services/payload.test.ts b/api/src/services/payload.test.ts index b13fe93548..3494f9358d 100644 --- a/api/src/services/payload.test.ts +++ b/api/src/services/payload.test.ts @@ -1,7 +1,8 @@ -import knex, { Knex } from 'knex'; +import knex from 'knex'; +import type { Knex } from 'knex'; import { MockClient, Tracker, createTracker } from 'knex-mock-client'; -import { PayloadService } from '../../src/services'; -import { getHelpers, Helpers } from '../../src/database/helpers'; +import { PayloadService } from '../../src/services/index.js'; +import { getHelpers, Helpers } from '../../src/database/helpers/index.js'; import { describe, beforeAll, afterEach, it, expect, vi, beforeEach, MockedFunction } from 'vitest'; vi.mock('../../src/database/index', () => ({ @@ -13,7 +14,7 @@ describe('Integration Tests', () => { let tracker: Tracker; beforeAll(async () => { - db = vi.mocked(knex({ client: MockClient })); + db = vi.mocked(knex.default({ client: MockClient })); tracker = createTracker(db); }); diff --git a/api/src/services/payload.ts b/api/src/services/payload.ts index 50c96bb3de..5bb01485ba 100644 --- a/api/src/services/payload.ts +++ b/api/src/services/payload.ts @@ -1,15 +1,15 @@ -import type { Accountability, Query, SchemaOverview } from '@directus/shared/types'; +import type { Accountability, Query, SchemaOverview } from '@directus/types'; import { format, parseISO, isValid } from 'date-fns'; -import { parseJSON, toArray } from '@directus/shared/utils'; -import { unflatten } from 'flat'; +import { parseJSON, toArray } from '@directus/utils'; +import flat from 'flat'; import Joi from 'joi'; import type { Knex } from 'knex'; -import { clone, cloneDeep, isNil, isObject, isPlainObject, omit, pick } from 'lodash'; +import { clone, cloneDeep, isNil, isObject, isPlainObject, omit, pick } from 'lodash-es'; import { v4 as uuid } from 'uuid'; import { parse as wktToGeoJSON } from 'wellknown'; -import getDatabase from '../database'; -import { getHelpers, Helpers } from '../database/helpers'; -import { ForbiddenException, InvalidPayloadException } from '../exceptions'; +import getDatabase from '../database/index.js'; +import { getHelpers, Helpers } from '../database/helpers/index.js'; +import { ForbiddenException, InvalidPayloadException } from '../exceptions/index.js'; import type { AbstractServiceOptions, ActionEventParams, @@ -17,9 +17,9 @@ import type { Item, MutationOptions, PrimaryKey, -} from '../types'; -import { generateHash } from '../utils/generate-hash'; -import { ItemsService } from './items'; +} from '../types/index.js'; +import { generateHash } from '../utils/generate-hash.js'; +import { ItemsService } from './items.js'; type Action = 'create' | 'read' | 'update'; @@ -207,7 +207,7 @@ export class PayloadService { const aggregateKeys = Object.keys(payload[0]!).filter((key) => key.includes('->')); if (aggregateKeys.length) { for (const item of payload) { - Object.assign(item, unflatten(pick(item, aggregateKeys), { delimiter: '->' })); + Object.assign(item, flat.unflatten(pick(item, aggregateKeys), { delimiter: '->' })); aggregateKeys.forEach((key) => delete item[key]); } } diff --git a/api/src/services/permissions.test.ts b/api/src/services/permissions.test.ts deleted file mode 100644 index adf137a001..0000000000 --- a/api/src/services/permissions.test.ts +++ /dev/null @@ -1,158 +0,0 @@ -import knex, { Knex } from 'knex'; -import { createTracker, MockClient, Tracker } from 'knex-mock-client'; -import { afterEach, beforeAll, beforeEach, describe, expect, it, SpyInstance, vi } from 'vitest'; -import { ItemsService, PermissionsService } from '.'; -import * as cache from '../cache'; - -vi.mock('../../src/database/index', () => { - return { __esModule: true, default: vi.fn(), getDatabaseClient: vi.fn().mockReturnValue('postgres') }; -}); - -describe('Integration Tests', () => { - let db: Knex; - let tracker: Tracker; - - beforeAll(async () => { - db = knex({ client: MockClient }); - tracker = createTracker(db); - }); - - beforeEach(() => { - tracker.on.any('directus_permissions').response({}); - tracker.on - .select( - /"directus_permissions"."id" from "directus_permissions" order by "directus_permissions"."id" asc limit .*/ - ) - .response([]); - }); - - afterEach(() => { - tracker.reset(); - }); - - describe('Services / Permissions', () => { - let service: PermissionsService; - let clearSystemCacheSpy: SpyInstance; - - beforeEach(() => { - service = new PermissionsService({ - knex: db, - schema: { - collections: { - directus_permissions: { - collection: 'directus_permissions', - primary: 'id', - singleton: false, - sortField: null, - note: null, - accountability: null, - fields: { - id: { - field: 'id', - defaultValue: null, - nullable: false, - generated: true, - type: 'integer', - dbType: 'integer', - precision: null, - scale: null, - special: [], - note: null, - validation: null, - alias: false, - }, - }, - }, - }, - relations: [], - }, - }); - clearSystemCacheSpy = vi.spyOn(cache, 'clearSystemCache').mockResolvedValue(); - }); - - afterEach(() => { - clearSystemCacheSpy.mockClear(); - }); - - describe('createOne', () => { - it('should clearSystemCache once', async () => { - await service.createOne({}); - expect(clearSystemCacheSpy).toBeCalledTimes(1); - }); - }); - - describe('createMany', () => { - it('should clearSystemCache once', async () => { - await service.createMany([{}]); - expect(clearSystemCacheSpy).toBeCalledTimes(1); - }); - }); - - describe('updateOne', () => { - it('should clearSystemCache once', async () => { - await service.updateOne(1, {}); - expect(clearSystemCacheSpy).toBeCalledTimes(1); - }); - }); - - describe('updateMany', () => { - it('should clearSystemCache once', async () => { - await service.updateMany([1], {}); - expect(clearSystemCacheSpy).toBeCalledTimes(1); - }); - }); - - describe('updateBatch', () => { - it('should clearSystemCache once', async () => { - await service.updateBatch([{ id: 1 }]); - expect(clearSystemCacheSpy).toBeCalledTimes(1); - }); - }); - - describe('updateByQuery', () => { - it('should clearSystemCache once', async () => { - // mock return value for following empty query - vi.spyOn(ItemsService.prototype, 'getKeysByQuery').mockResolvedValue([1]); - await service.updateByQuery({}, {}); - expect(clearSystemCacheSpy).toBeCalledTimes(1); - }); - }); - - describe('upsertOne', () => { - it('should clearSystemCache once', async () => { - await service.upsertOne({}); - expect(clearSystemCacheSpy).toBeCalledTimes(1); - }); - }); - - describe('upsertMany', () => { - it('should clearSystemCache once', async () => { - await service.upsertMany([{ id: 1 }]); - expect(clearSystemCacheSpy).toBeCalledTimes(1); - }); - }); - - describe('deleteOne', () => { - it('should clearSystemCache once', async () => { - await service.deleteOne(1); - expect(clearSystemCacheSpy).toBeCalledTimes(1); - }); - }); - - describe('deleteMany', () => { - it('should clearSystemCache once', async () => { - await service.deleteMany([1]); - expect(clearSystemCacheSpy).toBeCalledTimes(1); - }); - }); - - describe('deleteByQuery', () => { - it('should clearSystemCache once', async () => { - // mock return value for following empty query - vi.spyOn(ItemsService.prototype, 'getKeysByQuery').mockResolvedValue([1]); - await service.deleteByQuery({}); - expect(clearSystemCacheSpy).toBeCalledTimes(1); - }); - }); - }); -}); diff --git a/api/src/services/permissions.ts b/api/src/services/permissions.ts index 0fec4e72f9..edaa1617b6 100644 --- a/api/src/services/permissions.ts +++ b/api/src/services/permissions.ts @@ -1,10 +1,10 @@ -import type { PermissionsAction, Query } from '@directus/shared/types'; +import type { PermissionsAction, Query } from '@directus/types'; import type Keyv from 'keyv'; -import { clearSystemCache, getCache } from '../cache'; -import { appAccessMinimalPermissions } from '../database/system-data/app-access-permissions'; -import { ItemsService, QueryOptions } from '../services/items'; -import type { AbstractServiceOptions, Item, MutationOptions, PrimaryKey } from '../types'; -import { filterItems } from '../utils/filter-items'; +import { clearSystemCache, getCache } from '../cache.js'; +import { appAccessMinimalPermissions } from '../database/system-data/app-access-permissions/index.js'; +import { ItemsService, QueryOptions } from '../services/items.js'; +import type { AbstractServiceOptions, Item, MutationOptions, PrimaryKey } from '../types/index.js'; +import { filterItems } from '../utils/filter-items.js'; export class PermissionsService extends ItemsService { systemCache: Keyv; diff --git a/api/src/services/presets.ts b/api/src/services/presets.ts index 57db95b6a3..dd3aee0f13 100644 --- a/api/src/services/presets.ts +++ b/api/src/services/presets.ts @@ -1,5 +1,5 @@ -import type { AbstractServiceOptions } from '../types'; -import { ItemsService } from './items'; +import type { AbstractServiceOptions } from '../types/index.js'; +import { ItemsService } from './items.js'; export class PresetsService extends ItemsService { constructor(options: AbstractServiceOptions) { diff --git a/api/src/services/relations.ts b/api/src/services/relations.ts index 3993753dcc..df62e7b067 100644 --- a/api/src/services/relations.ts +++ b/api/src/services/relations.ts @@ -1,25 +1,25 @@ -import SchemaInspector from '@directus/schema'; -import type { Accountability, Query, Relation, RelationMeta, SchemaOverview } from '@directus/shared/types'; -import { toArray } from '@directus/shared/utils'; +import { createInspector } from '@directus/schema'; +import type { Accountability, Query, Relation, RelationMeta, SchemaOverview } from '@directus/types'; +import { toArray } from '@directus/utils'; import type Keyv from 'keyv'; import type { Knex } from 'knex'; -import type { ForeignKey } from 'knex-schema-inspector/dist/types/foreign-key'; -import { clearSystemCache, getCache } from '../cache'; -import getDatabase, { getSchemaInspector } from '../database'; -import { getHelpers, Helpers } from '../database/helpers'; -import { systemRelationRows } from '../database/system-data/relations'; -import emitter from '../emitter'; -import { ForbiddenException, InvalidPayloadException } from '../exceptions'; -import type { AbstractServiceOptions, ActionEventParams, MutationOptions } from '../types'; -import { getDefaultIndexName } from '../utils/get-default-index-name'; -import { getSchema } from '../utils/get-schema'; -import { ItemsService, QueryOptions } from './items'; -import { PermissionsService } from './permissions'; +import type { ForeignKey, SchemaInspector } from '@directus/schema'; +import { clearSystemCache, getCache } from '../cache.js'; +import getDatabase, { getSchemaInspector } from '../database/index.js'; +import { getHelpers, Helpers } from '../database/helpers/index.js'; +import { systemRelationRows } from '../database/system-data/relations/index.js'; +import emitter from '../emitter.js'; +import { ForbiddenException, InvalidPayloadException } from '../exceptions/index.js'; +import type { AbstractServiceOptions, ActionEventParams, MutationOptions } from '../types/index.js'; +import { getDefaultIndexName } from '../utils/get-default-index-name.js'; +import { getSchema } from '../utils/get-schema.js'; +import { ItemsService, QueryOptions } from './items.js'; +import { PermissionsService } from './permissions.js'; export class RelationsService { knex: Knex; permissionsService: PermissionsService; - schemaInspector: ReturnType; + schemaInspector: SchemaInspector; accountability: Accountability | null; schema: SchemaOverview; relationsItemService: ItemsService; @@ -29,7 +29,7 @@ export class RelationsService { constructor(options: AbstractServiceOptions) { this.knex = options.knex || getDatabase(); this.permissionsService = new PermissionsService(options); - this.schemaInspector = options.knex ? SchemaInspector(options.knex) : getSchemaInspector(); + this.schemaInspector = options.knex ? createInspector(options.knex) : getSchemaInspector(); this.schema = options.schema; this.accountability = options.accountability || null; this.relationsItemService = new ItemsService('directus_relations', { diff --git a/api/src/services/revisions.ts b/api/src/services/revisions.ts index fbdbaaea1c..198f5ca014 100644 --- a/api/src/services/revisions.ts +++ b/api/src/services/revisions.ts @@ -1,6 +1,6 @@ -import { ForbiddenException, InvalidPayloadException } from '../exceptions'; -import type { AbstractServiceOptions, PrimaryKey } from '../types'; -import { ItemsService } from './index'; +import { ForbiddenException, InvalidPayloadException } from '../exceptions/index.js'; +import type { AbstractServiceOptions, PrimaryKey } from '../types/index.js'; +import { ItemsService } from './items.js'; export class RevisionsService extends ItemsService { constructor(options: AbstractServiceOptions) { diff --git a/api/src/services/roles.test.ts b/api/src/services/roles.test.ts index 3826335858..7eaab1d5dc 100644 --- a/api/src/services/roles.test.ts +++ b/api/src/services/roles.test.ts @@ -1,9 +1,10 @@ -import type { SchemaOverview } from '@directus/shared/types'; -import knex, { Knex } from 'knex'; +import type { SchemaOverview } from '@directus/types'; +import knex from 'knex'; +import type { Knex } from 'knex'; import { createTracker, MockClient, Tracker } from 'knex-mock-client'; import { afterEach, beforeAll, beforeEach, describe, expect, it, MockedFunction, SpyInstance, vi } from 'vitest'; -import { ItemsService, PermissionsService, PresetsService, RolesService, UsersService } from '.'; -import { ForbiddenException, UnprocessableEntityException } from '../exceptions'; +import { ItemsService, PermissionsService, PresetsService, RolesService, UsersService } from './index.js'; +import { ForbiddenException, UnprocessableEntityException } from '../exceptions/index.js'; vi.mock('../../src/database/index', () => { return { __esModule: true, default: vi.fn(), getDatabaseClient: vi.fn().mockReturnValue('postgres') }; @@ -44,7 +45,7 @@ describe('Integration Tests', () => { let tracker: Tracker; beforeAll(async () => { - db = vi.mocked(knex({ client: MockClient })); + db = vi.mocked(knex.default({ client: MockClient })); tracker = createTracker(db); }); diff --git a/api/src/services/roles.ts b/api/src/services/roles.ts index b39aa8bb9b..429b4e9ecf 100644 --- a/api/src/services/roles.ts +++ b/api/src/services/roles.ts @@ -1,10 +1,10 @@ -import type { Query } from '@directus/shared/types'; -import { ForbiddenException, UnprocessableEntityException } from '../exceptions'; -import type { AbstractServiceOptions, Alterations, Item, MutationOptions, PrimaryKey } from '../types'; -import { ItemsService } from './items'; -import { PermissionsService } from './permissions'; -import { PresetsService } from './presets'; -import { UsersService } from './users'; +import type { Query } from '@directus/types'; +import { ForbiddenException, UnprocessableEntityException } from '../exceptions/index.js'; +import type { AbstractServiceOptions, Alterations, Item, MutationOptions, PrimaryKey } from '../types/index.js'; +import { ItemsService } from './items.js'; +import { PermissionsService } from './permissions.js'; +import { PresetsService } from './presets.js'; +import { UsersService } from './users.js'; export class RolesService extends ItemsService { constructor(options: AbstractServiceOptions) { diff --git a/api/src/services/schema.test.ts b/api/src/services/schema.test.ts index 03158b44e5..a33f3f7871 100644 --- a/api/src/services/schema.test.ts +++ b/api/src/services/schema.test.ts @@ -1,25 +1,26 @@ import type { Diff } from 'deep-diff'; -import knex, { Knex } from 'knex'; +import knex from 'knex'; +import type { Knex } from 'knex'; import { createTracker, MockClient, Tracker } from 'knex-mock-client'; import { afterEach, beforeAll, describe, expect, it, vi } from 'vitest'; -import { SchemaService } from '.'; -import { ForbiddenException } from '..'; -import type { Collection } from '../types/collection'; -import type { Snapshot, SnapshotDiffWithHash } from '../types/snapshot'; -import { applyDiff } from '../utils/apply-diff'; -import { getSnapshot } from '../utils/get-snapshot'; +import { SchemaService } from './schema.js'; +import { ForbiddenException } from '../exceptions/forbidden.js'; +import type { Collection } from '../types/collection.js'; +import type { Snapshot, SnapshotDiffWithHash } from '../types/snapshot.js'; +import { applyDiff } from '../utils/apply-diff.js'; +import { getSnapshot } from '../utils/get-snapshot.js'; -vi.mock('../../package.json', () => ({ version: '0.0.0' })); +vi.mock('../utils/package.js', () => ({ version: '0.0.0' })); -vi.mock('../../src/database/index', () => { +vi.mock('../../src/database/index.js', () => { return { __esModule: true, default: vi.fn(), getDatabaseClient: vi.fn().mockReturnValue('postgres') }; }); -vi.mock('../utils/get-snapshot', () => ({ +vi.mock('../utils/get-snapshot.js', () => ({ getSnapshot: vi.fn(), })); -vi.mock('../utils/apply-diff', () => ({ +vi.mock('../utils/apply-diff.js', () => ({ applyDiff: vi.fn(), })); @@ -62,7 +63,7 @@ const testCollectionDiff = { }; beforeAll(() => { - db = knex({ client: Client_PG }); + db = knex.default({ client: Client_PG }); tracker = createTracker(db); }); diff --git a/api/src/services/schema.ts b/api/src/services/schema.ts index e0f6c69de7..7d2cd80791 100644 --- a/api/src/services/schema.ts +++ b/api/src/services/schema.ts @@ -1,14 +1,20 @@ -import type { Accountability } from '@directus/shared/types'; +import type { Accountability } from '@directus/types'; import type { Knex } from 'knex'; -import getDatabase from '../database'; -import { ForbiddenException } from '../exceptions'; -import type { AbstractServiceOptions, Snapshot, SnapshotDiff, SnapshotDiffWithHash, SnapshotWithHash } from '../types'; -import { applyDiff } from '../utils/apply-diff'; -import { getSnapshot } from '../utils/get-snapshot'; -import { getSnapshotDiff } from '../utils/get-snapshot-diff'; -import { getVersionedHash } from '../utils/get-versioned-hash'; -import { validateApplyDiff } from '../utils/validate-diff'; -import { validateSnapshot } from '../utils/validate-snapshot'; +import getDatabase from '../database/index.js'; +import { ForbiddenException } from '../exceptions/index.js'; +import type { + AbstractServiceOptions, + Snapshot, + SnapshotDiff, + SnapshotDiffWithHash, + SnapshotWithHash, +} from '../types/index.js'; +import { applyDiff } from '../utils/apply-diff.js'; +import { getSnapshot } from '../utils/get-snapshot.js'; +import { getSnapshotDiff } from '../utils/get-snapshot-diff.js'; +import { getVersionedHash } from '../utils/get-versioned-hash.js'; +import { validateApplyDiff } from '../utils/validate-diff.js'; +import { validateSnapshot } from '../utils/validate-snapshot.js'; export class SchemaService { knex: Knex; diff --git a/api/src/services/server.ts b/api/src/services/server.ts index b0c7d71202..030b25818d 100644 --- a/api/src/services/server.ts +++ b/api/src/services/server.ts @@ -1,23 +1,22 @@ import type { Knex } from 'knex'; -import { merge } from 'lodash'; +import { merge } from 'lodash-es'; import os from 'os'; import { performance } from 'perf_hooks'; -import type { Accountability, SchemaOverview } from '@directus/shared/types'; -import { toArray } from '@directus/shared/utils'; +import type { Accountability, SchemaOverview } from '@directus/types'; +import { toArray } from '@directus/utils'; import { Readable } from 'node:stream'; -// @ts-ignore -import { version } from '../../package.json'; -import { getCache } from '../cache'; -import getDatabase, { hasDatabaseConnection } from '../database'; -import env from '../env'; -import logger from '../logger'; -import getMailer from '../mailer'; -import { rateLimiterGlobal } from '../middleware/rate-limiter-global'; -import { rateLimiter } from '../middleware/rate-limiter-ip'; -import { getStorage } from '../storage'; -import type { AbstractServiceOptions } from '../types'; -import { getOSInfo } from '../utils/get-os-info'; -import { SettingsService } from './settings'; +import { version } from '../utils/package.js'; +import { getCache } from '../cache.js'; +import getDatabase, { hasDatabaseConnection } from '../database/index.js'; +import env from '../env.js'; +import logger from '../logger.js'; +import getMailer from '../mailer.js'; +import { rateLimiterGlobal } from '../middleware/rate-limiter-global.js'; +import { rateLimiter } from '../middleware/rate-limiter-ip.js'; +import { getStorage } from '../storage/index.js'; +import type { AbstractServiceOptions } from '../types/index.js'; +import { getOSInfo } from '../utils/get-os-info.js'; +import { SettingsService } from './settings.js'; export class ServerService { knex: Knex; diff --git a/api/src/services/settings.ts b/api/src/services/settings.ts index b5c043f250..51dab148e4 100644 --- a/api/src/services/settings.ts +++ b/api/src/services/settings.ts @@ -1,5 +1,5 @@ -import type { AbstractServiceOptions } from '../types'; -import { ItemsService } from './items'; +import type { AbstractServiceOptions } from '../types/index.js'; +import { ItemsService } from './items.js'; export class SettingsService extends ItemsService { constructor(options: AbstractServiceOptions) { diff --git a/api/src/services/shares.ts b/api/src/services/shares.ts index 7920595d52..109dec0bf6 100644 --- a/api/src/services/shares.ts +++ b/api/src/services/shares.ts @@ -1,7 +1,7 @@ import argon2 from 'argon2'; import jwt from 'jsonwebtoken'; -import env from '../env'; -import { ForbiddenException, InvalidCredentialsException } from '../exceptions'; +import env from '../env.js'; +import { ForbiddenException, InvalidCredentialsException } from '../exceptions/index.js'; import type { AbstractServiceOptions, DirectusTokenPayload, @@ -10,15 +10,15 @@ import type { MutationOptions, PrimaryKey, ShareData, -} from '../types'; -import { getMilliseconds } from '../utils/get-milliseconds'; -import { md } from '../utils/md'; -import { Url } from '../utils/url'; -import { userName } from '../utils/user-name'; -import { AuthorizationService } from './authorization'; -import { ItemsService } from './items'; -import { MailService } from './mail'; -import { UsersService } from './users'; +} from '../types/index.js'; +import { getMilliseconds } from '../utils/get-milliseconds.js'; +import { md } from '../utils/md.js'; +import { Url } from '../utils/url.js'; +import { userName } from '../utils/user-name.js'; +import { AuthorizationService } from './authorization.js'; +import { ItemsService } from './items.js'; +import { MailService } from './mail/index.js'; +import { UsersService } from './users.js'; export class SharesService extends ItemsService { authorizationService: AuthorizationService; diff --git a/api/src/services/specifications.test.ts b/api/src/services/specifications.test.ts index 436696b0fd..c279232414 100644 --- a/api/src/services/specifications.test.ts +++ b/api/src/services/specifications.test.ts @@ -1,8 +1,9 @@ -import knex, { Knex } from 'knex'; +import knex from 'knex'; +import type { Knex } from 'knex'; import { createTracker, MockClient, Tracker } from 'knex-mock-client'; import { afterEach, beforeAll, beforeEach, describe, expect, it, MockedFunction, vi } from 'vitest'; -import { CollectionsService, FieldsService, RelationsService, SpecificationService } from '../../src/services'; -import type { Collection } from '../types'; +import { CollectionsService, FieldsService, RelationsService, SpecificationService } from '../../src/services/index.js'; +import type { Collection } from '../types/index.js'; class Client_PG extends MockClient {} @@ -11,7 +12,7 @@ describe('Integration Tests', () => { let tracker: Tracker; beforeAll(async () => { - db = vi.mocked(knex({ client: Client_PG })); + db = vi.mocked(knex.default({ client: Client_PG })); tracker = createTracker(db); }); diff --git a/api/src/services/specifications.ts b/api/src/services/specifications.ts index e9a9117f8c..b4b92118c8 100644 --- a/api/src/services/specifications.ts +++ b/api/src/services/specifications.ts @@ -1,6 +1,6 @@ -import openapi from '@directus/specs'; +import { spec } from '@directus/specs'; import type { Knex } from 'knex'; -import { cloneDeep, mergeWith } from 'lodash'; +import { cloneDeep, mergeWith } from 'lodash-es'; import type { OpenAPIObject, ParameterObject, @@ -9,19 +9,17 @@ import type { SchemaObject, TagObject, } from 'openapi3-ts'; -import type { Accountability, Field, Permission, Relation, SchemaOverview, Type } from '@directus/shared/types'; -import { version } from '../../package.json'; -import { OAS_REQUIRED_SCHEMAS } from '../constants'; -import getDatabase from '../database'; -import env from '../env'; -import type { AbstractServiceOptions, Collection } from '../types'; -import { getRelationType } from '../utils/get-relation-type'; -import { CollectionsService } from './collections'; -import { FieldsService } from './fields'; -import { GraphQLService } from './graphql'; -import { RelationsService } from './relations'; - -// @ts-ignore +import type { Accountability, Field, Permission, Relation, SchemaOverview, Type } from '@directus/types'; +import { version } from '../utils/package.js'; +import { OAS_REQUIRED_SCHEMAS } from '../constants.js'; +import getDatabase from '../database/index.js'; +import env from '../env.js'; +import type { AbstractServiceOptions, Collection } from '../types/index.js'; +import { getRelationType } from '../utils/get-relation-type.js'; +import { CollectionsService } from './collections.js'; +import { FieldsService } from './fields.js'; +import { GraphQLService } from './graphql/index.js'; +import { RelationsService } from './relations.js'; import formatTitle from '@directus/format-title'; export class SpecificationService { @@ -123,7 +121,7 @@ class OASSpecsService implements SpecificationSubService { } private async generateTags(collections: Collection[]): Promise { - const systemTags = cloneDeep(openapi.tags)!; + const systemTags = cloneDeep(spec.tags)!; const tags: OpenAPIObject['tags'] = []; @@ -139,7 +137,7 @@ class OASSpecsService implements SpecificationSubService { // If the collection is one of the system collections, pull the tag from the static spec if (isSystem) { - for (const tag of openapi.tags!) { + for (const tag of spec.tags!) { if (tag['x-collection'] === collection.collection) { tags.push(tag); break; @@ -172,7 +170,7 @@ class OASSpecsService implements SpecificationSubService { const isSystem = 'x-collection' in tag === false || tag['x-collection'].startsWith('directus_'); if (isSystem) { - for (const [path, pathItem] of Object.entries(openapi.paths)) { + for (const [path, pathItem] of Object.entries(spec.paths)) { for (const [method, operation] of Object.entries(pathItem)) { if (operation.tags?.includes(tag.name)) { if (!paths[path]) { @@ -202,8 +200,8 @@ class OASSpecsService implements SpecificationSubService { } } } else { - const listBase = cloneDeep(openapi.paths['/items/{collection}']); - const detailBase = cloneDeep(openapi.paths['/items/{collection}/{id}']); + const listBase = cloneDeep(spec.paths['/items/{collection}']); + const detailBase = cloneDeep(spec.paths['/items/{collection}/{id}']); const collection = tag['x-collection']; for (const method of ['post', 'get', 'patch', 'delete']) { @@ -333,17 +331,17 @@ class OASSpecsService implements SpecificationSubService { relations: Relation[], tags: OpenAPIObject['tags'] ): Promise { - let components: OpenAPIObject['components'] = cloneDeep(openapi.components); + let components: OpenAPIObject['components'] = cloneDeep(spec.components); if (!components) components = {}; components.schemas = {}; // Always includes the schemas with these names - if (openapi.components?.schemas !== null) { + if (spec.components?.schemas !== null) { for (const schemaName of OAS_REQUIRED_SCHEMAS) { - if (openapi.components!.schemas![schemaName] !== null) { - components.schemas[schemaName] = cloneDeep(openapi.components!.schemas![schemaName])!; + if (spec.components!.schemas![schemaName] !== null) { + components.schemas[schemaName] = cloneDeep(spec.components!.schemas![schemaName])!; } } } @@ -360,14 +358,14 @@ class OASSpecsService implements SpecificationSubService { const fieldsInCollection = fields.filter((field) => field.collection === collection.collection); if (isSystem) { - const schemaComponent = cloneDeep(openapi.components!.schemas![tag.name]) as SchemaObject; + const schemaComponent = cloneDeep(spec.components!.schemas![tag.name]) as SchemaObject; schemaComponent.properties = {}; for (const field of fieldsInCollection) { schemaComponent.properties[field.field] = (cloneDeep( - (openapi.components!.schemas![tag.name] as SchemaObject).properties![field.field] + (spec.components!.schemas![tag.name] as SchemaObject).properties![field.field] ) as SchemaObject) || this.generateField(field, relations, tags, fields); } diff --git a/api/src/services/tfa.ts b/api/src/services/tfa.ts index 9de590156b..08509b6443 100644 --- a/api/src/services/tfa.ts +++ b/api/src/services/tfa.ts @@ -1,9 +1,9 @@ import type { Knex } from 'knex'; import { authenticator } from 'otplib'; -import getDatabase from '../database'; -import { InvalidPayloadException } from '../exceptions'; -import type { AbstractServiceOptions, PrimaryKey } from '../types'; -import { ItemsService } from './items'; +import getDatabase from '../database/index.js'; +import { InvalidPayloadException } from '../exceptions/index.js'; +import type { AbstractServiceOptions, PrimaryKey } from '../types/index.js'; +import { ItemsService } from './items.js'; export class TFAService { knex: Knex; diff --git a/api/src/services/users.test.ts b/api/src/services/users.test.ts index 82531d1f35..a6e8b2adcb 100644 --- a/api/src/services/users.test.ts +++ b/api/src/services/users.test.ts @@ -1,10 +1,11 @@ -import type { SchemaOverview } from '@directus/shared/types'; -import knex, { Knex } from 'knex'; +import type { SchemaOverview } from '@directus/types'; +import knex from 'knex'; +import type { Knex } from 'knex'; import { createTracker, MockClient, Tracker } from 'knex-mock-client'; import { afterEach, beforeAll, beforeEach, describe, expect, it, MockedFunction, SpyInstance, vi } from 'vitest'; -import { ItemsService, UsersService } from '.'; -import { ForbiddenException, InvalidPayloadException } from '../exceptions'; -import { RecordNotUniqueException } from '../exceptions/database/record-not-unique'; +import { ItemsService, UsersService } from './index.js'; +import { ForbiddenException, InvalidPayloadException } from '../exceptions/index.js'; +import { RecordNotUniqueException } from '../exceptions/database/record-not-unique.js'; vi.mock('../../src/database/index', () => ({ default: vi.fn(), @@ -48,7 +49,7 @@ describe('Integration Tests', () => { let tracker: Tracker; beforeAll(async () => { - db = vi.mocked(knex({ client: MockClient })); + db = vi.mocked(knex.default({ client: MockClient })); tracker = createTracker(db); }); diff --git a/api/src/services/users.ts b/api/src/services/users.ts index 2e9e8fc8d6..5b0c79a8bd 100644 --- a/api/src/services/users.ts +++ b/api/src/services/users.ts @@ -1,20 +1,20 @@ -import { FailedValidationException } from '@directus/shared/exceptions'; -import type { Query } from '@directus/shared/types'; -import { getSimpleHash, toArray } from '@directus/shared/utils'; +import { FailedValidationException } from '@directus/exceptions'; +import type { Query } from '@directus/types'; +import { getSimpleHash, toArray } from '@directus/utils'; import jwt from 'jsonwebtoken'; -import { cloneDeep } from 'lodash'; +import { cloneDeep } from 'lodash-es'; import { performance } from 'perf_hooks'; -import getDatabase from '../database'; -import env from '../env'; -import { ForbiddenException, InvalidPayloadException, UnprocessableEntityException } from '../exceptions'; -import { RecordNotUniqueException } from '../exceptions/database/record-not-unique'; -import type { AbstractServiceOptions, Item, MutationOptions, PrimaryKey } from '../types'; -import isUrlAllowed from '../utils/is-url-allowed'; -import { stall } from '../utils/stall'; -import { Url } from '../utils/url'; -import { ItemsService } from './items'; -import { MailService } from './mail'; -import { SettingsService } from './settings'; +import getDatabase from '../database/index.js'; +import env from '../env.js'; +import { ForbiddenException, InvalidPayloadException, UnprocessableEntityException } from '../exceptions/index.js'; +import { RecordNotUniqueException } from '../exceptions/database/record-not-unique.js'; +import type { AbstractServiceOptions, Item, MutationOptions, PrimaryKey } from '../types/index.js'; +import isUrlAllowed from '../utils/is-url-allowed.js'; +import { stall } from '../utils/stall.js'; +import { Url } from '../utils/url.js'; +import { ItemsService } from './items.js'; +import { MailService } from './mail/index.js'; +import { SettingsService } from './settings.js'; export class UsersService extends ItemsService { constructor(options: AbstractServiceOptions) { diff --git a/api/src/services/utils.ts b/api/src/services/utils.ts index a16b3273ab..08b6612925 100644 --- a/api/src/services/utils.ts +++ b/api/src/services/utils.ts @@ -1,10 +1,10 @@ -import type { Accountability, SchemaOverview } from '@directus/shared/types'; +import type { Accountability, SchemaOverview } from '@directus/types'; import type { Knex } from 'knex'; -import getDatabase from '../database'; -import { systemCollectionRows } from '../database/system-data/collections'; -import emitter from '../emitter'; -import { ForbiddenException, InvalidPayloadException } from '../exceptions'; -import type { AbstractServiceOptions, PrimaryKey } from '../types'; +import getDatabase from '../database/index.js'; +import { systemCollectionRows } from '../database/system-data/collections/index.js'; +import emitter from '../emitter.js'; +import { ForbiddenException, InvalidPayloadException } from '../exceptions/index.js'; +import type { AbstractServiceOptions, PrimaryKey } from '../types/index.js'; export class UtilsService { knex: Knex; diff --git a/api/src/services/webhooks.test.ts b/api/src/services/webhooks.test.ts index f95c763d2e..f341b8275c 100644 --- a/api/src/services/webhooks.test.ts +++ b/api/src/services/webhooks.test.ts @@ -1,8 +1,9 @@ -import knex, { Knex } from 'knex'; +import knex from 'knex'; +import type { Knex } from 'knex'; import { createTracker, MockClient, Tracker } from 'knex-mock-client'; import { afterEach, beforeAll, beforeEach, describe, expect, it, SpyInstance, vi } from 'vitest'; -import { WebhooksService } from '.'; -import { getMessenger } from '../messenger'; +import { WebhooksService } from './index.js'; +import { getMessenger } from '../messenger.js'; vi.mock('../../src/database/index', () => { return { __esModule: true, default: vi.fn(), getDatabaseClient: vi.fn().mockReturnValue('postgres') }; @@ -17,7 +18,7 @@ describe('Integration Tests', () => { let tracker: Tracker; beforeAll(async () => { - db = knex({ client: MockClient }); + db = knex.default({ client: MockClient }); tracker = createTracker(db); }); diff --git a/api/src/services/webhooks.ts b/api/src/services/webhooks.ts index dfa1c97ef6..3d855667af 100644 --- a/api/src/services/webhooks.ts +++ b/api/src/services/webhooks.ts @@ -1,6 +1,6 @@ -import { getMessenger, Messenger } from '../messenger'; -import type { AbstractServiceOptions, Item, MutationOptions, PrimaryKey, Webhook } from '../types'; -import { ItemsService } from './items'; +import { getMessenger, Messenger } from '../messenger.js'; +import type { AbstractServiceOptions, Item, MutationOptions, PrimaryKey, Webhook } from '../types/index.js'; +import { ItemsService } from './items.js'; export class WebhooksService extends ItemsService { messenger: Messenger; diff --git a/api/src/start.ts b/api/src/start.ts index 14f398d03a..655ad7fe56 100644 --- a/api/src/start.ts +++ b/api/src/start.ts @@ -1,3 +1,3 @@ -import { startServer } from './server'; +import { startServer } from './server.js'; startServer(); diff --git a/api/src/storage/get-storage-driver.ts b/api/src/storage/get-storage-driver.ts index 87f6f48385..9944e8e2bd 100644 --- a/api/src/storage/get-storage-driver.ts +++ b/api/src/storage/get-storage-driver.ts @@ -1,4 +1,3 @@ -// @ts-expect-error https://github.com/microsoft/TypeScript/issues/49721 import type { Driver } from '@directus/storage'; export const _aliasMap: Record = { diff --git a/api/src/storage/index.test.ts b/api/src/storage/index.test.ts index 527644d5bd..86895db8d0 100644 --- a/api/src/storage/index.test.ts +++ b/api/src/storage/index.test.ts @@ -1,6 +1,4 @@ -// @ts-expect-error https://github.com/microsoft/TypeScript/issues/49721 import { StorageManager } from '@directus/storage'; - import { afterEach, beforeEach, expect, test, vi } from 'vitest'; import { validateEnv } from '../utils/validate-env.js'; import { getStorage, _cache } from './index.js'; diff --git a/api/src/storage/index.ts b/api/src/storage/index.ts index aa52b43625..be42b6cf1f 100644 --- a/api/src/storage/index.ts +++ b/api/src/storage/index.ts @@ -1,8 +1,6 @@ -import { validateEnv } from '../utils/validate-env'; -import { registerDrivers } from './register-drivers'; -import { registerLocations } from './register-locations'; - -// @ts-expect-error https://github.com/microsoft/TypeScript/issues/49721 +import { validateEnv } from '../utils/validate-env.js'; +import { registerDrivers } from './register-drivers.js'; +import { registerLocations } from './register-locations.js'; import type { StorageManager } from '@directus/storage'; export const _cache: { storage: any | null } = { diff --git a/api/src/storage/register-drivers.test.ts b/api/src/storage/register-drivers.test.ts index e04990ec08..aa3b47c001 100644 --- a/api/src/storage/register-drivers.test.ts +++ b/api/src/storage/register-drivers.test.ts @@ -3,8 +3,6 @@ import { afterEach, beforeEach, expect, test, vi } from 'vitest'; import { getEnv } from '../env.js'; import { getStorageDriver } from './get-storage-driver.js'; import { registerDrivers } from './register-drivers.js'; - -// @ts-expect-error https://github.com/microsoft/TypeScript/issues/49721 import type { Driver, StorageManager } from '@directus/storage'; vi.mock('./get-storage-driver.js'); diff --git a/api/src/storage/register-drivers.ts b/api/src/storage/register-drivers.ts index 6980e8fb85..b89719b477 100644 --- a/api/src/storage/register-drivers.ts +++ b/api/src/storage/register-drivers.ts @@ -1,7 +1,5 @@ -import { getEnv } from '../env'; -import { getStorageDriver } from './get-storage-driver'; - -// @ts-expect-error https://github.com/microsoft/TypeScript/issues/49721 +import { getEnv } from '../env.js'; +import { getStorageDriver } from './get-storage-driver.js'; import type { StorageManager } from '@directus/storage'; export const registerDrivers = async (storage: StorageManager) => { diff --git a/api/src/storage/register-locations.test.ts b/api/src/storage/register-locations.test.ts index 5e7fa89597..97bfac951e 100644 --- a/api/src/storage/register-locations.test.ts +++ b/api/src/storage/register-locations.test.ts @@ -1,5 +1,4 @@ -import { toArray } from '@directus/shared/utils'; -// @ts-expect-error https://github.com/microsoft/TypeScript/issues/49721 +import { toArray } from '@directus/utils'; import type { StorageManager } from '@directus/storage'; import { randNumber, randWord } from '@ngneat/falso'; import { afterEach, beforeEach, expect, test, vi } from 'vitest'; @@ -8,7 +7,7 @@ import { getConfigFromEnv } from '../utils/get-config-from-env.js'; import { registerLocations } from './register-locations.js'; vi.mock('../env.js'); -vi.mock('@directus/shared/utils'); +vi.mock('@directus/utils'); vi.mock('../utils/get-config-from-env.js'); let sample: { diff --git a/api/src/storage/register-locations.ts b/api/src/storage/register-locations.ts index 3da54b2892..523461de94 100644 --- a/api/src/storage/register-locations.ts +++ b/api/src/storage/register-locations.ts @@ -1,9 +1,7 @@ -// @ts-expect-error https://github.com/microsoft/TypeScript/issues/49721 import type { StorageManager } from '@directus/storage'; - -import { toArray } from '@directus/shared/utils'; -import { getEnv } from '../env'; -import { getConfigFromEnv } from '../utils/get-config-from-env'; +import { toArray } from '@directus/utils'; +import { getEnv } from '../env.js'; +import { getConfigFromEnv } from '../utils/get-config-from-env.js'; export const registerLocations = async (storage: StorageManager) => { const env = getEnv(); diff --git a/api/src/types/ast.ts b/api/src/types/ast.ts index ff09710983..f9812e6799 100644 --- a/api/src/types/ast.ts +++ b/api/src/types/ast.ts @@ -1,4 +1,4 @@ -import type { Query, Relation } from '@directus/shared/types'; +import type { Query, Relation } from '@directus/types'; export type M2ONode = { type: 'm2o'; diff --git a/api/src/types/auth.ts b/api/src/types/auth.ts index 669bfc827c..4b43261113 100644 --- a/api/src/types/auth.ts +++ b/api/src/types/auth.ts @@ -1,4 +1,4 @@ -import type { SchemaOverview } from '@directus/shared/types'; +import type { SchemaOverview } from '@directus/types'; import type { Knex } from 'knex'; export interface AuthDriverOptions { diff --git a/api/src/types/collection.ts b/api/src/types/collection.ts index 105a2624ea..f4454ae2fb 100644 --- a/api/src/types/collection.ts +++ b/api/src/types/collection.ts @@ -1,5 +1,5 @@ -import type { Field } from '@directus/shared/types'; -import type { Table } from 'knex-schema-inspector/dist/types/table'; +import type { Field } from '@directus/types'; +import type { Table } from '@directus/schema'; export type CollectionMeta = { collection: string; diff --git a/api/src/types/events.ts b/api/src/types/events.ts index dd02daa8d0..b44aa51728 100644 --- a/api/src/types/events.ts +++ b/api/src/types/events.ts @@ -1,4 +1,4 @@ -import type { ActionHandler, FilterHandler, InitHandler } from '@directus/shared/types'; +import type { ActionHandler, FilterHandler, InitHandler } from '@directus/types'; import type { ScheduledTask } from 'node-cron'; export type EventHandler = diff --git a/api/src/types/express.d.ts b/api/src/types/express.d.ts index 63ba65c10b..50d34fd29c 100644 --- a/api/src/types/express.d.ts +++ b/api/src/types/express.d.ts @@ -2,8 +2,7 @@ * Custom properties on the req object in express */ -import { Accountability, Query } from '@directus/shared/types'; -import { SchemaOverview } from '@directus/schema'; +import { Accountability, Query, SchemaOverview } from '@directus/types'; export {}; diff --git a/api/src/types/index.ts b/api/src/types/index.ts index 7dc87dc525..3ef7b8c676 100644 --- a/api/src/types/index.ts +++ b/api/src/types/index.ts @@ -1,15 +1,15 @@ -export * from './assets'; -export * from './ast'; -export * from './auth'; -export * from './collection'; -export * from './database'; -export * from './events'; -export * from './files'; -export * from './graphql'; -export * from './items'; -export * from './meta'; -export * from './migration'; -export * from './revision'; -export * from './services'; -export * from './snapshot'; -export * from './webhooks'; +export * from './assets.js'; +export * from './ast.js'; +export * from './auth.js'; +export * from './collection.js'; +export * from './database.js'; +export * from './events.js'; +export * from './files.js'; +export * from './graphql.js'; +export * from './items.js'; +export * from './meta.js'; +export * from './migration.js'; +export * from './revision.js'; +export * from './services.js'; +export * from './snapshot.js'; +export * from './webhooks.js'; diff --git a/api/src/types/items.ts b/api/src/types/items.ts index ad854e8de7..82777858c9 100644 --- a/api/src/types/items.ts +++ b/api/src/types/items.ts @@ -3,8 +3,8 @@ * expecting an item vs any other generic object. */ -import type { BaseException } from '@directus/shared/exceptions'; -import type { EventContext } from '@directus/shared/types'; +import type { BaseException } from '@directus/exceptions'; +import type { EventContext } from '@directus/types'; export type Item = Record; diff --git a/api/src/types/services.ts b/api/src/types/services.ts index 6ea137848f..c915fa012a 100644 --- a/api/src/types/services.ts +++ b/api/src/types/services.ts @@ -1,6 +1,6 @@ -import type { Accountability, Query, SchemaOverview } from '@directus/shared/types'; +import type { Accountability, Query, SchemaOverview } from '@directus/types'; import type { Knex } from 'knex'; -import type { Item, PrimaryKey } from './items'; +import type { Item, PrimaryKey } from './items.js'; export type AbstractServiceOptions = { knex?: Knex; diff --git a/api/src/types/snapshot.ts b/api/src/types/snapshot.ts index 4601005ef1..6fee38c337 100644 --- a/api/src/types/snapshot.ts +++ b/api/src/types/snapshot.ts @@ -1,7 +1,7 @@ -import type { Field, FieldMeta, Relation, RelationMeta } from '@directus/shared/types'; +import type { Field, FieldMeta, Relation, RelationMeta } from '@directus/types'; import type { Diff } from 'deep-diff'; -import type { Collection } from './collection'; -import type { DatabaseClient } from './database'; +import type { Collection } from './collection.js'; +import type { DatabaseClient } from './database.js'; export type Snapshot = { version: number; diff --git a/api/src/utils/apply-diff.test.ts b/api/src/utils/apply-diff.test.ts index e9a1df580e..f0d75c0074 100644 --- a/api/src/utils/apply-diff.test.ts +++ b/api/src/utils/apply-diff.test.ts @@ -1,8 +1,8 @@ import type { Diff } from 'deep-diff'; import { describe, expect, it } from 'vitest'; -import type { SnapshotField } from '../types/snapshot'; +import type { SnapshotField } from '../types/snapshot.js'; -import { isNestedMetaUpdate } from './apply-diff'; +import { isNestedMetaUpdate } from './apply-diff.js'; describe('isNestedMetaUpdate', () => { it.each([ diff --git a/api/src/utils/apply-diff.ts b/api/src/utils/apply-diff.ts index 8619654462..7bd7fa9504 100644 --- a/api/src/utils/apply-diff.ts +++ b/api/src/utils/apply-diff.ts @@ -1,12 +1,15 @@ -import type { Field, Relation, SchemaOverview } from '@directus/shared/types'; -import { applyChange, Diff, DiffDeleted, DiffNew } from 'deep-diff'; +import type { Field, Relation, SchemaOverview } from '@directus/types'; +import type { Diff, DiffDeleted, DiffNew } from 'deep-diff'; +import deepDiff from 'deep-diff'; import type { Knex } from 'knex'; -import { cloneDeep, merge, set } from 'lodash'; -import { clearSystemCache } from '../cache'; -import getDatabase from '../database'; -import emitter from '../emitter'; -import logger from '../logger'; -import { CollectionsService, FieldsService, RelationsService } from '../services'; +import { cloneDeep, merge, set } from 'lodash-es'; +import { clearSystemCache } from '../cache.js'; +import getDatabase from '../database/index.js'; +import emitter from '../emitter.js'; +import logger from '../logger.js'; +import { CollectionsService } from '../services/collections.js'; +import { FieldsService } from '../services/fields.js'; +import { RelationsService } from '../services/relations.js'; import { ActionEventParams, Collection, @@ -15,8 +18,8 @@ import { Snapshot, SnapshotDiff, SnapshotField, -} from '../types'; -import { getSchema } from './get-schema'; +} from '../types/index.js'; +import { getSchema } from './get-schema.js'; type CollectionDelta = { collection: string; @@ -183,7 +186,7 @@ export async function applyDiff( if (currentCollection) { try { const newValues = diff.reduce((acc, currentDiff) => { - applyChange(acc, undefined, currentDiff); + deepDiff.applyChange(acc, undefined, currentDiff); return acc; }, cloneDeep(currentCollection)); @@ -219,7 +222,7 @@ export async function applyDiff( if (currentField) { try { const newValues = diff.reduce((acc, currentDiff) => { - applyChange(acc, undefined, currentDiff); + deepDiff.applyChange(acc, undefined, currentDiff); return acc; }, cloneDeep(currentField)); await fieldsService.updateField(collection, newValues, mutationOptions); @@ -275,7 +278,7 @@ export async function applyDiff( if (currentRelation) { try { const newValues = diff.reduce((acc, currentDiff) => { - applyChange(acc, undefined, currentDiff); + deepDiff.applyChange(acc, undefined, currentDiff); return acc; }, cloneDeep(currentRelation)); await relationsService.updateOne(collection, field, newValues, mutationOptions); diff --git a/api/src/utils/apply-function-to-column-name.test.ts b/api/src/utils/apply-function-to-column-name.test.ts index a2cc9f4fe5..e5cbd4b4bb 100644 --- a/api/src/utils/apply-function-to-column-name.test.ts +++ b/api/src/utils/apply-function-to-column-name.test.ts @@ -1,6 +1,6 @@ import { expect, test } from 'vitest'; -import { applyFunctionToColumnName } from './apply-function-to-column-name'; +import { applyFunctionToColumnName } from './apply-function-to-column-name.js'; test.each([ { input: 'test', expected: 'test' }, diff --git a/api/src/utils/apply-function-to-column-name.ts b/api/src/utils/apply-function-to-column-name.ts index 4c8a17bcfa..09621906d5 100644 --- a/api/src/utils/apply-function-to-column-name.ts +++ b/api/src/utils/apply-function-to-column-name.ts @@ -1,4 +1,4 @@ -import { REGEX_BETWEEN_PARENS } from '@directus/shared/constants'; +import { REGEX_BETWEEN_PARENS } from '@directus/constants'; /** * Takes in a column name, and transforms the original name with the generated column name based on diff --git a/api/src/utils/apply-query.ts b/api/src/utils/apply-query.ts index 1f934c9e07..7daa441757 100644 --- a/api/src/utils/apply-query.ts +++ b/api/src/utils/apply-query.ts @@ -8,17 +8,17 @@ import type { Relation, SchemaOverview, Type, -} from '@directus/shared/types'; -import { getFilterOperatorsForType, getOutputTypeForFunction } from '@directus/shared/utils'; +} from '@directus/types'; +import { getFilterOperatorsForType, getOutputTypeForFunction } from '@directus/utils'; import type { Knex } from 'knex'; -import { clone, isPlainObject } from 'lodash'; +import { clone, isPlainObject } from 'lodash-es'; import validate from 'uuid-validate'; -import { getHelpers } from '../database/helpers'; -import { InvalidQueryException } from '../exceptions/invalid-query'; -import { getColumn } from './get-column'; -import { AliasMap, getColumnPath } from './get-column-path'; -import { getRelationInfo } from './get-relation-info'; -import { stripFunction } from './strip-function'; +import { getHelpers } from '../database/helpers/index.js'; +import { InvalidQueryException } from '../exceptions/invalid-query.js'; +import { getColumn } from './get-column.js'; +import { AliasMap, getColumnPath } from './get-column-path.js'; +import { getRelationInfo } from './get-relation-info.js'; +import { stripFunction } from './strip-function.js'; // @ts-ignore import { customAlphabet } from 'nanoid/non-secure'; diff --git a/api/src/utils/apply-snapshot.test.ts b/api/src/utils/apply-snapshot.test.ts index 85e6ebe9f6..ceab23e363 100644 --- a/api/src/utils/apply-snapshot.test.ts +++ b/api/src/utils/apply-snapshot.test.ts @@ -1,17 +1,18 @@ -import knex, { Knex } from 'knex'; +import knex from 'knex'; +import type { Knex } from 'knex'; import { createTracker, MockClient, Tracker } from 'knex-mock-client'; import { afterEach, beforeEach, describe, expect, it, MockedFunction, vi } from 'vitest'; -import { CollectionsService, FieldsService } from '../services'; -import type { Snapshot, SnapshotField } from '../types'; -import { snapshotApplyTestSchema } from '../__utils__/schemas'; +import { CollectionsService, FieldsService } from '../services/index.js'; +import type { Snapshot, SnapshotField } from '../types/index.js'; +import { snapshotApplyTestSchema } from '../__utils__/schemas.js'; import { snapshotBeforeCreateCollection, snapshotBeforeDeleteCollection, snapshotCreateCollection, snapshotCreateCollectionNotNested, -} from '../__utils__/snapshots'; -import { applySnapshot } from './apply-snapshot'; -import * as getSchema from './get-schema'; +} from '../__utils__/snapshots.js'; +import { applySnapshot } from './apply-snapshot.js'; +import * as getSchema from './get-schema.js'; class Client_PG extends MockClient {} @@ -25,7 +26,7 @@ describe('applySnapshot', () => { }; beforeEach(() => { - db = vi.mocked(knex({ client: Client_PG })); + db = vi.mocked(knex.default({ client: Client_PG })); tracker = createTracker(db); }); diff --git a/api/src/utils/apply-snapshot.ts b/api/src/utils/apply-snapshot.ts index 44f1a374d4..518dc5bba3 100644 --- a/api/src/utils/apply-snapshot.ts +++ b/api/src/utils/apply-snapshot.ts @@ -1,12 +1,12 @@ -import type { SchemaOverview } from '@directus/shared/types'; +import type { SchemaOverview } from '@directus/types'; import type { Knex } from 'knex'; -import { getCache } from '../cache'; -import getDatabase from '../database'; -import type { Snapshot, SnapshotDiff } from '../types'; -import { applyDiff } from './apply-diff'; -import { getSchema } from './get-schema'; -import { getSnapshot } from './get-snapshot'; -import { getSnapshotDiff } from './get-snapshot-diff'; +import { getCache } from '../cache.js'; +import getDatabase from '../database/index.js'; +import type { Snapshot, SnapshotDiff } from '../types/index.js'; +import { applyDiff } from './apply-diff.js'; +import { getSchema } from './get-schema.js'; +import { getSnapshot } from './get-snapshot.js'; +import { getSnapshotDiff } from './get-snapshot-diff.js'; export async function applySnapshot( snapshot: Snapshot, diff --git a/api/src/utils/async-handler.test.ts b/api/src/utils/async-handler.test.ts index 95d40dfd69..ed3cd9d724 100644 --- a/api/src/utils/async-handler.test.ts +++ b/api/src/utils/async-handler.test.ts @@ -1,6 +1,6 @@ import type { RequestHandler, Request, Response } from 'express'; import '../../src/types/express.d.ts'; -import asyncHandler from './async-handler'; +import asyncHandler from './async-handler.js'; import { expect, vi, test } from 'vitest'; let mockRequest: Partial; diff --git a/api/src/utils/calculate-field-depth.test.ts b/api/src/utils/calculate-field-depth.test.ts index e66f5ff82c..baf9b4f006 100644 --- a/api/src/utils/calculate-field-depth.test.ts +++ b/api/src/utils/calculate-field-depth.test.ts @@ -1,4 +1,4 @@ -import { calculateFieldDepth } from '../../src/utils/calculate-field-depth'; +import { calculateFieldDepth } from '../../src/utils/calculate-field-depth.js'; import { test, expect } from 'vitest'; test('Calculates basic depth', () => { diff --git a/api/src/utils/calculate-field-depth.ts b/api/src/utils/calculate-field-depth.ts index 8632fa8e34..21f1ddf487 100644 --- a/api/src/utils/calculate-field-depth.ts +++ b/api/src/utils/calculate-field-depth.ts @@ -1,4 +1,4 @@ -import { isPlainObject, isArray } from 'lodash'; +import { isPlainObject, isArray } from 'lodash-es'; /** * Calculates the depth of a given JSON structure, not counting any _ prefixed properties diff --git a/api/src/utils/compress.ts b/api/src/utils/compress.ts index 7683e5dfc9..7bafed442d 100644 --- a/api/src/utils/compress.ts +++ b/api/src/utils/compress.ts @@ -1,5 +1,5 @@ import { compress as compressSnappy, uncompress as uncompressSnappy } from 'snappy'; -import { compress as compressJSON, decompress as decompressJSON } from '@directus/shared/utils'; +import { compress as compressJSON, decompress as decompressJSON } from '@directus/utils'; export async function compress(raw: Record | Record[]): Promise { if (!raw) return raw; diff --git a/api/src/utils/construct-flow-tree.ts b/api/src/utils/construct-flow-tree.ts index dd09f57970..691b3ccff5 100644 --- a/api/src/utils/construct-flow-tree.ts +++ b/api/src/utils/construct-flow-tree.ts @@ -1,5 +1,5 @@ -import type { Flow, FlowRaw, Operation, OperationRaw } from '@directus/shared/types'; -import { omit } from 'lodash'; +import type { Flow, FlowRaw, Operation, OperationRaw } from '@directus/types'; +import { omit } from 'lodash-es'; export function constructFlowTree(flow: FlowRaw): Flow { const rootOperation = flow.operations.find((operation) => operation.id === flow.operation) ?? null; diff --git a/api/src/utils/dynamic-import.ts b/api/src/utils/dynamic-import.ts deleted file mode 100644 index ffd30cf008..0000000000 --- a/api/src/utils/dynamic-import.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const dynamicImport = async (mod: string) => { - return process.env['VITEST'] ? await import(mod) : require(mod); -}; diff --git a/api/src/utils/filter-items.test.ts b/api/src/utils/filter-items.test.ts index d78c8097ec..f987ec7121 100644 --- a/api/src/utils/filter-items.test.ts +++ b/api/src/utils/filter-items.test.ts @@ -1,4 +1,4 @@ -import { filterItems } from '../../src/utils/filter-items'; +import { filterItems } from '../../src/utils/filter-items.js'; import { describe, test, expect } from 'vitest'; const items = [ diff --git a/api/src/utils/filter-items.ts b/api/src/utils/filter-items.ts index e0246baf0e..691ee5c22d 100644 --- a/api/src/utils/filter-items.ts +++ b/api/src/utils/filter-items.ts @@ -1,5 +1,5 @@ -import type { FieldFilter, Query } from '@directus/shared/types'; -import { generateJoi } from '@directus/shared/utils'; +import type { FieldFilter, Query } from '@directus/types'; +import { generateJoi } from '@directus/utils'; /* Note: Filtering is normally done through SQL in run-ast. This function can be used in case an already diff --git a/api/src/utils/generate-hash.ts b/api/src/utils/generate-hash.ts index 5f11482a3c..a916ae0323 100644 --- a/api/src/utils/generate-hash.ts +++ b/api/src/utils/generate-hash.ts @@ -1,5 +1,5 @@ import argon2 from 'argon2'; -import { getConfigFromEnv } from './get-config-from-env'; +import { getConfigFromEnv } from './get-config-from-env.js'; export function generateHash(stringToHash: string): Promise { const argon2HashConfigOptions = getConfigFromEnv('HASH_', 'HASH_RAW'); // Disallow the HASH_RAW option, see https://github.com/directus/directus/discussions/7670#discussioncomment-1255805 diff --git a/api/src/utils/get-accountability-for-role.ts b/api/src/utils/get-accountability-for-role.ts index efaac1ce4f..047053e0b4 100644 --- a/api/src/utils/get-accountability-for-role.ts +++ b/api/src/utils/get-accountability-for-role.ts @@ -1,7 +1,7 @@ -import type { Accountability, SchemaOverview } from '@directus/shared/types'; +import type { Accountability, SchemaOverview } from '@directus/types'; import type { Knex } from 'knex'; -import { InvalidConfigException } from '../exceptions'; -import { getPermissions } from './get-permissions'; +import { InvalidConfigException } from '../exceptions/index.js'; +import { getPermissions } from './get-permissions.js'; export async function getAccountabilityForRole( role: null | string, diff --git a/api/src/utils/get-ast-from-query.ts b/api/src/utils/get-ast-from-query.ts index 5819705ddf..0f063ac1da 100644 --- a/api/src/utils/get-ast-from-query.ts +++ b/api/src/utils/get-ast-from-query.ts @@ -2,12 +2,12 @@ * Generate an AST based on a given collection and query */ -import { REGEX_BETWEEN_PARENS } from '@directus/shared/constants'; -import type { Accountability, PermissionsAction, Query, SchemaOverview } from '@directus/shared/types'; +import { REGEX_BETWEEN_PARENS } from '@directus/constants'; +import type { Accountability, PermissionsAction, Query, SchemaOverview } from '@directus/types'; import type { Knex } from 'knex'; -import { cloneDeep, isEmpty, mapKeys, omitBy, uniq } from 'lodash'; -import type { AST, FieldNode, FunctionFieldNode, NestedCollectionNode } from '../types'; -import { getRelationType } from '../utils/get-relation-type'; +import { cloneDeep, isEmpty, mapKeys, omitBy, uniq } from 'lodash-es'; +import type { AST, FieldNode, FunctionFieldNode, NestedCollectionNode } from '../types/index.js'; +import { getRelationType } from '../utils/get-relation-type.js'; type GetASTOptions = { accountability?: Accountability | null; diff --git a/api/src/utils/get-auth-providers.test.ts b/api/src/utils/get-auth-providers.test.ts index f294ce059c..bd1a12cfbe 100644 --- a/api/src/utils/get-auth-providers.test.ts +++ b/api/src/utils/get-auth-providers.test.ts @@ -1,5 +1,5 @@ import { describe, expect, vi, test } from 'vitest'; -import { getAuthProviders } from '../../src/utils/get-auth-providers'; +import { getAuthProviders } from '../../src/utils/get-auth-providers.js'; let factoryEnv: { [k: string]: any } = {}; diff --git a/api/src/utils/get-auth-providers.ts b/api/src/utils/get-auth-providers.ts index 678cda4727..18c0afd9bc 100644 --- a/api/src/utils/get-auth-providers.ts +++ b/api/src/utils/get-auth-providers.ts @@ -1,5 +1,5 @@ -import { toArray } from '@directus/shared/utils'; -import env from '../env'; +import { toArray } from '@directus/utils'; +import env from '../env.js'; interface AuthProvider { label: string; diff --git a/api/src/utils/get-cache-headers.test.ts b/api/src/utils/get-cache-headers.test.ts index fa73bee407..f162564fc3 100644 --- a/api/src/utils/get-cache-headers.test.ts +++ b/api/src/utils/get-cache-headers.test.ts @@ -1,6 +1,6 @@ import type { Request } from 'express'; import { describe, expect, vi, test } from 'vitest'; -import { getCacheControlHeader } from './get-cache-headers'; +import { getCacheControlHeader } from './get-cache-headers.js'; let factoryEnv: { [k: string]: any } = {}; diff --git a/api/src/utils/get-cache-headers.ts b/api/src/utils/get-cache-headers.ts index 403030dc46..54aca9044f 100644 --- a/api/src/utils/get-cache-headers.ts +++ b/api/src/utils/get-cache-headers.ts @@ -1,6 +1,6 @@ import type { Request } from 'express'; -import env from '../env'; -import { shouldSkipCache } from './should-skip-cache'; +import env from '../env.js'; +import { shouldSkipCache } from './should-skip-cache.js'; /** * Returns the Cache-Control header for the current request diff --git a/api/src/utils/get-cache-key.test.ts b/api/src/utils/get-cache-key.test.ts index 9dc5ea452a..963878d74b 100644 --- a/api/src/utils/get-cache-key.test.ts +++ b/api/src/utils/get-cache-key.test.ts @@ -1,7 +1,7 @@ import type { Request } from 'express'; import { afterEach, beforeAll, describe, expect, SpyInstance, test, vi } from 'vitest'; -import { getCacheKey } from './get-cache-key'; -import * as getGraphqlQueryUtil from './get-graphql-query-and-variables'; +import { getCacheKey } from './get-cache-key.js'; +import * as getGraphqlQueryUtil from './get-graphql-query-and-variables.js'; const baseUrl = 'http://localhost'; const restUrl = `${baseUrl}/items/example`; diff --git a/api/src/utils/get-cache-key.ts b/api/src/utils/get-cache-key.ts index 8232935914..9572b27920 100644 --- a/api/src/utils/get-cache-key.ts +++ b/api/src/utils/get-cache-key.ts @@ -1,7 +1,7 @@ import type { Request } from 'express'; import hash from 'object-hash'; import url from 'url'; -import { getGraphqlQueryAndVariables } from './get-graphql-query-and-variables'; +import { getGraphqlQueryAndVariables } from './get-graphql-query-and-variables.js'; export function getCacheKey(req: Request): string { const path = url.parse(req.originalUrl).pathname; diff --git a/api/src/utils/get-collection-from-alias.test.ts b/api/src/utils/get-collection-from-alias.test.ts index d5e23a246b..409e8f7877 100644 --- a/api/src/utils/get-collection-from-alias.test.ts +++ b/api/src/utils/get-collection-from-alias.test.ts @@ -1,6 +1,6 @@ import { expect, it } from 'vitest'; -import { getCollectionFromAlias } from './get-collection-from-alias'; -import type { AliasMap } from './get-column-path'; +import { getCollectionFromAlias } from './get-collection-from-alias.js'; +import type { AliasMap } from './get-column-path.js'; it('Returns the correct collection', () => { const aliasMap: AliasMap = { diff --git a/api/src/utils/get-collection-from-alias.ts b/api/src/utils/get-collection-from-alias.ts index a55acf7d7f..cda2c49bac 100644 --- a/api/src/utils/get-collection-from-alias.ts +++ b/api/src/utils/get-collection-from-alias.ts @@ -1,4 +1,4 @@ -import type { AliasMap } from './get-column-path'; +import type { AliasMap } from './get-column-path.js'; /** * Extract the collection of an alias within an aliasMap diff --git a/api/src/utils/get-column-path.test.ts b/api/src/utils/get-column-path.test.ts index 1b021c261b..f70ccbc94a 100644 --- a/api/src/utils/get-column-path.test.ts +++ b/api/src/utils/get-column-path.test.ts @@ -1,7 +1,7 @@ -import type { DeepPartial } from '@directus/shared/types'; +import type { DeepPartial } from '@directus/types'; import { expect, test } from 'vitest'; -import { InvalidQueryException } from '../../src/exceptions'; -import { ColPathProps, getColumnPath } from '../../src/utils/get-column-path'; +import { InvalidQueryException } from '../../src/exceptions/index.js'; +import { ColPathProps, getColumnPath } from '../../src/utils/get-column-path.js'; /* { diff --git a/api/src/utils/get-column-path.ts b/api/src/utils/get-column-path.ts index 7c3c7774e9..c83fd4b7e7 100644 --- a/api/src/utils/get-column-path.ts +++ b/api/src/utils/get-column-path.ts @@ -1,6 +1,6 @@ -import type { Relation, SchemaOverview } from '@directus/shared/types'; -import { InvalidQueryException } from '../exceptions'; -import { getRelationInfo } from './get-relation-info'; +import type { Relation, SchemaOverview } from '@directus/types'; +import { InvalidQueryException } from '../exceptions/index.js'; +import { getRelationInfo } from './get-relation-info.js'; export type AliasMap = { [key: string]: { alias: string; collection: string } }; diff --git a/api/src/utils/get-column.ts b/api/src/utils/get-column.ts index 5a3249009f..e8a183edc4 100644 --- a/api/src/utils/get-column.ts +++ b/api/src/utils/get-column.ts @@ -1,10 +1,10 @@ -import { REGEX_BETWEEN_PARENS } from '@directus/shared/constants'; -import type { FieldFunction, Query, SchemaOverview } from '@directus/shared/types'; -import { getFunctionsForType } from '@directus/shared/utils'; +import { REGEX_BETWEEN_PARENS } from '@directus/constants'; +import type { FieldFunction, Query, SchemaOverview } from '@directus/types'; +import { getFunctionsForType } from '@directus/utils'; import type { Knex } from 'knex'; -import { getFunctions } from '../database/helpers'; -import { InvalidQueryException } from '../exceptions'; -import { applyFunctionToColumnName } from './apply-function-to-column-name'; +import { getFunctions } from '../database/helpers/index.js'; +import { InvalidQueryException } from '../exceptions/index.js'; +import { applyFunctionToColumnName } from './apply-function-to-column-name.js'; type GetColumnOptions = { query?: Query | undefined; diff --git a/api/src/utils/get-config-from-env.test.ts b/api/src/utils/get-config-from-env.test.ts index 7551ed8d4b..13ca335982 100644 --- a/api/src/utils/get-config-from-env.test.ts +++ b/api/src/utils/get-config-from-env.test.ts @@ -1,4 +1,4 @@ -import { getConfigFromEnv } from '../../src/utils/get-config-from-env'; +import { getConfigFromEnv } from '../../src/utils/get-config-from-env.js'; import { describe, test, expect, vi } from 'vitest'; vi.mock('../../src/env', () => { diff --git a/api/src/utils/get-config-from-env.ts b/api/src/utils/get-config-from-env.ts index 46877b0692..7fe17a891a 100644 --- a/api/src/utils/get-config-from-env.ts +++ b/api/src/utils/get-config-from-env.ts @@ -1,6 +1,6 @@ import camelcase from 'camelcase'; -import { set } from 'lodash'; -import { getEnv } from '../env'; +import { set } from 'lodash-es'; +import { getEnv } from '../env.js'; export function getConfigFromEnv( prefix: string, diff --git a/api/src/utils/get-date-formatted.test.ts b/api/src/utils/get-date-formatted.test.ts index 9394bf4266..a1a346f226 100644 --- a/api/src/utils/get-date-formatted.test.ts +++ b/api/src/utils/get-date-formatted.test.ts @@ -1,6 +1,6 @@ import { afterEach, beforeEach, expect, test, vi } from 'vitest'; -import { getDateFormatted } from './get-date-formatted'; +import { getDateFormatted } from './get-date-formatted.js'; beforeEach(() => { vi.useFakeTimers(); diff --git a/api/src/utils/get-default-index-name.ts b/api/src/utils/get-default-index-name.ts index c1ad083a3c..f2c16260a6 100644 --- a/api/src/utils/get-default-index-name.ts +++ b/api/src/utils/get-default-index-name.ts @@ -1,4 +1,4 @@ -import { getSimpleHash } from '@directus/shared/utils'; +import { getSimpleHash } from '@directus/utils'; /** * Generate an index name for a given collection + fields combination. * diff --git a/api/src/utils/get-default-value.ts b/api/src/utils/get-default-value.ts index 10023fa96e..fd8227badf 100644 --- a/api/src/utils/get-default-value.ts +++ b/api/src/utils/get-default-value.ts @@ -1,9 +1,9 @@ import type { SchemaOverview } from '@directus/schema/types/overview'; -import { parseJSON } from '@directus/shared/utils'; -import type { Column } from 'knex-schema-inspector/dist/types/column'; -import env from '../env'; -import logger from '../logger'; -import getLocalType from './get-local-type'; +import { parseJSON } from '@directus/utils'; +import type { Column } from '@directus/schema'; +import env from '../env.js'; +import logger from '../logger.js'; +import getLocalType from './get-local-type.js'; export default function getDefaultValue( column: SchemaOverview[string]['columns'][string] | Column diff --git a/api/src/utils/get-graphql-query-and-variables.test.ts b/api/src/utils/get-graphql-query-and-variables.test.ts index d18e702e73..24f9dc8303 100644 --- a/api/src/utils/get-graphql-query-and-variables.test.ts +++ b/api/src/utils/get-graphql-query-and-variables.test.ts @@ -1,7 +1,7 @@ import type { Request } from 'express'; import { expect, test } from 'vitest'; -import { getGraphqlQueryAndVariables } from './get-graphql-query-and-variables'; +import { getGraphqlQueryAndVariables } from './get-graphql-query-and-variables.js'; const query = ` query getProduct($id: ID!) { diff --git a/api/src/utils/get-graphql-query-and-variables.ts b/api/src/utils/get-graphql-query-and-variables.ts index d951c48412..6f0ccccfa7 100644 --- a/api/src/utils/get-graphql-query-and-variables.ts +++ b/api/src/utils/get-graphql-query-and-variables.ts @@ -1,5 +1,5 @@ import type { Request } from 'express'; -import { pick } from 'lodash'; +import { pick } from 'lodash-es'; export function getGraphqlQueryAndVariables(req: Request) { const isGet = req.method?.toLowerCase() === 'get'; diff --git a/api/src/utils/get-graphql-type.ts b/api/src/utils/get-graphql-type.ts index 53728a357b..acec3878cc 100644 --- a/api/src/utils/get-graphql-type.ts +++ b/api/src/utils/get-graphql-type.ts @@ -1,4 +1,4 @@ -import type { Type } from '@directus/shared/types'; +import type { Type } from '@directus/types'; import { GraphQLBoolean, GraphQLFloat, @@ -9,10 +9,10 @@ import { GraphQLType, } from 'graphql'; import { GraphQLJSON } from 'graphql-compose'; -import { GraphQLBigInt } from '../services/graphql/types/bigint'; -import { GraphQLDate } from '../services/graphql/types/date'; -import { GraphQLGeoJSON } from '../services/graphql/types/geojson'; -import { GraphQLHash } from '../services/graphql/types/hash'; +import { GraphQLBigInt } from '../services/graphql/types/bigint.js'; +import { GraphQLDate } from '../services/graphql/types/date.js'; +import { GraphQLGeoJSON } from '../services/graphql/types/geojson.js'; +import { GraphQLHash } from '../services/graphql/types/hash.js'; export function getGraphQLType( localType: Type | 'alias' | 'unknown', diff --git a/api/src/utils/get-ip-from-req.ts b/api/src/utils/get-ip-from-req.ts index 86888d8655..75d725546d 100644 --- a/api/src/utils/get-ip-from-req.ts +++ b/api/src/utils/get-ip-from-req.ts @@ -1,7 +1,7 @@ import type { Request } from 'express'; import { isIP } from 'net'; -import env from '../env'; -import logger from '../logger'; +import env from '../env.js'; +import logger from '../logger.js'; export function getIPFromReq(req: Request): string { let ip = req.ip; diff --git a/api/src/utils/get-local-type.ts b/api/src/utils/get-local-type.ts index cc8b0cadb4..fb66a124af 100644 --- a/api/src/utils/get-local-type.ts +++ b/api/src/utils/get-local-type.ts @@ -1,4 +1,4 @@ -import type { FieldMeta, Type } from '@directus/shared/types'; +import type { FieldMeta, Type } from '@directus/types'; const localTypeMap: Record = { // Shared diff --git a/api/src/utils/get-milliseconds.test.ts b/api/src/utils/get-milliseconds.test.ts index b9a0f683a2..39554ab604 100644 --- a/api/src/utils/get-milliseconds.test.ts +++ b/api/src/utils/get-milliseconds.test.ts @@ -1,5 +1,5 @@ import { expect, test } from 'vitest'; -import { getMilliseconds } from './get-milliseconds'; +import { getMilliseconds } from './get-milliseconds.js'; test.each([ // accept human readable time format and plain number diff --git a/api/src/utils/get-permissions.ts b/api/src/utils/get-permissions.ts index 870653c734..cd97d5d599 100644 --- a/api/src/utils/get-permissions.ts +++ b/api/src/utils/get-permissions.ts @@ -1,16 +1,16 @@ -import type { Accountability, Permission, SchemaOverview } from '@directus/shared/types'; -import { deepMap, parseFilter, parseJSON, parsePreset } from '@directus/shared/utils'; -import { cloneDeep } from 'lodash'; +import type { Accountability, Permission, SchemaOverview } from '@directus/types'; +import { deepMap, parseFilter, parseJSON, parsePreset } from '@directus/utils'; +import { cloneDeep } from 'lodash-es'; import hash from 'object-hash'; -import { getCache, getCacheValue, getSystemCache, setCacheValue, setSystemCache } from '../cache'; -import getDatabase from '../database'; -import { appAccessMinimalPermissions } from '../database/system-data/app-access-permissions'; -import env from '../env'; -import logger from '../logger'; -import { RolesService } from '../services/roles'; -import { UsersService } from '../services/users'; -import { mergePermissions } from '../utils/merge-permissions'; -import { mergePermissionsForShare } from './merge-permissions-for-share'; +import { getCache, getCacheValue, getSystemCache, setCacheValue, setSystemCache } from '../cache.js'; +import getDatabase from '../database/index.js'; +import { appAccessMinimalPermissions } from '../database/system-data/app-access-permissions/index.js'; +import env from '../env.js'; +import logger from '../logger.js'; +import { RolesService } from '../services/roles.js'; +import { UsersService } from '../services/users.js'; +import { mergePermissions } from '../utils/merge-permissions.js'; +import { mergePermissionsForShare } from './merge-permissions-for-share.js'; export async function getPermissions(accountability: Accountability, schema: SchemaOverview) { const database = getDatabase(); diff --git a/api/src/utils/get-relation-info.test.ts b/api/src/utils/get-relation-info.test.ts index 6f6a257d0c..a2732678aa 100644 --- a/api/src/utils/get-relation-info.test.ts +++ b/api/src/utils/get-relation-info.test.ts @@ -1,6 +1,6 @@ -import type { DeepPartial, Relation } from '@directus/shared/types'; +import type { DeepPartial, Relation } from '@directus/types'; import { describe, expect, it } from 'vitest'; -import { getRelationInfo } from '../../src/utils/get-relation-info'; +import { getRelationInfo } from '../../src/utils/get-relation-info.js'; describe('getRelationInfo', () => { it('Errors on suspiciously long implicit $FOLLOW', () => { diff --git a/api/src/utils/get-relation-info.ts b/api/src/utils/get-relation-info.ts index 3f97eb4a6c..c6af6cce68 100644 --- a/api/src/utils/get-relation-info.ts +++ b/api/src/utils/get-relation-info.ts @@ -1,5 +1,5 @@ -import type { Relation, RelationMeta } from '@directus/shared/types'; -import { getRelationType } from './get-relation-type'; +import type { Relation, RelationMeta } from '@directus/types'; +import { getRelationType } from './get-relation-type.js'; type RelationInfo = { relation: Relation | null; diff --git a/api/src/utils/get-relation-type.test.ts b/api/src/utils/get-relation-type.test.ts index 106dd885ad..21a6882f05 100644 --- a/api/src/utils/get-relation-type.test.ts +++ b/api/src/utils/get-relation-type.test.ts @@ -1,6 +1,6 @@ -import type { Relation } from '@directus/shared/types'; +import type { Relation } from '@directus/types'; import { expect, test } from 'vitest'; -import { getRelationType } from '../../src/utils/get-relation-type'; +import { getRelationType } from '../../src/utils/get-relation-type.js'; test('Returns null if no relation object is included', () => { const result = getRelationType({ relation: null, collection: null, field: 'test' }); diff --git a/api/src/utils/get-relation-type.ts b/api/src/utils/get-relation-type.ts index 302003cd1d..687e842ae5 100644 --- a/api/src/utils/get-relation-type.ts +++ b/api/src/utils/get-relation-type.ts @@ -1,4 +1,4 @@ -import type { Relation } from '@directus/shared/types'; +import type { Relation } from '@directus/types'; export function getRelationType(getRelationOptions: { relation?: Relation | null; diff --git a/api/src/utils/get-schema.ts b/api/src/utils/get-schema.ts index 5767d25ee8..a190e7ac6f 100644 --- a/api/src/utils/get-schema.ts +++ b/api/src/utils/get-schema.ts @@ -1,18 +1,19 @@ -import SchemaInspector from '@directus/schema'; -import type { Filter, SchemaOverview } from '@directus/shared/types'; -import { parseJSON, toArray } from '@directus/shared/utils'; +import type { SchemaInspector } from '@directus/schema'; +import { createInspector } from '@directus/schema'; +import type { Filter, SchemaOverview } from '@directus/types'; +import { parseJSON, toArray } from '@directus/utils'; import type { Knex } from 'knex'; -import { mapValues } from 'lodash'; -import { getSchemaCache, setSchemaCache } from '../cache'; -import { ALIAS_TYPES } from '../constants'; -import getDatabase from '../database'; -import { systemCollectionRows } from '../database/system-data/collections'; -import { systemFieldRows } from '../database/system-data/fields'; -import env from '../env'; -import logger from '../logger'; -import { RelationsService } from '../services'; -import getDefaultValue from './get-default-value'; -import getLocalType from './get-local-type'; +import { mapValues } from 'lodash-es'; +import { getSchemaCache, setSchemaCache } from '../cache.js'; +import { ALIAS_TYPES } from '../constants.js'; +import getDatabase from '../database/index.js'; +import { systemCollectionRows } from '../database/system-data/collections/index.js'; +import { systemFieldRows } from '../database/system-data/fields/index.js'; +import env from '../env.js'; +import logger from '../logger.js'; +import { RelationsService } from '../services/relations.js'; +import getDefaultValue from './get-default-value.js'; +import getLocalType from './get-local-type.js'; export async function getSchema(options?: { database?: Knex; @@ -24,7 +25,7 @@ export async function getSchema(options?: { bypassCache?: boolean; }): Promise { const database = options?.database || getDatabase(); - const schemaInspector = SchemaInspector(database); + const schemaInspector = createInspector(database); let result: SchemaOverview; @@ -55,10 +56,7 @@ export async function getSchema(options?: { return result; } -async function getDatabaseSchema( - database: Knex, - schemaInspector: ReturnType -): Promise { +async function getDatabaseSchema(database: Knex, schemaInspector: SchemaInspector): Promise { const result: SchemaOverview = { collections: {}, relations: [], diff --git a/api/src/utils/get-snapshot-diff.ts b/api/src/utils/get-snapshot-diff.ts index 95bbd775b2..cf6dd62c06 100644 --- a/api/src/utils/get-snapshot-diff.ts +++ b/api/src/utils/get-snapshot-diff.ts @@ -1,7 +1,7 @@ -import { diff } from 'deep-diff'; -import { orderBy } from 'lodash'; -import { Snapshot, SnapshotDiff, DiffKind } from '../types'; -import { sanitizeCollection, sanitizeField, sanitizeRelation } from './sanitize-schema'; +import deepDiff from 'deep-diff'; +import { orderBy } from 'lodash-es'; +import { Snapshot, SnapshotDiff, DiffKind } from '../types/index.js'; +import { sanitizeCollection, sanitizeField, sanitizeRelation } from './sanitize-schema.js'; export function getSnapshotDiff(current: Snapshot, after: Snapshot): SnapshotDiff { const diffedSnapshot: SnapshotDiff = { @@ -14,7 +14,7 @@ export function getSnapshotDiff(current: Snapshot, after: Snapshot): SnapshotDif return { collection: currentCollection.collection, - diff: diff(sanitizeCollection(currentCollection), sanitizeCollection(afterCollection)), + diff: deepDiff.diff(sanitizeCollection(currentCollection), sanitizeCollection(afterCollection)), }; }), ...after.collections @@ -27,7 +27,7 @@ export function getSnapshotDiff(current: Snapshot, after: Snapshot): SnapshotDif }) .map((afterCollection) => ({ collection: afterCollection.collection, - diff: diff(undefined, sanitizeCollection(afterCollection)), + diff: deepDiff.diff(undefined, sanitizeCollection(afterCollection)), })), ].filter((obj) => Array.isArray(obj.diff)) as SnapshotDiff['collections'], 'collection' @@ -45,7 +45,7 @@ export function getSnapshotDiff(current: Snapshot, after: Snapshot): SnapshotDif return { collection: currentField.collection, field: currentField.field, - diff: diff( + diff: deepDiff.diff( sanitizeField(currentField, isAutoIncrementPrimaryKey), sanitizeField(afterField, isAutoIncrementPrimaryKey) ), @@ -63,7 +63,7 @@ export function getSnapshotDiff(current: Snapshot, after: Snapshot): SnapshotDif .map((afterField) => ({ collection: afterField.collection, field: afterField.field, - diff: diff(undefined, sanitizeField(afterField)), + diff: deepDiff.diff(undefined, sanitizeField(afterField)), })), ].filter((obj) => Array.isArray(obj.diff)) as SnapshotDiff['fields'], ['collection'] @@ -80,7 +80,7 @@ export function getSnapshotDiff(current: Snapshot, after: Snapshot): SnapshotDif collection: currentRelation.collection, field: currentRelation.field, related_collection: currentRelation.related_collection, - diff: diff(sanitizeRelation(currentRelation), sanitizeRelation(afterRelation)), + diff: deepDiff.diff(sanitizeRelation(currentRelation), sanitizeRelation(afterRelation)), }; }), ...after.relations @@ -96,7 +96,7 @@ export function getSnapshotDiff(current: Snapshot, after: Snapshot): SnapshotDif collection: afterRelation.collection, field: afterRelation.field, related_collection: afterRelation.related_collection, - diff: diff(undefined, sanitizeRelation(afterRelation)), + diff: deepDiff.diff(undefined, sanitizeRelation(afterRelation)), })), ].filter((obj) => Array.isArray(obj.diff)) as SnapshotDiff['relations'], ['collection'] diff --git a/api/src/utils/get-snapshot.ts b/api/src/utils/get-snapshot.ts index 292cc533a4..de41964203 100644 --- a/api/src/utils/get-snapshot.ts +++ b/api/src/utils/get-snapshot.ts @@ -1,12 +1,14 @@ -import type { SchemaOverview } from '@directus/shared/types'; +import type { SchemaOverview } from '@directus/types'; import type { Knex } from 'knex'; -import { fromPairs, isArray, isPlainObject, mapValues, omit, sortBy, toPairs } from 'lodash'; -import { version } from '../../package.json'; -import getDatabase, { getDatabaseClient } from '../database'; -import { CollectionsService, FieldsService, RelationsService } from '../services'; -import type { Collection, Snapshot, SnapshotField, SnapshotRelation } from '../types'; -import { getSchema } from './get-schema'; -import { sanitizeCollection, sanitizeField, sanitizeRelation } from './sanitize-schema'; +import { fromPairs, isArray, isPlainObject, mapValues, omit, sortBy, toPairs } from 'lodash-es'; +import getDatabase, { getDatabaseClient } from '../database/index.js'; +import { CollectionsService } from '../services/collections.js'; +import { FieldsService } from '../services/fields.js'; +import { RelationsService } from '../services/relations.js'; +import type { Collection, Snapshot, SnapshotField, SnapshotRelation } from '../types/index.js'; +import { getSchema } from './get-schema.js'; +import { version } from './package.js'; +import { sanitizeCollection, sanitizeField, sanitizeRelation } from './sanitize-schema.js'; export async function getSnapshot(options?: { database?: Knex; schema?: SchemaOverview }): Promise { const database = options?.database ?? getDatabase(); diff --git a/api/src/utils/get-string-byte-size.test.ts b/api/src/utils/get-string-byte-size.test.ts index 6ca5121063..dc857f7eac 100644 --- a/api/src/utils/get-string-byte-size.test.ts +++ b/api/src/utils/get-string-byte-size.test.ts @@ -1,4 +1,4 @@ -import { stringByteSize } from '../../src/utils/get-string-byte-size'; +import { stringByteSize } from '../../src/utils/get-string-byte-size.js'; import { test, expect } from 'vitest'; test('Returns correct byte size for given input string', () => { diff --git a/api/src/utils/get-versioned-hash.test.ts b/api/src/utils/get-versioned-hash.test.ts index de8bacd38c..54ffebe846 100644 --- a/api/src/utils/get-versioned-hash.test.ts +++ b/api/src/utils/get-versioned-hash.test.ts @@ -1,8 +1,8 @@ import { test, expect, describe, vi } from 'vitest'; -import { getVersionedHash } from './get-versioned-hash'; +import { getVersionedHash } from './get-versioned-hash.js'; -vi.mock('../../package.json', () => ({ +vi.mock('./package.js', () => ({ version: '10.10.10', })); diff --git a/api/src/utils/get-versioned-hash.ts b/api/src/utils/get-versioned-hash.ts index 8d96b0aa83..320c70f37c 100644 --- a/api/src/utils/get-versioned-hash.ts +++ b/api/src/utils/get-versioned-hash.ts @@ -1,5 +1,5 @@ import hash from 'object-hash'; -import { version } from '../../package.json'; +import { version } from './package.js'; export function getVersionedHash(item: Record): string { return hash({ item, version }); diff --git a/api/src/utils/is-directus-jwt.test.ts b/api/src/utils/is-directus-jwt.test.ts index 73a33f8a4e..1cebfcddef 100644 --- a/api/src/utils/is-directus-jwt.test.ts +++ b/api/src/utils/is-directus-jwt.test.ts @@ -1,4 +1,4 @@ -import isDirectusJWT from '../../src/utils/is-directus-jwt'; +import isDirectusJWT from '../../src/utils/is-directus-jwt.js'; import jwt from 'jsonwebtoken'; import { test, expect } from 'vitest'; diff --git a/api/src/utils/is-url-allowed.ts b/api/src/utils/is-url-allowed.ts index c56981baab..17e113fa20 100644 --- a/api/src/utils/is-url-allowed.ts +++ b/api/src/utils/is-url-allowed.ts @@ -1,5 +1,5 @@ -import { toArray } from '@directus/shared/utils'; -import logger from '../logger'; +import { toArray } from '@directus/utils'; +import logger from '../logger.js'; import { URL } from 'url'; /** diff --git a/api/src/utils/jwt.test.ts b/api/src/utils/jwt.test.ts index 6ca6253983..5bb5590e86 100644 --- a/api/src/utils/jwt.test.ts +++ b/api/src/utils/jwt.test.ts @@ -1,8 +1,12 @@ import jwt from 'jsonwebtoken'; import { expect, test, vi } from 'vitest'; -import { InvalidTokenException, ServiceUnavailableException, TokenExpiredException } from '../../src/exceptions'; -import type { DirectusTokenPayload } from '../../src/types'; -import { verifyAccessJWT } from '../../src/utils/jwt'; +import { + InvalidTokenException, + ServiceUnavailableException, + TokenExpiredException, +} from '../../src/exceptions/index.js'; +import type { DirectusTokenPayload } from '../../src/types/index.js'; +import { verifyAccessJWT } from '../../src/utils/jwt.js'; const payload: DirectusTokenPayload = { role: null, app_access: false, admin_access: false }; const secret = 'test-secret'; diff --git a/api/src/utils/jwt.ts b/api/src/utils/jwt.ts index 29c0ebdefa..21929bc990 100644 --- a/api/src/utils/jwt.ts +++ b/api/src/utils/jwt.ts @@ -1,6 +1,6 @@ -import jwt, { JsonWebTokenError, TokenExpiredError } from 'jsonwebtoken'; -import { InvalidTokenException, ServiceUnavailableException, TokenExpiredException } from '../exceptions'; -import type { DirectusTokenPayload } from '../types'; +import jwt from 'jsonwebtoken'; +import { InvalidTokenException, ServiceUnavailableException, TokenExpiredException } from '../exceptions/index.js'; +import type { DirectusTokenPayload } from '../types/index.js'; export function verifyAccessJWT(token: string, secret: string): DirectusTokenPayload { let payload; @@ -10,9 +10,9 @@ export function verifyAccessJWT(token: string, secret: string): DirectusTokenPay issuer: 'directus', }) as Record; } catch (err) { - if (err instanceof TokenExpiredError) { + if (err instanceof jwt.TokenExpiredError) { throw new TokenExpiredException(); - } else if (err instanceof JsonWebTokenError) { + } else if (err instanceof jwt.JsonWebTokenError) { throw new InvalidTokenException('Token invalid.'); } else { throw new ServiceUnavailableException(`Couldn't verify token.`, { service: 'jwt' }); diff --git a/api/src/utils/map-values-deep.test.ts b/api/src/utils/map-values-deep.test.ts index 9396d00f5a..741a3a4cf7 100644 --- a/api/src/utils/map-values-deep.test.ts +++ b/api/src/utils/map-values-deep.test.ts @@ -1,5 +1,5 @@ import { test, expect } from 'vitest'; -import { mapValuesDeep } from './map-values-deep'; +import { mapValuesDeep } from './map-values-deep.js'; test('Replace all undefined values with null', () => { const obj = { a: { b: { c: undefined } }, b: 'test' }; diff --git a/api/src/utils/md.test.ts b/api/src/utils/md.test.ts index 5777bb6a5d..476cffaada 100644 --- a/api/src/utils/md.test.ts +++ b/api/src/utils/md.test.ts @@ -1,6 +1,6 @@ import { expect, test } from 'vitest'; -import { md } from './md'; +import { md } from './md.js'; test.each([ { str: 'test', expected: '

test

\n' }, diff --git a/api/src/utils/merge-permissions-for-share.ts b/api/src/utils/merge-permissions-for-share.ts index 3b09c70cba..c9cb5647c4 100644 --- a/api/src/utils/merge-permissions-for-share.ts +++ b/api/src/utils/merge-permissions-for-share.ts @@ -1,9 +1,8 @@ -import type { Permission, Accountability, Filter, SchemaOverview } from '@directus/shared/types'; - -import { assign, set, uniq } from 'lodash'; -import { mergePermissions } from './merge-permissions'; -import { schemaPermissions } from '../database/system-data/app-access-permissions'; -import { reduceSchema } from './reduce-schema'; +import type { Accountability, Filter, Permission, SchemaOverview } from '@directus/types'; +import { assign, set, uniq } from 'lodash-es'; +import { schemaPermissions } from '../database/system-data/app-access-permissions/index.js'; +import { mergePermissions } from './merge-permissions.js'; +import { reduceSchema } from './reduce-schema.js'; export function mergePermissionsForShare( currentPermissions: Permission[], diff --git a/api/src/utils/merge-permissions.test.ts b/api/src/utils/merge-permissions.test.ts index 61ffd8177e..e9ae3cf3ff 100644 --- a/api/src/utils/merge-permissions.test.ts +++ b/api/src/utils/merge-permissions.test.ts @@ -1,6 +1,6 @@ -import type { Filter, Permission } from '@directus/shared/types'; +import type { Filter, Permission } from '@directus/types'; import { describe, expect, test } from 'vitest'; -import { mergePermission } from '../../src/utils/merge-permissions'; +import { mergePermission } from './merge-permissions.js'; const fullFilter = {} as Filter; const conditionalFilter = { user: { id: { _eq: '$CURRENT_USER' } } } as Filter; diff --git a/api/src/utils/merge-permissions.ts b/api/src/utils/merge-permissions.ts index 3e36addd57..b78554f9af 100644 --- a/api/src/utils/merge-permissions.ts +++ b/api/src/utils/merge-permissions.ts @@ -1,5 +1,5 @@ -import type { LogicalFilterAND, LogicalFilterOR, Permission } from '@directus/shared/types'; -import { flatten, intersection, isEqual, merge, omit } from 'lodash'; +import type { LogicalFilterAND, LogicalFilterOR, Permission } from '@directus/types'; +import { flatten, intersection, isEqual, merge, omit } from 'lodash-es'; export function mergePermissions(strategy: 'and' | 'or', ...permissions: Permission[][]): Permission[] { const allPermissions = flatten(permissions); diff --git a/api/src/utils/package.ts b/api/src/utils/package.ts new file mode 100644 index 0000000000..d9729880a4 --- /dev/null +++ b/api/src/utils/package.ts @@ -0,0 +1,12 @@ +import { readFileSync } from 'node:fs'; +import { dirname, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); + +const { name, version } = JSON.parse(readFileSync(resolve(__dirname, '../../package.json'), 'utf8')) as { + name: string; + version: string; +}; + +export { name, version }; diff --git a/api/src/utils/reduce-schema.ts b/api/src/utils/reduce-schema.ts index f5d08e6367..237673b108 100644 --- a/api/src/utils/reduce-schema.ts +++ b/api/src/utils/reduce-schema.ts @@ -1,5 +1,5 @@ -import type { Permission, PermissionsAction, SchemaOverview } from '@directus/shared/types'; -import { uniq } from 'lodash'; +import type { Permission, PermissionsAction, SchemaOverview } from '@directus/types'; +import { uniq } from 'lodash-es'; /** * Reduces the schema based on the included permissions. The resulting object is the schema structure, but with only diff --git a/api/src/utils/require-yaml.ts b/api/src/utils/require-yaml.ts index c3b69fb534..db07f2cbf7 100644 --- a/api/src/utils/require-yaml.ts +++ b/api/src/utils/require-yaml.ts @@ -3,6 +3,5 @@ import yaml from 'js-yaml'; export function requireYAML(filepath: string): Record { const yamlRaw = fse.readFileSync(filepath, 'utf8'); - return yaml.load(yamlRaw) as Record; } diff --git a/api/src/utils/sanitize-query.test.ts b/api/src/utils/sanitize-query.test.ts index 114a66c26d..ad63f2e9ee 100644 --- a/api/src/utils/sanitize-query.test.ts +++ b/api/src/utils/sanitize-query.test.ts @@ -1,9 +1,9 @@ import { describe, expect, test, vi } from 'vitest'; -import { sanitizeQuery } from './sanitize-query'; +import { sanitizeQuery } from './sanitize-query.js'; -vi.mock('@directus/shared/utils', async () => { - const actual = (await vi.importActual('@directus/shared/utils')) as any; +vi.mock('@directus/utils', async () => { + const actual = (await vi.importActual('@directus/utils')) as any; return { ...actual, diff --git a/api/src/utils/sanitize-query.ts b/api/src/utils/sanitize-query.ts index 7dbf9112e3..c51436e531 100644 --- a/api/src/utils/sanitize-query.ts +++ b/api/src/utils/sanitize-query.ts @@ -1,8 +1,8 @@ -import type { Accountability, Aggregate, Filter, Query } from '@directus/shared/types'; -import { parseFilter, parseJSON } from '@directus/shared/utils'; -import { flatten, get, isPlainObject, merge, set } from 'lodash'; -import logger from '../logger'; -import { Meta } from '../types'; +import type { Accountability, Aggregate, Filter, Query } from '@directus/types'; +import { parseFilter, parseJSON } from '@directus/utils'; +import { flatten, get, isPlainObject, merge, set } from 'lodash-es'; +import logger from '../logger.js'; +import { Meta } from '../types/index.js'; export function sanitizeQuery(rawQuery: Record, accountability?: Accountability | null): Query { const query: Query = {}; diff --git a/api/src/utils/sanitize-schema.test.ts b/api/src/utils/sanitize-schema.test.ts index 01ecf6f159..ba7e9e2c07 100644 --- a/api/src/utils/sanitize-schema.test.ts +++ b/api/src/utils/sanitize-schema.test.ts @@ -1,8 +1,7 @@ -import type { Field, Relation } from '@directus/shared/types'; +import type { Field, Relation } from '@directus/types'; import { expect, test, describe } from 'vitest'; -import type { Collection } from '../types'; - -import { sanitizeCollection, sanitizeField, sanitizeRelation } from './sanitize-schema'; +import type { Collection } from '../types/index.js'; +import { sanitizeCollection, sanitizeField, sanitizeRelation } from './sanitize-schema.js'; describe('sanitizeCollection', () => { test.each([ diff --git a/api/src/utils/sanitize-schema.ts b/api/src/utils/sanitize-schema.ts index 15e0b39199..a4743865e3 100644 --- a/api/src/utils/sanitize-schema.ts +++ b/api/src/utils/sanitize-schema.ts @@ -1,14 +1,12 @@ -import type { Field, Relation } from '@directus/shared/types'; -import { pick } from 'lodash'; -import type { Collection } from '../types'; +import type { Field, Relation } from '@directus/types'; +import { pick } from 'lodash-es'; +import type { Collection } from '../types/index.js'; /** * Pick certain database vendor specific collection properties that should be compared when performing diff * * @param collection collection to sanitize * @returns sanitized collection - * - * @see {@link https://github.com/knex/knex-schema-inspector/blob/master/lib/types/table.ts} */ export function sanitizeCollection(collection: Collection | undefined) { @@ -23,8 +21,6 @@ export function sanitizeCollection(collection: Collection | undefined) { * @param field field to sanitize * @param sanitizeAllSchema Whether or not the whole field schema should be sanitized. Mainly used to prevent modifying autoincrement fields * @returns sanitized field - * - * @see {@link https://github.com/knex/knex-schema-inspector/blob/master/lib/types/column.ts} */ export function sanitizeField(field: Field | undefined, sanitizeAllSchema = false) { if (!field) return field; @@ -59,8 +55,6 @@ export function sanitizeField(field: Field | undefined, sanitizeAllSchema = fals * * @param relation relation to sanitize * @returns sanitized relation - * - * @see {@link https://github.com/knex/knex-schema-inspector/blob/master/lib/types/foreign-key.ts} */ export function sanitizeRelation(relation: Relation | undefined) { if (!relation) return relation; diff --git a/api/src/utils/should-skip-cache.test.ts b/api/src/utils/should-skip-cache.test.ts index 920da0cab8..36796c8eb2 100644 --- a/api/src/utils/should-skip-cache.test.ts +++ b/api/src/utils/should-skip-cache.test.ts @@ -1,7 +1,7 @@ import type { Request } from 'express'; import { expect, test, vi } from 'vitest'; -import { getEnv } from '../env'; -import { shouldSkipCache } from './should-skip-cache'; +import { getEnv } from '../env.js'; +import { shouldSkipCache } from './should-skip-cache.js'; vi.mock('../env'); diff --git a/api/src/utils/should-skip-cache.ts b/api/src/utils/should-skip-cache.ts index e5374777d7..6e543d1df9 100644 --- a/api/src/utils/should-skip-cache.ts +++ b/api/src/utils/should-skip-cache.ts @@ -1,6 +1,6 @@ import type { Request } from 'express'; -import { getEnv } from '../env'; -import { Url } from './url'; +import { getEnv } from '../env.js'; +import { Url } from './url.js'; /** * Whether to skip caching for the current request diff --git a/api/src/utils/stall.test.ts b/api/src/utils/stall.test.ts index e427be5341..e09dfe7ffe 100644 --- a/api/src/utils/stall.test.ts +++ b/api/src/utils/stall.test.ts @@ -1,6 +1,5 @@ import { afterAll, beforeAll, expect, SpyInstance, test, vi } from 'vitest'; - -import { stall } from './stall'; +import { stall } from './stall.js'; let performanceNowSpy: SpyInstance; diff --git a/api/src/utils/strip-function.test.ts b/api/src/utils/strip-function.test.ts index e994021a5b..e2dfa0d583 100644 --- a/api/src/utils/strip-function.test.ts +++ b/api/src/utils/strip-function.test.ts @@ -1,6 +1,5 @@ import { expect, test } from 'vitest'; - -import { stripFunction } from './strip-function'; +import { stripFunction } from './strip-function.js'; test.each([ { field: 'year(date_created)', expected: 'date_created' }, diff --git a/api/src/utils/strip-function.ts b/api/src/utils/strip-function.ts index 9e502011d6..58763a08a2 100644 --- a/api/src/utils/strip-function.ts +++ b/api/src/utils/strip-function.ts @@ -1,4 +1,4 @@ -import { REGEX_BETWEEN_PARENS } from '@directus/shared/constants'; +import { REGEX_BETWEEN_PARENS } from '@directus/constants'; /** * Strip the function declarations from a list of fields diff --git a/api/src/utils/telemetry.ts b/api/src/utils/telemetry.ts index 1eb73e07de..7a9d37fc0b 100644 --- a/api/src/utils/telemetry.ts +++ b/api/src/utils/telemetry.ts @@ -1,7 +1,7 @@ -import { machineId } from 'node-machine-id'; -import { version } from '../../package.json'; -import env from '../env'; -import logger from '../logger'; +import mid from 'node-machine-id'; +import env from '../env.js'; +import logger from '../logger.js'; +import { version } from './package.js'; export async function collectTelemetry(): Promise { const axios = (await import('axios')).default; @@ -12,7 +12,7 @@ export async function collectTelemetry(): Promise { version: version, public_url: env['PUBLIC_URL'], project_id: env['KEY'], - machine_id: await machineId(), + machine_id: await mid.machineId(), db_client: env['DB_CLIENT'], }); } catch (err: any) { diff --git a/api/src/utils/transformations.ts b/api/src/utils/transformations.ts index f63e0e109e..a9c6972fc6 100644 --- a/api/src/utils/transformations.ts +++ b/api/src/utils/transformations.ts @@ -1,4 +1,4 @@ -import { isNil } from 'lodash'; +import { isNil } from 'lodash-es'; import type { File, Transformation, @@ -6,7 +6,7 @@ import type { TransformationPreset, TransformationPresetFormat, TransformationPresetResize, -} from '../types'; +} from '../types/index.js'; // Extract transforms from a preset export function resolvePreset(input: TransformationParams | TransformationPreset, file: File): Transformation[] { diff --git a/api/src/utils/url.test.ts b/api/src/utils/url.test.ts index 5e414d586a..92d4a6048f 100644 --- a/api/src/utils/url.test.ts +++ b/api/src/utils/url.test.ts @@ -1,5 +1,5 @@ import { expect, test, describe } from 'vitest'; -import { Url } from './url'; +import { Url } from './url.js'; describe('path handling', () => { test('parse and serialize an URL without path', () => { diff --git a/api/src/utils/user-name.test.ts b/api/src/utils/user-name.test.ts index 17b9181069..0497cd4a40 100644 --- a/api/src/utils/user-name.test.ts +++ b/api/src/utils/user-name.test.ts @@ -1,6 +1,5 @@ import { expect, test } from 'vitest'; - -import { userName } from './user-name'; +import { userName } from './user-name.js'; const unknownUser = 'Unknown User'; diff --git a/api/src/utils/user-name.ts b/api/src/utils/user-name.ts index 76c0d82658..57240c7579 100644 --- a/api/src/utils/user-name.ts +++ b/api/src/utils/user-name.ts @@ -1,4 +1,4 @@ -import type { User } from '@directus/shared/types'; +import type { User } from '@directus/types'; export function userName(user: Partial): string { if (!user) { diff --git a/api/src/utils/validate-diff.test.ts b/api/src/utils/validate-diff.test.ts index 1bec43ce0a..5d59f63a91 100644 --- a/api/src/utils/validate-diff.test.ts +++ b/api/src/utils/validate-diff.test.ts @@ -1,5 +1,5 @@ import { describe, expect, test } from 'vitest'; -import type { Collection } from '../types/collection'; +import type { Collection } from '../types/collection.js'; import type { Snapshot, SnapshotDiff, @@ -7,8 +7,8 @@ import type { SnapshotField, SnapshotRelation, SnapshotWithHash, -} from '../types/snapshot'; -import { validateApplyDiff } from './validate-diff'; +} from '../types/snapshot.js'; +import { validateApplyDiff } from './validate-diff.js'; test('should fail on invalid diff schema', () => { const diff = {} as SnapshotDiffWithHash; diff --git a/api/src/utils/validate-diff.ts b/api/src/utils/validate-diff.ts index 2cf4b77049..ac21226280 100644 --- a/api/src/utils/validate-diff.ts +++ b/api/src/utils/validate-diff.ts @@ -1,6 +1,6 @@ import Joi from 'joi'; -import { InvalidPayloadException } from '../index'; -import { DiffKind, SnapshotDiffWithHash, SnapshotWithHash } from '../types/snapshot'; +import { InvalidPayloadException } from '../exceptions/invalid-payload.js'; +import { DiffKind, SnapshotDiffWithHash, SnapshotWithHash } from '../types/snapshot.js'; const deepDiffSchema = Joi.object({ kind: Joi.string() diff --git a/api/src/utils/validate-env.test.ts b/api/src/utils/validate-env.test.ts index 6b7efce56d..f6f79996e9 100644 --- a/api/src/utils/validate-env.test.ts +++ b/api/src/utils/validate-env.test.ts @@ -1,7 +1,7 @@ import { afterEach, beforeAll, expect, test, vi } from 'vitest'; -import { validateEnv } from './validate-env'; -import logger from '../logger'; +import { validateEnv } from './validate-env.js'; +import logger from '../logger.js'; vi.mock('../env', () => ({ getEnv: vi.fn().mockReturnValue({ diff --git a/api/src/utils/validate-env.ts b/api/src/utils/validate-env.ts index 26b5e53af7..f734e0e328 100644 --- a/api/src/utils/validate-env.ts +++ b/api/src/utils/validate-env.ts @@ -1,5 +1,5 @@ -import { getEnv } from '../env'; -import logger from '../logger'; +import { getEnv } from '../env.js'; +import logger from '../logger.js'; export function validateEnv(requiredKeys: string[]): void { const env = getEnv(); diff --git a/api/src/utils/validate-keys.test.ts b/api/src/utils/validate-keys.test.ts index 69377b5dbd..8722e508a6 100644 --- a/api/src/utils/validate-keys.test.ts +++ b/api/src/utils/validate-keys.test.ts @@ -1,7 +1,7 @@ -import type { SchemaOverview } from '@directus/shared/types'; +import type { SchemaOverview } from '@directus/types'; import { v4 as uuid } from 'uuid'; import { describe, expect, it } from 'vitest'; -import { validateKeys } from '../../src/utils/validate-keys'; +import { validateKeys } from '../../src/utils/validate-keys.js'; const schema: SchemaOverview = { collections: { diff --git a/api/src/utils/validate-keys.ts b/api/src/utils/validate-keys.ts index d8def3a7b1..d6ae6a6a69 100644 --- a/api/src/utils/validate-keys.ts +++ b/api/src/utils/validate-keys.ts @@ -1,7 +1,7 @@ -import type { SchemaOverview } from '@directus/shared/types'; +import type { SchemaOverview } from '@directus/types'; import validateUUID from 'uuid-validate'; -import { ForbiddenException } from '../exceptions'; -import type { PrimaryKey } from '../types'; +import { ForbiddenException } from '../exceptions/forbidden.js'; +import type { PrimaryKey } from '../types/index.js'; /** * Validate keys based on its type diff --git a/api/src/utils/validate-query.test.ts b/api/src/utils/validate-query.test.ts index d5924ff82a..1e1f5e61ec 100644 --- a/api/src/utils/validate-query.test.ts +++ b/api/src/utils/validate-query.test.ts @@ -1,5 +1,5 @@ import { describe, expect, test, vi } from 'vitest'; -import { validateQuery } from './validate-query'; +import { validateQuery } from './validate-query.js'; vi.mock('../env', async () => { const actual = (await vi.importActual('../env')) as { default: Record }; diff --git a/api/src/utils/validate-query.ts b/api/src/utils/validate-query.ts index 036310fc4e..6ec5b10a69 100644 --- a/api/src/utils/validate-query.ts +++ b/api/src/utils/validate-query.ts @@ -1,10 +1,10 @@ -import type { Query } from '@directus/shared/types'; +import type { Query } from '@directus/types'; import Joi from 'joi'; -import { isPlainObject, uniq } from 'lodash'; +import { isPlainObject, uniq } from 'lodash-es'; import { stringify } from 'wellknown'; -import env from '../env'; -import { InvalidQueryException } from '../exceptions'; -import { calculateFieldDepth } from './calculate-field-depth'; +import env from '../env.js'; +import { InvalidQueryException } from '../exceptions/invalid-query.js'; +import { calculateFieldDepth } from './calculate-field-depth.js'; const querySchema = Joi.object({ fields: Joi.array().items(Joi.string()), diff --git a/api/src/utils/validate-snapshot.test.ts b/api/src/utils/validate-snapshot.test.ts index 81d42a7889..cb9fafd1c3 100644 --- a/api/src/utils/validate-snapshot.test.ts +++ b/api/src/utils/validate-snapshot.test.ts @@ -1,12 +1,12 @@ import { describe, expect, test, vi } from 'vitest'; -import type { Snapshot } from '../types/snapshot'; -import { validateSnapshot } from './validate-snapshot'; +import type { Snapshot } from '../types/snapshot.js'; +import { validateSnapshot } from './validate-snapshot.js'; -vi.mock('../../package.json', () => ({ +vi.mock('./package.js', () => ({ version: '9.22.4', })); -vi.mock('../database', () => ({ +vi.mock('../database/index.js', () => ({ getDatabaseClient: () => 'sqlite', })); diff --git a/api/src/utils/validate-snapshot.ts b/api/src/utils/validate-snapshot.ts index 2a41440850..18241b201f 100644 --- a/api/src/utils/validate-snapshot.ts +++ b/api/src/utils/validate-snapshot.ts @@ -1,10 +1,10 @@ -import { version as currentDirectusVersion } from '../../package.json'; -import { InvalidPayloadException } from '../exceptions'; -import { getDatabaseClient } from '../database'; +import { version as currentDirectusVersion } from './package.js'; +import { InvalidPayloadException } from '../exceptions/invalid-payload.js'; +import { getDatabaseClient } from '../database/index.js'; import Joi from 'joi'; -import { TYPES } from '@directus/shared/constants'; -import { ALIAS_TYPES } from '../constants'; -import { DatabaseClients, Snapshot } from '../types'; +import { TYPES } from '@directus/constants'; +import { ALIAS_TYPES } from '../constants.js'; +import { DatabaseClients, Snapshot } from '../types/index.js'; const snapshotJoiSchema = Joi.object({ version: Joi.number().valid(1).required(), diff --git a/api/src/utils/validate-storage.ts b/api/src/utils/validate-storage.ts index 713fa0d08f..e4cc177892 100644 --- a/api/src/utils/validate-storage.ts +++ b/api/src/utils/validate-storage.ts @@ -1,9 +1,9 @@ -import env from '../env'; -import logger from '../logger'; -import { access } from 'fs-extra'; +import env from '../env.js'; +import logger from '../logger.js'; +import { access } from 'node:fs/promises'; import { constants } from 'fs'; import path from 'path'; -import { toArray } from '@directus/shared/utils'; +import { toArray } from '@directus/utils'; export async function validateStorage(): Promise { if (env['DB_CLIENT'] === 'sqlite3') { diff --git a/api/src/webhooks.ts b/api/src/webhooks.ts index b56481fe16..03919ad508 100644 --- a/api/src/webhooks.ts +++ b/api/src/webhooks.ts @@ -1,13 +1,13 @@ -import type { ActionHandler } from '@directus/shared/types'; -import getDatabase from './database'; -import emitter from './emitter'; -import logger from './logger'; -import { getMessenger } from './messenger'; -import { getAxios } from './request/index'; -import { WebhooksService } from './services'; -import type { Webhook, WebhookHeader } from './types'; -import { getSchema } from './utils/get-schema'; -import { JobQueue } from './utils/job-queue'; +import type { ActionHandler } from '@directus/types'; +import getDatabase from './database/index.js'; +import emitter from './emitter.js'; +import logger from './logger.js'; +import { getMessenger } from './messenger.js'; +import { getAxios } from './request/index.js'; +import { WebhooksService } from './services/webhooks.js'; +import type { Webhook, WebhookHeader } from './types/index.js'; +import { getSchema } from './utils/get-schema.js'; +import { JobQueue } from './utils/job-queue.js'; let registered: { event: string; handler: ActionHandler }[] = []; diff --git a/api/tsconfig.json b/api/tsconfig.json index ee8c497b5d..88e4147178 100644 --- a/api/tsconfig.json +++ b/api/tsconfig.json @@ -1,32 +1,7 @@ { + "extends": "@directus/tsconfig/node18-esm.json", "compilerOptions": { - "allowSyntheticDefaultImports": true, - "allowUnreachableCode": false, - "allowUnusedLabels": false, - "checkJs": true, - "declaration": true, - "esModuleInterop": true, - "exactOptionalPropertyTypes": true, - "forceConsistentCasingInFileNames": true, - "importsNotUsedAsValues": "error", - "lib": ["es2022"], - "module": "commonjs", - "moduleResolution": "node16", - "noFallthroughCasesInSwitch": true, - "noImplicitOverride": true, - "noImplicitReturns": true, - "noPropertyAccessFromIndexSignature": true, - "noUncheckedIndexedAccess": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "outDir": "dist", - "resolveJsonModule": true, - "rootDir": "src", - "skipLibCheck": true, - "sourceMap": false, - "strict": true, - "target": "es2022", + "outDir": "dist" }, - "include": ["src"], - "exclude": ["node_modules", "dist", "extensions"] + "include": ["src"] } diff --git a/api/vitest.config.js b/api/vitest.config.js deleted file mode 100644 index 03728ac2e2..0000000000 --- a/api/vitest.config.js +++ /dev/null @@ -1,15 +0,0 @@ -import { defineConfig } from 'vitest/config'; -import path from 'path'; - -export default defineConfig({ - test: { - globalSetup: 'globalSetup.js', - alias: [ - // TODO: Remove this after moving to ESM - { - find: '@directus/format-title', - replacement: path.resolve(__dirname, '../app/node_modules/@directus/format-title'), - }, - ], - }, -}); diff --git a/api/vitest.config.ts b/api/vitest.config.ts new file mode 100644 index 0000000000..8ddf3d536b --- /dev/null +++ b/api/vitest.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + globalSetup: ['./globalSetup.js'], + }, +}); diff --git a/app/package.json b/app/package.json index 818c2b0c86..5d1a38ef0c 100644 --- a/app/package.json +++ b/app/package.json @@ -3,6 +3,7 @@ "version": "9.24.0", "description": "App dashboard for Directus", "homepage": "https://directus.io", + "type": "module", "repository": { "type": "git", "url": "https://github.com/directus/directus.git", @@ -31,9 +32,12 @@ "devDependencies": { "@babel/core": "7.21.3", "@babel/preset-env": "7.20.2", + "@directus/constants": "workspace:*", + "@directus/exceptions": "workspace:*", "@directus/extensions-sdk": "workspace:*", "@directus/format-title": "10.0.0", - "@directus/shared": "workspace:*", + "@directus/types": "workspace:*", + "@directus/utils": "workspace:*", "@fortawesome/fontawesome-svg-core": "6.3.0", "@fortawesome/free-brands-svg-icons": "6.3.0", "@fullcalendar/core": "6.1.4", @@ -119,8 +123,8 @@ "qrcode": "1.5.1", "react": "18", "react-dom": "18", - "storybook": "7.0.0-rc.4", "sass": "1.59.3", + "storybook": "7.0.0-rc.4", "tinymce": "5.10.7", "typescript": "4.9.5", "vite": "4.1.4", @@ -134,5 +138,8 @@ }, "publishConfig": { "access": "public" + }, + "dependencies": { + "@directus/composables": "workspace:*" } } diff --git a/app/src/app.vue b/app/src/app.vue index 3b6e00e745..4078c143ac 100644 --- a/app/src/app.vue +++ b/app/src/app.vue @@ -30,7 +30,7 @@ import { startIdleTracking, stopIdleTracking } from './idle'; import { useSystem } from '@/composables/use-system'; import { setFavicon } from '@/utils/set-favicon'; -import { User } from '@directus/shared/types'; +import { User } from '@directus/types'; export default defineComponent({ setup() { diff --git a/app/src/components/__snapshots__/v-avatar.test.ts.snap b/app/src/components/__snapshots__/v-avatar.test.ts.snap index e4fc286ead..e54910486d 100644 --- a/app/src/components/__snapshots__/v-avatar.test.ts.snap +++ b/app/src/components/__snapshots__/v-avatar.test.ts.snap @@ -1,3 +1,3 @@ -// Vitest Snapshot v1 +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[`Mount component 1`] = `"
Slot Content
"`; diff --git a/app/src/components/__snapshots__/v-badge.test.ts.snap b/app/src/components/__snapshots__/v-badge.test.ts.snap index a0d26ea9b0..6a0bf4d24d 100644 --- a/app/src/components/__snapshots__/v-badge.test.ts.snap +++ b/app/src/components/__snapshots__/v-badge.test.ts.snap @@ -1,3 +1,3 @@ -// Vitest Snapshot v1 +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[`Mount component 1`] = `"
Slot Content
"`; diff --git a/app/src/components/__snapshots__/v-breadcrumb.test.ts.snap b/app/src/components/__snapshots__/v-breadcrumb.test.ts.snap index 7f6dd0238b..59e73d387b 100644 --- a/app/src/components/__snapshots__/v-breadcrumb.test.ts.snap +++ b/app/src/components/__snapshots__/v-breadcrumb.test.ts.snap @@ -1,3 +1,3 @@ -// Vitest Snapshot v1 +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[`Mount component 1`] = `" Disabled"`; diff --git a/app/src/components/__snapshots__/v-button.test.ts.snap b/app/src/components/__snapshots__/v-button.test.ts.snap index 11c0601917..432b280cd7 100644 --- a/app/src/components/__snapshots__/v-button.test.ts.snap +++ b/app/src/components/__snapshots__/v-button.test.ts.snap @@ -1,4 +1,4 @@ -// Vitest Snapshot v1 +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[`Mount component 1`] = ` "