@directus/api 35.2.0 → 36.0.0-rc.1

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 (192) hide show
  1. package/dist/ai/chat/models/chat-request.js +48 -48
  2. package/dist/ai/chat/models/object-request.js +6 -6
  3. package/dist/ai/chat/models/providers.js +14 -14
  4. package/dist/ai/chat/utils/parse-json-schema-7.js +22 -22
  5. package/dist/ai/mcp/server.js +44 -6
  6. package/dist/ai/mcp/utils.js +31 -0
  7. package/dist/ai/tools/assets/index.js +3 -3
  8. package/dist/ai/tools/collections/index.js +18 -18
  9. package/dist/ai/tools/fields/index.js +18 -18
  10. package/dist/ai/tools/files/index.js +18 -18
  11. package/dist/ai/tools/flows/index.js +16 -16
  12. package/dist/ai/tools/folders/index.js +18 -18
  13. package/dist/ai/tools/items/index.js +17 -17
  14. package/dist/ai/tools/operations/index.js +16 -16
  15. package/dist/ai/tools/relations/index.js +22 -22
  16. package/dist/ai/tools/schema/index.js +3 -3
  17. package/dist/ai/tools/schema.js +159 -159
  18. package/dist/ai/tools/system/index.js +3 -3
  19. package/dist/ai/tools/trigger-flow/index.js +3 -3
  20. package/dist/app.js +35 -11
  21. package/dist/auth/drivers/ldap.js +3 -1
  22. package/dist/auth/drivers/local.js +2 -0
  23. package/dist/auth/drivers/oauth2.js +3 -1
  24. package/dist/auth/drivers/openid.js +3 -1
  25. package/dist/auth/drivers/saml.js +2 -0
  26. package/dist/auth/utils/check-local-disabled.js +16 -0
  27. package/dist/auth/utils/check-sso-enabled.js +14 -0
  28. package/dist/auth.js +8 -5
  29. package/dist/cli/commands/bootstrap/index.js +3 -0
  30. package/dist/cli/commands/cache/clear.js +6 -1
  31. package/dist/cli/commands/roles/create.js +4 -1
  32. package/dist/cli/commands/users/create.js +3 -0
  33. package/dist/constants.js +8 -1
  34. package/dist/controllers/access.js +1 -1
  35. package/dist/controllers/activity.js +2 -1
  36. package/dist/controllers/assets.js +2 -0
  37. package/dist/controllers/auth.js +13 -5
  38. package/dist/controllers/collections.js +1 -1
  39. package/dist/controllers/comments.js +1 -1
  40. package/dist/controllers/dashboards.js +1 -1
  41. package/dist/controllers/fields.js +1 -1
  42. package/dist/controllers/files.js +3 -1
  43. package/dist/controllers/flows.js +6 -5
  44. package/dist/controllers/folders.js +1 -1
  45. package/dist/controllers/graphql.js +2 -0
  46. package/dist/controllers/items.js +3 -1
  47. package/dist/controllers/license.js +119 -0
  48. package/dist/controllers/mcp/index.js +38 -0
  49. package/dist/controllers/mcp/oauth-clients.js +68 -0
  50. package/dist/controllers/mcp/oauth-consent-page.js +316 -0
  51. package/dist/controllers/mcp/oauth.js +381 -0
  52. package/dist/controllers/mcp/templates/oauth-consent.liquid +62 -0
  53. package/dist/controllers/mcp/templates/oauth-error.liquid +28 -0
  54. package/dist/controllers/notifications.js +1 -1
  55. package/dist/controllers/operations.js +1 -1
  56. package/dist/controllers/panels.js +1 -1
  57. package/dist/controllers/permissions.js +1 -1
  58. package/dist/controllers/policies.js +1 -1
  59. package/dist/controllers/presets.js +1 -1
  60. package/dist/controllers/revisions.js +3 -2
  61. package/dist/controllers/roles.js +1 -1
  62. package/dist/controllers/server.js +38 -10
  63. package/dist/controllers/shares.js +1 -1
  64. package/dist/controllers/translations.js +1 -1
  65. package/dist/controllers/users.js +1 -1
  66. package/dist/controllers/utils.js +2 -2
  67. package/dist/controllers/versions.js +12 -5
  68. package/dist/database/get-ast-from-query/lib/convert-wildcards.js +10 -1
  69. package/dist/database/get-ast-from-query/lib/parse-fields.js +2 -1
  70. package/dist/database/helpers/fn/dialects/mysql.js +7 -12
  71. package/dist/database/helpers/fn/dialects/oracle.js +3 -4
  72. package/dist/database/helpers/fn/dialects/postgres.js +4 -26
  73. package/dist/database/helpers/fn/json/mysql-json-path.js +22 -0
  74. package/dist/database/helpers/fn/json/parse-function.js +14 -6
  75. package/dist/database/helpers/fn/json/postgres-json-path.js +54 -0
  76. package/dist/database/migrations/20260110A-add-ai-provider-settings.js +4 -4
  77. package/dist/database/migrations/20260217A-null-item-versions.js +14 -0
  78. package/dist/database/migrations/20260312A-add-ai-translation-settings.js +18 -0
  79. package/dist/database/migrations/20260507A-add-licensing.js +22 -0
  80. package/dist/database/migrations/20260512A-add-autosave-revision-interval.js +14 -0
  81. package/dist/database/migrations/20260512B-add-mcp-oauth.js +87 -0
  82. package/dist/database/run-ast/lib/apply-query/filter/operator.js +116 -33
  83. package/dist/database/run-ast/lib/apply-query/index.js +4 -1
  84. package/dist/database/run-ast/lib/apply-query/sort.js +17 -7
  85. package/dist/database/run-ast/lib/get-db-query.js +21 -9
  86. package/dist/database/run-ast/lib/parse-current-level.js +2 -1
  87. package/dist/database/run-ast/run-ast.js +2 -1
  88. package/dist/database/run-ast/utils/get-column.js +2 -1
  89. package/dist/database/run-ast/utils/merge-with-parent-items.js +5 -3
  90. package/dist/extensions/lib/installation/manager.js +1 -1
  91. package/dist/extensions/lib/sandbox/register/operation.js +1 -1
  92. package/dist/extensions/lib/sync/sync.js +1 -1
  93. package/dist/extensions/manager.js +3 -3
  94. package/dist/flows.js +5 -5
  95. package/dist/license/entitlements/lib/collections.js +37 -0
  96. package/dist/license/entitlements/lib/custom-llms-enabled.js +18 -0
  97. package/dist/license/entitlements/lib/custom-permission-rules-enabled.js +41 -0
  98. package/dist/license/entitlements/lib/flows.js +29 -0
  99. package/dist/license/entitlements/lib/seats.js +103 -0
  100. package/dist/license/entitlements/lib/sso-enabled.js +45 -0
  101. package/dist/license/entitlements/manager.js +256 -0
  102. package/dist/license/index.js +4 -0
  103. package/dist/license/manager.js +505 -0
  104. package/dist/license/utils/compute-license-status.js +27 -0
  105. package/dist/license/utils/get-core-grace-expires-at.js +38 -0
  106. package/dist/license/utils/get-license-key.js +23 -0
  107. package/dist/license/utils/get-license-token.js +23 -0
  108. package/dist/license/utils/handle-license-error.js +41 -0
  109. package/dist/license/utils/is-in-core-grace-period.js +11 -0
  110. package/dist/license/utils/is-sso-bypass-allowed.js +21 -0
  111. package/dist/license/utils/use-rpc.js +33 -0
  112. package/dist/middleware/cache.js +4 -1
  113. package/dist/middleware/error-handler.js +11 -0
  114. package/dist/middleware/extract-token.js +11 -2
  115. package/dist/middleware/is-admin.js +16 -0
  116. package/dist/middleware/is-locked.js +16 -0
  117. package/dist/middleware/mcp-oauth-guard.js +23 -0
  118. package/dist/middleware/request-counter.js +5 -2
  119. package/dist/packages/types/dist/index.js +117 -122
  120. package/dist/permissions/modules/process-ast/utils/extract-paths-from-query.js +10 -1
  121. package/dist/permissions/utils/get-unaliased-field-key.js +2 -1
  122. package/dist/request/is-denied-ip.js +2 -0
  123. package/dist/schedules/license.js +31 -0
  124. package/dist/schedules/oauth-cleanup.js +26 -0
  125. package/dist/schedules/retention.js +1 -1
  126. package/dist/schedules/telemetry.js +4 -1
  127. package/dist/schedules/tus.js +1 -1
  128. package/dist/schedules/utils/duration-to-cron.js +36 -0
  129. package/dist/services/activity.js +15 -0
  130. package/dist/services/authentication.js +12 -5
  131. package/dist/services/collections.js +40 -10
  132. package/dist/services/fields.js +6 -6
  133. package/dist/services/flows.js +12 -0
  134. package/dist/services/graphql/resolvers/system-admin.js +2 -2
  135. package/dist/services/graphql/resolvers/system-global.js +1 -1
  136. package/dist/services/graphql/resolvers/system.js +43 -27
  137. package/dist/services/graphql/schema/get-types.js +28 -7
  138. package/dist/services/graphql/schema/parse-query.js +8 -0
  139. package/dist/services/graphql/schema/read.js +12 -0
  140. package/dist/services/graphql/types/json-filter.js +30 -0
  141. package/dist/services/index.js +6 -6
  142. package/dist/services/items.js +32 -14
  143. package/dist/services/mcp-oauth/cimd.js +307 -0
  144. package/dist/services/mcp-oauth/index.js +1185 -0
  145. package/dist/services/mcp-oauth/types/error.js +22 -0
  146. package/dist/services/mcp-oauth/utils/cimd-egress.js +182 -0
  147. package/dist/services/mcp-oauth/utils/domain.js +21 -0
  148. package/dist/services/mcp-oauth/utils/loopback.js +11 -0
  149. package/dist/services/mcp-oauth/utils/redirect.js +84 -0
  150. package/dist/services/mcp-oauth/utils/registration-debug.js +131 -0
  151. package/dist/services/payload.js +2 -1
  152. package/dist/services/permissions.js +31 -9
  153. package/dist/services/revisions.js +15 -0
  154. package/dist/services/server.js +66 -68
  155. package/dist/services/settings.js +37 -3
  156. package/dist/services/users.js +23 -6
  157. package/dist/services/utils.js +6 -1
  158. package/dist/services/versions.js +160 -70
  159. package/dist/utils/calculate-field-depth.js +1 -0
  160. package/dist/utils/create-admin.js +3 -3
  161. package/dist/utils/deep-freeze.js +24 -0
  162. package/dist/utils/extract-function-name.js +13 -0
  163. package/dist/utils/generate-translations.js +5 -5
  164. package/dist/utils/get-accountability-for-token.js +13 -1
  165. package/dist/utils/get-cache-key.js +1 -1
  166. package/dist/utils/get-history-filter-query.js +22 -0
  167. package/dist/utils/get-schema.js +2 -2
  168. package/dist/utils/get-service.js +3 -3
  169. package/dist/utils/is-admin.js +9 -0
  170. package/dist/utils/is-unauthenticated.js +15 -0
  171. package/dist/utils/parse-oauth-scope.js +12 -0
  172. package/dist/utils/sanitize-query.js +2 -2
  173. package/dist/utils/split-field-path.js +29 -0
  174. package/dist/utils/store.js +1 -1
  175. package/dist/utils/transaction.js +2 -2
  176. package/dist/utils/translations-validation.js +2 -2
  177. package/dist/utils/validate-query.js +35 -4
  178. package/dist/utils/validate-user-count-integrity.js +28 -5
  179. package/dist/utils/verify-session-jwt.js +5 -2
  180. package/dist/utils/versioning/handle-version.js +131 -48
  181. package/dist/utils/versioning/remove-circular.js +17 -0
  182. package/dist/websocket/authenticate.js +2 -1
  183. package/dist/websocket/collab/collab.js +1 -1
  184. package/dist/websocket/collab/room.js +1 -1
  185. package/dist/websocket/controllers/base.js +12 -0
  186. package/dist/websocket/controllers/graphql.js +1 -1
  187. package/dist/websocket/handlers/subscribe.js +1 -1
  188. package/dist/websocket/messages.js +64 -64
  189. package/dist/websocket/utils/items.js +2 -2
  190. package/license +90 -80
  191. package/package.json +33 -32
  192. package/dist/controllers/mcp.js +0 -31
