@directus/api 30.0.0 → 32.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app.js +7 -0
- package/dist/auth/auth.d.ts +2 -1
- package/dist/auth/auth.js +7 -2
- package/dist/auth/drivers/ldap.d.ts +0 -2
- package/dist/auth/drivers/ldap.js +9 -7
- package/dist/auth/drivers/oauth2.d.ts +0 -2
- package/dist/auth/drivers/oauth2.js +28 -11
- package/dist/auth/drivers/openid.d.ts +0 -2
- package/dist/auth/drivers/openid.js +28 -11
- package/dist/auth/drivers/saml.d.ts +0 -2
- package/dist/auth/drivers/saml.js +5 -5
- package/dist/auth.js +1 -2
- package/dist/cli/commands/bootstrap/index.js +12 -33
- package/dist/cli/commands/init/index.js +1 -1
- package/dist/cli/commands/schema/apply.d.ts +4 -0
- package/dist/cli/commands/schema/apply.js +26 -3
- package/dist/controllers/collections.js +7 -2
- package/dist/controllers/fields.js +31 -8
- package/dist/controllers/mcp.d.ts +2 -0
- package/dist/controllers/mcp.js +33 -0
- package/dist/controllers/server.js +26 -1
- package/dist/controllers/settings.js +9 -2
- package/dist/controllers/users.js +17 -7
- package/dist/controllers/versions.js +3 -2
- package/dist/database/errors/dialects/mssql.d.ts +1 -1
- package/dist/database/errors/dialects/mssql.js +18 -10
- package/dist/database/helpers/fn/types.js +3 -3
- package/dist/database/helpers/schema/dialects/cockroachdb.d.ts +2 -1
- package/dist/database/helpers/schema/dialects/cockroachdb.js +13 -0
- package/dist/database/helpers/schema/dialects/mssql.d.ts +2 -1
- package/dist/database/helpers/schema/dialects/mssql.js +23 -0
- package/dist/database/helpers/schema/dialects/mysql.d.ts +2 -1
- package/dist/database/helpers/schema/dialects/mysql.js +25 -0
- package/dist/database/helpers/schema/dialects/oracle.d.ts +2 -1
- package/dist/database/helpers/schema/dialects/oracle.js +13 -0
- package/dist/database/helpers/schema/dialects/postgres.d.ts +2 -1
- package/dist/database/helpers/schema/dialects/postgres.js +13 -0
- package/dist/database/helpers/schema/types.d.ts +5 -0
- package/dist/database/helpers/schema/types.js +6 -0
- package/dist/database/migrations/20250813A-add-mcp.d.ts +3 -0
- package/dist/database/migrations/20250813A-add-mcp.js +18 -0
- package/dist/database/migrations/20251012A-add-field-searchable.d.ts +3 -0
- package/dist/database/migrations/20251012A-add-field-searchable.js +10 -0
- package/dist/database/migrations/20251014A-add-project-owner.d.ts +3 -0
- package/dist/database/migrations/20251014A-add-project-owner.js +37 -0
- package/dist/database/migrations/20251028A-add-retention-indexes.d.ts +3 -0
- package/dist/database/migrations/20251028A-add-retention-indexes.js +42 -0
- package/dist/database/run-ast/README.md +46 -0
- package/dist/database/run-ast/lib/apply-query/add-join.js +2 -2
- package/dist/database/run-ast/lib/apply-query/filter/get-filter-type.d.ts +2 -2
- package/dist/database/run-ast/lib/apply-query/index.d.ts +0 -1
- package/dist/database/run-ast/lib/apply-query/index.js +4 -6
- package/dist/database/run-ast/lib/apply-query/search.js +2 -0
- package/dist/database/run-ast/lib/get-db-query.js +7 -6
- package/dist/database/run-ast/utils/generate-alias.d.ts +6 -0
- package/dist/database/run-ast/utils/generate-alias.js +57 -0
- package/dist/flows.js +1 -0
- package/dist/mcp/define.d.ts +2 -0
- package/dist/mcp/define.js +3 -0
- package/dist/mcp/index.d.ts +1 -0
- package/dist/mcp/index.js +1 -0
- package/dist/mcp/schema.d.ts +485 -0
- package/dist/mcp/schema.js +219 -0
- package/dist/mcp/server.d.ts +103 -0
- package/dist/mcp/server.js +310 -0
- package/dist/mcp/tools/assets.d.ts +3 -0
- package/dist/mcp/tools/assets.js +54 -0
- package/dist/mcp/tools/collections.d.ts +84 -0
- package/dist/mcp/tools/collections.js +90 -0
- package/dist/mcp/tools/fields.d.ts +101 -0
- package/dist/mcp/tools/fields.js +157 -0
- package/dist/mcp/tools/files.d.ts +235 -0
- package/dist/mcp/tools/files.js +103 -0
- package/dist/mcp/tools/flows.d.ts +323 -0
- package/dist/mcp/tools/flows.js +85 -0
- package/dist/mcp/tools/folders.d.ts +95 -0
- package/dist/mcp/tools/folders.js +96 -0
- package/dist/mcp/tools/index.d.ts +15 -0
- package/dist/mcp/tools/index.js +29 -0
- package/dist/mcp/tools/items.d.ts +87 -0
- package/dist/mcp/tools/items.js +141 -0
- package/dist/mcp/tools/operations.d.ts +171 -0
- package/dist/mcp/tools/operations.js +77 -0
- package/dist/mcp/tools/prompts/assets.md +8 -0
- package/dist/mcp/tools/prompts/collections.md +336 -0
- package/dist/mcp/tools/prompts/fields.md +521 -0
- package/dist/mcp/tools/prompts/files.md +180 -0
- package/dist/mcp/tools/prompts/flows.md +495 -0
- package/dist/mcp/tools/prompts/folders.md +34 -0
- package/dist/mcp/tools/prompts/index.d.ts +16 -0
- package/dist/mcp/tools/prompts/index.js +19 -0
- package/dist/mcp/tools/prompts/items.md +317 -0
- package/dist/mcp/tools/prompts/operations.md +721 -0
- package/dist/mcp/tools/prompts/relations.md +386 -0
- package/dist/mcp/tools/prompts/schema.md +130 -0
- package/dist/mcp/tools/prompts/system-prompt-description.md +1 -0
- package/dist/mcp/tools/prompts/system-prompt.md +44 -0
- package/dist/mcp/tools/prompts/trigger-flow.md +214 -0
- package/dist/mcp/tools/relations.d.ts +73 -0
- package/dist/mcp/tools/relations.js +93 -0
- package/dist/mcp/tools/schema.d.ts +54 -0
- package/dist/mcp/tools/schema.js +317 -0
- package/dist/mcp/tools/system.d.ts +3 -0
- package/dist/mcp/tools/system.js +22 -0
- package/dist/mcp/tools/trigger-flow.d.ts +8 -0
- package/dist/mcp/tools/trigger-flow.js +48 -0
- package/dist/mcp/transport.d.ts +13 -0
- package/dist/mcp/transport.js +18 -0
- package/dist/mcp/types.d.ts +56 -0
- package/dist/mcp/types.js +1 -0
- package/dist/metrics/lib/create-metrics.js +16 -25
- package/dist/middleware/collection-exists.js +2 -2
- package/dist/operations/mail/index.js +3 -1
- package/dist/operations/mail/rate-limiter.d.ts +1 -0
- package/dist/operations/mail/rate-limiter.js +29 -0
- package/dist/permissions/modules/process-payload/process-payload.js +3 -10
- package/dist/permissions/modules/validate-access/validate-access.js +2 -3
- package/dist/schedules/metrics.js +6 -2
- package/dist/schedules/project.d.ts +4 -0
- package/dist/schedules/project.js +27 -0
- package/dist/services/authentication.js +36 -0
- package/dist/services/collections.d.ts +3 -3
- package/dist/services/collections.js +16 -1
- package/dist/services/fields.d.ts +21 -5
- package/dist/services/fields.js +109 -32
- package/dist/services/graphql/resolvers/query.js +1 -1
- package/dist/services/graphql/resolvers/system-admin.js +49 -5
- package/dist/services/graphql/schema/parse-query.js +8 -8
- package/dist/services/graphql/utils/aggregate-query.d.ts +1 -1
- package/dist/services/graphql/utils/aggregate-query.js +5 -1
- package/dist/services/graphql/utils/filter-replace-m2a.js +2 -1
- package/dist/services/import-export.d.ts +9 -1
- package/dist/services/import-export.js +287 -101
- package/dist/services/items.d.ts +1 -1
- package/dist/services/items.js +50 -24
- package/dist/services/mail/index.js +2 -0
- package/dist/services/mail/rate-limiter.d.ts +1 -0
- package/dist/services/mail/rate-limiter.js +29 -0
- package/dist/services/meta.js +28 -24
- package/dist/services/payload.d.ts +7 -3
- package/dist/services/payload.js +26 -12
- package/dist/services/schema.js +4 -1
- package/dist/services/server.d.ts +1 -0
- package/dist/services/server.js +15 -18
- package/dist/services/settings.d.ts +2 -1
- package/dist/services/settings.js +15 -0
- package/dist/services/tfa.d.ts +1 -1
- package/dist/services/tfa.js +20 -5
- package/dist/services/tus/server.js +14 -9
- package/dist/services/versions.d.ts +6 -4
- package/dist/services/versions.js +84 -25
- package/dist/telemetry/lib/get-report.js +4 -4
- package/dist/telemetry/lib/send-report.d.ts +6 -1
- package/dist/telemetry/lib/send-report.js +3 -1
- package/dist/telemetry/types/report.d.ts +17 -1
- package/dist/telemetry/utils/get-settings.d.ts +9 -0
- package/dist/telemetry/utils/get-settings.js +14 -0
- package/dist/test-utils/README.md +760 -0
- package/dist/test-utils/cache.d.ts +51 -0
- package/dist/test-utils/cache.js +59 -0
- package/dist/test-utils/database.d.ts +48 -0
- package/dist/test-utils/database.js +52 -0
- package/dist/test-utils/emitter.d.ts +35 -0
- package/dist/test-utils/emitter.js +38 -0
- package/dist/test-utils/fields-service.d.ts +28 -0
- package/dist/test-utils/fields-service.js +36 -0
- package/dist/test-utils/items-service.d.ts +23 -0
- package/dist/test-utils/items-service.js +37 -0
- package/dist/test-utils/knex.d.ts +164 -0
- package/dist/test-utils/knex.js +268 -0
- package/dist/test-utils/schema.d.ts +26 -0
- package/dist/test-utils/schema.js +35 -0
- package/dist/types/auth.d.ts +2 -3
- package/dist/utils/apply-diff.js +15 -0
- package/dist/utils/create-admin.d.ts +11 -0
- package/dist/utils/create-admin.js +50 -0
- package/dist/utils/get-schema.js +5 -3
- package/dist/utils/get-snapshot-diff.js +49 -5
- package/dist/utils/get-snapshot.js +13 -7
- package/dist/utils/sanitize-schema.d.ts +11 -4
- package/dist/utils/sanitize-schema.js +9 -6
- package/dist/utils/schedule.js +15 -19
- package/dist/utils/validate-diff.js +31 -0
- package/dist/utils/validate-snapshot.js +7 -0
- package/dist/utils/versioning/deep-map-with-schema.d.ts +23 -0
- package/dist/utils/versioning/deep-map-with-schema.js +81 -0
- package/dist/utils/versioning/handle-version.d.ts +2 -2
- package/dist/utils/versioning/handle-version.js +47 -43
- package/dist/utils/versioning/split-recursive.d.ts +4 -0
- package/dist/utils/versioning/split-recursive.js +27 -0
- package/dist/websocket/controllers/hooks.js +12 -20
- package/dist/websocket/messages.d.ts +3 -3
- package/package.json +65 -66
- package/dist/cli/utils/defaults.d.ts +0 -4
- package/dist/cli/utils/defaults.js +0 -17
- package/dist/telemetry/utils/get-project-id.d.ts +0 -2
- package/dist/telemetry/utils/get-project-id.js +0 -4
package/dist/services/items.js
CHANGED
|
@@ -8,7 +8,7 @@ import { getCache } from '../cache.js';
|
|
|
8
8
|
import { translateDatabaseError } from '../database/errors/translate.js';
|
|
9
9
|
import { getAstFromQuery } from '../database/get-ast-from-query/get-ast-from-query.js';
|
|
10
10
|
import { getHelpers } from '../database/helpers/index.js';
|
|
11
|
-
import getDatabase from '../database/index.js';
|
|
11
|
+
import getDatabase, { getDatabaseClient } from '../database/index.js';
|
|
12
12
|
import { runAst } from '../database/run-ast/run-ast.js';
|
|
13
13
|
import emitter from '../emitter.js';
|
|
14
14
|
import { processAst } from '../permissions/modules/process-ast/process-ast.js';
|
|
@@ -148,6 +148,7 @@ export class ItemsService {
|
|
|
148
148
|
knex: trx,
|
|
149
149
|
schema: this.schema,
|
|
150
150
|
nested: this.nested,
|
|
151
|
+
overwriteDefaults: opts.overwriteDefaults,
|
|
151
152
|
});
|
|
152
153
|
const { payload: payloadWithM2O, revisions: revisionsM2O, nestedActionEvents: nestedActionEventsM2O, userIntegrityCheckFlags: userIntegrityCheckFlagsM2O, } = await payloadService.processM2O(payloadWithPresets, opts);
|
|
153
154
|
const { payload: payloadWithA2O, revisions: revisionsA2O, nestedActionEvents: nestedActionEventsA2O, userIntegrityCheckFlags: userIntegrityCheckFlagsA2O, } = await payloadService.processA2O(payloadWithM2O, opts);
|
|
@@ -172,10 +173,15 @@ export class ItemsService {
|
|
|
172
173
|
autoIncrementSequenceNeedsToBeReset = true;
|
|
173
174
|
}
|
|
174
175
|
try {
|
|
176
|
+
let returningOptions = undefined;
|
|
177
|
+
// Support MSSQL tables that have triggers.
|
|
178
|
+
if (getDatabaseClient(trx) === 'mssql') {
|
|
179
|
+
returningOptions = { includeTriggerModifications: true };
|
|
180
|
+
}
|
|
175
181
|
const result = await trx
|
|
176
182
|
.insert(payloadWithoutAliases)
|
|
177
183
|
.into(this.collection)
|
|
178
|
-
.returning(primaryKeyField)
|
|
184
|
+
.returning(primaryKeyField, returningOptions)
|
|
179
185
|
.then((result) => result[0]);
|
|
180
186
|
const returnedKey = typeof result === 'object' ? result[primaryKeyField] : result;
|
|
181
187
|
if (pkField.type === 'uuid') {
|
|
@@ -338,6 +344,7 @@ export class ItemsService {
|
|
|
338
344
|
onRequireUserIntegrityCheck: (flags) => (userIntegrityCheckFlags |= flags),
|
|
339
345
|
bypassEmitAction: (params) => nestedActionEvents.push(params),
|
|
340
346
|
mutationTracker: opts.mutationTracker,
|
|
347
|
+
overwriteDefaults: opts.overwriteDefaults?.[index],
|
|
341
348
|
bypassAutoIncrementSequenceReset,
|
|
342
349
|
});
|
|
343
350
|
primaryKeys.push(primaryKey);
|
|
@@ -434,8 +441,8 @@ export class ItemsService {
|
|
|
434
441
|
const filterWithKey = assign({}, query.filter, { [primaryKeyField]: { _eq: key } });
|
|
435
442
|
const queryWithKey = assign({}, query, { filter: filterWithKey });
|
|
436
443
|
let results = [];
|
|
437
|
-
if (query.version) {
|
|
438
|
-
results =
|
|
444
|
+
if (query.version && query.version !== 'main') {
|
|
445
|
+
results = [await handleVersion(this, key, queryWithKey, opts)];
|
|
439
446
|
}
|
|
440
447
|
else {
|
|
441
448
|
results = await this.readByQuery(queryWithKey, opts);
|
|
@@ -497,13 +504,15 @@ export class ItemsService {
|
|
|
497
504
|
await transaction(this.knex, async (knex) => {
|
|
498
505
|
const service = this.fork({ knex });
|
|
499
506
|
let userIntegrityCheckFlags = opts.userIntegrityCheckFlags ?? UserIntegrityCheckFlag.None;
|
|
500
|
-
for (const
|
|
507
|
+
for (const index in data) {
|
|
508
|
+
const item = data[index];
|
|
501
509
|
const primaryKey = item[primaryKeyField];
|
|
502
510
|
if (!primaryKey)
|
|
503
511
|
throw new InvalidPayloadError({ reason: `Item in update misses primary key` });
|
|
504
512
|
const combinedOpts = {
|
|
505
513
|
autoPurgeCache: false,
|
|
506
514
|
...opts,
|
|
515
|
+
overwriteDefaults: opts.overwriteDefaults?.[index],
|
|
507
516
|
onRequireUserIntegrityCheck: (flags) => (userIntegrityCheckFlags |= flags),
|
|
508
517
|
};
|
|
509
518
|
keys.push(await service.updateOne(primaryKey, omit(item, primaryKeyField), combinedOpts));
|
|
@@ -591,6 +600,7 @@ export class ItemsService {
|
|
|
591
600
|
knex: trx,
|
|
592
601
|
schema: this.schema,
|
|
593
602
|
nested: this.nested,
|
|
603
|
+
overwriteDefaults: opts.overwriteDefaults,
|
|
594
604
|
});
|
|
595
605
|
const { payload: payloadWithM2O, revisions: revisionsM2O, nestedActionEvents: nestedActionEventsM2O, userIntegrityCheckFlags: userIntegrityCheckFlagsM2O, } = await payloadService.processM2O(payloadWithPresets, opts);
|
|
596
606
|
const { payload: payloadWithA2O, revisions: revisionsA2O, nestedActionEvents: nestedActionEventsA2O, userIntegrityCheckFlags: userIntegrityCheckFlagsA2O, } = await payloadService.processA2O(payloadWithM2O, opts);
|
|
@@ -752,8 +762,13 @@ export class ItemsService {
|
|
|
752
762
|
const primaryKeys = await transaction(this.knex, async (knex) => {
|
|
753
763
|
const service = this.fork({ knex });
|
|
754
764
|
const primaryKeys = [];
|
|
755
|
-
for (const
|
|
756
|
-
const
|
|
765
|
+
for (const index in payloads) {
|
|
766
|
+
const payload = payloads[index];
|
|
767
|
+
const primaryKey = await service.upsertOne(payload, {
|
|
768
|
+
...(opts || {}),
|
|
769
|
+
overwriteDefaults: opts.overwriteDefaults?.[index],
|
|
770
|
+
autoPurgeCache: false,
|
|
771
|
+
});
|
|
757
772
|
primaryKeys.push(primaryKey);
|
|
758
773
|
}
|
|
759
774
|
return primaryKeys;
|
|
@@ -796,12 +811,23 @@ export class ItemsService {
|
|
|
796
811
|
}
|
|
797
812
|
const primaryKeyField = this.schema.collections[this.collection].primary;
|
|
798
813
|
validateKeys(this.schema, this.collection, primaryKeyField, keys);
|
|
814
|
+
const keysAfterHooks = opts.emitEvents !== false
|
|
815
|
+
? await emitter.emitFilter(this.eventScope === 'items'
|
|
816
|
+
? ['items.delete', `${this.collection}.items.delete`]
|
|
817
|
+
: `${this.eventScope}.delete`, keys, {
|
|
818
|
+
collection: this.collection,
|
|
819
|
+
}, {
|
|
820
|
+
database: this.knex,
|
|
821
|
+
schema: this.schema,
|
|
822
|
+
accountability: this.accountability,
|
|
823
|
+
})
|
|
824
|
+
: keys;
|
|
799
825
|
if (this.accountability) {
|
|
800
826
|
await validateAccess({
|
|
801
827
|
accountability: this.accountability,
|
|
802
828
|
action: 'delete',
|
|
803
829
|
collection: this.collection,
|
|
804
|
-
primaryKeys:
|
|
830
|
+
primaryKeys: keysAfterHooks,
|
|
805
831
|
}, {
|
|
806
832
|
knex: this.knex,
|
|
807
833
|
schema: this.schema,
|
|
@@ -810,17 +836,8 @@ export class ItemsService {
|
|
|
810
836
|
if (opts.preMutationError) {
|
|
811
837
|
throw opts.preMutationError;
|
|
812
838
|
}
|
|
813
|
-
if (opts.emitEvents !== false) {
|
|
814
|
-
await emitter.emitFilter(this.eventScope === 'items' ? ['items.delete', `${this.collection}.items.delete`] : `${this.eventScope}.delete`, keys, {
|
|
815
|
-
collection: this.collection,
|
|
816
|
-
}, {
|
|
817
|
-
database: this.knex,
|
|
818
|
-
schema: this.schema,
|
|
819
|
-
accountability: this.accountability,
|
|
820
|
-
});
|
|
821
|
-
}
|
|
822
839
|
await transaction(this.knex, async (trx) => {
|
|
823
|
-
await trx(this.collection).whereIn(primaryKeyField,
|
|
840
|
+
await trx(this.collection).whereIn(primaryKeyField, keysAfterHooks).delete();
|
|
824
841
|
if (opts.userIntegrityCheckFlags) {
|
|
825
842
|
if (opts.onRequireUserIntegrityCheck) {
|
|
826
843
|
opts.onRequireUserIntegrityCheck(opts.userIntegrityCheckFlags);
|
|
@@ -837,7 +854,7 @@ export class ItemsService {
|
|
|
837
854
|
knex: trx,
|
|
838
855
|
schema: this.schema,
|
|
839
856
|
});
|
|
840
|
-
await activityService.createMany(
|
|
857
|
+
await activityService.createMany(keysAfterHooks.map((key) => ({
|
|
841
858
|
action: Action.DELETE,
|
|
842
859
|
user: this.accountability.user,
|
|
843
860
|
collection: this.collection,
|
|
@@ -857,8 +874,8 @@ export class ItemsService {
|
|
|
857
874
|
? ['items.delete', `${this.collection}.items.delete`]
|
|
858
875
|
: `${this.eventScope}.delete`,
|
|
859
876
|
meta: {
|
|
860
|
-
payload:
|
|
861
|
-
keys:
|
|
877
|
+
payload: keysAfterHooks,
|
|
878
|
+
keys: keysAfterHooks,
|
|
862
879
|
collection: this.collection,
|
|
863
880
|
},
|
|
864
881
|
context: {
|
|
@@ -874,7 +891,7 @@ export class ItemsService {
|
|
|
874
891
|
emitter.emitAction(actionEvent.event, actionEvent.meta, actionEvent.context);
|
|
875
892
|
}
|
|
876
893
|
}
|
|
877
|
-
return
|
|
894
|
+
return keysAfterHooks;
|
|
878
895
|
}
|
|
879
896
|
/**
|
|
880
897
|
* Read/treat collection as singleton.
|
|
@@ -882,8 +899,17 @@ export class ItemsService {
|
|
|
882
899
|
async readSingleton(query, opts) {
|
|
883
900
|
query = clone(query);
|
|
884
901
|
query.limit = 1;
|
|
885
|
-
|
|
886
|
-
|
|
902
|
+
let record;
|
|
903
|
+
if (query.version && query.version !== 'main') {
|
|
904
|
+
const primaryKeyField = this.schema.collections[this.collection].primary;
|
|
905
|
+
const key = (await this.knex.select(primaryKeyField).from(this.collection).first())?.[primaryKeyField];
|
|
906
|
+
if (key) {
|
|
907
|
+
record = await handleVersion(this, key, query, opts);
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
else {
|
|
911
|
+
record = (await this.readByQuery(query, opts))[0];
|
|
912
|
+
}
|
|
887
913
|
if (!record) {
|
|
888
914
|
let fields = Object.entries(this.schema.collections[this.collection].fields);
|
|
889
915
|
const defaults = {};
|
|
@@ -10,6 +10,7 @@ import emitter from '../../emitter.js';
|
|
|
10
10
|
import { useLogger } from '../../logger/index.js';
|
|
11
11
|
import getMailer from '../../mailer.js';
|
|
12
12
|
import { Url } from '../../utils/url.js';
|
|
13
|
+
import { useEmailRateLimiterQueue } from './rate-limiter.js';
|
|
13
14
|
const env = useEnv();
|
|
14
15
|
const logger = useLogger();
|
|
15
16
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
@@ -37,6 +38,7 @@ export class MailService {
|
|
|
37
38
|
}
|
|
38
39
|
}
|
|
39
40
|
async send(options) {
|
|
41
|
+
await useEmailRateLimiterQueue();
|
|
40
42
|
const payload = await emitter.emitFilter(`email.send`, options, {});
|
|
41
43
|
if (!payload)
|
|
42
44
|
return null;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function useEmailRateLimiterQueue(): Promise<void>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { useEnv } from '@directus/env';
|
|
2
|
+
import { RateLimiterQueue } from 'rate-limiter-flexible';
|
|
3
|
+
import { createRateLimiter } from '../../rate-limiter.js';
|
|
4
|
+
import { toBoolean } from '@directus/utils';
|
|
5
|
+
import { EmailLimitExceededError } from '@directus/errors';
|
|
6
|
+
let emailRateLimiterQueue;
|
|
7
|
+
const env = useEnv();
|
|
8
|
+
if (toBoolean(env['RATE_LIMITER_EMAIL_ENABLED']) === true) {
|
|
9
|
+
emailRateLimiterQueue = new RateLimiterQueue(createRateLimiter('RATE_LIMITER_EMAIL'), {
|
|
10
|
+
maxQueueSize: Number(env['RATE_LIMITER_EMAIL_QUEUE_SIZE']),
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
export async function useEmailRateLimiterQueue() {
|
|
14
|
+
if (!emailRateLimiterQueue)
|
|
15
|
+
return;
|
|
16
|
+
try {
|
|
17
|
+
await emailRateLimiterQueue.removeTokens(1);
|
|
18
|
+
}
|
|
19
|
+
catch (err) {
|
|
20
|
+
if (err instanceof Error) {
|
|
21
|
+
throw new EmailLimitExceededError({
|
|
22
|
+
points: 'RATE_LIMITER_EMAIL_POINTS' in env ? Number(env['RATE_LIMITER_EMAIL_POINTS']) : undefined,
|
|
23
|
+
duration: 'RATE_LIMITER_EMAIL_DURATION' in env ? Number(env['RATE_LIMITER_EMAIL_DURATION']) : undefined,
|
|
24
|
+
message: 'RATE_LIMITER_EMAIL_ERROR_MESSAGE' in env ? String(env['RATE_LIMITER_EMAIL_ERROR_MESSAGE']) : undefined,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
throw err;
|
|
28
|
+
}
|
|
29
|
+
}
|
package/dist/services/meta.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { isArray } from 'lodash-es';
|
|
2
|
-
import { getAstFromQuery } from '../database/get-ast-from-query/get-ast-from-query.js';
|
|
3
2
|
import getDatabase from '../database/index.js';
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
3
|
+
import applyQuery from '../database/run-ast/lib/apply-query/index.js';
|
|
4
|
+
import { fetchPermissions } from '../permissions/lib/fetch-permissions.js';
|
|
5
|
+
import { fetchPolicies } from '../permissions/lib/fetch-policies.js';
|
|
6
|
+
import { getCases } from '../permissions/modules/process-ast/lib/get-cases.js';
|
|
7
|
+
import { validateAccess } from '../permissions/modules/validate-access/validate-access.js';
|
|
6
8
|
export class MetaService {
|
|
7
9
|
knex;
|
|
8
10
|
accountability;
|
|
@@ -33,27 +35,29 @@ export class MetaService {
|
|
|
33
35
|
return this.filterCount(collection, {});
|
|
34
36
|
}
|
|
35
37
|
async filterCount(collection, query) {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
38
|
+
let permissions = [];
|
|
39
|
+
if (this.accountability && this.accountability.admin !== true) {
|
|
40
|
+
const context = { knex: this.knex, schema: this.schema };
|
|
41
|
+
await validateAccess({
|
|
42
|
+
accountability: this.accountability,
|
|
43
|
+
action: 'read',
|
|
44
|
+
collection,
|
|
45
|
+
}, context);
|
|
46
|
+
const policies = await fetchPolicies(this.accountability, context);
|
|
47
|
+
permissions = await fetchPermissions({ action: 'read', accountability: this.accountability, policies }, context);
|
|
48
|
+
}
|
|
49
|
+
const { cases } = getCases(collection, permissions, []);
|
|
50
|
+
const { query: dbQuery, hasJoins } = applyQuery(this.knex, collection, this.knex(collection), {
|
|
42
51
|
filter: query.filter ?? null,
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
const records = await runAst(ast, this.schema, this.accountability, {
|
|
54
|
-
knex: this.knex,
|
|
55
|
-
});
|
|
56
|
-
return Number((isArray(records) ? records[0]?.['countDistinct'][primaryKeyName] : records?.['countDistinct'][primaryKeyName]) ??
|
|
57
|
-
0);
|
|
52
|
+
search: query.search ?? null,
|
|
53
|
+
}, this.schema, cases, permissions);
|
|
54
|
+
if (hasJoins) {
|
|
55
|
+
dbQuery.countDistinct({ count: [`${collection}.${this.schema.collections[collection].primary}`] });
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
dbQuery.count('*', { as: 'count' });
|
|
59
|
+
}
|
|
60
|
+
const records = await dbQuery;
|
|
61
|
+
return Number((isArray(records) ? records[0]?.['count'] : records?.['count']) ?? 0);
|
|
58
62
|
}
|
|
59
63
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AbstractServiceOptions, Accountability, Aggregate, FieldOverview, Item, MutationOptions, PayloadAction, PayloadServiceProcessRelationResult, PrimaryKey, SchemaOverview } from '@directus/types';
|
|
1
|
+
import type { AbstractServiceOptions, Accountability, Aggregate, DefaultOverwrite, FieldOverview, Item, MutationOptions, PayloadAction, PayloadServiceProcessRelationResult, PrimaryKey, SchemaOverview } from '@directus/types';
|
|
2
2
|
import type { Knex } from 'knex';
|
|
3
3
|
import type { Helpers } from '../database/helpers/index.js';
|
|
4
4
|
type Transformers = {
|
|
@@ -9,6 +9,7 @@ type Transformers = {
|
|
|
9
9
|
accountability: Accountability | null;
|
|
10
10
|
specials: string[];
|
|
11
11
|
helpers: Helpers;
|
|
12
|
+
overwriteDefaults: DefaultOverwrite | undefined;
|
|
12
13
|
}) => Promise<any>;
|
|
13
14
|
};
|
|
14
15
|
/**
|
|
@@ -22,7 +23,10 @@ export declare class PayloadService {
|
|
|
22
23
|
collection: string;
|
|
23
24
|
schema: SchemaOverview;
|
|
24
25
|
nested: string[];
|
|
25
|
-
|
|
26
|
+
overwriteDefaults: DefaultOverwrite | undefined;
|
|
27
|
+
constructor(collection: string, options: AbstractServiceOptions & {
|
|
28
|
+
overwriteDefaults?: DefaultOverwrite | undefined;
|
|
29
|
+
});
|
|
26
30
|
transformers: Transformers;
|
|
27
31
|
processValues(action: PayloadAction, payloads: Partial<Item>[]): Promise<Partial<Item>[]>;
|
|
28
32
|
processValues(action: PayloadAction, payload: Partial<Item>): Promise<Partial<Item>>;
|
|
@@ -62,6 +66,6 @@ export declare class PayloadService {
|
|
|
62
66
|
* Transforms the input partial payload to match the output structure, to have consistency
|
|
63
67
|
* between delta and data
|
|
64
68
|
*/
|
|
65
|
-
prepareDelta(
|
|
69
|
+
prepareDelta(delta: Partial<Item>): Promise<string | null>;
|
|
66
70
|
}
|
|
67
71
|
export {};
|
package/dist/services/payload.js
CHANGED
|
@@ -21,6 +21,7 @@ export class PayloadService {
|
|
|
21
21
|
collection;
|
|
22
22
|
schema;
|
|
23
23
|
nested;
|
|
24
|
+
overwriteDefaults;
|
|
24
25
|
constructor(collection, options) {
|
|
25
26
|
this.accountability = options.accountability || null;
|
|
26
27
|
this.knex = options.knex || getDatabase();
|
|
@@ -28,6 +29,7 @@ export class PayloadService {
|
|
|
28
29
|
this.collection = collection;
|
|
29
30
|
this.schema = options.schema;
|
|
30
31
|
this.nested = options.nested ?? [];
|
|
32
|
+
this.overwriteDefaults = options.overwriteDefaults;
|
|
31
33
|
return this;
|
|
32
34
|
}
|
|
33
35
|
transformers = {
|
|
@@ -77,14 +79,14 @@ export class PayloadService {
|
|
|
77
79
|
return value ? '**********' : null;
|
|
78
80
|
return value;
|
|
79
81
|
},
|
|
80
|
-
async 'user-created'({ action, value, accountability }) {
|
|
82
|
+
async 'user-created'({ action, value, accountability, overwriteDefaults }) {
|
|
81
83
|
if (action === 'create')
|
|
82
|
-
return accountability?.user
|
|
84
|
+
return (overwriteDefaults ? overwriteDefaults._user : accountability?.user) ?? null;
|
|
83
85
|
return value;
|
|
84
86
|
},
|
|
85
|
-
async 'user-updated'({ action, value, accountability }) {
|
|
87
|
+
async 'user-updated'({ action, value, accountability, overwriteDefaults }) {
|
|
86
88
|
if (action === 'update')
|
|
87
|
-
return accountability?.user
|
|
89
|
+
return (overwriteDefaults ? overwriteDefaults._user : accountability?.user) ?? null;
|
|
88
90
|
return value;
|
|
89
91
|
},
|
|
90
92
|
async 'role-created'({ action, value, accountability }) {
|
|
@@ -97,14 +99,14 @@ export class PayloadService {
|
|
|
97
99
|
return accountability?.role || null;
|
|
98
100
|
return value;
|
|
99
101
|
},
|
|
100
|
-
async 'date-created'({ action, value, helpers }) {
|
|
102
|
+
async 'date-created'({ action, value, helpers, overwriteDefaults }) {
|
|
101
103
|
if (action === 'create')
|
|
102
|
-
return new Date(helpers.date.writeTimestamp(new Date().toISOString()));
|
|
104
|
+
return new Date(overwriteDefaults ? overwriteDefaults._date : helpers.date.writeTimestamp(new Date().toISOString()));
|
|
103
105
|
return value;
|
|
104
106
|
},
|
|
105
|
-
async 'date-updated'({ action, value, helpers }) {
|
|
107
|
+
async 'date-updated'({ action, value, helpers, overwriteDefaults }) {
|
|
106
108
|
if (action === 'update')
|
|
107
|
-
return new Date(helpers.date.writeTimestamp(new Date().toISOString()));
|
|
109
|
+
return new Date(overwriteDefaults ? overwriteDefaults._date : helpers.date.writeTimestamp(new Date().toISOString()));
|
|
108
110
|
return value;
|
|
109
111
|
},
|
|
110
112
|
async 'cast-csv'({ action, value }) {
|
|
@@ -212,6 +214,7 @@ export class PayloadService {
|
|
|
212
214
|
accountability,
|
|
213
215
|
specials: fieldSpecials,
|
|
214
216
|
helpers: this.helpers,
|
|
217
|
+
overwriteDefaults: this.overwriteDefaults,
|
|
215
218
|
});
|
|
216
219
|
}
|
|
217
220
|
}
|
|
@@ -405,6 +408,7 @@ export class PayloadService {
|
|
|
405
408
|
autoPurgeCache: opts?.autoPurgeCache,
|
|
406
409
|
autoPurgeSystemCache: opts?.autoPurgeSystemCache,
|
|
407
410
|
skipTracking: opts?.skipTracking,
|
|
411
|
+
overwriteDefaults: opts?.overwriteDefaults?.[relation.field],
|
|
408
412
|
onItemCreate: opts?.onItemCreate,
|
|
409
413
|
mutationTracker: opts?.mutationTracker,
|
|
410
414
|
});
|
|
@@ -419,6 +423,7 @@ export class PayloadService {
|
|
|
419
423
|
autoPurgeCache: opts?.autoPurgeCache,
|
|
420
424
|
autoPurgeSystemCache: opts?.autoPurgeSystemCache,
|
|
421
425
|
skipTracking: opts?.skipTracking,
|
|
426
|
+
overwriteDefaults: opts?.overwriteDefaults?.[relation.field],
|
|
422
427
|
onItemCreate: opts?.onItemCreate,
|
|
423
428
|
mutationTracker: opts?.mutationTracker,
|
|
424
429
|
});
|
|
@@ -479,6 +484,7 @@ export class PayloadService {
|
|
|
479
484
|
autoPurgeCache: opts?.autoPurgeCache,
|
|
480
485
|
autoPurgeSystemCache: opts?.autoPurgeSystemCache,
|
|
481
486
|
skipTracking: opts?.skipTracking,
|
|
487
|
+
overwriteDefaults: opts?.overwriteDefaults?.[relation.field],
|
|
482
488
|
onItemCreate: opts?.onItemCreate,
|
|
483
489
|
mutationTracker: opts?.mutationTracker,
|
|
484
490
|
});
|
|
@@ -493,6 +499,7 @@ export class PayloadService {
|
|
|
493
499
|
autoPurgeCache: opts?.autoPurgeCache,
|
|
494
500
|
autoPurgeSystemCache: opts?.autoPurgeSystemCache,
|
|
495
501
|
skipTracking: opts?.skipTracking,
|
|
502
|
+
overwriteDefaults: opts?.overwriteDefaults?.[relation.field],
|
|
496
503
|
onItemCreate: opts?.onItemCreate,
|
|
497
504
|
mutationTracker: opts?.mutationTracker,
|
|
498
505
|
});
|
|
@@ -589,6 +596,7 @@ export class PayloadService {
|
|
|
589
596
|
autoPurgeCache: opts?.autoPurgeCache,
|
|
590
597
|
autoPurgeSystemCache: opts?.autoPurgeSystemCache,
|
|
591
598
|
skipTracking: opts?.skipTracking,
|
|
599
|
+
overwriteDefaults: opts?.overwriteDefaults?.[relation.meta.one_field],
|
|
592
600
|
onItemCreate: opts?.onItemCreate,
|
|
593
601
|
mutationTracker: opts?.mutationTracker,
|
|
594
602
|
})));
|
|
@@ -619,6 +627,7 @@ export class PayloadService {
|
|
|
619
627
|
autoPurgeCache: opts?.autoPurgeCache,
|
|
620
628
|
autoPurgeSystemCache: opts?.autoPurgeSystemCache,
|
|
621
629
|
skipTracking: opts?.skipTracking,
|
|
630
|
+
overwriteDefaults: opts?.overwriteDefaults?.[relation.meta.one_field],
|
|
622
631
|
onItemCreate: opts?.onItemCreate,
|
|
623
632
|
mutationTracker: opts?.mutationTracker,
|
|
624
633
|
});
|
|
@@ -632,6 +641,7 @@ export class PayloadService {
|
|
|
632
641
|
autoPurgeCache: opts?.autoPurgeCache,
|
|
633
642
|
autoPurgeSystemCache: opts?.autoPurgeSystemCache,
|
|
634
643
|
skipTracking: opts?.skipTracking,
|
|
644
|
+
overwriteDefaults: opts?.overwriteDefaults?.[relation.meta.one_field],
|
|
635
645
|
onItemCreate: opts?.onItemCreate,
|
|
636
646
|
mutationTracker: opts?.mutationTracker,
|
|
637
647
|
});
|
|
@@ -679,13 +689,14 @@ export class PayloadService {
|
|
|
679
689
|
autoPurgeCache: opts?.autoPurgeCache,
|
|
680
690
|
autoPurgeSystemCache: opts?.autoPurgeSystemCache,
|
|
681
691
|
skipTracking: opts?.skipTracking,
|
|
692
|
+
overwriteDefaults: opts?.overwriteDefaults?.[relation.meta.one_field]?.['create'],
|
|
682
693
|
onItemCreate: opts?.onItemCreate,
|
|
683
694
|
mutationTracker: opts?.mutationTracker,
|
|
684
695
|
});
|
|
685
696
|
}
|
|
686
697
|
if (alterations.update) {
|
|
687
|
-
for (const
|
|
688
|
-
const { [relatedPrimaryKeyField]: key, ...record } =
|
|
698
|
+
for (const index in alterations.update) {
|
|
699
|
+
const { [relatedPrimaryKeyField]: key, ...record } = alterations.update[index];
|
|
689
700
|
const existingRecord = await this.knex
|
|
690
701
|
.select(relatedPrimaryKeyField, relation.field)
|
|
691
702
|
.from(relation.collection)
|
|
@@ -702,6 +713,7 @@ export class PayloadService {
|
|
|
702
713
|
autoPurgeCache: opts?.autoPurgeCache,
|
|
703
714
|
autoPurgeSystemCache: opts?.autoPurgeSystemCache,
|
|
704
715
|
skipTracking: opts?.skipTracking,
|
|
716
|
+
overwriteDefaults: opts?.overwriteDefaults?.[relation.meta.one_field]?.['update'][index],
|
|
705
717
|
onItemCreate: opts?.onItemCreate,
|
|
706
718
|
mutationTracker: opts?.mutationTracker,
|
|
707
719
|
});
|
|
@@ -733,6 +745,7 @@ export class PayloadService {
|
|
|
733
745
|
autoPurgeCache: opts?.autoPurgeCache,
|
|
734
746
|
autoPurgeSystemCache: opts?.autoPurgeSystemCache,
|
|
735
747
|
skipTracking: opts?.skipTracking,
|
|
748
|
+
overwriteDefaults: opts?.overwriteDefaults?.[relation.meta.one_field]?.['delete'],
|
|
736
749
|
onItemCreate: opts?.onItemCreate,
|
|
737
750
|
mutationTracker: opts?.mutationTracker,
|
|
738
751
|
});
|
|
@@ -746,6 +759,7 @@ export class PayloadService {
|
|
|
746
759
|
autoPurgeCache: opts?.autoPurgeCache,
|
|
747
760
|
autoPurgeSystemCache: opts?.autoPurgeSystemCache,
|
|
748
761
|
skipTracking: opts?.skipTracking,
|
|
762
|
+
overwriteDefaults: opts?.overwriteDefaults?.[relation.meta.one_field]?.['delete'],
|
|
749
763
|
onItemCreate: opts?.onItemCreate,
|
|
750
764
|
mutationTracker: opts?.mutationTracker,
|
|
751
765
|
});
|
|
@@ -759,8 +773,8 @@ export class PayloadService {
|
|
|
759
773
|
* Transforms the input partial payload to match the output structure, to have consistency
|
|
760
774
|
* between delta and data
|
|
761
775
|
*/
|
|
762
|
-
async prepareDelta(
|
|
763
|
-
let payload = cloneDeep(
|
|
776
|
+
async prepareDelta(delta) {
|
|
777
|
+
let payload = cloneDeep(delta);
|
|
764
778
|
for (const key in payload) {
|
|
765
779
|
if (payload[key]?.isRawInstance) {
|
|
766
780
|
payload[key] = payload[key].bindings[0];
|
package/dist/services/schema.js
CHANGED
|
@@ -34,7 +34,10 @@ export class SchemaService {
|
|
|
34
34
|
validateSnapshot(snapshot, options?.force);
|
|
35
35
|
const currentSnapshot = options?.currentSnapshot ?? (await getSnapshot({ database: this.knex }));
|
|
36
36
|
const diff = getSnapshotDiff(currentSnapshot, snapshot);
|
|
37
|
-
if (diff.collections.length === 0 &&
|
|
37
|
+
if (diff.collections.length === 0 &&
|
|
38
|
+
diff.fields.length === 0 &&
|
|
39
|
+
diff.relations.length === 0 &&
|
|
40
|
+
(!diff.systemFields || diff.systemFields.length === 0)) {
|
|
38
41
|
return null;
|
|
39
42
|
}
|
|
40
43
|
return diff;
|
|
@@ -7,6 +7,7 @@ export declare class ServerService {
|
|
|
7
7
|
settingsService: SettingsService;
|
|
8
8
|
schema: SchemaOverview;
|
|
9
9
|
constructor(options: AbstractServiceOptions);
|
|
10
|
+
isSetupCompleted(): Promise<boolean>;
|
|
10
11
|
serverInfo(): Promise<Record<string, any>>;
|
|
11
12
|
health(): Promise<Record<string, any>>;
|
|
12
13
|
}
|
package/dist/services/server.js
CHANGED
|
@@ -28,8 +28,12 @@ export class ServerService {
|
|
|
28
28
|
this.schema = options.schema;
|
|
29
29
|
this.settingsService = new SettingsService({ knex: this.knex, schema: this.schema });
|
|
30
30
|
}
|
|
31
|
+
async isSetupCompleted() {
|
|
32
|
+
return Boolean(await this.knex('directus_users').first());
|
|
33
|
+
}
|
|
31
34
|
async serverInfo() {
|
|
32
35
|
const info = {};
|
|
36
|
+
const setupComplete = await this.isSetupCompleted();
|
|
33
37
|
const projectInfo = await this.settingsService.readSingleton({
|
|
34
38
|
fields: [
|
|
35
39
|
'project_name',
|
|
@@ -53,6 +57,8 @@ export class ServerService {
|
|
|
53
57
|
],
|
|
54
58
|
});
|
|
55
59
|
info['project'] = projectInfo;
|
|
60
|
+
info['mcp_enabled'] = toBoolean(env['MCP_ENABLED'] ?? true);
|
|
61
|
+
info['setupCompleted'] = setupComplete;
|
|
56
62
|
if (this.accountability?.user) {
|
|
57
63
|
if (env['RATE_LIMITER_ENABLED']) {
|
|
58
64
|
info['rateLimit'] = {
|
|
@@ -111,8 +117,9 @@ export class ServerService {
|
|
|
111
117
|
chunkSize: RESUMABLE_UPLOADS.CHUNK_SIZE,
|
|
112
118
|
};
|
|
113
119
|
}
|
|
114
|
-
info['version'] = version;
|
|
115
120
|
}
|
|
121
|
+
if (this.accountability?.user || !setupComplete)
|
|
122
|
+
info['version'] = version;
|
|
116
123
|
return info;
|
|
117
124
|
}
|
|
118
125
|
async health() {
|
|
@@ -221,8 +228,8 @@ export class ServerService {
|
|
|
221
228
|
};
|
|
222
229
|
const startTime = performance.now();
|
|
223
230
|
try {
|
|
224
|
-
await cache.set(`health-${checkID}`, true, 5);
|
|
225
|
-
await cache.delete(`health-${checkID}`);
|
|
231
|
+
await cache.set(`directus-health-${checkID}`, true, 5);
|
|
232
|
+
await cache.delete(`directus-health-${checkID}`);
|
|
226
233
|
}
|
|
227
234
|
catch (err) {
|
|
228
235
|
checks['cache:responseTime'][0].status = 'error';
|
|
@@ -255,8 +262,8 @@ export class ServerService {
|
|
|
255
262
|
};
|
|
256
263
|
const startTime = performance.now();
|
|
257
264
|
try {
|
|
258
|
-
await rateLimiter.consume(`health-${checkID}`, 1);
|
|
259
|
-
await rateLimiter.delete(`health-${checkID}`);
|
|
265
|
+
await rateLimiter.consume(`directus-health-${checkID}`, 1);
|
|
266
|
+
await rateLimiter.delete(`directus-health-${checkID}`);
|
|
260
267
|
}
|
|
261
268
|
catch (err) {
|
|
262
269
|
checks['rateLimiter:responseTime'][0].status = 'error';
|
|
@@ -291,8 +298,8 @@ export class ServerService {
|
|
|
291
298
|
};
|
|
292
299
|
const startTime = performance.now();
|
|
293
300
|
try {
|
|
294
|
-
await rateLimiterGlobal.consume(`health-${checkID}`, 1);
|
|
295
|
-
await rateLimiterGlobal.delete(`health-${checkID}`);
|
|
301
|
+
await rateLimiterGlobal.consume(`directus-health-${checkID}`, 1);
|
|
302
|
+
await rateLimiterGlobal.delete(`directus-health-${checkID}`);
|
|
296
303
|
}
|
|
297
304
|
catch (err) {
|
|
298
305
|
checks['rateLimiterGlobal:responseTime'][0].status = 'error';
|
|
@@ -326,17 +333,7 @@ export class ServerService {
|
|
|
326
333
|
];
|
|
327
334
|
const startTime = performance.now();
|
|
328
335
|
try {
|
|
329
|
-
await disk.write(
|
|
330
|
-
const fileStream = await disk.read(`health-${checkID}`);
|
|
331
|
-
fileStream.on('data', async () => {
|
|
332
|
-
try {
|
|
333
|
-
fileStream.destroy();
|
|
334
|
-
await disk.delete(`health-${checkID}`);
|
|
335
|
-
}
|
|
336
|
-
catch (error) {
|
|
337
|
-
logger.error(error);
|
|
338
|
-
}
|
|
339
|
-
});
|
|
336
|
+
await disk.write('directus-health-file', Readable.from([checkID]));
|
|
340
337
|
}
|
|
341
338
|
catch (err) {
|
|
342
339
|
checks[`storage:${location}:responseTime`][0].status = 'error';
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type { AbstractServiceOptions } from '@directus/types';
|
|
1
|
+
import type { AbstractServiceOptions, OwnerInformation } from '@directus/types';
|
|
2
2
|
import { ItemsService } from './items.js';
|
|
3
3
|
export declare class SettingsService extends ItemsService {
|
|
4
4
|
constructor(options: AbstractServiceOptions);
|
|
5
|
+
setOwner(data: OwnerInformation): Promise<import("@directus/types").PrimaryKey>;
|
|
5
6
|
}
|
|
@@ -1,6 +1,21 @@
|
|
|
1
1
|
import { ItemsService } from './items.js';
|
|
2
|
+
import { sendReport } from '../telemetry/index.js';
|
|
3
|
+
import { version } from 'directus/version';
|
|
2
4
|
export class SettingsService extends ItemsService {
|
|
3
5
|
constructor(options) {
|
|
4
6
|
super('directus_settings', options);
|
|
5
7
|
}
|
|
8
|
+
async setOwner(data) {
|
|
9
|
+
const { project_id } = await this.knex.select('project_id').from('directus_settings').first();
|
|
10
|
+
sendReport({ ...data, project_id, version }).catch(async () => {
|
|
11
|
+
await this.knex.update('project_status', 'pending').from('directus_settings');
|
|
12
|
+
});
|
|
13
|
+
return await this.upsertSingleton({
|
|
14
|
+
project_owner: data.project_owner,
|
|
15
|
+
project_usage: data.project_usage,
|
|
16
|
+
org_name: data.org_name,
|
|
17
|
+
product_updates: data.product_updates,
|
|
18
|
+
project_status: null,
|
|
19
|
+
});
|
|
20
|
+
}
|
|
6
21
|
}
|
package/dist/services/tfa.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ export declare class TFAService {
|
|
|
6
6
|
itemsService: ItemsService;
|
|
7
7
|
constructor(options: AbstractServiceOptions);
|
|
8
8
|
verifyOTP(key: PrimaryKey, otp: string, secret?: string): Promise<boolean>;
|
|
9
|
-
generateTFA(key: PrimaryKey): Promise<Record<string, string>>;
|
|
9
|
+
generateTFA(key: PrimaryKey, requiresPassword?: boolean): Promise<Record<string, string>>;
|
|
10
10
|
enableTFA(key: PrimaryKey, otp: string, secret: string): Promise<void>;
|
|
11
11
|
disableTFA(key: PrimaryKey): Promise<void>;
|
|
12
12
|
}
|