@directus/api 17.1.0 → 18.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/dist/app.js +8 -2
  2. package/dist/auth/drivers/ldap.js +14 -16
  3. package/dist/auth/drivers/local.js +16 -10
  4. package/dist/auth/drivers/oauth2.js +16 -11
  5. package/dist/auth/drivers/openid.js +16 -11
  6. package/dist/auth/drivers/saml.js +27 -12
  7. package/dist/cli/commands/init/index.js +3 -3
  8. package/dist/cli/commands/security/key.js +2 -2
  9. package/dist/cli/utils/create-env/env-stub.liquid +19 -4
  10. package/dist/cli/utils/create-env/index.js +2 -2
  11. package/dist/constants.d.ts +2 -1
  12. package/dist/constants.js +11 -4
  13. package/dist/controllers/auth.js +54 -19
  14. package/dist/controllers/extensions.js +102 -5
  15. package/dist/controllers/items.js +3 -2
  16. package/dist/controllers/permissions.js +1 -1
  17. package/dist/controllers/shares.js +19 -4
  18. package/dist/database/migrations/20220429A-add-flows.js +3 -3
  19. package/dist/database/migrations/20230526A-migrate-translation-strings.js +2 -2
  20. package/dist/database/migrations/20240204A-marketplace.d.ts +3 -0
  21. package/dist/database/migrations/20240204A-marketplace.js +68 -0
  22. package/dist/database/migrations/run.js +3 -2
  23. package/dist/extensions/lib/get-extensions-settings.d.ts +6 -2
  24. package/dist/extensions/lib/get-extensions-settings.js +70 -22
  25. package/dist/extensions/lib/get-extensions.d.ts +5 -1
  26. package/dist/extensions/lib/get-extensions.js +7 -31
  27. package/dist/extensions/lib/installation/index.d.ts +2 -0
  28. package/dist/extensions/lib/installation/index.js +9 -0
  29. package/dist/extensions/lib/installation/manager.d.ts +5 -0
  30. package/dist/extensions/lib/installation/manager.js +90 -0
  31. package/dist/extensions/lib/sandbox/generate-api-extensions-sandbox-entrypoint.d.ts +1 -1
  32. package/dist/extensions/lib/sync-extensions.js +11 -10
  33. package/dist/extensions/manager.d.ts +27 -25
  34. package/dist/extensions/manager.js +214 -183
  35. package/dist/middleware/authenticate.d.ts +1 -0
  36. package/dist/middleware/error-handler.js +22 -18
  37. package/dist/middleware/extract-token.d.ts +6 -5
  38. package/dist/middleware/extract-token.js +27 -11
  39. package/dist/middleware/merge-content-versions.d.ts +2 -0
  40. package/dist/middleware/merge-content-versions.js +26 -0
  41. package/dist/middleware/respond.js +0 -12
  42. package/dist/middleware/validate-batch.d.ts +1 -0
  43. package/dist/request/agent-with-ip-validation.d.ts +1 -1
  44. package/dist/request/agent-with-ip-validation.js +5 -1
  45. package/dist/services/activity.js +3 -3
  46. package/dist/services/assets.js +2 -3
  47. package/dist/services/authentication.d.ts +7 -2
  48. package/dist/services/authentication.js +21 -13
  49. package/dist/services/extensions.d.ts +4 -8
  50. package/dist/services/extensions.js +110 -93
  51. package/dist/services/fields.js +28 -22
  52. package/dist/services/graphql/index.js +98 -42
  53. package/dist/services/index.d.ts +1 -1
  54. package/dist/services/index.js +1 -1
  55. package/dist/services/mail/index.d.ts +1 -1
  56. package/dist/services/mail/index.js +4 -2
  57. package/dist/services/payload.js +2 -2
  58. package/dist/services/{permissions.d.ts → permissions/index.d.ts} +3 -4
  59. package/dist/services/{permissions.js → permissions/index.js} +6 -23
  60. package/dist/services/permissions/lib/with-app-minimal-permissions.d.ts +2 -0
  61. package/dist/services/permissions/lib/with-app-minimal-permissions.js +13 -0
  62. package/dist/services/relations.d.ts +2 -3
  63. package/dist/services/relations.js +2 -2
  64. package/dist/services/roles.js +1 -1
  65. package/dist/services/server.js +3 -0
  66. package/dist/services/shares.d.ts +3 -1
  67. package/dist/services/shares.js +9 -5
  68. package/dist/storage/index.js +5 -4
  69. package/dist/types/auth.d.ts +6 -4
  70. package/dist/types/graphql.d.ts +1 -0
  71. package/dist/utils/apply-query.js +3 -3
  72. package/dist/utils/filter-items.d.ts +2 -2
  73. package/dist/utils/filter-items.js +1 -3
  74. package/dist/utils/get-cache-headers.d.ts +1 -0
  75. package/dist/utils/get-cache-key.d.ts +1 -0
  76. package/dist/utils/get-graphql-query-and-variables.d.ts +1 -0
  77. package/dist/utils/get-ip-from-req.d.ts +1 -0
  78. package/dist/utils/get-milliseconds.d.ts +1 -1
  79. package/dist/utils/get-milliseconds.js +4 -1
  80. package/dist/utils/is-login-redirect-allowed.d.ts +4 -0
  81. package/dist/utils/is-login-redirect-allowed.js +34 -0
  82. package/dist/utils/is-url-allowed.d.ts +1 -1
  83. package/dist/utils/is-url-allowed.js +5 -5
  84. package/dist/utils/is-valid-uuid.d.ts +3 -0
  85. package/dist/utils/is-valid-uuid.js +21 -0
  86. package/dist/utils/jwt.d.ts +1 -1
  87. package/dist/utils/jwt.js +3 -3
  88. package/dist/utils/merge-version-data.d.ts +3 -0
  89. package/dist/utils/merge-version-data.js +134 -0
  90. package/dist/utils/sanitize-query.js +2 -0
  91. package/dist/utils/should-skip-cache.d.ts +1 -0
  92. package/dist/utils/validate-keys.js +2 -2
  93. package/dist/utils/validate-query.js +1 -0
  94. package/dist/websocket/controllers/base.js +2 -2
  95. package/package.json +44 -45