@@ -0,0 +1,21 @@
1
+ import { isInCoreGracePeriod } from "./is-in-core-grace-period.js";
2
+ import { getLicenseManager } from "../manager.js";
3
+
4
+ //#region src/license/utils/is-sso-bypass-allowed.ts
5
+ /**
6
+ * Keep SSO reachable for unentitled installs when the license is locked or in the v12 core grace
7
+ * period, so admins can still sign in and resolve licensing.
8
+ *
9
+ * 'grace' only bypasses when also in the core grace period, so licensed expiry-grace doesn't qualify.
10
+ */
11
+ async function isSSOBypassAllowed() {
12
+ const licenseManager = getLicenseManager();
13
+ const status = await licenseManager.getStatus();
14
+ const source = licenseManager.getSource();
15
+ if (status === "locked") return true;
16
+ if (status === "grace" && source === null) return isInCoreGracePeriod();
17
+ return false;
18
+ }
19
+
20
+ //#endregion
21
+ export { isSSOBypassAllowed };
@@ -0,0 +1,33 @@
1
+ import { useBus } from "../../bus/lib/use-bus.js";
2
+ import "../../bus/index.js";
3
+ import { randomUUID } from "crypto";
4
+
5
+ //#region src/license/utils/use-rpc.ts
6
+ /**
7
+ * RPC means remote procedure call, allowing to call functions across multiple instances in a code native manner.
8
+ *
9
+ * Does not call the function on its OWN instance
10
+ */
11
+ function useRPC(self, channel) {
12
+ const uid = randomUUID();
13
+ const messenger = useBus();
14
+ messenger.subscribe(channel, async ({ uid: id, method, args }) => {
15
+ if (uid == id) return;
16
+ const fn = self[method];
17
+ if (typeof fn === "function") try {
18
+ await fn.apply(self, args);
19
+ } catch {}
20
+ });
21
+ return new Proxy({}, { get(_, method) {
22
+ return async (...args) => {
23
+ await messenger.publish(channel, {
24
+ uid,
25
+ method,
26
+ args
27
+ });
28
+ };
29
+ } });
30
+ }
31
+
32
+ //#endregion
33
+ export { useRPC };
@@ -2,9 +2,11 @@ import async_handler_default from "../utils/async-handler.js";
2
2
  import { useLogger } from "../logger/index.js";
