@okam/directus-next 2.0.3 → 2.2.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/CHANGELOG.md CHANGED
@@ -1,3 +1,39 @@
1
+ ## 2.1.1 (2026-03-26)
2
+
3
+ ### 🚀 Features
4
+
5
+ - **directus-next:** getPageSettings props accepts gql client ([a6d983fa](https://github.com/OKAMca/stack/commit/a6d983fa))
6
+
7
+ ### 🩹 Fixes
8
+
9
+ - **directus-next:** getPageSettings also allows custom query fn ([c76c5163](https://github.com/OKAMca/stack/commit/c76c5163))
10
+ - **directus-next:** remove props client memoization to match config arg ([fb169f6a](https://github.com/OKAMca/stack/commit/fb169f6a))
11
+
12
+ ### 🧱 Updated Dependencies
13
+
14
+ - Updated directus-query to 2.0.1
15
+
16
+ ### ❤️ Thank You
17
+
18
+ - poclerson
19
+
20
+ ## 2.1.0 (2026-03-26)
21
+
22
+ ### 🚀 Features
23
+
24
+ - **directus-next:** directus router default locale + display options ([#420](https://github.com/OKAMca/stack/pull/420))
25
+
26
+ ### 🩹 Fixes
27
+
28
+ - resolve dependabot security alerts and clean up published package dependencies ([#441](https://github.com/OKAMca/stack/pull/441))
29
+ - replace use server by server-only in server chunks ([#437](https://github.com/OKAMca/stack/pull/437))
30
+
31
+ ### ❤️ Thank You
32
+
33
+ - Claude Opus 4.6 (1M context)
34
+ - Marie-Maxime Tanguay @marie-maxime
35
+ - Pierre-Olivier Clerson @poclerson
36
+
1
37
  ## 2.0.3 (2026-03-20)
2
38
 
3
39
  ### 🩹 Fixes
package/index.d.ts CHANGED
@@ -4,4 +4,4 @@ export { logger as DirectusNextLogger } from './logger';
4
4
  export * from './redirect';
5
5
  export { getJsonErrorResponse } from './response';
6
6
  export { directusRouteRouter } from './router/router';
7
- export type * from './types';
7
+ export * from './types';
package/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const router = require("./router-CwzG5Cu9.js");
3
+ const router = require("./router-gCcQYkLJ.js");
4
4
  const headers = require("next/headers");
5
5
  const navigation = require("next/navigation");
6
6
  const radashi = require("radashi");
@@ -36,6 +36,7 @@ function getJsonErrorResponse(data, status) {
36
36
  headers: headers2
37
37
  });
38
38
  }
39
+ const TEMPLATE_VAR_RE = /\{\{([a-z]+)\}\}/gi;
39
40
  function jsonStringsArraySchema(message, code) {
40
41
  return zod__namespace.string().transform((val, ctx) => {
41
42
  try {
@@ -97,7 +98,7 @@ function parseDraftParams(url, expectedSecret) {
97
98
  }
98
99
  function getPathFromRoute(routeUrl, url, index = 0) {
99
100
  const { searchParams } = new URL(url);
100
- const matches = [...routeUrl.matchAll(/\{\{([a-z]+)\}\}/gi)];
101
+ const matches = [...routeUrl.matchAll(TEMPLATE_VAR_RE)];
101
102
  const map = {};
102
103
  matches.forEach((match) => {
103
104
  const key = match[1] ?? "";
@@ -202,12 +203,18 @@ async function handleRedirectsRoute({
202
203
  const { redirects, rewrites } = await edge.fetchRedirectsData({ graphqlEndpoint, graphqlApiKey, limit }, init);
203
204
  return new Response(JSON.stringify({ redirects, rewrites }), { status: 200 });
204
205
  }
206
+ var DirectusRouteLocalePrefix = /* @__PURE__ */ ((DirectusRouteLocalePrefix2) => {
207
+ DirectusRouteLocalePrefix2["AsNeeded"] = "as-needed";
208
+ DirectusRouteLocalePrefix2["Always"] = "always";
209
+ return DirectusRouteLocalePrefix2;
210
+ })(DirectusRouteLocalePrefix || {});
205
211
  exports.DirectusNextLogger = router.logger;
206
212
  exports.directusRouteRouter = router.directusRouteRouter;
207
213
  exports.getApiRouteUrlDefault = router.getApiRouteUrlDefault;
208
214
  exports.getRedirectSecretDefault = router.getRedirectSecretDefault;
209
215
  exports.getRedirectsRoute = router.getRedirectsRoute;
210
216
  exports.handleRedirect = router.handleRedirect;
217
+ exports.DirectusRouteLocalePrefix = DirectusRouteLocalePrefix;
211
218
  exports.getDraftSecretDefault = getDraftSecretDefault;
212
219
  exports.getJsonErrorResponse = getJsonErrorResponse;
213
220
  exports.getPathFromRoute = getPathFromRoute;
package/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import { g as getRedirectSecretDefault } from "./router-16XNi-G3.mjs";
2
- import { l, d, a, b, h } from "./router-16XNi-G3.mjs";
1
+ import { g as getRedirectSecretDefault } from "./router-CnD4Qckn.mjs";
2
+ import { l, d, a, b, h } from "./router-CnD4Qckn.mjs";
3
3
  import { draftMode } from "next/headers";
4
4
  import { redirect } from "next/navigation";
5
5
  import { template } from "radashi";
@@ -18,6 +18,7 @@ function getJsonErrorResponse(data, status) {
18
18
  headers
19
19
  });
20
20
  }
21
+ const TEMPLATE_VAR_RE = /\{\{([a-z]+)\}\}/gi;
21
22
  function jsonStringsArraySchema(message, code) {
22
23
  return zod.string().transform((val, ctx) => {
23
24
  try {
@@ -79,7 +80,7 @@ function parseDraftParams(url, expectedSecret) {
79
80
  }
80
81
  function getPathFromRoute(routeUrl, url, index = 0) {
81
82
  const { searchParams } = new URL(url);
82
- const matches = [...routeUrl.matchAll(/\{\{([a-z]+)\}\}/gi)];
83
+ const matches = [...routeUrl.matchAll(TEMPLATE_VAR_RE)];
83
84
  const map = {};
84
85
  matches.forEach((match) => {
85
86
  const key = match[1] ?? "";
@@ -184,8 +185,14 @@ async function handleRedirectsRoute({
184
185
  const { redirects, rewrites } = await fetchRedirectsData({ graphqlEndpoint, graphqlApiKey, limit }, init);
185
186
  return new Response(JSON.stringify({ redirects, rewrites }), { status: 200 });
186
187
  }
188
+ var DirectusRouteLocalePrefix = /* @__PURE__ */ ((DirectusRouteLocalePrefix2) => {
189
+ DirectusRouteLocalePrefix2["AsNeeded"] = "as-needed";
190
+ DirectusRouteLocalePrefix2["Always"] = "always";
191
+ return DirectusRouteLocalePrefix2;
192
+ })(DirectusRouteLocalePrefix || {});
187
193
  export {
188
194
  l as DirectusNextLogger,
195
+ DirectusRouteLocalePrefix,
189
196
  d as directusRouteRouter,
190
197
  a as getApiRouteUrlDefault,
191
198
  getDraftSecretDefault,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@okam/directus-next",
3
- "version": "2.0.3",
3
+ "version": "2.2.0",
4
4
  "repository": {
5
5
  "url": "https://github.com/OKAMca/stack.git"
6
6
  },
@@ -42,11 +42,11 @@
42
42
  },
43
43
  "dependencies": {
44
44
  "@graphql-typed-document-node/core": "3.2.0",
45
- "@okam/core-lib": "2.0.0",
46
- "@okam/directus-node": "1.0.0",
47
- "@okam/directus-query": "2.0.0",
45
+ "@okam/core-lib": "2.1.0",
46
+ "@okam/directus-node": "1.1.0",
47
+ "@okam/directus-query": "2.1.0",
48
48
  "@okam/logger": "1.1.0",
49
- "@okam/next-component": "2.0.3",
49
+ "@okam/next-component": "2.1.0",
50
50
  "graphql-request": "^7.1.2",
51
51
  "radashi": "^12.3.0",
52
52
  "server-only": "0.0.1",
@@ -1,5 +1,5 @@
1
1
  import { TypedDocumentNode } from '@graphql-typed-document-node/core';
2
- import { Variables } from 'graphql-request';
2
+ import { GraphQLClient, Variables } from 'graphql-request';
3
3
  import { TDirectusRouteConfig } from '../types/directusRouteConfig';
4
4
  import { Fragmentize } from '../types/Fragments';
5
5
  import { TPageSettings, TPageSettingsItemQuery, TPageSettingsQueryItem } from '../types/pageSettings';
@@ -19,6 +19,30 @@ export interface TGetPageSettingsProps<Item extends TPageSettingsQueryItem, Item
19
19
  * Either a directus route config or directly a locale map. Not passing a config while passing a document will result in direct usage of the `locale` variable.
20
20
  */
21
21
  config?: TGetPageSettingsConfig;
22
+ /**
23
+ * GraphQL client to use for the query done via {@link queryGql}. Defaults to `@okam/directus-query` `defaultGraphqlRequestClient`
24
+ * @default defaultGraphqlRequestClient
25
+ */
26
+ client?: GraphQLClient;
27
+ /**
28
+ * Query function to replace the default {@link queryGql}. Note that `document`, `variables` and `client` still get passed to this function, but they can be overriden easily.
29
+ *
30
+ * @example
31
+ * ```ts
32
+ * const customGqlClient = new GraphQLClient()
33
+ *
34
+ * const product = await getPageSettings({
35
+ * queryGqlFn: async (document, variables) => {
36
+ * // ignore the `client` argument passed in the callback
37
+ * const result = await queryGql(document, variables, customGqlClient)
38
+ * return result
39
+ * }
40
+ * })
41
+ * ```
42
+ *
43
+ * @default queryGql
44
+ */
45
+ queryGqlFn?: (document: TPageSettingsItemDocument<Item, ItemKey, QueryVariables>, queryKey?: QueryVariables | undefined, client?: GraphQLClient) => Promise<TPageSettingsItemQuery<Item, ItemKey>>;
22
46
  }
23
47
  export type TGetPageSettingsReturn<Item extends TPageSettingsQueryItem> = Omit<Item, 'page_settings'> & {
24
48
  page_settings?: Exclude<NonNullable<Item>['page_settings'], Fragmentize<TPageSettings, 'PageSettingsFragment'>> | null | undefined;
@@ -1,3 +1,4 @@
1
+ import { LocalePrefix } from "@okam/next-component/server";
1
2
  import { NextResponse } from "next/server";
2
3
  import { capitalize, isEmpty } from "radashi";
3
4
  import { createLogger } from "@okam/logger";
@@ -190,14 +191,21 @@ async function directusRouteRouter(request, config, NextResponse$1 = NextRespons
190
191
  log(`PageSettings with id ${id} was found but is not associated with any locale.`, { id }, "warn");
191
192
  return NextResponse$1.next();
192
193
  }
193
- const mappedLocale = config.localeMap?.[directusLocale] || directusLocale;
194
- const idField = config.collectionSettings[collection]?.idField || config.collectionSettings.default.idField;
194
+ const { localeMap, collectionSettings, localePrefix = LocalePrefix.Always, defaultLocale } = config;
195
+ const mappedLocale = localeMap?.[directusLocale] || directusLocale;
196
+ const isDirectusRouteLocalePrefixedMap = {
197
+ [LocalePrefix.Always]: true,
198
+ [LocalePrefix.AsNeeded]: directusLocale !== defaultLocale
199
+ };
200
+ const isDirectusRouteLocalePrefixed = isDirectusRouteLocalePrefixedMap[localePrefix];
201
+ const displayedLocale = isDirectusRouteLocalePrefixed ? `/${mappedLocale}` : "";
202
+ const idField = collectionSettings[collection]?.idField || collectionSettings.default.idField;
195
203
  log("Directus locale:", directusLocale);
196
204
  log("Mapped locale:", mappedLocale);
197
205
  log("Collection:", collection);
198
206
  log("ID Field:", idField);
199
207
  log("ID:", id);
200
- const newPath = `/${mappedLocale}/${collection}/${id}`;
208
+ const newPath = `${displayedLocale}/${collection}/${id}`;
201
209
  log(`Rewriting path: ${pathname} -> ${newPath}`);
202
210
  const url = request.nextUrl.clone();
203
211
  url.pathname = newPath;
@@ -1,4 +1,5 @@
1
1
  "use strict";
2
+ const server$1 = require("@okam/next-component/server");
2
3
  const server = require("next/server");
3
4
  const radashi = require("radashi");
4
5
  const logger$1 = require("@okam/logger");
@@ -191,14 +192,21 @@ async function directusRouteRouter(request, config, NextResponse = server.NextRe
191
192
  log(`PageSettings with id ${id} was found but is not associated with any locale.`, { id }, "warn");
192
193
  return NextResponse.next();
193
194
  }
194
- const mappedLocale = config.localeMap?.[directusLocale] || directusLocale;
195
- const idField = config.collectionSettings[collection]?.idField || config.collectionSettings.default.idField;
195
+ const { localeMap, collectionSettings, localePrefix = server$1.LocalePrefix.Always, defaultLocale } = config;
196
+ const mappedLocale = localeMap?.[directusLocale] || directusLocale;
197
+ const isDirectusRouteLocalePrefixedMap = {
198
+ [server$1.LocalePrefix.Always]: true,
199
+ [server$1.LocalePrefix.AsNeeded]: directusLocale !== defaultLocale
200
+ };
201
+ const isDirectusRouteLocalePrefixed = isDirectusRouteLocalePrefixedMap[localePrefix];
202
+ const displayedLocale = isDirectusRouteLocalePrefixed ? `/${mappedLocale}` : "";
203
+ const idField = collectionSettings[collection]?.idField || collectionSettings.default.idField;
196
204
  log("Directus locale:", directusLocale);
197
205
  log("Mapped locale:", mappedLocale);
198
206
  log("Collection:", collection);
199
207
  log("ID Field:", idField);
200
208
  log("ID:", id);
201
- const newPath = `/${mappedLocale}/${collection}/${id}`;
209
+ const newPath = `${displayedLocale}/${collection}/${id}`;
202
210
  log(`Rewriting path: ${pathname} -> ${newPath}`);
203
211
  const url = request.nextUrl.clone();
204
212
  url.pathname = newPath;
package/server.js CHANGED
@@ -1,7 +1,7 @@
1
1
  require("server-only");
2
2
  "use strict";
3
3
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
4
- const router = require("./router-CwzG5Cu9.js");
4
+ const router = require("./router-gCcQYkLJ.js");
5
5
  const directusQuery = require("@okam/directus-query");
6
6
  const radashi = require("radashi");
7
7
  const server = require("@okam/next-component/server");
@@ -16,11 +16,11 @@ function pageSettingsVariablesContext(variables) {
16
16
  }
17
17
  const [getPageSettingsContext, setPageSettingsContext] = pageSettingsContext();
18
18
  const [getVariables, setVariables] = pageSettingsVariablesContext();
19
- function isTDirectusRouteConfig(config) {
20
- return config != null && "localeMap" in config;
19
+ function isDirectusRouteConfig(config) {
20
+ return config != null && "collectionSettings" in config;
21
21
  }
22
22
  function getDirectusVariables(variables, config) {
23
- const localeMap = isTDirectusRouteConfig(config) ? config.localeMap : config;
23
+ const localeMap = isDirectusRouteConfig(config) ? config.localeMap : config;
24
24
  if (localeMap == null) {
25
25
  return variables;
26
26
  }
@@ -29,7 +29,7 @@ function getDirectusVariables(variables, config) {
29
29
  return { ...variables, locale: directusLocale };
30
30
  }
31
31
  async function getPageSettings(props, itemKey) {
32
- const { variables, config } = props ?? {};
32
+ const { variables, config, client = directusQuery.defaultGraphqlRequestClient, queryGqlFn = directusQuery.queryGql } = props ?? {};
33
33
  const directusVariables = getDirectusVariables(variables, config);
34
34
  const defaultReturn = getPageSettingsContext();
35
35
  if (props == null || radashi.isEqual(getVariables(), directusVariables)) {
@@ -39,7 +39,7 @@ async function getPageSettings(props, itemKey) {
39
39
  const { document } = props;
40
40
  const key = itemKey ?? radashi.get(document, "definitions[0].selectionSet.selections[0].name.value");
41
41
  router.log("Querying new page settings", directusVariables);
42
- const result = await directusQuery.queryGql(document, directusVariables);
42
+ const result = await queryGqlFn(document, directusVariables, client);
43
43
  const items = result?.[key];
44
44
  const currentItem = Array.isArray(items) ? items?.[0] : items;
45
45
  const currentPageSettings = currentItem?.page_settings;
package/server.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import "server-only";
2
- import { c as log } from "./router-16XNi-G3.mjs";
3
- import { d } from "./router-16XNi-G3.mjs";
4
- import { queryGql } from "@okam/directus-query";
2
+ import { c as log } from "./router-CnD4Qckn.mjs";
3
+ import { d } from "./router-CnD4Qckn.mjs";
4
+ import { queryGql, defaultGraphqlRequestClient } from "@okam/directus-query";
5
5
  import { isEqual, get, invert } from "radashi";
6
6
  import { createServerContext } from "@okam/next-component/server";
7
7
  import "server-only";
@@ -15,11 +15,11 @@ function pageSettingsVariablesContext(variables) {
15
15
  }
16
16
  const [getPageSettingsContext, setPageSettingsContext] = pageSettingsContext();
17
17
  const [getVariables, setVariables] = pageSettingsVariablesContext();
18
- function isTDirectusRouteConfig(config) {
19
- return config != null && "localeMap" in config;
18
+ function isDirectusRouteConfig(config) {
19
+ return config != null && "collectionSettings" in config;
20
20
  }
21
21
  function getDirectusVariables(variables, config) {
22
- const localeMap = isTDirectusRouteConfig(config) ? config.localeMap : config;
22
+ const localeMap = isDirectusRouteConfig(config) ? config.localeMap : config;
23
23
  if (localeMap == null) {
24
24
  return variables;
25
25
  }
@@ -28,7 +28,7 @@ function getDirectusVariables(variables, config) {
28
28
  return { ...variables, locale: directusLocale };
29
29
  }
30
30
  async function getPageSettings(props, itemKey) {
31
- const { variables, config } = props ?? {};
31
+ const { variables, config, client = defaultGraphqlRequestClient, queryGqlFn = queryGql } = props ?? {};
32
32
  const directusVariables = getDirectusVariables(variables, config);
33
33
  const defaultReturn = getPageSettingsContext();
34
34
  if (props == null || isEqual(getVariables(), directusVariables)) {
@@ -38,7 +38,7 @@ async function getPageSettings(props, itemKey) {
38
38
  const { document } = props;
39
39
  const key = itemKey ?? get(document, "definitions[0].selectionSet.selections[0].name.value");
40
40
  log("Querying new page settings", directusVariables);
41
- const result = await queryGql(document, directusVariables);
41
+ const result = await queryGqlFn(document, directusVariables, client);
42
42
  const items = result?.[key];
43
43
  const currentItem = Array.isArray(items) ? items?.[0] : items;
44
44
  const currentPageSettings = currentItem?.page_settings;
@@ -1,3 +1,4 @@
1
+ import { LocalePrefix } from '@okam/next-component/server';
1
2
  export interface TDirectusRouteRedirectsModule {
2
3
  /**
3
4
  * @default process.env.NEXT_API_REDIRECT_SECRET
@@ -12,8 +13,71 @@ export interface TDirectusRouteRedirectsModule {
12
13
  */
13
14
  apiRoute?: string;
14
15
  }
15
- export interface TDirectusRouteConfig {
16
- localeMap?: Record<string, string>;
16
+ /**
17
+ * @deprecated
18
+ * Use `LocalePrefix` from `@okam/next-component` instead.
19
+ */
20
+ export declare enum DirectusRouteLocalePrefix {
21
+ /**
22
+ * The pathname will be prefixed with the locale only when it is not the default locale
23
+ *
24
+ * @example
25
+ * ```ts
26
+ * const directusConfig = {
27
+ * localePrefix: 'as-needed',
28
+ * defaultLocale: 'en-CA',
29
+ * localeMap: {
30
+ * 'fr-CA': 'fr',
31
+ * 'en-CA': 'en',
32
+ * }
33
+ * }
34
+ *
35
+ * // navigate to /en/products/1
36
+ * // output: /products/1 with english language
37
+ *
38
+ * // navigate to /products/1
39
+ * // output: /products/1 with english language
40
+ *
41
+ * // navigate to /fr/produits/1
42
+ * // output: /fr/produits/1 with french language
43
+ * ```
44
+ */
45
+ AsNeeded = "as-needed",
46
+ /**
47
+ * The pathname will always be prefixed by the locale
48
+ *
49
+ * @example
50
+ * ```ts
51
+ * const directusConfig = {
52
+ * localePrefix: 'always',
53
+ * defaultLocale: 'en-CA',
54
+ * localeMap: {
55
+ * 'fr-CA': 'fr',
56
+ * 'en-CA': 'en',
57
+ * }
58
+ * }
59
+ *
60
+ * // navigate to /en/products/1
61
+ * // output: /en/products/1 with english language
62
+ *
63
+ * // navigate to /products/1
64
+ * // output: /en/products/1 with english language
65
+ *
66
+ * // navigate to /fr/produits/1
67
+ * // output: /fr/produits/1 with french language
68
+ * ```
69
+ */
70
+ Always = "always"
71
+ }
72
+ export type TDirectusRouteI18n<Locales extends string> = {
73
+ defaultLocale: Locales;
74
+ localePrefix: `${LocalePrefix.AsNeeded}`;
75
+ } | {
76
+ defaultLocale?: Locales;
77
+ localePrefix?: `${LocalePrefix.Always}` | undefined;
78
+ };
79
+ export type TDirectusRouteConfig<Locales extends string = string> = {
80
+ localeMap?: Record<Locales, string>;
17
81
  collectionSettings: {
18
82
  [collection: string]: {
19
83
  idField: string;
@@ -26,4 +90,4 @@ export interface TDirectusRouteConfig {
26
90
  modules?: {
27
91
  redirects?: TDirectusRouteRedirectsModule;
28
92
  };
29
- }
93
+ } & TDirectusRouteI18n<Locales>;
package/types/index.d.ts CHANGED
@@ -1,2 +1,3 @@
1
+ export { DirectusRouteLocalePrefix } from './directusRouteConfig';
1
2
  export type { TDirectusRouteConfig, TDirectusRouteRedirectsModule } from './directusRouteConfig';
2
3
  export type { TPageSettings, TPageSettingsItemQuery, TPageSettingsQueryItem, TPageSettingsTranslation, } from './pageSettings';