@@ -1,9 +1,8 @@
1
1
  import { useEnv } from '@directus/env';
2
- import { NESTED_EXTENSION_TYPES } from '@directus/extensions';
3
- import { ensureExtensionDirs } from '@directus/extensions/node';
2
+ import { exists } from 'fs-extra';
4
3
  import mid from 'node-machine-id';
5
4
  import { createWriteStream } from 'node:fs';
6
- import { mkdir } from 'node:fs/promises';
5
+ import { mkdir, rm } from 'node:fs/promises';
7
6
  import { dirname, join, relative, resolve, sep } from 'node:path';
8
7
  import { pipeline } from 'node:stream/promises';
9
8
  import Queue from 'p-queue';
@@ -16,10 +15,7 @@ export const syncExtensions = async () => {
16
15
  const env = useEnv();
17
16
  const logger = useLogger();
18
17
  const extensionsPath = getExtensionsPath();
19
- if (!env['EXTENSIONS_LOCATION']) {
20
- // Safe to run with multiple instances since dirs are created with `recursive: true`
21
- return ensureExtensionDirs(extensionsPath, NESTED_EXTENSION_TYPES);
22
- }
18
+ const storageExtensionsPath = env['EXTENSIONS_PATH'];
23
19
  const messenger = useBus();
24
20
  const isPrimaryProcess = String(process.env['NODE_APP_INSTANCE']) === '0' || process.env['NODE_APP_INSTANCE'] === undefined;
25
21
  const id = await mid.machineId();
@@ -36,6 +32,12 @@ export const syncExtensions = async () => {
36
32
  messenger.subscribe(message, () => resolve());
37
33
  });
38
34
  }
35
+ if (await exists(extensionsPath)) {
36
+ // In case the FS still contains the cached extensions from a previous invocation. We have to
37
+ // clear them out to ensure the remote extensions folder remains the source of truth for all
38
+ // extensions that are loaded.
39
+ await rm(extensionsPath, { recursive: true, force: true });
40
+ }
39
41
  // Ensure that the local extensions cache path exists
40
42
  await mkdir(extensionsPath, { recursive: true });
41
43
  await setSyncStatus(SyncStatus.SYNCING);
