nuxt-directus-sdk 6.0.0 → 6.1.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.
package/README.md CHANGED
@@ -4,6 +4,7 @@
4
4
  [![npm downloads][npm-downloads-src]][npm-downloads-href]
5
5
  [![CI][ci-src]][ci-href]
6
6
  [![Install size][install-size-src]][install-size-href]
7
+ [![Nuxt Care][nuxt-care-src]][nuxt-care-href]
7
8
  [![License][license-src]][license-href]
8
9
  [![Nuxt][nuxt-src]][nuxt-href]
9
10
 
@@ -136,6 +137,9 @@ Contributions are welcome. Please target the `next` branch for new features and
136
137
  [install-size-src]: https://packagephobia.com/badge?p=nuxt-directus-sdk
137
138
  [install-size-href]: https://packagephobia.com/result?p=nuxt-directus-sdk
138
139
 
140
+ [nuxt-care-src]: https://img.shields.io/endpoint?url=https%3A%2F%2Fnuxt.care%2Fapi%2Fv1%2Fbadge%3Fpackage%3Dnuxt-directus-sdk
141
+ [nuxt-care-href]: https://nuxt.care/?search=nuxt-directus-sdk
142
+
139
143
  [license-src]: https://img.shields.io/npm/l/nuxt-directus-sdk.svg?style=flat&colorA=18181B&colorB=28CF8D
140
144
  [license-href]: https://npmjs.com/package/nuxt-directus-sdk
141
145
 
@@ -3,7 +3,7 @@ import { existsSync, readFileSync, mkdirSync, writeFileSync } from 'node:fs';
3
3
  import { resolve, dirname } from 'node:path';
4
4
  import { parseArgs } from 'node:util';
5
5
  import { createDirectus, staticToken, rest } from '@directus/sdk';
6
- import { d as diffRemoteRules, e as formatDiff, c as compareRulesPayloads, f as fetchRemoteRules, k as loadRulesFromPayload, o as pushRules, g as formatPushResult, b as fetchRemoteRulesAsJson } from '../shared/nuxt-directus-sdk.CtcY1peN.mjs';
6
+ import { d as diffRemoteRules, f as formatDiff, c as compareRulesPayloads, a as fetchRemoteRules, l as loadRulesFromPayload, p as pushRules, b as formatPushResult, e as fetchRemoteRulesAsJson } from '../shared/nuxt-directus-sdk.sBTh4hx5.mjs';
7
7
  import { generateTypesFromDirectus } from '../../dist/runtime/types/generate.js';
8
8
 