3
3
  import { getCache, getCacheValue } from "../cache.js";
4
4
  import { useBufferedCounter } from "../telemetry/counter/use-buffered-counter.js";
5
+ import { getEntitlementManager } from "../license/entitlements/manager.js";
5
6
  import { shouldSkipCache } from "../utils/should-skip-cache.js";
6
7
  import { getCacheControlHeader } from "../utils/get-cache-headers.js";
7
8
  import { getCacheKey } from "../utils/get-cache-key.js";
9
+ import "../license/index.js";
8
10
  import { useEnv } from "@directus/env";
9
11
  import { toBoolean } from "@directus/utils";
10
12
 
@@ -13,6 +15,7 @@ const checkCacheMiddleware = async_handler_default(async (req, res, next) => {
13
15
  const env = useEnv();
14
16
  const { cache } = getCache();
15
17
  const logger = useLogger();
18
+ const entitlementManager = getEntitlementManager();
16
19
  if (req.method.toLowerCase() !== "get" && req.originalUrl?.startsWith("/graphql") === false) return next();
17
20
  if (env["CACHE_ENABLED"] !== true) return next();
18
21
  if (!cache) return next();
@@ -42,7 +45,7 @@ const checkCacheMiddleware = async_handler_default(async (req, res, next) => {
42
45
  res.setHeader("Cache-Control", getCacheControlHeader(req, cacheTTL, true, true));
43
46
  res.setHeader("Vary", "Origin, Cache-Control");
44
47
  if (env["CACHE_STATUS_HEADER"]) res.setHeader(`${env["CACHE_STATUS_HEADER"]}`, "HIT");
45
- if (toBoolean(env["TELEMETRY"])) try {
48
+ if (entitlementManager.isEntitled("telemetry_required") || toBoolean(env["TELEMETRY"])) try {
46
49
  useBufferedCounter("api-requests").increment("cached");
47
50
  } catch (err) {
48
51
  logger.trace(err, "Failed to increment cached request counter");
@@ -1,6 +1,8 @@
1
1
  import { useLogger } from "../logger/index.js";
2
2
  import database_default from "../database/index.js";
3
3
  import emitter_default from "../emitter.js";
4
+ import { buildMcpWWWAuthenticateHeader, getMcpUrls, isMcpPath } from "../ai/mcp/utils.js";
5
+ import { useEnv } from "@directus/env";
4
6
  import { ErrorCode, InternalServerError, isDirectusError } from "@directus/errors";
5
7
  import { isObject } from "@directus/utils";
6
8
  import { getNodeEnv } from "@directus/utils/node";
@@ -8,11 +10,20 @@ import { getNodeEnv } from "@directus/utils/node";
8
10
  //#region src/middleware/error-handler.ts
9
11
  const FALLBACK_ERROR = new InternalServerError();
10
12
  const errorHandler = asyncErrorHandler(async (err, req, res) => {
13
+ const env = useEnv();
11
14
  const logger = useLogger();
12
15
  let errors = [];
13
16
  let status = null;
14
17
  const receivedErrors = Array.isArray(err) ? err : [err];
15
18
  for (const error of receivedErrors) {
19
+ if ((isDirectusError(error, ErrorCode.InvalidCredentials) || isDirectusError(error, ErrorCode.InvalidToken) || isDirectusError(error, ErrorCode.TokenExpired)) && isMcpPath(req.path) && env["MCP_OAUTH_ENABLED"] === true) {
20
+ const { metadataUrl } = getMcpUrls();
21
+ res.status(401).set("WWW-Authenticate", buildMcpWWWAuthenticateHeader(metadataUrl, "invalid_token")).set("Access-Control-Expose-Headers", "WWW-Authenticate").json({
22
+ error: "invalid_token",
23
+ error_description: error.message
24
+ });
25
+ return;
26
+ }
16
27
  if (getNodeEnv() === "development" && error instanceof Error && error.stack) (error.extensions ??= {})["stack"] = error.stack;
17
28
  if (isDirectusError(error)) {
18
29
  logger.debug(error);
@@ -14,18 +14,27 @@ import { InvalidPayloadError } from "@directus/errors";
14
14
  const extractToken = (req, _res, next) => {
15
15
  const env = useEnv();
16
16
  let token = null;
17
- if (req.query && req.query["access_token"]) token = req.query["access_token"];
17
+ let tokenSource = null;
18
+ if (req.query && req.query["access_token"]) {
19
+ token = req.query["access_token"];
20
+ tokenSource = "query";
21
+ }
18
22
  if (req.headers && req.headers.authorization) {
19
23
  const parts = req.headers.authorization.split(" ");
20
24
  if (parts.length === 2 && parts[0].toLowerCase() === "bearer") {
21
25
  if (token !== null) throw new InvalidPayloadError({ reason: "The request uses more than one method for including an access token" });
22
26
  token = parts[1];
27
+ tokenSource = "header";
23
28
  }
24
29
  }
25
30
  if (req.cookies && req.cookies[env["SESSION_COOKIE_NAME"]]) {
26
- if (token === null) token = req.cookies[env["SESSION_COOKIE_NAME"]];
31
+ if (token === null) {
32
+ token = req.cookies[env["SESSION_COOKIE_NAME"]];
33
+ tokenSource = "cookie";
34
+ }
27
35
  }
28
36
  req.token = token;
37
+ req.tokenSource = tokenSource;
29
38
  next();
30
39
  };
31
40
  var extract_token_default = extractToken;
@@ -0,0 +1,16 @@
1
+ import async_handler_default from "../utils/async-handler.js";
2
+ import { isAdmin } from "../utils/is-admin.js";
3
+ import { ForbiddenError } from "@directus/errors";
4
+
5
+ //#region src/middleware/is-admin.ts
6
+ /**
7
+ * Require the request to have been made by an admin
8
+ */
9
+ const handler = async (req, _res, next) => {
10
+ if (!isAdmin(req.accountability)) throw new ForbiddenError();
11
+ return next();
12
+ };
13
+ var is_admin_default = async_handler_default(handler);
14
+
15
+ //#endregion
16
+ export { is_admin_default as default, handler };
@@ -0,0 +1,16 @@
1
+ import async_handler_default from "../utils/async-handler.js";
2
+ import { getLicenseManager } from "../license/manager.js";
3
+ import { ResourceRestrictedError } from "@directus/errors";
4
+
5
+ //#region src/middleware/is-locked.ts
6
+ /**
7
+ * Throws an error if the license is in a locked state
8
+ */
9
+ const handler = (resource) => async_handler_default(async (_req, _res, next) => {
10
+ if (await getLicenseManager().isLocked()) throw new ResourceRestrictedError({ category: resource });
11
+ return next();
12
+ });
13
+ var is_locked_default = handler;
14
+
15
+ //#endregion
16
+ export { is_locked_default as default, handler };
@@ -0,0 +1,23 @@
1
+ import { isMcpPath } from "../ai/mcp/utils.js";
2
+ import { ForbiddenError } from "@directus/errors";
3
+
4
+ //#region src/middleware/mcp-oauth-guard.ts
5
+ /**
6
+ * OAuth session route guard. If `accountability.oauth` is set, restrict to MCP endpoints only.
7
+ * All other Directus API routes are forbidden. Regular sessions pass through untouched.
8
+ */
9
+ function handler(req, _res, next) {
10
+ if (!req.accountability?.oauth) {
11
+ next();
12
+ return;
13
+ }
14
+ if (!isMcpPath(req.path) || req.method !== "GET" && req.method !== "POST") {
15
+ next(new ForbiddenError());
16
+ return;
17
+ }
18
+ next();
19
+ }
20
+ var mcp_oauth_guard_default = handler;
21
+
22
+ //#endregion
23
+ export { mcp_oauth_guard_default as default, handler };
@@ -1,13 +1,16 @@
1
1
  import { useLogger } from "../logger/index.js";
2
2
  import { useBufferedCounter } from "../telemetry/counter/use-buffered-counter.js";
3
3
  import { TRACKED_METHODS } from "../telemetry/utils/format-api-request-counts.js";
4
+ import { getEntitlementManager } from "../license/entitlements/manager.js";
5
+ import "../license/index.js";
4
6
  import { useEnv } from "@directus/env";
5
7
  import { toBoolean } from "@directus/utils";
6
8
 
7
9
  //#region src/middleware/request-counter.ts
8
10
  const TRACKED_METHODS_UPPER = new Set(TRACKED_METHODS.map((m) => m.toUpperCase()));
9
- let requestCounterMiddleware = (_req, _res, next) => next();
10
- if (toBoolean(useEnv()["TELEMETRY"])) requestCounterMiddleware = (req, _res, next) => {
11
+ const env = useEnv();
12
+ const requestCounterMiddleware = (req, _res, next) => {
13
+ if (!getEntitlementManager().isEntitled("telemetry_required") && toBoolean(env["TELEMETRY"]) === false) return next();
11
14
  if (TRACKED_METHODS_UPPER.has(req.method)) try {
12
15
  useBufferedCounter("api-requests").increment(req.method.toLowerCase());
13
16
  } catch (err) {
@@ -1,4 +1,4 @@
1
- import z$1, { z } from "zod";
1
+ import z, { z as z$1 } from "zod";
2
2
  import { PERMISSION_ACTIONS } from "@directus/constants";
3
3
 
4
4
  //#region ../packages/types/dist/index.js
@@ -53,69 +53,67 @@ const DatabaseClients = [
53
53
  * Supported deployment provider types
54
54
  */
55
55
  const DEPLOYMENT_PROVIDER_TYPES = ["vercel", "netlify"];
56
- const SplitEntrypoint = z.object({
57
- app: z.string(),
58
- api: z.string()
56
+ const SplitEntrypoint = z$1.object({
57
+ app: z$1.string(),
58
+ api: z$1.string()
59
59
  });
60
- const ExtensionSandboxRequestedScopes = z.object({
61
- request: z.optional(z.object({
62
- urls: z.array(z.string()),
63
- methods: z.array(z.union([
64
- z.literal("GET"),
65
- z.literal("POST"),
66
- z.literal("PATCH"),
67
- z.literal("PUT"),
68
- z.literal("DELETE")
60
+ const ExtensionSandboxRequestedScopes = z$1.object({
61
+ request: z$1.optional(z$1.object({
62
+ urls: z$1.array(z$1.string()),
63
+ methods: z$1.array(z$1.union([
64
+ z$1.literal("GET"),
65
+ z$1.literal("POST"),
66
+ z$1.literal("PATCH"),
67
+ z$1.literal("PUT"),
68
+ z$1.literal("DELETE")
69
69
  ]))
70
70
  })),
71
- log: z.optional(z.object({})),
72
- sleep: z.optional(z.object({}))
71
+ log: z$1.optional(z$1.object({})),
72
+ sleep: z$1.optional(z$1.object({}))
73
73
  });
74
- const ExtensionSandboxOptions = z.optional(z.object({
75
- enabled: z.boolean(),
74
+ const ExtensionSandboxOptions = z$1.optional(z$1.object({
75
+ enabled: z$1.boolean(),
76
76
  requestedScopes: ExtensionSandboxRequestedScopes
77
77
  }));
78
- const Color = z.string();
79
- const FamilyName = z.string().meta({ $ref: "FamilyName" });
80
- const FontWeight = z.string().meta({ $ref: "FontWeight" });
81
- const Length = z.string();
82
- const Percentage = z.string();
83
- const BoxShadow = z.string();
84
- const Number = z.string();
85
- const Size = z.string();
86
- const LineWidth = z.union([
87
- z.string(),
88
- z.literal("thin"),
89
- z.literal("medium"),
90
- z.literal("thick")
78
+ const Color = z$1.string();
79
+ const FamilyName = z$1.string().meta({ $ref: "FamilyName" });
80
+ const FontWeight = z$1.string().meta({ $ref: "FontWeight" });
81
+ const Length = z$1.string();
82
+ const Percentage = z$1.string();
83
+ const BoxShadow = z$1.string();
84
+ const Number = z$1.string();
85
+ const Size = z$1.string();
86
+ const LineWidth = z$1.union([
87
+ z$1.string(),
88
+ z$1.literal("thin"),
89
+ z$1.literal("medium"),
90
+ z$1.literal("thick")
91
91
  ]);
92
- const FormRules = z.object({
93
- columnGap: z.union([Length, Percentage]).optional(),
94
- rowGap: z.union([Length, Percentage]).optional(),
95
- field: z.object({
96
- label: z.object({
92
+ const FormRules = z$1.object({
93
+ columnGap: z$1.union([Length, Percentage]).optional(),
94
+ rowGap: z$1.union([Length, Percentage]).optional(),
95
+ field: z$1.object({
96
+ label: z$1.object({
97
97
  foreground: Color.optional(),
98
98
  fontFamily: FamilyName.optional(),
99
99
  fontWeight: FontWeight.optional()
100
100
  }).optional(),
101
- input: z.object({
101
+ input: z$1.object({
102
102
  background: Color.optional(),
103
103
  backgroundSubdued: Color.optional(),
104
104
  foreground: Color.optional(),
105
105
  foregroundSubdued: Color.optional(),
106
106
  borderColor: Color.optional(),
107
107
  borderColorHover: Color.optional(),
108
- borderColorFocus: Color.optional(),
108
+ focusRingColor: Color.optional(),
109
109
  boxShadow: BoxShadow.optional(),
110
- boxShadowHover: BoxShadow.optional(),
111
- boxShadowFocus: BoxShadow.optional(),
112
110
  height: Size.optional(),
113
- padding: z.union([Length, Percentage]).optional()
111
+ padding: z$1.union([Length, Percentage]).optional()
114
112
  }).optional()
115
113
  }).optional()
116
114
  }).optional();
117
- const Rules = z.object({
118
- borderRadius: z.union([Length, Percentage]).optional(),
115
+ const Rules = z$1.object({
116
+ borderRadius: z$1.union([Length, Percentage]).optional(),
119
117
  borderWidth: LineWidth.optional(),
120
118
  foreground: Color.optional(),
121
119
  foregroundSubdued: Color.optional(),
@@ -147,41 +145,44 @@ const Rules = z.object({
147
145
  dangerBackground: Color.optional(),
148
146
  dangerSubdued: Color.optional(),
149
147
  dangerAccent: Color.optional(),
150
- fonts: z.object({
151
- display: z.object({
148
+ fonts: z$1.object({
149
+ display: z$1.object({
152
150
  fontFamily: FamilyName.optional(),
153
151
  fontWeight: FontWeight.optional()
154
152
  }).optional(),
155
- sans: z.object({
153
+ title: z$1.object({
156
154
  fontFamily: FamilyName.optional(),
157
155
  fontWeight: FontWeight.optional()
158
156
  }).optional(),
159
- serif: z.object({
157
+ sans: z$1.object({
160
158
  fontFamily: FamilyName.optional(),
161
159
  fontWeight: FontWeight.optional()
162
160
  }).optional(),
163
- monospace: z.object({
161
+ serif: z$1.object({
162
+ fontFamily: FamilyName.optional(),
163
+ fontWeight: FontWeight.optional()
164
+ }).optional(),
165
+ monospace: z$1.object({
164
166
  fontFamily: FamilyName.optional(),
165
167
  fontWeight: FontWeight.optional()
166
168
  }).optional()
167
169
  }).optional(),
168
- navigation: z.object({
170
+ shell: z$1.object({
169
171
  background: Color.optional(),
170
172
  backgroundAccent: Color.optional(),
171
173
  borderWidth: LineWidth.optional(),
172
- borderColor: Color.optional(),
173
- project: z.object({
174
- background: Color.optional(),
174
+ borderColor: Color.optional()
175
+ }).optional(),
176
+ navigation: z$1.object({
177
+ project: z$1.object({
175
178
  foreground: Color.optional(),
176
- fontFamily: FamilyName.optional(),
177
- borderWidth: LineWidth.optional(),
178
- borderColor: Color.optional()
179
+ fontFamily: FamilyName.optional()
179
180
  }).optional(),
180
- modules: z.object({
181
+ modules: z$1.object({
181
182
  background: Color.optional(),
182
183
  borderWidth: LineWidth.optional(),
183
184
  borderColor: Color.optional(),
184
- button: z.object({
185
+ button: z$1.object({
185
186
  foreground: Color.optional(),
186
187
  foregroundHover: Color.optional(),
187
188
  foregroundActive: Color.optional(),
@@ -190,8 +191,8 @@ const Rules = z.object({
190
191
  backgroundActive: Color.optional()
191
192
  }).optional()
192
193
  }).optional(),
193
- list: z.object({
194
- icon: z.object({
194
+ list: z$1.object({
195
+ icon: z$1.object({
195
196
  foreground: Color.optional(),
196
197
  foregroundHover: Color.optional(),
197
198
  foregroundActive: Color.optional()
@@ -203,37 +204,33 @@ const Rules = z.object({
203
204
  backgroundHover: Color.optional(),
204
205
  backgroundActive: Color.optional(),
205
206
  fontFamily: FamilyName.optional(),
206
- divider: z.object({
207
+ divider: z$1.object({
207
208
  borderColor: Color.optional(),
208
209
  borderWidth: LineWidth.optional()
209
210
  })
210
211
  }).optional()
211
212
  }).optional(),
212
- header: z.object({
213
- background: Color.optional(),
214
- borderWidth: LineWidth.optional(),
215
- borderColor: Color.optional(),
216
- boxShadow: BoxShadow.optional(),
217
- headline: z.object({
218
- foreground: Color.optional(),
219
- fontFamily: FamilyName.optional()
220
- }).optional(),
221
- title: z.object({
222
- foreground: Color.optional(),
223
- fontFamily: FamilyName.optional(),
224
- fontWeight: FontWeight.optional()
225
- }).optional()
226
- }).optional(),
213
+ header: z$1.object({ title: z$1.object({
214
+ foreground: Color.optional(),
215
+ fontFamily: FamilyName.optional(),
216
+ fontWeight: FontWeight.optional()
217
+ }).optional() }).optional(),
227
218
  form: FormRules,
228
- sidebar: z.object({
219
+ sidebar: z$1.object({
229
220
  background: Color.optional(),
230
221
  foreground: Color.optional(),
231
222
  fontFamily: FamilyName.optional(),
232
223
  borderWidth: LineWidth.optional(),
233
224
  borderColor: Color.optional(),
234
- section: z.object({
235
- toggle: z.object({
236
- icon: z.object({
225
+ section: z$1.object({
226
+ borderWidth: LineWidth.optional(),
227
+ borderColor: Color.optional(),
228
+ active: z$1.object({
229
+ borderWidth: LineWidth.optional(),
230
+ borderColor: Color.optional()
231
+ }).optional(),
232
+ toggle: z$1.object({
233
+ icon: z$1.object({
237
234
  foreground: Color.optional(),
238
235
  foregroundHover: Color.optional(),
239
236
  foregroundActive: Color.optional()
@@ -244,18 +241,16 @@ const Rules = z.object({
244
241
  background: Color.optional(),
245
242
  backgroundHover: Color.optional(),
246
243
  backgroundActive: Color.optional(),
247
- fontFamily: FamilyName.optional(),
248
- borderWidth: LineWidth.optional(),
249
- borderColor: Color.optional()
244
+ fontFamily: FamilyName.optional()
250
245
  }).optional(),
251
246
  form: FormRules
252
247
  }).optional()
253
248
  }).optional(),
254
- public: z.object({
249
+ public: z$1.object({
255
250
  background: Color.optional(),
256
251
  foreground: Color.optional(),
257
252
  foregroundAccent: Color.optional(),
258
- art: z.object({
253
+ art: z$1.object({
259
254
  background: Color.optional(),
260
255
  primary: Color.optional(),
261
256
  secondary: Color.optional(),
@@ -263,42 +258,42 @@ const Rules = z.object({
263
258
  }).optional(),
264
259
  form: FormRules
265
260
  }).optional(),
266
- popover: z.object({ menu: z.object({
261
+ popover: z$1.object({ menu: z$1.object({
267
262
  background: Color.optional(),
268
- borderRadius: z.union([Length, Percentage]).optional(),
263
+ borderRadius: z$1.union([Length, Percentage]).optional(),
269
264
  boxShadow: BoxShadow.optional()
270
265
  }).optional() }).optional(),
271
- banner: z.object({
266
+ banner: z$1.object({
272
267
  background: Color.optional(),
273
- padding: z.union([Length, Percentage]).optional(),
274
- borderRadius: z.union([Length, Percentage]).optional(),
275
- avatar: z.object({
268
+ padding: z$1.union([Length, Percentage]).optional(),
269
+ borderRadius: z$1.union([Length, Percentage]).optional(),
270
+ avatar: z$1.object({
276
271
  background: Color.optional(),
277
272
  foreground: Color.optional(),
278
- borderRadius: z.union([Length, Percentage]).optional()
273
+ borderRadius: z$1.union([Length, Percentage]).optional()
279
274
  }).optional(),
280
- headline: z.object({
275
+ headline: z$1.object({
281
276
  foreground: Color.optional(),
282
277
  fontFamily: FamilyName.optional(),
283
278
  fontWeight: FontWeight.optional()
284
279
  }).optional(),
285
- title: z.object({
280
+ title: z$1.object({
286
281
  foreground: Color.optional(),
287
282
  fontFamily: FamilyName.optional(),
288
283
  fontWeight: FontWeight.optional()
289
284
  }).optional(),
290
- subtitle: z.object({
285
+ subtitle: z$1.object({
291
286
  foreground: Color.optional(),
292
287
  fontFamily: FamilyName.optional(),
293
288
  fontWeight: FontWeight.optional()
294
289
  }).optional(),
295
- art: z.object({ foreground: Color.optional() }).optional()
290
+ art: z$1.object({ foreground: Color.optional() }).optional()
296
291
  }).optional()
297
292
  });
298
- const ThemeSchema = z.object({
299
- id: z.string(),
300
- name: z.string(),
301
- appearance: z.union([z.literal("light"), z.literal("dark")]),
293
+ const ThemeSchema = z$1.object({
294
+ id: z$1.string(),
295
+ name: z$1.string(),
296
+ appearance: z$1.union([z$1.literal("light"), z$1.literal("dark")]),
302
297
  rules: Rules
303
298
  });
304
299
  /**
@@ -319,9 +314,9 @@ let UserIntegrityCheckFlag = /* @__PURE__ */ function(UserIntegrityCheckFlag$1)
319
314
  UserIntegrityCheckFlag$1[UserIntegrityCheckFlag$1["All"] = 3] = "All";
320
315
  return UserIntegrityCheckFlag$1;
321
316
  }({});
322
- const zodStringOrNumber = z.union([z.string(), z.number()]);
323
- const WebSocketMessage = z.object({
324
- type: z.string(),
317
+ const zodStringOrNumber = z$1.union([z$1.string(), z$1.number()]);
318
+ const WebSocketMessage = z$1.object({
319
+ type: z$1.string(),
325
320
  uid: zodStringOrNumber.optional()
326
321
  }).passthrough();
327
322
  const TYPE = { COLLAB: "collab" };
@@ -356,35 +351,35 @@ const ACTION = {
356
351
  ERROR: "error"
357
352
  }
358
353
  };
359
- const BaseClientMessage = z$1.object({
360
- type: z$1.literal(TYPE.COLLAB),
361
- room: z$1.string()
354
+ const BaseClientMessage = z.object({
355
+ type: z.literal(TYPE.COLLAB),
356
+ room: z.string()
362
357
  });
363
- const ClientMessage = z$1.discriminatedUnion("action", [
364
- z$1.object({
365
- type: z$1.literal(TYPE.COLLAB),
366
- action: z$1.literal(ACTION.CLIENT.JOIN),
367
- collection: z$1.string(),
368
- item: z$1.union([z$1.string(), z$1.number()]).nullable(),
369
- version: z$1.string().nullable(),
370
- color: z$1.enum(COLORS).nullable().optional(),
371
- initialChanges: z$1.record(z$1.string(), z$1.any()).optional()
358
+ const ClientMessage = z.discriminatedUnion("action", [
359
+ z.object({
360
+ type: z.literal(TYPE.COLLAB),
361
+ action: z.literal(ACTION.CLIENT.JOIN),
362
+ collection: z.string(),
363
+ item: z.union([z.string(), z.number()]).nullable(),
364
+ version: z.string().nullable(),
365
+ color: z.enum(COLORS).nullable().optional(),
366
+ initialChanges: z.record(z.string(), z.any()).optional()
372
367
  }),
373
- BaseClientMessage.extend({ action: z$1.literal(ACTION.CLIENT.LEAVE) }),
368
+ BaseClientMessage.extend({ action: z.literal(ACTION.CLIENT.LEAVE) }),
374
369
  BaseClientMessage.extend({
375
- action: z$1.literal(ACTION.CLIENT.UPDATE),
376
- field: z$1.string(),
377
- changes: z$1.unknown().optional()
370
+ action: z.literal(ACTION.CLIENT.UPDATE),
371
+ field: z.string(),
372
+ changes: z.unknown().optional()
378
373
  }),
379
374
  BaseClientMessage.extend({
380
- action: z$1.literal(ACTION.CLIENT.UPDATE_ALL),
381
- changes: z$1.record(z$1.string(), z$1.any()).optional()
375
+ action: z.literal(ACTION.CLIENT.UPDATE_ALL),
376
+ changes: z.record(z.string(), z.any()).optional()
382
377
  }),
383
378
  BaseClientMessage.extend({
384
- action: z$1.literal(ACTION.CLIENT.FOCUS),
385
- field: z$1.string().nullable()
379
+ action: z.literal(ACTION.CLIENT.FOCUS),
380
+ field: z.string().nullable()
386
381
  }),
387
- BaseClientMessage.extend({ action: z$1.literal(ACTION.CLIENT.DISCARD) })
382
+ BaseClientMessage.extend({ action: z.literal(ACTION.CLIENT.DISCARD) })
388
383
  ]);
389
384
 
390
385
  //#endregion
@@ -1,3 +1,5 @@
1
+ import { parseJsonFunction } from "../../../../database/helpers/fn/json/parse-function.js";
2
+ import { extractFunctionName } from "../../../../utils/extract-function-name.js";
1
3
  import { flattenFilter } from "./flatten-filter.js";
2
4
  import { isEqual, uniqWith } from "lodash-es";
3
5
 
@@ -21,7 +23,14 @@ function extractPathsFromQuery(query) {
21
23
  const readOnlyPaths = [];
22
24
  if (query.filter) flattenFilter(readOnlyPaths, query.filter);
23
25
  if (query.sort) for (const field of query.sort) {
24
- const parts = field.split(".").map((field$1) => field$1.startsWith("-") ? field$1.substring(1) : field$1);
26
+ const stripped = field.startsWith("-") ? field.substring(1) : field;
27
+ const resolved = query.alias?.[stripped] ?? stripped;
28
+ if (extractFunctionName(resolved) === "json") {
29
+ const { field: jsonField } = parseJsonFunction(resolved);
30
+ readOnlyPaths.push([jsonField]);
31
+ continue;
32
+ }
33
+ const parts = resolved.split(".");
25
34
  if (query.aggregate && parts.length > 0 && parts[0] in query.aggregate) continue;
26
35
  readOnlyPaths.push(parts);
27
36
  }
@@ -1,4 +1,5 @@
1
1
  import { parseJsonFunction } from "../../database/helpers/fn/json/parse-function.js";
2
+ import { extractFunctionName } from "../../utils/extract-function-name.js";
2
3
  import { parseFilterKey } from "../../utils/parse-filter-key.js";
3
4
 
4
5
  //#region src/permissions/utils/get-unaliased-field-key.ts
@@ -11,7 +12,7 @@ function getUnaliasedFieldKey(node) {
11
12
  case "a2o":
12
13
  case "m2o": return node.relation.field;
13
14
  case "field": return parseFilterKey(node.name).fieldName;
14
- case "functionField": if (node.name.startsWith("json")) return parseJsonFunction(node.name).field;
15
+ case "functionField": if (extractFunctionName(node.name) === "json") return parseJsonFunction(node.name).field;
15
16
  else return parseFilterKey(node.name).fieldName;
16
17
  }
17
18
  }
@@ -15,6 +15,8 @@ function isDeniedIp(ip) {
15
15
  const blockNetwork = blockNetworkRaw.trim();
16
16
  if (blockNetwork === "0.0.0.0") {
17
17
  blockNetworkInterfaces = true;
18
+ blockList.parseSubnet("0.0.0.0/8");
19
+ blockList.parseAddress("::");
18
20
  continue;
19
21
  }
20
22
  if (blockNetwork.includes("-")) {