nuxt-directus-sdk 4.0.4 → 5.0.0-beta.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.
@@ -0,0 +1 @@
1
+
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,298 @@
1
+ #!/usr/bin/env node
2
+ import { existsSync, readFileSync, writeFileSync } from 'node:fs';
3
+ import { resolve } from 'node:path';
4
+ import { parseArgs } from 'node:util';
5
+ import { createDirectus, staticToken, rest } from '@directus/sdk';
6
+ import { g as diffRemoteRules, m as formatDiff, f as compareRulesPayloads, j as fetchRemoteRules, b as loadRulesFromPayload, q as pushRules, o as formatPushResult, k as fetchRemoteRulesAsJson } from '../shared/nuxt-directus-sdk.BpCtdNcG.mjs';
7
+
8
+ function loadEnv() {
9
+ const envPath = resolve(process.cwd(), ".env");
10
+ if (existsSync(envPath)) {
11
+ const content = readFileSync(envPath, "utf-8");
12
+ for (const line of content.split("\n")) {
13
+ const trimmed = line.trim();
14
+ if (!trimmed || trimmed.startsWith("#"))
15
+ continue;
16
+ const [key, ...valueParts] = trimmed.split("=");
17
+ if (key && valueParts.length > 0) {
18
+ const value = valueParts.join("=").replace(/^["']|["']$/g, "");
19
+ if (!process.env[key]) {
20
+ process.env[key] = value;
21
+ }
22
+ }
23
+ }
24
+ }
25
+ }
26
+ function getConnectionConfig(urlFlag, tokenFlag, label) {
27
+ const url = urlFlag ?? process.env.DIRECTUS_URL;
28
+ const token = tokenFlag ?? process.env.DIRECTUS_ADMIN_TOKEN;
29
+ if (!url) {
30
+ console.error(`Error: ${label} URL is required`);
31
+ console.error(`Provide --${label.toLowerCase()}-url or set DIRECTUS_URL in your .env file`);
32
+ process.exit(1);
33
+ }
34
+ if (!token) {
35
+ console.error(`Error: ${label} token is required`);
36
+ console.error(`Provide --${label.toLowerCase()}-token or set DIRECTUS_ADMIN_TOKEN in your .env file`);
37
+ process.exit(1);
38
+ }
39
+ return { url, token };
40
+ }
41
+ function createClient(url, token) {
42
+ return createDirectus(url).with(staticToken(token)).with(rest());
43
+ }
44
+ function printHelp() {
45
+ console.log(`
46
+ Directus Rules CLI
47
+
48
+ Usage:
49
+ npx nuxt-directus-sdk <command> [options]
50
+
51
+ Commands:
52
+ rules:pull Download rules from Directus and save as JSON
53
+ rules:push <file> Push local JSON rules to remote Directus
54
+ rules:diff <file> Compare local JSON file with remote Directus
55
+ rules:diff-files <a> <b> Compare two local JSON files
56
+ rules:diff-remote Compare two remote Directus instances
57
+
58
+ Options:
59
+ -h, --help Show this help message
60
+ -o, --output <file> Output file path (default: rules.json)
61
+ --compact Output compact JSON (no pretty-print)
62
+ --dry-run Show what would be changed without making changes (rules:push)
63
+ --add-only Only add new items, don't modify or delete existing (rules:push)
64
+ --skip-deletes Skip deleting items that exist remotely but not locally (rules:push)
65
+
66
+ Connection options (override DIRECTUS_URL / DIRECTUS_ADMIN_TOKEN):
67
+ --source-url <url> Source Directus URL
68
+ --source-token <token> Source admin token
69
+ --target-url <url> Target Directus URL (for rules:diff-remote)
70
+ --target-token <token> Target admin token (for rules:diff-remote)
71
+
72
+ Environment Variables:
73
+ DIRECTUS_URL Default Directus URL (used if --source-url not provided)
74
+ DIRECTUS_ADMIN_TOKEN Default admin token (used if --source-token not provided)
75
+
76
+ Examples:
77
+ # Pull rules from Directus (uses env vars)
78
+ npx nuxt-directus-sdk rules:pull
79
+
80
+ # Pull from a specific instance
81
+ npx nuxt-directus-sdk rules:pull --source-url https://my-directus.com --source-token my-token
82
+
83
+ # Preview what would be pushed (dry run)
84
+ npx nuxt-directus-sdk rules:push rules.json --dry-run
85
+
86
+ # Push rules to Directus
87
+ npx nuxt-directus-sdk rules:push rules.json
88
+
89
+ # Push only new items (safe mode)
90
+ npx nuxt-directus-sdk rules:push rules.json --add-only
91
+
92
+ # Compare local file with remote
93
+ npx nuxt-directus-sdk rules:diff rules.json
94
+
95
+ # Compare two local JSON files
96
+ npx nuxt-directus-sdk rules:diff-files staging.json production.json
97
+
98
+ # Compare two remote instances
99
+ npx nuxt-directus-sdk rules:diff-remote \\
100
+ --source-url https://staging.example.com --source-token staging-token \\
101
+ --target-url https://production.example.com --target-token production-token
102
+ `);
103
+ }
104
+ function loadJsonFile(filePath) {
105
+ if (!existsSync(filePath)) {
106
+ console.error(`Error: File not found: ${filePath}`);
107
+ process.exit(1);
108
+ }
109
+ const content = readFileSync(filePath, "utf-8");
110
+ try {
111
+ return JSON.parse(content);
112
+ } catch {
113
+ console.error(`Error: Invalid JSON in ${filePath}`);
114
+ process.exit(1);
115
+ }
116
+ }
117
+ async function commandPull(options, connection) {
118
+ const client = createClient(connection.url, connection.token);
119
+ console.log(`Fetching rules from ${connection.url}...`);
120
+ const json = await fetchRemoteRulesAsJson(client, !options.compact);
121
+ writeFileSync(options.output, json);
122
+ console.log(`Rules saved to ${options.output}`);
123
+ const rules = JSON.parse(json);
124
+ console.log(` ${rules.roles.length} roles`);
125
+ console.log(` ${rules.policies.length} policies`);
126
+ console.log(` ${rules.permissions.length} permissions`);
127
+ }
128
+ async function commandDiff(localFile, connection) {
129
+ const local = loadJsonFile(localFile);
130
+ console.log(`Comparing ${localFile} with ${connection.url}...`);
131
+ const client = createClient(connection.url, connection.token);
132
+ const remote = await fetchRemoteRules(client);
133
+ const diff = compareRulesPayloads(local, remote);
134
+ console.log();
135
+ console.log(formatDiff(diff));
136
+ if (diff.hasChanges) {
137
+ process.exit(1);
138
+ }
139
+ }
140
+ async function commandDiffFiles(fileA, fileB) {
141
+ console.log(`Comparing ${fileA} with ${fileB}...`);
142
+ const rulesA = loadJsonFile(fileA);
143
+ const rulesB = loadJsonFile(fileB);
144
+ const diff = compareRulesPayloads(rulesA, rulesB);
145
+ console.log();
146
+ console.log(formatDiff(diff));
147
+ if (diff.hasChanges) {
148
+ process.exit(1);
149
+ }
150
+ }
151
+ async function commandDiffRemote(source, target) {
152
+ console.log(`Comparing ${source.url} with ${target.url}...`);
153
+ const sourceClient = createClient(source.url, source.token);
154
+ const targetClient = createClient(target.url, target.token);
155
+ const diff = await diffRemoteRules(sourceClient, targetClient);
156
+ console.log();
157
+ console.log(formatDiff(diff));
158
+ if (diff.hasChanges) {
159
+ process.exit(1);
160
+ }
161
+ }
162
+ async function commandPush(localFile, connection, options) {
163
+ const payload = loadJsonFile(localFile);
164
+ const rules = loadRulesFromPayload(payload);
165
+ const client = createClient(connection.url, connection.token);
166
+ if (options.dryRun) {
167
+ console.log(`Dry run: comparing ${localFile} with ${connection.url}...`);
168
+ const remote = await fetchRemoteRules(client);
169
+ const diff = compareRulesPayloads(payload, remote);
170
+ console.log();
171
+ console.log(formatDiff(diff));
172
+ if (!diff.hasChanges) {
173
+ console.log("\nNo changes to push.");
174
+ } else {
175
+ console.log("\nRun without --dry-run to apply these changes.");
176
+ }
177
+ return;
178
+ }
179
+ console.log(`Pushing rules from ${localFile} to ${connection.url}...`);
180
+ const result = await pushRules(client, rules, {
181
+ addOnly: options.addOnly,
182
+ skipDeletes: options.skipDeletes,
183
+ onProgress: (event) => {
184
+ const action = event.action === "create" ? "+" : event.action === "update" ? "~" : "-";
185
+ console.log(` [${event.current}/${event.total}] ${action} ${event.phase}: ${event.name}`);
186
+ }
187
+ });
188
+ console.log();
189
+ console.log(formatPushResult(result));
190
+ if (!result.success) {
191
+ process.exit(1);
192
+ }
193
+ }
194
+ async function main() {
195
+ loadEnv();
196
+ const { values, positionals } = parseArgs({
197
+ allowPositionals: true,
198
+ options: {
199
+ "help": { type: "boolean", short: "h" },
200
+ "output": { type: "string", short: "o", default: "rules.json" },
201
+ "compact": { type: "boolean", default: false },
202
+ "dry-run": { type: "boolean", default: false },
203
+ "add-only": { type: "boolean", default: false },
204
+ "skip-deletes": { type: "boolean", default: false },
205
+ "source-url": { type: "string" },
206
+ "source-token": { type: "string" },
207
+ "target-url": { type: "string" },
208
+ "target-token": { type: "string" }
209
+ }
210
+ });
211
+ if (values.help || positionals.length === 0) {
212
+ printHelp();
213
+ process.exit(0);
214
+ }
215
+ const command = positionals[0];
216
+ try {
217
+ switch (command) {
218
+ case "rules:pull": {
219
+ const connection = getConnectionConfig(
220
+ values["source-url"],
221
+ values["source-token"],
222
+ "Source"
223
+ );
224
+ await commandPull({
225
+ output: values.output,
226
+ compact: values.compact
227
+ }, connection);
228
+ break;
229
+ }
230
+ case "rules:push": {
231
+ if (!positionals[1]) {
232
+ console.error("Error: rules:push requires a file path");
233
+ console.error("Usage: npx nuxt-directus-sdk rules:push <file> [--dry-run]");
234
+ process.exit(1);
235
+ }
236
+ const connection = getConnectionConfig(
237
+ values["source-url"],
238
+ values["source-token"],
239
+ "Source"
240
+ );
241
+ await commandPush(positionals[1], connection, {
242
+ dryRun: values["dry-run"],
243
+ addOnly: values["add-only"],
244
+ skipDeletes: values["skip-deletes"]
245
+ });
246
+ break;
247
+ }
248
+ case "rules:diff": {
249
+ if (!positionals[1]) {
250
+ console.error("Error: rules:diff requires a file path");
251
+ console.error("Usage: npx nuxt-directus-sdk rules:diff <file>");
252
+ process.exit(1);
253
+ }
254
+ const connection = getConnectionConfig(
255
+ values["source-url"],
256
+ values["source-token"],
257
+ "Source"
258
+ );
259
+ await commandDiff(positionals[1], connection);
260
+ break;
261
+ }
262
+ case "rules:diff-files":
263
+ if (!positionals[1] || !positionals[2]) {
264
+ console.error("Error: rules:diff-files requires two file paths");
265
+ console.error("Usage: npx nuxt-directus-sdk rules:diff-files <file-a> <file-b>");
266
+ process.exit(1);
267
+ }
268
+ await commandDiffFiles(positionals[1], positionals[2]);
269
+ break;
270
+ case "rules:diff-remote": {
271
+ const source = getConnectionConfig(
272
+ values["source-url"],
273
+ values["source-token"],
274
+ "Source"
275
+ );
276
+ const target = getConnectionConfig(
277
+ values["target-url"],
278
+ values["target-token"],
279
+ "Target"
280
+ );
281
+ await commandDiffRemote(source, target);
282
+ break;
283
+ }
284
+ default:
285
+ console.error(`Unknown command: ${command}`);
286
+ printHelp();
287
+ process.exit(1);
288
+ }
289
+ } catch (error) {
290
+ if (error instanceof Error) {
291
+ console.error(`Error: ${error.message}`);
292
+ } else {
293
+ console.error("An unknown error occurred");
294
+ }
295
+ process.exit(1);
296
+ }
297
+ }
298
+ main();
package/dist/module.d.mts CHANGED
@@ -1,5 +1,6 @@
1
1
  import * as _nuxt_schema from '@nuxt/schema';
2
2
  import { Query } from '@directus/sdk';
3
+ import { ImageProviders, ImageModifiers } from '@nuxt/image';
3
4
 
4
5
  interface ModuleOptions {
5
6
  /**
@@ -12,8 +13,8 @@ interface ModuleOptions {
12
13
  * Development proxy configuration
13
14
  * When enabled, creates a proxy at /directus that forwards to your Directus URL
14
15
  * This solves CORS and cookie issues in development
15
- * @default { enabled: true, path: '/directus' } in dev mode
16
- * @type boolean | { enabled?: boolean, path?: string }
16
+ * @default { enabled: true, path: '/directus', wsPath: '/directus-ws' } in dev mode
17
+ * @type boolean | { enabled?: boolean, path?: string, wsPath?: string }
17
18
  */
18
19
  devProxy?: boolean | {
19
20
  /**
@@ -26,6 +27,11 @@ interface ModuleOptions {
26
27
  * @default '/directus'
27
28
  */
28
29
  path?: string;
30
+ /**
31
+ * WebSocket proxy path (for realtime connections)
32
+ * @default '/directus-ws'
33
+ */
34
+ wsPath?: string;
29
35
  };
30
36
  /**
31
37
  * Admin Auth Token used for generating types and server functions
@@ -35,16 +41,38 @@ interface ModuleOptions {
35
41
  adminToken?: string;
36
42
  /**
37
43
  * Add Directus Admin in Nuxt Devtools
38
- *
39
44
  * @default true
40
45
  */
41
46
  devtools?: boolean;
42
47
  /**
43
48
  * Add Directus Visual Editor capabilities
44
- *
45
49
  * @default true
46
50
  */
47
51
  visualEditor?: boolean;
52
+ /**
53
+ * @nuxt/image integration
54
+ * @default true
55
+ */
56
+ image?: boolean | {
57
+ /**
58
+ * Enable @nuxt/image integration
59
+ * @default true
60
+ */
61
+ enabled?: boolean;
62
+ /**
63
+ * Set Directus as the default provider for NuxtImg
64
+ * @default false
65
+ */
66
+ setDefaultProvider?: boolean;
67
+ /**
68
+ * Custom Directus provider configuration
69
+ */
70
+ directus?: ImageProviders['directus'];
71
+ /**
72
+ * Default modifiers for Directus provider
73
+ */
74
+ modifiers?: ImageModifiers;
75
+ };
48
76
  /**
49
77
  * Auth options
50
78
  */
@@ -53,7 +81,6 @@ interface ModuleOptions {
53
81
  * Enable auth middleware
54
82
  * @default true
55
83
  * @type boolean
56
- *
57
84
  */
58
85
  enabled?: boolean;
59
86
  /**
@@ -90,30 +117,30 @@ interface ModuleOptions {
90
117
  redirect?: {
91
118
  /**
92
119
  * Redirect to home page after login
93
- * @default '/home'
120
+ * @default '/'
94
121
  */
95
122
  home?: string;
96
123
  /**
97
- * Redirect to login page after logout
124
+ * Redirect to login when using auth middleware
98
125
  * @default '/auth/login'
99
126
  */
100
127
  login?: string;
101
128
  /**
102
- * Redirect to login page after logout
103
- * @default '/auth/login'
129
+ * Redirect to home page page after logout
130
+ * @default '/'
104
131
  */
105
132
  logout?: string;
106
133
  };
107
134
  };
108
- types?: {
135
+ types?: boolean | {
109
136
  /**
110
- * Generate types for your Directus instance
137
+ * Enable type generation
111
138
  * @type boolean
112
139
  * @default true
113
140
  */
114
141
  enabled?: boolean;
115
142
  /**
116
- * The prefix to your custom types
143
+ * Prefix for custom collection types (does not affect DirectusSchema keys)
117
144
  * @type string
118
145
  * @default ''
119
146
  */
@@ -0,0 +1,166 @@
1
+ import * as _nuxt_schema from '@nuxt/schema';
2
+ import { Query } from '@directus/sdk';
3
+ import { ImageProviders, ImageModifiers } from '@nuxt/image';
4
+
5
+ interface ModuleOptions {
6
+ /**
7
+ * Directus API URL
8
+ * @default process.env.DIRECTUS_URL
9
+ * @type string
10
+ */
11
+ url: string;
12
+ /**
13
+ * Development proxy configuration
14
+ * When enabled, creates a proxy at /directus that forwards to your Directus URL
15
+ * This solves CORS and cookie issues in development
16
+ * @default { enabled: true, path: '/directus', wsPath: '/directus-ws' } in dev mode
17
+ * @type boolean | { enabled?: boolean, path?: string, wsPath?: string }
18
+ */
19
+ devProxy?: boolean | {
20
+ /**
21
+ * Enable the development proxy
22
+ * @default true in dev mode, false in production
23
+ */
24
+ enabled?: boolean;
25
+ /**
26
+ * Proxy path (where the proxy will be mounted)
27
+ * @default '/directus'
28
+ */
29
+ path?: string;
30
+ /**
31
+ * WebSocket proxy path (for realtime connections)
32
+ * @default '/directus-ws'
33
+ */
34
+ wsPath?: string;
35
+ };
36
+ /**
37
+ * Admin Auth Token used for generating types and server functions
38
+ * @default process.env.DIRECTUS_ADMIN_TOKEN
39
+ * @type string
40
+ */
41
+ adminToken?: string;
42
+ /**
43
+ * Add Directus Admin in Nuxt Devtools
44
+ * @default true
45
+ */
46
+ devtools?: boolean;
47
+ /**
48
+ * Add Directus Visual Editor capabilities
49
+ * @default true
50
+ */
51
+ visualEditor?: boolean;
52
+ /**
53
+ * @nuxt/image integration
54
+ * @default true
55
+ */
56
+ image?: boolean | {
57
+ /**
58
+ * Enable @nuxt/image integration
59
+ * @default true
60
+ */
61
+ enabled?: boolean;
62
+ /**
63
+ * Set Directus as the default provider for NuxtImg
64
+ * @default false
65
+ */
66
+ setDefaultProvider?: boolean;
67
+ /**
68
+ * Custom Directus provider configuration
69
+ */
70
+ directus?: ImageProviders['directus'];
71
+ /**
72
+ * Default modifiers for Directus provider
73
+ */
74
+ modifiers?: ImageModifiers;
75
+ };
76
+ /**
77
+ * Auth options
78
+ */
79
+ auth?: {
80
+ /**
81
+ * Enable auth middleware
82
+ * @default true
83
+ * @type boolean
84
+ */
85
+ enabled?: boolean;
86
+ /**
87
+ * Enable global auth middleware
88
+ * @default false
89
+ * @type boolean
90
+ */
91
+ enableGlobalAuthMiddleware?: boolean;
92
+ /**
93
+ * Auto refresh tokens
94
+ * @default true
95
+ * @type boolean
96
+ */
97
+ autoRefresh?: boolean;
98
+ /**
99
+ * Credentials mode for cross-domain requests
100
+ * Set to 'include' when your frontend and backend are on different domains
101
+ * @default 'include'
102
+ * @type RequestCredentials
103
+ */
104
+ credentials?: RequestCredentials;
105
+ /**
106
+ * Realtime/WebSocket authentication mode
107
+ * @default 'handshake'
108
+ * @type 'public' | 'handshake' | 'strict'
109
+ */
110
+ realtimeAuthMode?: 'public' | 'handshake' | 'strict';
111
+ /**
112
+ * ReadMe fields to fetch
113
+ * @default []
114
+ * @type Query<DirectusSchema, DirectusSchema['directus_users']>['fields']
115
+ */
116
+ readMeFields?: Query<DirectusSchema, DirectusSchema['directus_users']>['fields'];
117
+ redirect?: {
118
+ /**
119
+ * Redirect to home page after login
120
+ * @default '/'
121
+ */
122
+ home?: string;
123
+ /**
124
+ * Redirect to login when using auth middleware
125
+ * @default '/auth/login'
126
+ */
127
+ login?: string;
128
+ /**
129
+ * Redirect to home page page after logout
130
+ * @default '/'
131
+ */
132
+ logout?: string;
133
+ };
134
+ };
135
+ types?: boolean | {
136
+ /**
137
+ * Enable type generation
138
+ * @type boolean
139
+ * @default true
140
+ */
141
+ enabled?: boolean;
142
+ /**
143
+ * Prefix for custom collection types (does not affect DirectusSchema keys)
144
+ * @type string
145
+ * @default ''
146
+ */
147
+ prefix?: string;
148
+ };
149
+ }
150
+ declare const _default: _nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>;
151
+
152
+ interface NuxtDirectusModuleOptions extends ModuleOptions {
153
+ directusUrl: string;
154
+ wsProxyUrl?: string;
155
+ }
156
+ declare module '@nuxt/schema' {
157
+ interface ConfigSchema {
158
+ directus?: NuxtDirectusModuleOptions;
159
+ publicRuntimeConfig?: {
160
+ directus?: Omit<NuxtDirectusModuleOptions, 'adminToken'>;
161
+ };
162
+ }
163
+ }
164
+
165
+ export { _default as default };
166
+ export type { ModuleOptions };
package/dist/module.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nuxt-directus-sdk",
3
- "version": "4.0.4",
3
+ "version": "5.0.0-beta.1",
4
4
  "configKey": "directus",
5
5
  "compatibility": {
6
6
  "nuxt": "^4.0.0"