@directus/api 32.1.1 → 33.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/ai/chat/constants/system-prompt.d.ts +1 -0
- package/dist/ai/chat/constants/system-prompt.js +51 -0
- package/dist/ai/chat/controllers/chat.post.d.ts +2 -0
- package/dist/ai/chat/controllers/chat.post.js +47 -0
- package/dist/ai/chat/lib/create-ui-stream.d.ts +15 -0
- package/dist/ai/chat/lib/create-ui-stream.js +42 -0
- package/dist/ai/chat/middleware/load-settings.d.ts +2 -0
- package/dist/ai/chat/middleware/load-settings.js +18 -0
- package/dist/ai/chat/models/chat-request.d.ts +34 -0
- package/dist/ai/chat/models/chat-request.js +26 -0
- package/dist/ai/chat/models/providers.d.ts +9 -0
- package/dist/ai/chat/models/providers.js +9 -0
- package/dist/ai/chat/router.d.ts +1 -0
- package/dist/ai/chat/router.js +5 -0
- package/dist/ai/chat/utils/chat-request-tool-to-ai-sdk-tool.d.ts +9 -0
- package/dist/ai/chat/utils/chat-request-tool-to-ai-sdk-tool.js +38 -0
- package/dist/ai/chat/utils/fix-error-tool-calls.d.ts +12 -0
- package/dist/ai/chat/utils/fix-error-tool-calls.js +30 -0
- package/dist/ai/chat/utils/parse-json-schema-7.d.ts +13 -0
- package/dist/ai/chat/utils/parse-json-schema-7.js +75 -0
- package/dist/{mcp → ai/mcp}/server.d.ts +13 -16
- package/dist/{mcp → ai/mcp}/server.js +4 -13
- package/dist/ai/mcp/types.d.ts +15 -0
- package/dist/{mcp/tools/assets.js → ai/tools/assets/index.js} +8 -5
- package/dist/{mcp/tools/collections.js → ai/tools/collections/index.js} +7 -4
- package/dist/{mcp/tools/fields.js → ai/tools/fields/index.js} +12 -9
- package/dist/{mcp/tools/files.js → ai/tools/files/index.js} +11 -5
- package/dist/{mcp/tools/flows.js → ai/tools/flows/index.js} +11 -5
- package/dist/{mcp/tools/folders.js → ai/tools/folders/index.js} +12 -5
- package/dist/ai/tools/index.d.ts +15 -0
- package/dist/ai/tools/index.js +29 -0
- package/dist/{mcp/tools/items.js → ai/tools/items/index.js} +13 -6
- package/dist/{mcp/tools/prompts/items.md → ai/tools/items/prompt.md} +19 -15
- package/dist/{mcp/tools/operations.d.ts → ai/tools/operations/index.d.ts} +46 -0
- package/dist/{mcp/tools/operations.js → ai/tools/operations/index.js} +12 -5
- package/dist/{mcp/tools/relations.js → ai/tools/relations/index.js} +7 -4
- package/dist/{mcp/tools/schema.d.ts → ai/tools/schema/index.d.ts} +1 -1
- package/dist/{mcp/tools/schema.js → ai/tools/schema/index.js} +9 -6
- package/dist/{mcp/tools/system.js → ai/tools/system/index.js} +7 -4
- package/dist/{mcp/tools/trigger-flow.js → ai/tools/trigger-flow/index.js} +8 -5
- package/dist/{mcp → ai/tools}/types.d.ts +1 -17
- package/dist/ai/tools/utils.d.ts +9 -0
- package/dist/ai/tools/utils.js +17 -0
- package/dist/app.js +11 -6
- package/dist/auth/drivers/ldap.js +2 -2
- package/dist/auth/drivers/local.js +1 -1
- package/dist/auth/drivers/oauth2.d.ts +1 -2
- package/dist/auth/drivers/oauth2.js +22 -17
- package/dist/auth/drivers/openid.d.ts +1 -2
- package/dist/auth/drivers/openid.js +18 -13
- package/dist/auth/drivers/saml.js +6 -3
- package/dist/auth/utils/generate-callback-url.d.ts +11 -0
- package/dist/auth/utils/generate-callback-url.js +40 -0
- package/dist/auth/utils/is-login-redirect-allowed.d.ts +7 -0
- package/dist/{utils → auth/utils}/is-login-redirect-allowed.js +12 -9
- package/dist/cache.js +2 -2
- package/dist/cli/commands/bootstrap/index.js +2 -2
- package/dist/cli/commands/database/install.js +1 -1
- package/dist/cli/commands/database/migrate.js +1 -1
- package/dist/cli/commands/init/index.js +2 -2
- package/dist/cli/commands/roles/create.js +4 -4
- package/dist/cli/commands/schema/apply.js +3 -3
- package/dist/cli/commands/schema/snapshot.js +1 -1
- package/dist/cli/utils/create-db-connection.d.ts +1 -1
- package/dist/cli/utils/create-db-connection.js +1 -1
- package/dist/cli/utils/create-env/index.js +1 -1
- package/dist/constants.d.ts +7 -3
- package/dist/constants.js +7 -3
- package/dist/controllers/access.js +1 -1
- package/dist/controllers/assets.js +40 -3
- package/dist/controllers/extensions.js +1 -1
- package/dist/controllers/fields.js +2 -2
- package/dist/controllers/files.js +1 -1
- package/dist/controllers/items.js +1 -1
- package/dist/controllers/mcp.js +1 -1
- package/dist/controllers/not-found.js +1 -1
- package/dist/controllers/relations.js +1 -1
- package/dist/database/errors/dialects/mysql.d.ts +1 -1
- package/dist/database/errors/dialects/postgres.d.ts +1 -1
- package/dist/database/errors/dialects/sqlite.d.ts +1 -1
- package/dist/database/errors/translate.d.ts +1 -1
- package/dist/database/errors/translate.js +1 -1
- package/dist/database/helpers/date/dialects/mssql.js +1 -1
- package/dist/database/helpers/date/dialects/mysql.js +1 -1
- package/dist/database/helpers/date/types.js +1 -1
- package/dist/database/helpers/schema/dialects/cockroachdb.d.ts +1 -0
- package/dist/database/helpers/schema/dialects/cockroachdb.js +24 -1
- package/dist/database/helpers/schema/dialects/mssql.d.ts +1 -1
- package/dist/database/helpers/schema/dialects/mysql.d.ts +2 -1
- package/dist/database/helpers/schema/dialects/mysql.js +16 -3
- package/dist/database/helpers/schema/dialects/postgres.d.ts +1 -1
- package/dist/database/helpers/schema/types.d.ts +13 -0
- package/dist/database/helpers/schema/types.js +24 -0
- package/dist/database/index.js +4 -4
- package/dist/database/migrations/20220429A-add-flows.js +1 -1
- package/dist/database/migrations/20230526A-migrate-translation-strings.js +1 -1
- package/dist/database/migrations/20231009A-update-csv-fields-to-text.js +1 -1
- package/dist/database/migrations/20240204A-marketplace.js +9 -7
- package/dist/database/migrations/20240311A-deprecate-webhooks.d.ts +15 -0
- package/dist/database/migrations/20240311A-deprecate-webhooks.js +1 -1
- package/dist/database/migrations/20240806A-permissions-policies.js +3 -3
- package/dist/database/migrations/20240924A-migrate-legacy-comments.js +1 -1
- package/dist/database/migrations/20251014A-add-project-owner.js +1 -1
- package/dist/database/migrations/20251103A-add-ai-settings.d.ts +3 -0
- package/dist/database/migrations/20251103A-add-ai-settings.js +14 -0
- package/dist/database/migrations/20251224A-remove-webhooks.d.ts +3 -0
- package/dist/database/migrations/20251224A-remove-webhooks.js +19 -0
- package/dist/database/migrations/20260113A-add-revisions-index.d.ts +3 -0
- package/dist/database/migrations/20260113A-add-revisions-index.js +41 -0
- package/dist/database/migrations/run.js +3 -3
- package/dist/database/run-ast/lib/apply-query/filter/get-filter-type.d.ts +2 -2
- package/dist/database/run-ast/lib/apply-query/filter/get-filter-type.js +1 -1
- package/dist/database/run-ast/lib/apply-query/filter/operator.js +1 -1
- package/dist/database/run-ast/lib/apply-query/sort.js +1 -1
- package/dist/database/run-ast/run-ast.js +1 -1
- package/dist/database/run-ast/utils/get-column-pre-processor.js +2 -2
- package/dist/database/run-ast/utils/get-column.js +1 -1
- package/dist/database/seeds/run.js +3 -3
- package/dist/extensions/lib/get-extensions-path.js +1 -1
- package/dist/extensions/lib/get-extensions-settings.js +1 -1
- package/dist/extensions/lib/get-extensions.js +1 -1
- package/dist/extensions/lib/get-shared-deps-mapping.js +3 -3
- package/dist/extensions/lib/installation/manager.js +8 -12
- package/dist/extensions/lib/sandbox/register/route.d.ts +1 -1
- package/dist/extensions/lib/sync/status.d.ts +11 -0
- package/dist/extensions/lib/sync/status.js +34 -0
- package/dist/extensions/lib/sync/sync.d.ts +6 -0
- package/dist/extensions/lib/sync/sync.js +90 -0
- package/dist/extensions/lib/sync/tracker.d.ts +18 -0
- package/dist/extensions/lib/sync/tracker.js +71 -0
- package/dist/extensions/lib/sync/utils.d.ts +24 -0
- package/dist/extensions/lib/sync/utils.js +62 -0
- package/dist/extensions/manager.d.ts +9 -5
- package/dist/extensions/manager.js +36 -19
- package/dist/flows.d.ts +1 -1
- package/dist/logger/index.js +1 -1
- package/dist/logger/logs-stream.d.ts +1 -1
- package/dist/logger/logs-stream.js +1 -1
- package/dist/mailer.js +1 -1
- package/dist/metrics/lib/create-metrics.js +2 -2
- package/dist/middleware/authenticate.js +3 -3
- package/dist/middleware/collection-exists.js +1 -1
- package/dist/middleware/extract-token.js +1 -1
- package/dist/middleware/graphql.js +2 -2
- package/dist/middleware/respond.js +2 -2
- package/dist/middleware/validate-batch.js +1 -1
- package/dist/operations/exec/index.js +2 -1
- package/dist/operations/mail/index.js +1 -1
- package/dist/operations/mail/rate-limiter.js +2 -2
- package/dist/permissions/cache.js +5 -0
- package/dist/permissions/lib/fetch-policies.d.ts +1 -1
- package/dist/permissions/lib/fetch-roles-tree.d.ts +6 -3
- package/dist/permissions/lib/fetch-roles-tree.js +5 -27
- package/dist/permissions/modules/fetch-allowed-collections/fetch-allowed-collections.js +1 -1
- package/dist/permissions/modules/fetch-allowed-field-map/fetch-allowed-field-map.js +1 -1
- package/dist/permissions/modules/fetch-global-access/fetch-global-access.d.ts +9 -7
- package/dist/permissions/modules/fetch-global-access/fetch-global-access.js +17 -9
- package/dist/permissions/modules/fetch-inconsistent-field-map/fetch-inconsistent-field-map.js +2 -2
- package/dist/permissions/modules/fetch-policies-ip-access/fetch-policies-ip-access.d.ts +1 -1
- package/dist/permissions/modules/process-ast/lib/inject-cases.js +1 -1
- package/dist/permissions/modules/process-ast/process-ast.js +1 -1
- package/dist/permissions/modules/process-payload/process-payload.js +1 -1
- package/dist/permissions/modules/validate-access/lib/validate-item-access.d.ts +13 -1
- package/dist/permissions/modules/validate-access/lib/validate-item-access.js +54 -6
- package/dist/permissions/modules/validate-access/validate-access.js +3 -2
- package/dist/permissions/utils/fetch-raw-permissions.d.ts +1 -1
- package/dist/permissions/utils/fetch-share-info.d.ts +1 -1
- package/dist/permissions/utils/fetch-share-info.js +1 -1
- package/dist/permissions/utils/filter-policies-by-ip.js +1 -1
- package/dist/permissions/utils/get-permissions-for-share.js +8 -8
- package/dist/permissions/utils/with-cache.d.ts +8 -6
- package/dist/permissions/utils/with-cache.js +12 -10
- package/dist/rate-limiter.js +1 -1
- package/dist/request/is-denied-ip.js +2 -2
- package/dist/schedules/project.js +1 -1
- package/dist/schedules/telemetry.js +1 -1
- package/dist/schedules/tus.js +1 -1
- package/dist/server.js +4 -4
- package/dist/services/assets/name-deduper.d.ts +7 -0
- package/dist/services/assets/name-deduper.js +23 -0
- package/dist/services/assets.d.ts +17 -3
- package/dist/services/assets.js +133 -13
- package/dist/services/authentication.js +6 -6
- package/dist/services/collections.js +1 -1
- package/dist/services/comments.js +2 -2
- package/dist/services/extensions.d.ts +1 -1
- package/dist/services/extensions.js +4 -0
- package/dist/services/files/utils/get-metadata.d.ts +1 -1
- package/dist/services/files/utils/get-metadata.js +1 -1
- package/dist/services/files.d.ts +1 -1
- package/dist/services/files.js +4 -4
- package/dist/services/folders.d.ts +27 -2
- package/dist/services/folders.js +75 -0
- package/dist/services/graphql/index.d.ts +1 -1
- package/dist/services/graphql/index.js +1 -1
- package/dist/services/graphql/resolvers/mutation.js +1 -1
- package/dist/services/graphql/schema/get-types.d.ts +1 -1
- package/dist/services/graphql/schema/read.js +1 -1
- package/dist/services/graphql/subscription.d.ts +1 -1
- package/dist/services/graphql/types/date.js +1 -1
- package/dist/services/graphql/types/hash.js +1 -1
- package/dist/services/graphql/utils/add-path-to-validation-error.js +1 -1
- package/dist/services/import-export.d.ts +2 -2
- package/dist/services/import-export.js +6 -7
- package/dist/services/index.d.ts +0 -1
- package/dist/services/index.js +0 -1
- package/dist/services/mail/index.js +2 -2
- package/dist/services/mail/rate-limiter.js +2 -2
- package/dist/services/notifications.js +2 -2
- package/dist/services/payload.js +21 -1
- package/dist/services/roles.js +2 -2
- package/dist/services/schema.js +1 -1
- package/dist/services/server.js +12 -4
- package/dist/services/settings.js +2 -2
- package/dist/services/tfa.js +1 -1
- package/dist/services/translations.js +1 -1
- package/dist/services/tus/data-store.d.ts +1 -3
- package/dist/services/tus/data-store.js +2 -5
- package/dist/services/tus/server.js +9 -9
- package/dist/services/users.js +4 -4
- package/dist/services/versions.js +1 -1
- package/dist/telemetry/lib/send-report.d.ts +1 -1
- package/dist/telemetry/lib/send-report.js +1 -1
- package/dist/telemetry/lib/track.js +1 -1
- package/dist/telemetry/utils/get-settings.d.ts +15 -0
- package/dist/telemetry/utils/get-settings.js +13 -1
- package/dist/test-utils/README.md +95 -24
- package/dist/test-utils/cache.d.ts +2 -2
- package/dist/test-utils/cache.js +2 -2
- package/dist/test-utils/knex.js +1 -1
- package/dist/test-utils/{fields-service.d.ts → services/fields-service.d.ts} +1 -1
- package/dist/test-utils/{fields-service.js → services/fields-service.js} +3 -2
- package/dist/test-utils/services/files-service.d.ts +28 -0
- package/dist/test-utils/services/files-service.js +34 -0
- package/dist/test-utils/services/folders-service.d.ts +28 -0
- package/dist/test-utils/services/folders-service.js +33 -0
- package/dist/types/collection.d.ts +1 -1
- package/dist/utils/async-handler.d.ts +1 -1
- package/dist/utils/calculate-field-depth.js +1 -1
- package/dist/utils/compress.js +1 -1
- package/dist/utils/deep-map-response.js +2 -2
- package/dist/utils/encrypt.d.ts +2 -0
- package/dist/utils/encrypt.js +64 -0
- package/dist/utils/get-accountability-for-role.js +2 -2
- package/dist/utils/get-accountability-for-token.js +4 -4
- package/dist/utils/get-cache-key.js +3 -3
- package/dist/utils/get-field-system-rows.js +1 -1
- package/dist/utils/get-ip-from-req.d.ts +1 -1
- package/dist/utils/get-ip-from-req.js +1 -1
- package/dist/utils/get-local-type.js +7 -3
- package/dist/utils/get-service.js +1 -3
- package/dist/utils/get-snapshot-diff.js +1 -1
- package/dist/utils/is-url-allowed.js +1 -1
- package/dist/utils/jwt.js +1 -1
- package/dist/utils/require-text.d.ts +1 -0
- package/dist/utils/require-text.js +4 -0
- package/dist/utils/require-yaml.js +2 -2
- package/dist/utils/sanitize-schema.d.ts +1 -1
- package/dist/utils/should-clear-cache.d.ts +1 -1
- package/dist/utils/should-skip-cache.js +2 -2
- package/dist/utils/validate-diff.js +1 -1
- package/dist/utils/validate-snapshot.js +3 -3
- package/dist/utils/validate-storage.js +2 -2
- package/dist/utils/verify-session-jwt.js +1 -1
- package/dist/utils/versioning/deep-map-with-schema.js +2 -2
- package/dist/websocket/controllers/base.d.ts +2 -2
- package/dist/websocket/controllers/base.js +3 -3
- package/dist/websocket/controllers/graphql.d.ts +1 -1
- package/dist/websocket/controllers/graphql.js +1 -1
- package/dist/websocket/controllers/logs.d.ts +1 -1
- package/dist/websocket/controllers/rest.d.ts +1 -1
- package/dist/websocket/controllers/rest.js +2 -2
- package/dist/websocket/handlers/heartbeat.js +1 -1
- package/dist/websocket/handlers/items.js +2 -2
- package/dist/websocket/handlers/subscribe.js +1 -1
- package/dist/websocket/types.d.ts +1 -1
- package/dist/websocket/utils/wait-for-message.js +1 -1
- package/package.json +34 -28
- package/dist/controllers/webhooks.d.ts +0 -2
- package/dist/controllers/webhooks.js +0 -74
- package/dist/extensions/lib/sync-extensions.d.ts +0 -3
- package/dist/extensions/lib/sync-extensions.js +0 -70
- package/dist/extensions/lib/sync-status.d.ts +0 -10
- package/dist/extensions/lib/sync-status.js +0 -27
- package/dist/mcp/tools/index.d.ts +0 -15
- package/dist/mcp/tools/index.js +0 -29
- package/dist/mcp/tools/prompts/index.d.ts +0 -16
- package/dist/mcp/tools/prompts/index.js +0 -19
- package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-roles.d.ts +0 -5
- package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-roles.js +0 -7
- package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-user.d.ts +0 -5
- package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-user.js +0 -10
- package/dist/permissions/modules/fetch-global-access/types.d.ts +0 -4
- package/dist/permissions/modules/fetch-global-access/utils/fetch-global-access-for-query.d.ts +0 -4
- package/dist/permissions/modules/fetch-global-access/utils/fetch-global-access-for-query.js +0 -27
- package/dist/services/webhooks.d.ts +0 -14
- package/dist/services/webhooks.js +0 -32
- package/dist/utils/get-date-formatted.d.ts +0 -1
- package/dist/utils/get-date-formatted.js +0 -10
- package/dist/utils/ip-in-networks.d.ts +0 -6
- package/dist/utils/ip-in-networks.js +0 -13
- package/dist/utils/is-login-redirect-allowed.d.ts +0 -4
- /package/dist/{mcp → ai/mcp}/index.d.ts +0 -0
- /package/dist/{mcp → ai/mcp}/index.js +0 -0
- /package/dist/{mcp → ai/mcp}/transport.d.ts +0 -0
- /package/dist/{mcp → ai/mcp}/transport.js +0 -0
- /package/dist/{mcp → ai/mcp}/types.js +0 -0
- /package/dist/{mcp/tools/assets.d.ts → ai/tools/assets/index.d.ts} +0 -0
- /package/dist/{mcp/tools/prompts/assets.md → ai/tools/assets/prompt.md} +0 -0
- /package/dist/{mcp/tools/collections.d.ts → ai/tools/collections/index.d.ts} +0 -0
- /package/dist/{mcp/tools/prompts/collections.md → ai/tools/collections/prompt.md} +0 -0
- /package/dist/{mcp/define.d.ts → ai/tools/define-tool.d.ts} +0 -0
- /package/dist/{mcp/define.js → ai/tools/define-tool.js} +0 -0
- /package/dist/{mcp/tools/fields.d.ts → ai/tools/fields/index.d.ts} +0 -0
- /package/dist/{mcp/tools/prompts/fields.md → ai/tools/fields/prompt.md} +0 -0
- /package/dist/{mcp/tools/files.d.ts → ai/tools/files/index.d.ts} +0 -0
- /package/dist/{mcp/tools/prompts/files.md → ai/tools/files/prompt.md} +0 -0
- /package/dist/{mcp/tools/flows.d.ts → ai/tools/flows/index.d.ts} +0 -0
- /package/dist/{mcp/tools/prompts/flows.md → ai/tools/flows/prompt.md} +0 -0
- /package/dist/{mcp/tools/folders.d.ts → ai/tools/folders/index.d.ts} +0 -0
- /package/dist/{mcp/tools/prompts/folders.md → ai/tools/folders/prompt.md} +0 -0
- /package/dist/{mcp/tools/items.d.ts → ai/tools/items/index.d.ts} +0 -0
- /package/dist/{mcp/tools/prompts/operations.md → ai/tools/operations/prompt.md} +0 -0
- /package/dist/{mcp/tools/relations.d.ts → ai/tools/relations/index.d.ts} +0 -0
- /package/dist/{mcp/tools/prompts/relations.md → ai/tools/relations/prompt.md} +0 -0
- /package/dist/{mcp/tools/prompts/schema.md → ai/tools/schema/prompt.md} +0 -0
- /package/dist/{mcp → ai/tools}/schema.d.ts +0 -0
- /package/dist/{mcp → ai/tools}/schema.js +0 -0
- /package/dist/{mcp/tools/system.d.ts → ai/tools/system/index.d.ts} +0 -0
- /package/dist/{mcp/tools/prompts/system-prompt-description.md → ai/tools/system/prompt-description.md} +0 -0
- /package/dist/{mcp/tools/prompts/system-prompt.md → ai/tools/system/prompt.md} +0 -0
- /package/dist/{mcp/tools/trigger-flow.d.ts → ai/tools/trigger-flow/index.d.ts} +0 -0
- /package/dist/{mcp/tools/prompts/trigger-flow.md → ai/tools/trigger-flow/prompt.md} +0 -0
- /package/dist/{permissions/modules/fetch-global-access → ai/tools}/types.js +0 -0
- /package/dist/test-utils/{items-service.d.ts → services/items-service.d.ts} +0 -0
- /package/dist/test-utils/{items-service.js → services/items-service.js} +0 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { stat } from 'node:fs/promises';
|
|
2
|
+
import { join, relative, resolve, sep } from 'node:path';
|
|
3
|
+
import { useEnv } from '@directus/env';
|
|
4
|
+
import { normalizePath } from '@directus/utils';
|
|
5
|
+
import { getExtensionsPath } from '../get-extensions-path.js';
|
|
6
|
+
/**
|
|
7
|
+
* Returns the directory depth of the provided path
|
|
8
|
+
*/
|
|
9
|
+
export function pathDepth(path) {
|
|
10
|
+
let count = 0;
|
|
11
|
+
for (let i = 0; i < path.length; i++) {
|
|
12
|
+
if (path[i] === sep)
|
|
13
|
+
count++;
|
|
14
|
+
}
|
|
15
|
+
return count;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Reads the size and modified date of a file if it exists
|
|
19
|
+
*/
|
|
20
|
+
export async function fsStat(path) {
|
|
21
|
+
const data = await stat(path, { bigint: false }).catch(() => {
|
|
22
|
+
/* file not available */
|
|
23
|
+
});
|
|
24
|
+
if (!data)
|
|
25
|
+
return null;
|
|
26
|
+
return {
|
|
27
|
+
size: data.size,
|
|
28
|
+
modified: data.mtime,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Builds up the local and remote paths to use with syncing
|
|
33
|
+
*/
|
|
34
|
+
export function getSyncPaths(partialPath) {
|
|
35
|
+
const env = useEnv();
|
|
36
|
+
const localRootPath = getExtensionsPath();
|
|
37
|
+
const remoteRootPath = env['EXTENSIONS_PATH'];
|
|
38
|
+
if (!partialPath) {
|
|
39
|
+
return {
|
|
40
|
+
localExtensionsPath: localRootPath,
|
|
41
|
+
remoteExtensionsPath: normalizePath(remoteRootPath),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
const resolvedPartialPath = relative(sep, resolve(sep, partialPath));
|
|
45
|
+
return {
|
|
46
|
+
localExtensionsPath: join(localRootPath, resolvedPartialPath),
|
|
47
|
+
remoteExtensionsPath: normalizePath(join(remoteRootPath, resolvedPartialPath)),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Retrieve the stats for local and remote files and check if they are the same
|
|
52
|
+
* Returns false if files are differnt else true
|
|
53
|
+
*/
|
|
54
|
+
export async function compareFileMetadata(localPath, remotePath, disk) {
|
|
55
|
+
const localStat = await fsStat(localPath).catch(() => { });
|
|
56
|
+
if (!localStat)
|
|
57
|
+
return false;
|
|
58
|
+
const remoteStat = await disk.stat(remotePath).catch(() => { });
|
|
59
|
+
if (!remoteStat)
|
|
60
|
+
return false;
|
|
61
|
+
return remoteStat.modified <= localStat.modified && remoteStat.size === localStat.size;
|
|
62
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import type { ReadStream } from 'node:fs';
|
|
1
2
|
import type { Extension, ExtensionManagerOptions } from '@directus/types';
|
|
2
3
|
import { Router } from 'express';
|
|
3
|
-
import type
|
|
4
|
+
import { type ExtensionSyncOptions } from './lib/sync/sync.js';
|
|
4
5
|
export declare class ExtensionManager {
|
|
5
6
|
private options;
|
|
6
7
|
/**
|
|
@@ -47,6 +48,10 @@ export declare class ExtensionManager {
|
|
|
47
48
|
* sequence.
|
|
48
49
|
*/
|
|
49
50
|
private reloadQueue;
|
|
51
|
+
/**
|
|
52
|
+
* Used to prevent race condition when reading extension data while reloading extensions
|
|
53
|
+
*/
|
|
54
|
+
private reloadPromise;
|
|
50
55
|
/**
|
|
51
56
|
* Optional file system watcher to auto-reload extensions when the local file system changes
|
|
52
57
|
*/
|
|
@@ -76,7 +81,7 @@ export declare class ExtensionManager {
|
|
|
76
81
|
*/
|
|
77
82
|
install(versionId: string): Promise<void>;
|
|
78
83
|
uninstall(folder: string): Promise<void>;
|
|
79
|
-
broadcastReloadNotification(): Promise<void>;
|
|
84
|
+
broadcastReloadNotification(options?: ExtensionSyncOptions): Promise<void>;
|
|
80
85
|
/**
|
|
81
86
|
* Load all extensions from disk and register them in their respective places
|
|
82
87
|
*/
|
|
@@ -88,9 +93,8 @@ export declare class ExtensionManager {
|
|
|
88
93
|
/**
|
|
89
94
|
* Reload all the extensions. Will unload if extensions have already been loaded
|
|
90
95
|
*/
|
|
91
|
-
reload(options?:
|
|
92
|
-
|
|
93
|
-
}): Promise<unknown>;
|
|
96
|
+
reload(options?: ExtensionSyncOptions): Promise<unknown>;
|
|
97
|
+
isReloading(): Promise<void>;
|
|
94
98
|
/**
|
|
95
99
|
* Return the previously generated app extension bundle chunk by name.
|
|
96
100
|
* Providing no name will return the entry bundle.
|
|
@@ -1,7 +1,13 @@
|
|
|
1
|
+
import { readdir, readFile } from 'node:fs/promises';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import { dirname, join, relative, resolve, sep } from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import path from 'path';
|
|
6
|
+
import { HYBRID_EXTENSION_TYPES } from '@directus/constants';
|
|
1
7
|
import { useEnv } from '@directus/env';
|
|
2
8
|
import { APP_SHARED_DEPS } from '@directus/extensions';
|
|
3
|
-
import { HYBRID_EXTENSION_TYPES } from '@directus/constants';
|
|
4
9
|
import { generateExtensionsEntrypoint } from '@directus/extensions/node';
|
|
10
|
+
import DriverLocal from '@directus/storage-driver-local';
|
|
5
11
|
import { isTypeIn, toBoolean } from '@directus/utils';
|
|
6
12
|
import { pathToRelativeUrl, processId } from '@directus/utils/node';
|
|
7
13
|
import aliasDefault from '@rollup/plugin-alias';
|
|
@@ -11,11 +17,6 @@ import chokidar, { FSWatcher } from 'chokidar';
|
|
|
11
17
|
import express, { Router } from 'express';
|
|
12
18
|
import ivm from 'isolated-vm';
|
|
13
19
|
import { clone, debounce, isPlainObject } from 'lodash-es';
|
|
14
|
-
import { readFile, readdir } from 'node:fs/promises';
|
|
15
|
-
import os from 'node:os';
|
|
16
|
-
import { dirname, join } from 'node:path';
|
|
17
|
-
import { fileURLToPath } from 'node:url';
|
|
18
|
-
import path from 'path';
|
|
19
20
|
import { rolldown } from 'rolldown';
|
|
20
21
|
import { rollup } from 'rollup';
|
|
21
22
|
import { useBus } from '../bus/index.js';
|
|
@@ -37,9 +38,8 @@ import { getSharedDepsMapping } from './lib/get-shared-deps-mapping.js';
|
|
|
37
38
|
import { getInstallationManager } from './lib/installation/index.js';
|
|
38
39
|
import { generateApiExtensionsSandboxEntrypoint } from './lib/sandbox/generate-api-extensions-sandbox-entrypoint.js';
|
|
39
40
|
import { instantiateSandboxSdk } from './lib/sandbox/sdk/instantiate.js';
|
|
40
|
-
import { syncExtensions } from './lib/sync
|
|
41
|
+
import { syncExtensions } from './lib/sync/sync.js';
|
|
41
42
|
import { wrapEmbeds } from './lib/wrap-embeds.js';
|
|
42
|
-
import DriverLocal from '@directus/storage-driver-local';
|
|
43
43
|
// Workaround for https://github.com/rollup/plugins/issues/1329
|
|
44
44
|
const virtual = virtualDefault;
|
|
45
45
|
const alias = aliasDefault;
|
|
@@ -99,6 +99,10 @@ export class ExtensionManager {
|
|
|
99
99
|
* sequence.
|
|
100
100
|
*/
|
|
101
101
|
reloadQueue = new JobQueue();
|
|
102
|
+
/**
|
|
103
|
+
* Used to prevent race condition when reading extension data while reloading extensions
|
|
104
|
+
*/
|
|
105
|
+
reloadPromise = Promise.resolve();
|
|
102
106
|
/**
|
|
103
107
|
* Optional file system watcher to auto-reload extensions when the local file system changes
|
|
104
108
|
*/
|
|
@@ -148,7 +152,7 @@ export class ExtensionManager {
|
|
|
148
152
|
await this.closeWatcher();
|
|
149
153
|
}
|
|
150
154
|
if (!this.isLoaded) {
|
|
151
|
-
await this.load();
|
|
155
|
+
await this.load({ forceSync: true });
|
|
152
156
|
if (this.extensions.length > 0) {
|
|
153
157
|
logger.info(`Loaded extensions: ${this.extensions.map((ext) => ext.name).join(', ')}`);
|
|
154
158
|
}
|
|
@@ -160,7 +164,13 @@ export class ExtensionManager {
|
|
|
160
164
|
// Ignore requests for reloading that were published by the current process
|
|
161
165
|
if (isPlainObject(payload) && 'origin' in payload && payload['origin'] === this.processId)
|
|
162
166
|
return;
|
|
163
|
-
|
|
167
|
+
// Reload extensions with event options
|
|
168
|
+
const options = {};
|
|
169
|
+
if (typeof payload['forceSync'] === 'boolean')
|
|
170
|
+
options.forceSync = payload['forceSync'];
|
|
171
|
+
if (typeof payload['partialSync'] === 'string')
|
|
172
|
+
options.partialSync = payload['partialSync'];
|
|
173
|
+
this.reload(options);
|
|
164
174
|
});
|
|
165
175
|
}
|
|
166
176
|
/**
|
|
@@ -169,27 +179,31 @@ export class ExtensionManager {
|
|
|
169
179
|
async install(versionId) {
|
|
170
180
|
const logger = useLogger();
|
|
171
181
|
await this.installationManager.install(versionId);
|
|
172
|
-
|
|
182
|
+
const resolvedFolder = relative(sep, resolve(sep, versionId));
|
|
183
|
+
const syncFolder = join('.registry', resolvedFolder);
|
|
184
|
+
await this.broadcastReloadNotification({ partialSync: syncFolder });
|
|
185
|
+
await this.reload({ skipSync: true });
|
|
173
186
|
emitter.emitAction('extensions.installed', {
|
|
174
187
|
extensions: this.extensions,
|
|
175
188
|
versionId,
|
|
176
189
|
});
|
|
177
190
|
logger.info(`Installed extension: ${versionId}`);
|
|
178
|
-
await this.broadcastReloadNotification();
|
|
179
191
|
}
|
|
180
192
|
async uninstall(folder) {
|
|
181
193
|
const logger = useLogger();
|
|
182
194
|
await this.installationManager.uninstall(folder);
|
|
183
|
-
|
|
195
|
+
const resolvedFolder = relative(sep, resolve(sep, folder));
|
|
196
|
+
const syncFolder = join('.registry', resolvedFolder);
|
|
197
|
+
await this.broadcastReloadNotification({ partialSync: syncFolder });
|
|
198
|
+
await this.reload({ skipSync: true });
|
|
184
199
|
emitter.emitAction('extensions.uninstalled', {
|
|
185
200
|
extensions: this.extensions,
|
|
186
201
|
folder,
|
|
187
202
|
});
|
|
188
203
|
logger.info(`Uninstalled extension: ${folder}`);
|
|
189
|
-
await this.broadcastReloadNotification();
|
|
190
204
|
}
|
|
191
|
-
async broadcastReloadNotification() {
|
|
192
|
-
await this.messenger.publish(this.reloadChannel, { origin: this.processId });
|
|
205
|
+
async broadcastReloadNotification(options) {
|
|
206
|
+
await this.messenger.publish(this.reloadChannel, { ...options, origin: this.processId });
|
|
193
207
|
}
|
|
194
208
|
/**
|
|
195
209
|
* Load all extensions from disk and register them in their respective places
|
|
@@ -198,7 +212,7 @@ export class ExtensionManager {
|
|
|
198
212
|
const logger = useLogger();
|
|
199
213
|
if (env['EXTENSIONS_LOCATION']) {
|
|
200
214
|
try {
|
|
201
|
-
await syncExtensions(
|
|
215
|
+
await syncExtensions(options);
|
|
202
216
|
}
|
|
203
217
|
catch (error) {
|
|
204
218
|
logger.error(`Failed to sync extensions`);
|
|
@@ -250,7 +264,7 @@ export class ExtensionManager {
|
|
|
250
264
|
const logger = useLogger();
|
|
251
265
|
let resolve;
|
|
252
266
|
let reject;
|
|
253
|
-
|
|
267
|
+
this.reloadPromise = new Promise((res, rej) => {
|
|
254
268
|
resolve = res;
|
|
255
269
|
reject = rej;
|
|
256
270
|
});
|
|
@@ -283,7 +297,10 @@ export class ExtensionManager {
|
|
|
283
297
|
reject(new Error('Extensions have to be loaded before they can be reloaded'));
|
|
284
298
|
}
|
|
285
299
|
});
|
|
286
|
-
return
|
|
300
|
+
return this.reloadPromise;
|
|
301
|
+
}
|
|
302
|
+
isReloading() {
|
|
303
|
+
return this.reloadPromise;
|
|
287
304
|
}
|
|
288
305
|
/**
|
|
289
306
|
* Return the previously generated app extension bundle chunk by name.
|
package/dist/flows.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Accountability,
|
|
1
|
+
import type { Accountability, OperationHandler, SchemaOverview } from '@directus/types';
|
|
2
2
|
export declare function getFlowManager(): FlowManager;
|
|
3
3
|
declare class FlowManager {
|
|
4
4
|
private isLoaded;
|
package/dist/logger/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { URL } from 'node:url';
|
|
1
2
|
import { useEnv } from '@directus/env';
|
|
2
3
|
import { REDACTED_TEXT, toArray, toBoolean } from '@directus/utils';
|
|
3
4
|
import { merge } from 'lodash-es';
|
|
4
|
-
import { URL } from 'node:url';
|
|
5
5
|
import { pino } from 'pino';
|
|
6
6
|
import { pinoHttp, stdSerializers } from 'pino-http';
|
|
7
7
|
import { httpPrintFactory } from 'pino-http-print';
|
package/dist/mailer.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
1
2
|
import { useEnv } from '@directus/env';
|
|
2
3
|
import nodemailer from 'nodemailer';
|
|
3
4
|
import { useLogger } from './logger/index.js';
|
|
4
5
|
import { getConfigFromEnv } from './utils/get-config-from-env.js';
|
|
5
|
-
import { createRequire } from 'node:module';
|
|
6
6
|
const require = createRequire(import.meta.url);
|
|
7
7
|
let transporter;
|
|
8
8
|
export default function getMailer() {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { useEnv } from '@directus/env';
|
|
2
|
-
import { toArray } from '@directus/utils';
|
|
3
1
|
import { randomUUID } from 'node:crypto';
|
|
4
2
|
import { Readable } from 'node:stream';
|
|
5
3
|
import { promisify } from 'node:util';
|
|
4
|
+
import { useEnv } from '@directus/env';
|
|
5
|
+
import { toArray } from '@directus/utils';
|
|
6
6
|
import pm2 from 'pm2';
|
|
7
7
|
import { AggregatorRegistry, Counter, Histogram, register } from 'prom-client';
|
|
8
8
|
import { getCache } from '../../cache.js';
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
+
import { useEnv } from '@directus/env';
|
|
2
|
+
import { ErrorCode, isDirectusError } from '@directus/errors';
|
|
1
3
|
import { isEqual } from 'lodash-es';
|
|
4
|
+
import { SESSION_COOKIE_OPTIONS } from '../constants.js';
|
|
2
5
|
import getDatabase from '../database/index.js';
|
|
3
6
|
import emitter from '../emitter.js';
|
|
4
7
|
import { createDefaultAccountability } from '../permissions/utils/create-default-accountability.js';
|
|
5
8
|
import asyncHandler from '../utils/async-handler.js';
|
|
6
9
|
import { getAccountabilityForToken } from '../utils/get-accountability-for-token.js';
|
|
7
10
|
import { getIPFromReq } from '../utils/get-ip-from-req.js';
|
|
8
|
-
import { ErrorCode, isDirectusError } from '@directus/errors';
|
|
9
|
-
import { useEnv } from '@directus/env';
|
|
10
|
-
import { SESSION_COOKIE_OPTIONS } from '../constants.js';
|
|
11
11
|
/**
|
|
12
12
|
* Verify the passed JWT and assign the user ID and role to `req`
|
|
13
13
|
*/
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* Check if requested collection exists, and save it to req.collection
|
|
3
3
|
*/
|
|
4
4
|
import { systemCollectionRows } from '@directus/system-data';
|
|
5
|
-
import asyncHandler from '../utils/async-handler.js';
|
|
6
5
|
import { createCollectionForbiddenError } from '../permissions/modules/process-ast/utils/validate-path/create-error.js';
|
|
6
|
+
import asyncHandler from '../utils/async-handler.js';
|
|
7
7
|
const collectionExists = asyncHandler(async (req, _res, next) => {
|
|
8
8
|
if (!req.params['collection'])
|
|
9
9
|
return next();
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
+
import { useEnv } from '@directus/env';
|
|
2
|
+
import { InvalidPayloadError, InvalidQueryError, MethodNotAllowedError } from '@directus/errors';
|
|
1
3
|
import { parseJSON } from '@directus/utils';
|
|
2
4
|
import { getOperationAST, parse, Source } from 'graphql';
|
|
3
|
-
import { InvalidPayloadError, InvalidQueryError, MethodNotAllowedError } from '@directus/errors';
|
|
4
5
|
import { GraphQLValidationError } from '../services/graphql/errors/validation.js';
|
|
5
6
|
import asyncHandler from '../utils/async-handler.js';
|
|
6
|
-
import { useEnv } from '@directus/env';
|
|
7
7
|
export const parseGraphQL = asyncHandler(async (req, res, next) => {
|
|
8
8
|
if (req.method !== 'GET' && req.method !== 'POST') {
|
|
9
9
|
throw new MethodNotAllowedError({ allowed: ['GET', 'POST'], current: req.method });
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useEnv } from '@directus/env';
|
|
2
|
+
import { getDateTimeFormatted } from '@directus/utils';
|
|
2
3
|
import { parse as parseBytesConfiguration } from 'bytes';
|
|
3
4
|
import { getCache, setCacheValue } from '../cache.js';
|
|
4
5
|
import getDatabase from '../database/index.js';
|
|
@@ -7,7 +8,6 @@ import { ExportService } from '../services/import-export.js';
|
|
|
7
8
|
import asyncHandler from '../utils/async-handler.js';
|
|
8
9
|
import { getCacheControlHeader } from '../utils/get-cache-headers.js';
|
|
9
10
|
import { getCacheKey } from '../utils/get-cache-key.js';
|
|
10
|
-
import { getDateFormatted } from '../utils/get-date-formatted.js';
|
|
11
11
|
import { getMilliseconds } from '../utils/get-milliseconds.js';
|
|
12
12
|
import { stringByteSize } from '../utils/get-string-byte-size.js';
|
|
13
13
|
import { permissionsCacheable } from '../utils/permissions-cacheable.js';
|
|
@@ -58,7 +58,7 @@ export const respond = asyncHandler(async (req, res) => {
|
|
|
58
58
|
else {
|
|
59
59
|
filename += 'Export';
|
|
60
60
|
}
|
|
61
|
-
filename += ' ' +
|
|
61
|
+
filename += ' ' + getDateTimeFormatted();
|
|
62
62
|
if (req.sanitizedQuery.export === 'json') {
|
|
63
63
|
res.attachment(`${filename}.json`);
|
|
64
64
|
res.set('Content-Type', 'application/json');
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import Joi from 'joi';
|
|
2
1
|
import { InvalidPayloadError } from '@directus/errors';
|
|
2
|
+
import Joi from 'joi';
|
|
3
3
|
import asyncHandler from '../utils/async-handler.js';
|
|
4
4
|
import { sanitizeQuery } from '../utils/sanitize-query.js';
|
|
5
5
|
import { validateQuery } from '../utils/validate-query.js';
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { defineOperationApi } from '@directus/extensions';
|
|
2
1
|
import { createRequire } from 'node:module';
|
|
2
|
+
import { defineOperationApi } from '@directus/extensions';
|
|
3
|
+
// eslint-disable-next-line import/order
|
|
3
4
|
import { sieveFunctions } from '@directus/utils';
|
|
4
5
|
const require = createRequire(import.meta.url);
|
|
5
6
|
const ivm = require('isolated-vm');
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { defineOperationApi } from '@directus/extensions';
|
|
2
|
+
import { useLogger } from '../../logger/index.js';
|
|
2
3
|
import { MailService } from '../../services/mail/index.js';
|
|
3
4
|
import { md } from '../../utils/md.js';
|
|
4
|
-
import { useLogger } from '../../logger/index.js';
|
|
5
5
|
import { useFlowsEmailRateLimiter } from './rate-limiter.js';
|
|
6
6
|
const logger = useLogger();
|
|
7
7
|
export default defineOperationApi({
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { useEnv } from '@directus/env';
|
|
2
|
+
import { EmailLimitExceededError } from '@directus/errors';
|
|
3
|
+
import { toBoolean } from '@directus/utils';
|
|
2
4
|
import { RateLimiterMemory, RateLimiterRedis, RateLimiterRes } from 'rate-limiter-flexible';
|
|
3
5
|
import { createRateLimiter } from '../../rate-limiter.js';
|
|
4
|
-
import { toBoolean } from '@directus/utils';
|
|
5
|
-
import { EmailLimitExceededError } from '@directus/errors';
|
|
6
6
|
let emailRateLimiter;
|
|
7
7
|
const env = useEnv();
|
|
8
8
|
if (toBoolean(env['RATE_LIMITER_EMAIL_FLOWS_ENABLED']) === true) {
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
+
import { useEnv } from '@directus/env';
|
|
1
2
|
import { defineCache } from '@directus/memory';
|
|
2
3
|
import { redisConfigAvailable, useRedis } from '../redis/index.js';
|
|
4
|
+
import { getMilliseconds } from '../utils/get-milliseconds.js';
|
|
3
5
|
const localOnly = redisConfigAvailable() === false;
|
|
6
|
+
const env = useEnv();
|
|
7
|
+
const ttl = getMilliseconds(env['CACHE_SYSTEM_TTL']);
|
|
4
8
|
const config = localOnly
|
|
5
9
|
? {
|
|
6
10
|
type: 'local',
|
|
@@ -11,6 +15,7 @@ const config = localOnly
|
|
|
11
15
|
redis: {
|
|
12
16
|
namespace: 'permissions',
|
|
13
17
|
redis: useRedis(),
|
|
18
|
+
...(ttl !== undefined ? { ttl } : {}),
|
|
14
19
|
},
|
|
15
20
|
local: {
|
|
16
21
|
maxKeys: 100,
|
|
@@ -7,7 +7,7 @@ export interface AccessRow {
|
|
|
7
7
|
};
|
|
8
8
|
role: string | null;
|
|
9
9
|
}
|
|
10
|
-
export declare const fetchPolicies:
|
|
10
|
+
export declare const fetchPolicies: (args_0: Pick<Accountability, "user" | "roles" | "ip">, context: Context) => Promise<string[]>;
|
|
11
11
|
/**
|
|
12
12
|
* Fetch the policies associated with the current user accountability
|
|
13
13
|
*/
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Fetches the roles tree starting from a specific role.
|
|
3
|
+
*/
|
|
4
|
+
export declare const fetchRolesTree: (start: string | null, context: {
|
|
5
|
+
knex: import("knex").Knex;
|
|
6
|
+
}) => Promise<string[]>;
|
|
@@ -1,28 +1,6 @@
|
|
|
1
|
+
import { fetchRolesTree as _fetchRolesTree } from '@directus/utils/node';
|
|
1
2
|
import { withCache } from '../utils/with-cache.js';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
let parent = start;
|
|
7
|
-
const roles = [];
|
|
8
|
-
while (parent) {
|
|
9
|
-
const role = await knex
|
|
10
|
-
.select('id', 'parent')
|
|
11
|
-
.from('directus_roles')
|
|
12
|
-
.where({ id: parent })
|
|
13
|
-
.first();
|
|
14
|
-
if (!role) {
|
|
15
|
-
break;
|
|
16
|
-
}
|
|
17
|
-
roles.push(role.id);
|
|
18
|
-
// Prevent infinite recursion loops
|
|
19
|
-
if (role.parent && roles.includes(role.parent) === true) {
|
|
20
|
-
roles.reverse();
|
|
21
|
-
const rolesStr = roles.map((role) => `"${role}"`).join('->');
|
|
22
|
-
throw new Error(`Recursion encountered: role "${role.id}" already exists in tree path ${rolesStr}`);
|
|
23
|
-
}
|
|
24
|
-
parent = role.parent;
|
|
25
|
-
}
|
|
26
|
-
roles.reverse();
|
|
27
|
-
return roles;
|
|
28
|
-
}
|
|
3
|
+
/**
|
|
4
|
+
* Fetches the roles tree starting from a specific role.
|
|
5
|
+
*/
|
|
6
|
+
export const fetchRolesTree = withCache('roles-tree', _fetchRolesTree, (start) => ({ start }));
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { uniq } from 'lodash-es';
|
|
2
|
-
import { fetchPolicies } from '../../lib/fetch-policies.js';
|
|
3
2
|
import { fetchPermissions } from '../../lib/fetch-permissions.js';
|
|
3
|
+
import { fetchPolicies } from '../../lib/fetch-policies.js';
|
|
4
4
|
export async function fetchAllowedCollections({ action, accountability }, { knex, schema }) {
|
|
5
5
|
if (accountability.admin) {
|
|
6
6
|
return Object.keys(schema.collections);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { uniq } from 'lodash-es';
|
|
2
|
-
import { fetchPolicies } from '../../lib/fetch-policies.js';
|
|
3
2
|
import { fetchPermissions } from '../../lib/fetch-permissions.js';
|
|
3
|
+
import { fetchPolicies } from '../../lib/fetch-policies.js';
|
|
4
4
|
export async function fetchAllowedFieldMap({ accountability, action }, { knex, schema }) {
|
|
5
5
|
const fieldMap = {};
|
|
6
6
|
if (accountability.admin) {
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import type { Accountability } from '@directus/types';
|
|
1
|
+
import type { Accountability, GlobalAccess } from '@directus/types';
|
|
2
2
|
import type { Knex } from 'knex';
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
interface FetchGlobalAccessContext {
|
|
4
|
+
knex: Knex;
|
|
5
|
+
ip?: Accountability['ip'];
|
|
6
|
+
}
|
|
7
|
+
export declare const fetchGlobalAccess: (accountability: Pick<Accountability, "user" | "roles" | "ip">, context: FetchGlobalAccessContext) => Promise<GlobalAccess>;
|
|
5
8
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* Will fetch roles and user info separately so they can be cached and reused individually
|
|
9
|
+
* Re-implements fetchGlobalAccess to add caching, fetches roles and user info separately so they can be cached and reused individually
|
|
9
10
|
*/
|
|
10
|
-
export declare function _fetchGlobalAccess(accountability: Pick<Accountability, 'user' | 'roles' | 'ip'>,
|
|
11
|
+
export declare function _fetchGlobalAccess(accountability: Pick<Accountability, 'user' | 'roles' | 'ip'>, context: FetchGlobalAccessContext): Promise<GlobalAccess>;
|
|
12
|
+
export {};
|
|
@@ -1,20 +1,28 @@
|
|
|
1
|
+
import { fetchGlobalAccessForRoles as _fetchGlobalAccessForRoles, fetchGlobalAccessForUser as _fetchGlobalAccessForUser, } from '@directus/utils/node';
|
|
1
2
|
import { withCache } from '../../utils/with-cache.js';
|
|
2
|
-
|
|
3
|
-
import { fetchGlobalAccessForUser } from './lib/fetch-global-access-for-user.js';
|
|
4
|
-
export const fetchGlobalAccess = withCache('global-access', _fetchGlobalAccess, ({ user, roles, ip }) => ({
|
|
3
|
+
export const fetchGlobalAccess = withCache('global-access', _fetchGlobalAccess, ({ user, roles }, { ip }) => ({
|
|
5
4
|
user,
|
|
6
5
|
roles,
|
|
7
6
|
ip,
|
|
8
7
|
}));
|
|
8
|
+
const fetchGlobalAccessForRoles = withCache('global-access-roles', _fetchGlobalAccessForRoles, (roles, { ip }) => ({
|
|
9
|
+
roles,
|
|
10
|
+
ip,
|
|
11
|
+
}));
|
|
12
|
+
const fetchGlobalAccessForUser = withCache('global-access-user', _fetchGlobalAccessForUser, (user, { ip }) => ({
|
|
13
|
+
user,
|
|
14
|
+
ip,
|
|
15
|
+
}));
|
|
9
16
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* Will fetch roles and user info separately so they can be cached and reused individually
|
|
17
|
+
* Re-implements fetchGlobalAccess to add caching, fetches roles and user info separately so they can be cached and reused individually
|
|
13
18
|
*/
|
|
14
|
-
export async function _fetchGlobalAccess(accountability,
|
|
15
|
-
const access = await fetchGlobalAccessForRoles(accountability, knex);
|
|
19
|
+
export async function _fetchGlobalAccess(accountability, context) {
|
|
20
|
+
const access = await fetchGlobalAccessForRoles(accountability.roles, { knex: context.knex, ip: accountability.ip });
|
|
16
21
|
if (accountability.user !== undefined) {
|
|
17
|
-
const userAccess = await fetchGlobalAccessForUser(accountability,
|
|
22
|
+
const userAccess = await fetchGlobalAccessForUser(accountability.user, {
|
|
23
|
+
knex: context.knex,
|
|
24
|
+
ip: accountability.ip,
|
|
25
|
+
});
|
|
18
26
|
// If app/admin is already true, keep it true
|
|
19
27
|
access.app ||= userAccess.app;
|
|
20
28
|
access.admin ||= userAccess.admin;
|
package/dist/permissions/modules/fetch-inconsistent-field-map/fetch-inconsistent-field-map.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { fetchPolicies } from '../../lib/fetch-policies.js';
|
|
1
|
+
import { difference, intersection, uniq } from 'lodash-es';
|
|
3
2
|
import { fetchPermissions } from '../../lib/fetch-permissions.js';
|
|
3
|
+
import { fetchPolicies } from '../../lib/fetch-policies.js';
|
|
4
4
|
/**
|
|
5
5
|
* Fetch a field map for fields that may or may not be null based on item-by-item permissions.
|
|
6
6
|
*/
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { Accountability } from '@directus/types';
|
|
2
2
|
import type { Knex } from 'knex';
|
|
3
|
-
export declare const fetchPoliciesIpAccess:
|
|
3
|
+
export declare const fetchPoliciesIpAccess: (accountability: Pick<Accountability, "user" | "roles">, knex: Knex<any, any[]>) => Promise<string[][]>;
|
|
4
4
|
export declare function _fetchPoliciesIpAccess(accountability: Pick<Accountability, 'user' | 'roles'>, knex: Knex): Promise<string[][]>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { getUnaliasedFieldKey } from '../../../utils/get-unaliased-field-key.js';
|
|
2
1
|
import { uniq } from 'lodash-es';
|
|
2
|
+
import { getUnaliasedFieldKey } from '../../../utils/get-unaliased-field-key.js';
|
|
3
3
|
import { getCases } from './get-cases.js';
|
|
4
4
|
/**
|
|
5
5
|
* Mutates passed AST
|
|
@@ -3,8 +3,8 @@ import { fetchPolicies } from '../../lib/fetch-policies.js';
|
|
|
3
3
|
import { fieldMapFromAst } from './lib/field-map-from-ast.js';
|
|
4
4
|
import { injectCases } from './lib/inject-cases.js';
|
|
5
5
|
import { collectionsInFieldMap } from './utils/collections-in-field-map.js';
|
|
6
|
-
import { validatePathPermissions } from './utils/validate-path/validate-path-permissions.js';
|
|
7
6
|
import { validatePathExistence } from './utils/validate-path/validate-path-existence.js';
|
|
7
|
+
import { validatePathPermissions } from './utils/validate-path/validate-path-permissions.js';
|
|
8
8
|
export async function processAst(options, context) {
|
|
9
9
|
// FieldMap is a Map of paths in the AST, with each path containing the collection and fields in
|
|
10
10
|
// that collection that the AST path tries to access
|
|
@@ -6,8 +6,8 @@ import { fetchPolicies } from '../../lib/fetch-policies.js';
|
|
|
6
6
|
import { extractRequiredDynamicVariableContext } from '../../utils/extract-required-dynamic-variable-context.js';
|
|
7
7
|
import { fetchDynamicVariableData } from '../../utils/fetch-dynamic-variable-data.js';
|
|
8
8
|
import { contextHasDynamicVariables } from '../process-ast/utils/context-has-dynamic-variables.js';
|
|
9
|
-
import { isFieldNullable } from './lib/is-field-nullable.js';
|
|
10
9
|
import { createCollectionForbiddenError, createFieldsForbiddenError, } from '../process-ast/utils/validate-path/create-error.js';
|
|
10
|
+
import { isFieldNullable } from './lib/is-field-nullable.js';
|
|
11
11
|
/**
|
|
12
12
|
* @note this only validates the top-level fields. The expectation is that this function is called
|
|
13
13
|
* for each level of nested insert separately
|
|
@@ -6,5 +6,17 @@ export interface ValidateItemAccessOptions {
|
|
|
6
6
|
collection: string;
|
|
7
7
|
primaryKeys: PrimaryKey[];
|
|
8
8
|
fields?: string[];
|
|
9
|
+
returnAllowedRootFields?: boolean;
|
|
9
10
|
}
|
|
10
|
-
export
|
|
11
|
+
export interface ValidateItemAccessOptionsWithRootFields extends ValidateItemAccessOptions {
|
|
12
|
+
returnAllowedRootFields: true;
|
|
13
|
+
}
|
|
14
|
+
export interface ValidateItemAccessResult {
|
|
15
|
+
accessAllowed: boolean;
|
|
16
|
+
allowedRootFields?: string[];
|
|
17
|
+
}
|
|
18
|
+
export interface ValidateItemAccessResultWithRootFields extends ValidateItemAccessResult {
|
|
19
|
+
allowedRootFields: string[];
|
|
20
|
+
}
|
|
21
|
+
export declare function validateItemAccess(options: ValidateItemAccessOptionsWithRootFields, context: Context): Promise<ValidateItemAccessResultWithRootFields>;
|
|
22
|
+
export declare function validateItemAccess(options: ValidateItemAccessOptions, context: Context): Promise<ValidateItemAccessResult>;
|