9
9
  function parseCsv(raw) {
package/dist/module.d.mts CHANGED
@@ -7,6 +7,27 @@ type DirectusUrl = string | {
7
7
  server: string;
8
8
  };
9
9
  type ReadMeFields = Query<DirectusSchema, DirectusUser<DirectusSchema>>['fields'];
10
+ /**
11
+ * Shape of the `proxy` (and deprecated `devProxy`) module option.
12
+ */
13
+ type ProxyOption = boolean | {
14
+ /**
15
+ * Enable the proxy. Defaults to true in dev, false in production.
16
+ * Explicitly setting `true` enables HTTP proxying in production too.
17
+ */
18
+ enabled?: boolean;
19
+ /**
20
+ * HTTP proxy path (where the Nitro server handler is mounted).
21
+ * @default '/directus'
22
+ */
23
+ path?: string;
24
+ /**
25
+ * WebSocket proxy path (for realtime connections). Dev-mode only;
26
+ * ignored in production builds.
27
+ * @default '/directus-ws'
28
+ */
29
+ wsPath?: string;
30
+ };
10
31
  interface ModuleOptions {
11
32
  /**
12
33
  * Directus API URL
@@ -18,29 +39,27 @@ interface ModuleOptions {
18
39
  */
19
40
  url: DirectusUrl;
20
41
  /**
21
- * Development proxy configuration
22
- * When enabled, creates a proxy at /directus that forwards to your Directus URL
23
- * This solves CORS and cookie issues in development
24
- * @default { enabled: true, path: '/directus', wsPath: '/directus-ws' } in dev mode
42
+ * Proxy configuration. When enabled, creates a Nitro server handler at
43
+ * `path` that forwards HTTP requests to your Directus URL. Useful for
44
+ * cookie-scope (login on the same origin) and CORS workarounds.
45
+ *
46
+ * - Defaults to on in dev, off in production.
47
+ * - Setting `true` (or `{ enabled: true }`) explicitly turns the HTTP
48
+ * proxy on in production too.
49
+ * - The WebSocket proxy (for realtime) is dev-only; it relies on the
50
+ * dev-server's upgrade hook which doesn't exist in production builds.
51
+ * When the HTTP proxy is on in production, realtime connects directly
52
+ * to Directus, so realtime auth still requires same-domain cookies
53
+ * (or a public `realtimeAuthMode`).
54
+ *
55
+ * @default { enabled: <isDev>, path: '/directus', wsPath: '/directus-ws' (dev only) }
25
56
  * @type boolean | { enabled?: boolean, path?: string, wsPath?: string }
26
57
  */
27
- devProxy?: boolean | {
28
- /**
29
- * Enable the development proxy
30
- * @default true in dev mode, false in production
31
- */
32
- enabled?: boolean;
33
- /**
34
- * Proxy path (where the proxy will be mounted)
35
- * @default '/directus'
36
- */
37
- path?: string;
38
- /**
39
- * WebSocket proxy path (for realtime connections)
40
- * @default '/directus-ws'
41
- */
42
- wsPath?: string;
43
- };
58
+ proxy?: ProxyOption;
59
+ /**
60
+ * @deprecated Use `proxy` instead. `devProxy` will be removed in the next major release.
61
+ */
62
+ devProxy?: ProxyOption;
44
63
  /**
45
64
  * Admin Auth Token used for generating types and server functions
46
65
  * @default process.env.DIRECTUS_ADMIN_TOKEN
@@ -227,4 +246,4 @@ declare module '@nuxt/schema' {
227
246
  }
228
247
 
229
248
  export { _default as default };
230
- export type { DirectusUrl, ModuleOptions, ReadMeFields };
249
+ export type { DirectusUrl, ModuleOptions, ProxyOption, ReadMeFields };
package/dist/module.d.ts CHANGED
@@ -7,6 +7,27 @@ type DirectusUrl = string | {
7
7
  server: string;
8
8
  };
9
9
  type ReadMeFields = Query<DirectusSchema, DirectusUser<DirectusSchema>>['fields'];
10
+ /**
11
+ * Shape of the `proxy` (and deprecated `devProxy`) module option.
12
+ */
13
+ type ProxyOption = boolean | {
14
+ /**
15
+ * Enable the proxy. Defaults to true in dev, false in production.
16
+ * Explicitly setting `true` enables HTTP proxying in production too.
17
+ */
18
+ enabled?: boolean;
19
+ /**
20
+ * HTTP proxy path (where the Nitro server handler is mounted).
21
+ * @default '/directus'
22
+ */
23
+ path?: string;
24
+ /**
25
+ * WebSocket proxy path (for realtime connections). Dev-mode only;
26
+ * ignored in production builds.
27
+ * @default '/directus-ws'
28
+ */
29
+ wsPath?: string;
30
+ };
10
31
  interface ModuleOptions {
11
32
  /**
12
33
  * Directus API URL
@@ -18,29 +39,27 @@ interface ModuleOptions {
18
39
  */
19
40
  url: DirectusUrl;
20
41
  /**
21
- * Development proxy configuration
22
- * When enabled, creates a proxy at /directus that forwards to your Directus URL
23
- * This solves CORS and cookie issues in development
24
- * @default { enabled: true, path: '/directus', wsPath: '/directus-ws' } in dev mode
42
+ * Proxy configuration. When enabled, creates a Nitro server handler at
43
+ * `path` that forwards HTTP requests to your Directus URL. Useful for
44
+ * cookie-scope (login on the same origin) and CORS workarounds.
45
+ *
46
+ * - Defaults to on in dev, off in production.
47
+ * - Setting `true` (or `{ enabled: true }`) explicitly turns the HTTP
48
+ * proxy on in production too.
49
+ * - The WebSocket proxy (for realtime) is dev-only; it relies on the
50
+ * dev-server's upgrade hook which doesn't exist in production builds.
51
+ * When the HTTP proxy is on in production, realtime connects directly
52
+ * to Directus, so realtime auth still requires same-domain cookies
53
+ * (or a public `realtimeAuthMode`).
54
+ *
55
+ * @default { enabled: <isDev>, path: '/directus', wsPath: '/directus-ws' (dev only) }
25
56
  * @type boolean | { enabled?: boolean, path?: string, wsPath?: string }
26
57
  */
27
- devProxy?: boolean | {
28
- /**
29
- * Enable the development proxy
30
- * @default true in dev mode, false in production
31
- */
32
- enabled?: boolean;
33
- /**
34
- * Proxy path (where the proxy will be mounted)
35
- * @default '/directus'
36
- */
37
- path?: string;
38
- /**
39
- * WebSocket proxy path (for realtime connections)
40
- * @default '/directus-ws'
41
- */
42
- wsPath?: string;
43
- };
58
+ proxy?: ProxyOption;
59
+ /**
60
+ * @deprecated Use `proxy` instead. `devProxy` will be removed in the next major release.
61
+ */
62
+ devProxy?: ProxyOption;
44
63
  /**
45
64
  * Admin Auth Token used for generating types and server functions
46
65
  * @default process.env.DIRECTUS_ADMIN_TOKEN
@@ -227,4 +246,4 @@ declare module '@nuxt/schema' {
227
246
  }
228
247
 
229
248
  export { _default as default };
230
- export type { DirectusUrl, ModuleOptions, ReadMeFields };
249
+ export type { DirectusUrl, ModuleOptions, ProxyOption, ReadMeFields };
package/dist/module.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nuxt-directus-sdk",
3
- "version": "6.0.0",
3
+ "version": "6.1.1",
4
4
  "configKey": "directus",
5
5
  "compatibility": {
6
6
  "nuxt": "^4.0.0"
package/dist/module.mjs CHANGED
@@ -8,7 +8,7 @@ import { generateTypesFromDirectus } from '../dist/runtime/types/index.js';
8
8
  import { useUrl } from '../dist/runtime/utils/index.js';
9
9
 
10
10
  const name = "nuxt-directus-sdk";
11
- const version = "6.0.0";
11
+ const version = "6.1.1";
12
12
 
13
13
  const SDK_CLIENT_FACTORIES = /* @__PURE__ */ new Set([
14
14
  "createDirectus",
@@ -68,8 +68,9 @@ const module$1 = defineNuxtModule({
68
68
  },
69
69
  defaults: {
70
70
  url: import.meta.env.DIRECTUS_URL ?? "",
71
+ proxy: void 0,
72
+ // Resolved in setup based on dev mode.
71
73
  devProxy: void 0,
72
- // Will be set based on dev mode in setup
73
74
  adminToken: import.meta.env.DIRECTUS_ADMIN_TOKEN ?? "",
74
75
  devtools: true,
75
76
  visualEditor: true,
@@ -109,76 +110,93 @@ const module$1 = defineNuxtModule({
109
110
  nuxtApp.options[key] = defu(nuxtApp.options[key], moduleOptions);
110
111
  }
111
112
  }
112
- const devProxyConfig = typeof options.devProxy === "boolean" ? { enabled: options.devProxy } : { ...options.devProxy };
113
+ if (options.proxy !== void 0 && options.devProxy !== void 0) {
114
+ logger.warn(
115
+ "Both `proxy` and `devProxy` are set in directus module config. `proxy` wins; `devProxy` is ignored. Remove the deprecated `devProxy` entry."
116
+ );
117
+ } else if (options.proxy === void 0 && options.devProxy !== void 0) {
118
+ logger.warn(
119
+ "`directus.devProxy` is deprecated and will be removed in a future major release. Rename it to `directus.proxy`."
120
+ );
121
+ options.proxy = options.devProxy;
122
+ }
123
+ options.devProxy = void 0;
124
+ const proxyConfig = typeof options.proxy === "boolean" ? { enabled: options.proxy } : { ...options.proxy };
113
125
  const directusUrl = serverUrl || clientUrl;
114
- const devProxyEnabled = devProxyConfig.enabled ?? nuxtApp.options.dev;
115
- const devProxyPath = devProxyConfig.path ?? "/directus";
116
- const wsProxyPath = devProxyConfig.wsPath ?? `${devProxyPath}-ws`;
126
+ const proxyEnabled = proxyConfig.enabled ?? nuxtApp.options.dev;
127
+ const proxyPath = proxyConfig.path ?? "/directus";
128
+ const wsProxyPath = proxyConfig.wsPath ?? `${proxyPath}-ws`;
117
129
  const wsTarget = joinURL(directusUrl, "websocket");
118
- if (devProxyEnabled && nuxtApp.options.dev) {
119
- loggerMessage.push(`\u{1F310} Development Proxy Mode Enabled:`);
120
- loggerMessage.push(` - URL${colors.dim(` ${devProxyPath}`)} proxies ${colors.underline(colors.green(`${directusUrl}`))}`);
121
- loggerMessage.push(` - WS URL${colors.dim(` ${wsProxyPath}`)} proxies ${colors.underline(colors.green(`${wsTarget}`))}`, "");
122
- nuxtApp.options.nitro = nuxtApp.options.nitro || {};
123
- nuxtApp.options.nitro.devProxy = nuxtApp.options.nitro.devProxy || {};
124
- nuxtApp.options.nitro.devProxy[wsProxyPath] = {
125
- target: directusUrl,
126
- changeOrigin: true,
127
- ws: true
128
- };
129
- const httpProxy = await import('http-proxy');
130
- const proxy = httpProxy.default.createProxyServer({
131
- target: directusUrl,
132
- changeOrigin: true,
133
- ws: true,
134
- secure: false
135
- // Allow self-signed certificates
136
- });
137
- proxy.on("error", (err, _req, socket) => {
138
- logger.error(`WebSocket proxy error:`, err.message);
139
- if (socket && !socket.destroyed) {
140
- socket.end();
141
- }
142
- });
143
- proxy.on("proxyReqWs", (proxyReq, req, _socket) => {
144
- proxyReq.path = "/websocket";
145
- if (req.headers.cookie) {
146
- proxyReq.setHeader("cookie", req.headers.cookie);
147
- }
148
- });
149
- nuxtApp.hook("ready", () => {
150
- const originalUpgrade = nuxtApp.server?.upgrade;
151
- if (nuxtApp.server) {
152
- nuxtApp.server.upgrade = (req, socket, head) => {
153
- if (req.url?.startsWith(wsProxyPath)) {
154
- try {
155
- proxy.ws(req, socket, head);
156
- } catch (error) {
157
- logger.error("WebSocket proxy error:", error instanceof Error ? error.message : String(error));
158
- if (!socket.destroyed) {
159
- socket.destroy();
160
- }
161
- }
162
- } else if (originalUpgrade) {
163
- return originalUpgrade(req, socket, head);
164
- } else if (!socket.destroyed) {
165
- socket.destroy();
166
- }
167
- };
168
- }
169
- });
130
+ const isDev = nuxtApp.options.dev;
131
+ if (proxyEnabled) {
132
+ const headerLabel = isDev ? "\u{1F310} Development Proxy Mode Enabled:" : "\u{1F310} Proxy Mode Enabled (production):";
133
+ loggerMessage.push(headerLabel);
134
+ loggerMessage.push(` - URL${colors.dim(` ${proxyPath}`)} proxies ${colors.underline(colors.green(`${directusUrl}`))}`);
170
135
  addServerHandler({
171
- route: `${devProxyPath}/**`,
136
+ route: `${proxyPath}/**`,
172
137
  handler: resolver.resolve("./runtime/server/routes/directus")
173
138
  });
174
- options.devProxy = {
139
+ if (isDev) {
140
+ loggerMessage.push(` - WS URL${colors.dim(` ${wsProxyPath}`)} proxies ${colors.underline(colors.green(`${wsTarget}`))}`, "");
141
+ nuxtApp.options.nitro = nuxtApp.options.nitro || {};
142
+ nuxtApp.options.nitro.devProxy = nuxtApp.options.nitro.devProxy || {};
143
+ nuxtApp.options.nitro.devProxy[wsProxyPath] = {
144
+ target: directusUrl,
145
+ changeOrigin: true,
146
+ ws: true
147
+ };
148
+ const httpProxy = await import('http-proxy');
149
+ const proxy = httpProxy.default.createProxyServer({
150
+ target: directusUrl,
151
+ changeOrigin: true,
152
+ ws: true,
153
+ secure: false
154
+ // Allow self-signed certificates
155
+ });
156
+ proxy.on("error", (err, _req, socket) => {
157
+ logger.error(`WebSocket proxy error:`, err.message);
158
+ if (socket && !socket.destroyed) {
159
+ socket.end();
160
+ }
161
+ });
162
+ proxy.on("proxyReqWs", (proxyReq, req, _socket) => {
163
+ proxyReq.path = "/websocket";
164
+ if (req.headers.cookie) {
165
+ proxyReq.setHeader("cookie", req.headers.cookie);
166
+ }
167
+ });
168
+ nuxtApp.hook("ready", () => {
169
+ const originalUpgrade = nuxtApp.server?.upgrade;
170
+ if (nuxtApp.server) {
171
+ nuxtApp.server.upgrade = (req, socket, head) => {
172
+ if (req.url?.startsWith(wsProxyPath)) {
173
+ try {
174
+ proxy.ws(req, socket, head);
175
+ } catch (error) {
176
+ logger.error("WebSocket proxy error:", error instanceof Error ? error.message : String(error));
177
+ if (!socket.destroyed) {
178
+ socket.destroy();
179
+ }
180
+ }
181
+ } else if (originalUpgrade) {
182
+ return originalUpgrade(req, socket, head);
183
+ } else if (!socket.destroyed) {
184
+ socket.destroy();
185
+ }
186
+ };
187
+ }
188
+ });
189
+ } else {
190
+ loggerMessage.push(` - ${colors.yellow("WebSocket proxy is disabled in production")}; connect realtime directly to ${colors.dim(`${wsTarget}`)}`, "");
191
+ }
192
+ options.proxy = {
175
193
  enabled: true,
176
- path: devProxyPath,
177
- wsPath: wsProxyPath
194
+ path: proxyPath,
195
+ wsPath: isDev ? wsProxyPath : void 0
178
196
  };
179
- } else if (!nuxtApp.options.dev && directusUrl) {
197
+ } else if (!isDev && directusUrl) {
180
198
  loggerMessage.push(`\u{1F310} Production Mode:`, ` - SDK connects directly to ${colors.dim(`${directusUrl}`)}`, "");
181
- options.devProxy = false;
199
+ options.proxy = false;
182
200
  }
183
201
  options.directusUrl = clientUrl;
184
202
  options.serverDirectusUrl = serverUrl || clientUrl;
@@ -187,12 +205,14 @@ const module$1 = defineNuxtModule({
187
205
  nuxtApp.options.runtimeConfig.public[configKey] = defu(nuxtApp.options.runtimeConfig.public[configKey], options);
188
206
  delete nuxtApp.options.runtimeConfig.public[configKey].adminToken;
189
207
  delete nuxtApp.options.runtimeConfig.public[configKey].serverDirectusUrl;
208
+ delete nuxtApp.options.runtimeConfig.public[configKey].devProxy;
209
+ delete nuxtApp.options.runtimeConfig[configKey].devProxy;
190
210
  const imageConfig = typeof options.image === "boolean" ? { enabled: options.image } : options.image;
191
211
  const imageEnabled = imageConfig?.enabled ?? true;
192
212
  const hasNuxtImage = imageEnabled && (hasNuxtModule("@nuxt/image") || await tryResolveModule("@nuxt/image", new URL(import.meta.url)));
193
213
  if (hasNuxtImage) {
194
214
  const { setDefaultProvider, modifiers } = imageConfig || {};
195
- const imageBaseUrl = devProxyEnabled ? `${devProxyPath}/assets` : useUrl(clientUrl, "assets");
215
+ const imageBaseUrl = proxyEnabled ? `${proxyPath}/assets` : useUrl(clientUrl, "assets");
196
216
  await registerModule("@nuxt/image", "image", {
197
217
  // Set default provider if requested
198
218
  ...setDefaultProvider && { provider: "directus" },
@@ -1,11 +1,40 @@
1
- import { i as isStandardSchema } from '../shared/nuxt-directus-sdk.CtcY1peN.mjs';
2
- export { c as compareRulesPayloads, d as diffRemoteRules, a as diffRules, f as fetchRemoteRules, b as fetchRemoteRulesAsJson, e as formatDiff, g as formatPushResult, h as isValidationStandardSchema, l as loadRulesFromJson, j as loadRulesFromJsonFile, k as loadRulesFromPayload, m as loadRulesFromPayloadFile, n as normalizeRules, p as pullRules, o as pushRules, r as rulesToJson, s as serializeToDirectusApi, q as serializeToJson, t as toDirectusValidation } from '../shared/nuxt-directus-sdk.CtcY1peN.mjs';
1
+ import { i as isStandardSchema } from '../shared/nuxt-directus-sdk.sBTh4hx5.mjs';
2
+ export { c as compareRulesPayloads, d as diffRemoteRules, g as diffRules, a as fetchRemoteRules, e as fetchRemoteRulesAsJson, f as formatDiff, b as formatPushResult, h as isValidationStandardSchema, j as loadRulesFromJson, k as loadRulesFromJsonFile, l as loadRulesFromPayload, m as loadRulesFromPayloadFile, n as normalizeRules, o as pullRules, p as pushRules, r as rulesToJson, s as serializeToDirectusApi, q as serializeToJson, t as toDirectusValidation } from '../shared/nuxt-directus-sdk.sBTh4hx5.mjs';
3
3
  import '@directus/sdk';
4
4
 
5
5
  function isPolicyReference(input) {
6
6
  return "id" in input && !("name" in input);
7
7
  }
8
8
 
9
+ function directusValidation(validation) {
10
+ return validation;
11
+ }
12
+ function field(fieldName, rules) {
13
+ return { [fieldName]: rules };
14
+ }
15
+ function allOf(...validations) {
16
+ return { _and: validations };
17
+ }
18
+ function oneOf(...validations) {
19
+ return { _or: validations };
20
+ }
21
+ function required(fieldName) {
22
+ return { [fieldName]: { _nnull: true } };
23
+ }
24
+ function pattern(fieldName, regex) {
25
+ const regexStr = regex instanceof RegExp ? regex.source : regex;
26
+ return { [fieldName]: { _regex: regexStr } };
27
+ }
28
+ function length(fieldName, options) {
29
+ const min = options.min ?? 0;
30
+ const max = options.max ?? "";
31
+ const regex = `^.{${min},${max}}$`;
32
+ return { [fieldName]: { _regex: regex } };
33
+ }
34
+ function oneOfValues(fieldName, values) {
35
+ return { [fieldName]: { _in: values } };
36
+ }
37
+
9
38
  function parseRulesInput(input) {
10
39
  const policyRegistry = /* @__PURE__ */ new Map();
11
40
  const policies = (input.policies ?? []).map((p) => {
@@ -88,35 +117,6 @@ function defineDirectusRules(input) {
88
117
  return parseRulesInput(input);
89
118
  }
90
119
 
91
- function directusValidation(validation) {
92
- return validation;
93
- }
94
- function field(fieldName, rules) {
95
- return { [fieldName]: rules };
96
- }
97
- function allOf(...validations) {
98
- return { _and: validations };
99
- }
100
- function oneOf(...validations) {
101
- return { _or: validations };
102
- }
103
- function required(fieldName) {
104
- return { [fieldName]: { _nnull: true } };
105
- }
106
- function pattern(fieldName, regex) {
107
- const regexStr = regex instanceof RegExp ? regex.source : regex;
108
- return { [fieldName]: { _regex: regexStr } };
109
- }
110
- function length(fieldName, options) {
111
- const min = options.min ?? 0;
112
- const max = options.max ?? "";
113
- const regex = `^.{${min},${max}}$`;
114
- return { [fieldName]: { _regex: regex } };
115
- }
116
- function oneOfValues(fieldName, values) {
117
- return { [fieldName]: { _in: values } };
118
- }
119
-
120
120
  function evaluateFilter(filter, item, context = {}) {
121
121
  if (!filter || Object.keys(filter).length === 0) {
122
122
  return true;
@@ -18,10 +18,10 @@ function resolveServerUrl() {
18
18
  }
19
19
  export function useDirectusUrl(path = "") {
20
20
  const config = useRuntimeConfig();
21
- const devProxy = config.public.directus.devProxy;
22
- const devProxyEnabled = typeof devProxy === "object" ? devProxy.enabled === true : devProxy === true;
23
- if (devProxyEnabled) {
24
- const proxyPath = typeof devProxy === "object" && devProxy.path ? devProxy.path : "/directus";
21
+ const proxy = config.public.directus.proxy;
22
+ const proxyEnabled = typeof proxy === "object" ? proxy.enabled === true : proxy === true;
23
+ if (proxyEnabled) {
24
+ const proxyPath = typeof proxy === "object" && proxy.path ? proxy.path : "/directus";
25
25
  if (import.meta.client) {
26
26
  return useUrl(`${window.location.origin}${proxyPath}`, path);
27
27
  } else {
@@ -58,8 +58,16 @@ function createDirectusClient() {
58
58
  return globalThis.$fetch(urlString, { ...options, credentials: "include" });
59
59
  };
60
60
  const baseUrl = useDirectusUrl();
61
- const devProxy = config.public.directus.devProxy;
62
- const devProxyWsUrl = devProxy && typeof devProxy === "object" && devProxy.wsPath && import.meta.client ? `${window.location.origin}${devProxy.wsPath}` : void 0;
61
+ const proxy = config.public.directus.proxy;
62
+ const proxyEnabled = typeof proxy === "object" ? proxy.enabled === true : proxy === true;
63
+ const proxyWsPath = typeof proxy === "object" ? proxy.wsPath : void 0;
64
+ let realtimeUrl;
65
+ if (proxyWsPath && import.meta.client) {
66
+ realtimeUrl = `${window.location.origin}${proxyWsPath}`;
67
+ } else if (proxyEnabled && import.meta.client) {
68
+ const directUrl = resolveClientUrl();
69
+ realtimeUrl = directUrl ? `${directUrl.replace(/^http/, "ws").replace(/\/$/, "")}/websocket` : void 0;
70
+ }
63
71
  const directus2 = createDirectus(baseUrl, {
64
72
  globals: {
65
73
  fetch: customFetch
@@ -73,8 +81,7 @@ function createDirectusClient() {
73
81
  credentials: authConfig.credentials || "include"
74
82
  })).with(realtime({
75
83
  authMode: authConfig.realtimeAuthMode || "public",
76
- // Only set custom URL if we have a proxy path (dev mode with proxy enabled)
77
- ...devProxyWsUrl ? { url: devProxyWsUrl } : {}
84
+ ...realtimeUrl ? { url: realtimeUrl } : {}
78
85
  }));
79
86
  return directus2;
80
87
  }
@@ -0,0 +1,28 @@
1
+ export interface RewriteOptions {
2
+ /**
3
+ * Whether the incoming request reaching the proxy is HTTPS.
4
+ * - On HTTPS (production, staging): preserve `Secure` and `SameSite=None` as
5
+ * Directus set them — they're valid and load-bearing for cross-context flows.
6
+ * - On HTTP (localhost dev): strip `Secure` (browser rejects on http://) and
7
+ * downgrade `SameSite=None` to `Lax` (browser rejects `None` without `Secure`).
8
+ */
9
+ isHttps: boolean;
10
+ }
11
+ /**
12
+ * Rewrite a single `Set-Cookie` header value from a proxied Directus response
13
+ * so it works on the proxy origin (e.g. `your-app.vercel.app` or `localhost`).
14
+ *
15
+ * Always:
16
+ * - Strips the `Domain` attribute. The cookie binds to the response origin
17
+ * instead, which is what we want — it lets the browser store the cookie on
18
+ * your Nuxt app's host rather than Directus's.
19
+ *
20
+ * On HTTP only:
21
+ * - Strips `Secure` (browsers reject `Secure` cookies over plain HTTP).
22
+ * - Downgrades `SameSite=None` to `SameSite=Lax` (browsers reject `None`
23
+ * without `Secure`).
24
+ * - Adds `SameSite=Lax` if the cookie has no `SameSite` directive at all
25
+ * (Safari/Chrome treat missing `SameSite` as `Lax` anyway; making it
26
+ * explicit avoids future warnings).
27
+ */
28
+ export declare function rewriteProxiedSetCookie(cookie: string, options: RewriteOptions): string;
@@ -0,0 +1,15 @@
1
+ export function rewriteProxiedSetCookie(cookie, options) {
2
+ let result = cookie.replace(/;\s*Domain=[^;]+/gi, "");
3
+ if (options.isHttps) {
4
+ return result;
5
+ }
6
+ if (/SameSite=None/i.test(result)) {
7
+ result = result.replace(/;\s*SameSite=None/gi, "; SameSite=Lax").replace(/;\s*Secure\s*(?=;|$)/gi, "");
8
+ } else {
9
+ result = result.replace(/;\s*Secure\s*(?=;|$)/gi, "");
10
+ if (!/SameSite=/i.test(result)) {
11
+ result += "; SameSite=Lax";
12
+ }
13
+ }
14
+ return result;
15
+ }
@@ -1,30 +1,24 @@
1
1
  import { useRuntimeConfig } from "#imports";
2
- import { defineEventHandler, getRequestURL, proxyRequest, setResponseHeaders } from "h3";
2
+ import { defineEventHandler, getRequestIP, getRequestURL, proxyRequest, setResponseHeaders } from "h3";
3
3
  import { joinURL } from "ufo";
4
+ import { rewriteProxiedSetCookie } from "./directus-cookie.js";
4
5
  export default defineEventHandler(async (event) => {
5
6
  const config = useRuntimeConfig();
6
7
  const serverUrl = config.directus?.serverDirectusUrl;
7
8
  const directusUrl = serverUrl || config.public.directus.directusUrl;
8
9
  const url = getRequestURL(event);
9
10
  const path = url.pathname.replace(/^\/directus/, "") + url.search;
11
+ const isHttps = url.protocol === "https:";
12
+ const clientIp = getRequestIP(event, { xForwardedFor: true });
13
+ const forwardedHeaders = clientIp ? { "x-forwarded-for": clientIp } : {};
10
14
  await proxyRequest(event, joinURL(directusUrl, path), {
11
- // Intercept response to rewrite cookies for local development
15
+ headers: forwardedHeaders,
12
16
  onResponse(proxyEvent, response) {
13
17
  const setCookieHeaders = response.headers.getSetCookie?.() || [];
14
18
  if (setCookieHeaders.length > 0) {
15
- const rewrittenCookies = setCookieHeaders.map((cookie) => {
16
- let rewrittenCookie = cookie.replace(/;\s*Domain=[^;]+/gi, "");
17
- const hasSameSiteNone = rewrittenCookie.match(/SameSite=None/i);
18
- if (hasSameSiteNone) {
19
- rewrittenCookie = rewrittenCookie.replace(/;\s*SameSite=None/gi, "; SameSite=Lax").replace(/;\s*Secure\s*(?=;|$)/gi, "");
20
- } else {
21
- rewrittenCookie = rewrittenCookie.replace(/;\s*Secure\s*(?=;|$)/gi, "");
22
- if (!rewrittenCookie.match(/SameSite=/i)) {
23
- rewrittenCookie += "; SameSite=Lax";
24
- }
25
- }
26
- return rewrittenCookie;
27
- });
19
+ const rewrittenCookies = setCookieHeaders.map(
20
+ (cookie) => rewriteProxiedSetCookie(cookie, { isHttps })
21
+ );
28
22
  setResponseHeaders(proxyEvent, {
29
23
  "set-cookie": rewrittenCookies
30
24
  });
@@ -3,7 +3,7 @@ import { typegenExtensions } from "./extensions/index.js";
3
3
  export async function generateTypesFromDirectus(url, token, prefix, options = {}) {
4
4
  const logs = [];
5
5
  const client = createDirectus(url).with(rest()).with(staticToken(token));
6
- let result = null;
6
+ let result;
7
7
  try {
8
8
  const [collections, fields, relations] = await Promise.all([
9
9
  client.request(readCollections()),
@@ -1,19 +1,5 @@
1
1
  import { readRoles, readPolicies, readPermissions, createPolicy, updatePolicy, createRole, updateRole, createPermission, updatePermission, deletePermission, deleteRole, deletePolicy } from '@directus/sdk';
2
2
 
3
- function isStandardSchema(value) {
4
- if (typeof value !== "object" || value === null) {
5
- return false;
6
- }
7
- if (!("~standard" in value)) {
8
- return false;
9
- }
10
- const standard = value["~standard"];
11
- if (typeof standard !== "object" || standard === null) {
12
- return false;
13
- }
14
- return standard.version === 1;
15
- }
16
-
17
3
  function loadRulesFromJson(json) {
18
4
  const data = typeof json === "string" ? JSON.parse(json) : json;
19
5
  return {
@@ -231,6 +217,20 @@ function convertPayloadRole(role, policies, originalPolicyIds) {
231
217
  };
232
218
  }
233
219
 
220
+ function isStandardSchema(value) {
221
+ if (typeof value !== "object" || value === null) {
222
+ return false;
223
+ }
224
+ if (!("~standard" in value)) {
225
+ return false;
226
+ }
227
+ const standard = value["~standard"];
228
+ if (typeof standard !== "object" || standard === null) {
229
+ return false;
230
+ }
231
+ return standard.version === 1;
232
+ }
233
+
234
234
  function toDirectusValidation(schema) {
235
235
  const vendor = schema["~standard"].vendor;
236
236
  switch (vendor) {
@@ -1404,4 +1404,4 @@ function formatPushResult(result) {
1404
1404
  return lines.join("\n");
1405
1405
  }
1406
1406
 
1407
- export { diffRules as a, fetchRemoteRulesAsJson as b, compareRulesPayloads as c, diffRemoteRules as d, formatDiff as e, fetchRemoteRules as f, formatPushResult as g, isValidationStandardSchema as h, isStandardSchema as i, loadRulesFromJsonFile as j, loadRulesFromPayload as k, loadRulesFromJson as l, loadRulesFromPayloadFile as m, normalizeRules as n, pushRules as o, pullRules as p, serializeToJson as q, rulesToJson as r, serializeToDirectusApi as s, toDirectusValidation as t };
1407
+ export { fetchRemoteRules as a, formatPushResult as b, compareRulesPayloads as c, diffRemoteRules as d, fetchRemoteRulesAsJson as e, formatDiff as f, diffRules as g, isValidationStandardSchema as h, isStandardSchema as i, loadRulesFromJson as j, loadRulesFromJsonFile as k, loadRulesFromPayload as l, loadRulesFromPayloadFile as m, normalizeRules as n, pullRules as o, pushRules as p, serializeToJson as q, rulesToJson as r, serializeToDirectusApi as s, toDirectusValidation as t };
package/dist/types.d.mts CHANGED
@@ -1,3 +1,3 @@
1
1
  export { default } from './module.mjs'
2
2
 
3
- export { type DirectusUrl, type ModuleOptions, type ReadMeFields } from './module.mjs'
3
+ export { type DirectusUrl, type ModuleOptions, type ProxyOption, type ReadMeFields } from './module.mjs'
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "nuxt-directus-sdk",
3
3
  "type": "module",
4
- "version": "6.0.0",
4
+ "version": "6.1.1",
5
5
  "packageManager": "pnpm@10.32.1",
6
6
  "description": "A Nuxt module for Directus with built-in authentication, realtime, file management, type generation, and visual editor support.",
7
7
  "author": "Matthew Rollinson <matt@rolley.io>",
@@ -84,9 +84,9 @@
84
84
  "ufo": "^1.6.3"
85
85
  },
86
86
  "devDependencies": {
87
- "@directus/sdk": "^21.2.2",
88
- "@directus/types": "^15.0.2",
89
- "@directus/visual-editing": "^2.0.0",
87
+ "@directus/sdk": "^22.0.0",
88
+ "@directus/types": "^16.0.0",
89
+ "@directus/visual-editing": "^2.1.0",
90
90
  "@nuxt/devtools": "^3.2.4",
91
91
  "@nuxt/eslint-config": "^1.15.2",
92
92
  "@nuxt/image": "^2.0.0",