@@ -44,18 +46,17 @@ export const syncExtensions = async () => {
44
46
  const disk = storage.location(env['EXTENSIONS_LOCATION']);
45
47
  // Make sure we don't overload the file handles
46
48
  const queue = new Queue({ concurrency: 1000 });
47
- for await (const filepath of disk.list(env['EXTENSIONS_PATH'])) {
49
+ for await (const filepath of disk.list(storageExtensionsPath)) {
48
50
  const readStream = await disk.read(filepath);
49
51
  // We want files to be stored in the root of `$TEMP_PATH/extensions`, so gotta remove the
50
52
  // extensions path on disk from the start of the file path
51
- const destPath = join(extensionsPath, relative(resolve(sep, env['EXTENSIONS_PATH']), resolve(sep, filepath)));
53
+ const destPath = join(extensionsPath, relative(resolve(sep, storageExtensionsPath), resolve(sep, filepath)));
52
54
  // Ensure that the directory path exists
53
55
  await mkdir(dirname(destPath), { recursive: true });
54
56
  const writeStream = createWriteStream(destPath);
55
57
  queue.add(() => pipeline(readStream, writeStream));
56
58
  }
57
59
  await queue.onIdle();
58
- await ensureExtensionDirs(extensionsPath, NESTED_EXTENSION_TYPES);
59
60
  await setSyncStatus(SyncStatus.DONE);
60
61
  messenger.publish(message, { ready: true });
61
62
  };
@@ -7,10 +7,9 @@ export declare class ExtensionManager {
7
7
  * Whether or not the extensions have been read from disk and registered into the system
8
8
  */
9
9
  private isLoaded;
10
- /**
11
- * All extensions that are loaded within the current process
12
- */
13
- private extensions;
10
+ private localExtensions;
11
+ private registryExtensions;
12
+ private moduleExtensions;
14
13
  /**
15
14
  * Settings for the extensions that are loaded within the current process
16
15
  */
@@ -57,6 +56,18 @@ export declare class ExtensionManager {
57
56
  * Optional file system watcher to auto-reload extensions when the local file system changes
58
57
  */
59
58
  private watcher;
59
+ /**
60
+ * installation manager responsible for installing extensions from registries
61
+ */
62
+ private installationManager;
63
+ private messenger;
64
+ /**
65
+ * channel to publish on registering extension from external registry
66
+ */
67
+ private reloadChannel;
68
+ private processId;
69
+ get extensions(): Extension[];
70
+ getExtension(source: string, folder: string): Extension | undefined;
60
71
  /**
61
72
  * Load and register all extensions
62
73
  *
@@ -65,6 +76,11 @@ export declare class ExtensionManager {
65
76
  * @param {boolean} options.watch - Whether or not to watch the local extensions folder for changes
66
77
  */
67
78
  initialize(options?: Partial<ExtensionManagerOptions>): Promise<void>;
79
+ /**
80
+ * Installs an external extension from registry
81
+ */
82
+ install(versionId: string): Promise<void>;
83
+ uninstall(folder: string): Promise<void>;
68
84
  /**
69
85
  * Load all extensions from disk and register them in their respective places
70
86
  */
@@ -76,7 +92,7 @@ export declare class ExtensionManager {
76
92
  /**
77
93
  * Reload all the extensions. Will unload if extensions have already been loaded
78
94
  */
79
- reload(): void;
95
+ reload(): Promise<unknown>;
80
96
  /**
81
97
  * Return the previously generated app extensions bundle
82
98
  */
@@ -96,10 +112,6 @@ export declare class ExtensionManager {
96
112
  head: string;
97
113
  body: string;
98
114
  };
99
- /**
100
- * Allow reading the installed extensions
101
- */
102
- getExtensions(): Extension[];
103
115
  /**
104
116
  * Start the chokidar watcher for extensions on the local filesystem
105
117
  */
@@ -119,26 +131,16 @@ export declare class ExtensionManager {
119
131
  */
120
132
  private generateExtensionBundle;
121
133
  private registerSandboxedApiExtension;
122
- /**
123
- * Import the hook module code for all hook extensions, and register them individually through
124
- * registerHook
125
- */
126
- private registerHooks;
127
- /**
128
- * Import the endpoint module code for all endpoint extensions, and register them individually through
129
- * registerEndpoint
130
- */
131
- private registerEndpoints;
134
+ private registerApiExtensions;
135
+ private registerHookExtension;
136
+ private registerEndpointExtension;
137
+ private registerOperationExtension;
138
+ private registerBundleExtension;
132
139
  /**
133
140
  * Import the operation module code for all operation extensions, and register them individually through
134
141
  * registerOperation
135
142
  */
136
- private registerOperations;
137
- /**
138
- * Import the module code for all hook, endpoint, and operation extensions registered within a
139
- * bundle, and register them with their respective registration function
140
- */
141
- private registerBundles;
143
+ private registerInternalOperations;
142
144
  /**
143
145
  * Register a single hook
144
146
  */