nuxt-directus-sdk 0.0.2 → 0.0.3

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
@@ -1,4 +1,4 @@
1
- # directus-nuxt-sdk
1
+ # nuxt-directus-sdk
2
2
 
3
3
  [![npm version][npm-version-src]][npm-version-href]
4
4
  [![npm downloads][npm-downloads-src]][npm-downloads-href]
@@ -16,28 +16,28 @@
16
16
 
17
17
  ## Quick Setup
18
18
 
19
- 1. Add `directus-nuxt-sdk` dependency to your project
19
+ 1. Add `nuxt-directus-sdk` dependency to your project
20
20
 
21
21
  ```bash
22
22
  # Using pnpm
23
- pnpm add -D directus-nuxt-sdk
23
+ pnpm add -D nuxt-directus-sdk
24
24
 
25
25
  # Using yarn
26
- yarn add --dev directus-nuxt-sdk
26
+ yarn add --dev nuxt-directus-sdk
27
27
 
28
28
  # Using npm
29
- npm install --save-dev directus-nuxt-sdk
29
+ npm install --save-dev nuxt-directus-sdk
30
30
 
31
31
  # Using bun
32
- bun install --save-dev directus-nuxt-sdk
32
+ bun install --save-dev nuxt-directus-sdk
33
33
  ```
34
34
 
35
- 2. Add `directus-nuxt-sdk` to the `modules` section of `nuxt.config.ts`
35
+ 2. Add `nuxt-directus-sdk` to the `modules` section of `nuxt.config.ts`
36
36
 
37
37
  ```js
38
38
  export default defineNuxtConfig({
39
39
  modules: [
40
- 'directus-nuxt-sdk'
40
+ 'nuxt-directus-sdk'
41
41
  ]
42
42
  })
43
43
  ```
@@ -71,14 +71,14 @@ npm run release
71
71
  ```
72
72
 
73
73
  <!-- Badges -->
74
- [npm-version-src]: https://img.shields.io/npm/v/directus-nuxt-sdk/latest.svg?style=flat&colorA=18181B&colorB=28CF8D
75
- [npm-version-href]: https://npmjs.com/package/directus-nuxt-sdk
74
+ [npm-version-src]: https://img.shields.io/npm/v/nuxt-directus-sdk/latest.svg?style=flat&colorA=18181B&colorB=28CF8D
75
+ [npm-version-href]: https://npmjs.com/package/nuxt-directus-sdk
76
76
 
77
- [npm-downloads-src]: https://img.shields.io/npm/dm/directus-nuxt-sdk.svg?style=flat&colorA=18181B&colorB=28CF8D
78
- [npm-downloads-href]: https://npmjs.com/package/directus-nuxt-sdk
77
+ [npm-downloads-src]: https://img.shields.io/npm/dm/nuxt-directus-sdk.svg?style=flat&colorA=18181B&colorB=28CF8D
78
+ [npm-downloads-href]: https://npmjs.com/package/nuxt-directus-sdk
79
79
 
80
- [license-src]: https://img.shields.io/npm/l/directus-nuxt-sdk.svg?style=flat&colorA=18181B&colorB=28CF8D
81
- [license-href]: https://npmjs.com/package/directus-nuxt-sdk
80
+ [license-src]: https://img.shields.io/npm/l/nuxt-directus-sdk.svg?style=flat&colorA=18181B&colorB=28CF8D
81
+ [license-href]: https://npmjs.com/package/nuxt-directus-sdk
82
82
 
83
83
  [nuxt-src]: https://img.shields.io/badge/Nuxt-18181B?logo=nuxt.js
84
84
  [nuxt-href]: https://nuxt.com
package/dist/module.d.mts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as _nuxt_schema from '@nuxt/schema';
2
2
  import { Query } from '@directus/sdk';
3
- import { DirectusCollections } from '#build/types/directus';
3
+ import { AllCollections } from '#build/types/directus';
4
4
 
5
5
  interface ModuleOptions {
6
6
  /**
@@ -24,9 +24,9 @@ interface ModuleOptions {
24
24
  /**
25
25
  * Directus Auth Options
26
26
  * @default {}
27
- * @type Query<DirectusCollections, 'directus_users'>
27
+ * @type Query<AllCollections, AllCollections['directus_users']>
28
28
  */
29
- fetchUserParams?: Query<DirectusCollections, 'directus_users'>;
29
+ fetchUserParams?: Query<AllCollections, AllCollections['directus_users']>;
30
30
  /**
31
31
  * Add Directus Admin in Nuxt Devtools
32
32
  *
@@ -36,9 +36,9 @@ interface ModuleOptions {
36
36
  /**
37
37
  * Token Cookie Name
38
38
  * @type string
39
- * @ default 'directus_token'
39
+ * @default 'directus_access_token'
40
40
  */
41
- cookieNameToken?: string;
41
+ cookieNameAccessToken?: string;
42
42
  /**
43
43
  * Refresh Token Cookie Name
44
44
  * @type string
package/dist/module.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as _nuxt_schema from '@nuxt/schema';
2
2
  import { Query } from '@directus/sdk';
3
- import { DirectusCollections } from '#build/types/directus';
3
+ import { AllCollections } from '#build/types/directus';
4
4
 
5
5
  interface ModuleOptions {
6
6
  /**
@@ -24,9 +24,9 @@ interface ModuleOptions {
24
24
  /**
25
25
  * Directus Auth Options
26
26
  * @default {}
27
- * @type Query<DirectusCollections, 'directus_users'>
27
+ * @type Query<AllCollections, AllCollections['directus_users']>
28
28
  */
29
- fetchUserParams?: Query<DirectusCollections, 'directus_users'>;
29
+ fetchUserParams?: Query<AllCollections, AllCollections['directus_users']>;
30
30
  /**
31
31
  * Add Directus Admin in Nuxt Devtools
32
32
  *
@@ -36,9 +36,9 @@ interface ModuleOptions {
36
36
  /**
37
37
  * Token Cookie Name
38
38
  * @type string
39
- * @ default 'directus_token'
39
+ * @default 'directus_access_token'
40
40
  */
41
- cookieNameToken?: string;
41
+ cookieNameAccessToken?: string;
42
42
  /**
43
43
  * Refresh Token Cookie Name
44
44
  * @type string
package/dist/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "nuxt-directus-sdk",
3
- "version": "0.0.2",
4
- "configKey": "rolley",
3
+ "version": "0.0.3",
4
+ "configKey": "directus",
5
5
  "compatibility": {
6
6
  "nuxt": "^3.0.0",
7
7
  "bridge": false
package/dist/module.mjs CHANGED
@@ -1,112 +1,135 @@
1
1
  import { defu } from 'defu';
2
- import { defineNuxtModule, createResolver, addPlugin, addImportsDir, addComponentsDir, addTypeTemplate, logger } from '@nuxt/kit';
2
+ import { useLogger, defineNuxtModule, createResolver, addPlugin, addImportsDir, addComponentsDir, addTypeTemplate } from '@nuxt/kit';
3
3
  import { joinURL } from 'ufo';
4
- import { snakeCase } from 'change-case';
5
- import { createDirectus, authentication, rest, readOpenApiSpec } from '@directus/sdk';
4
+ import { createDirectus, authentication, rest, readCollections, readFields, readRelations } from '@directus/sdk';
6
5
 
7
6
  const name = "nuxt-directus-sdk";
8
- const version = "0.0.2";
7
+ const version = "0.0.3";
9
8
 
10
- function mapPropertyType(propertyType) {
11
- return propertyType === "integer" ? "number" : propertyType;
9
+ function warn(message) {
10
+ useLogger(message);
12
11
  }
13
- function processOneOfProperty(schemas, name, property) {
14
- const ref = property.oneOf.find((item) => {
15
- return "$ref" in item;
12
+ async function generateTypes(options) {
13
+ const collections = await getCollections(options);
14
+ let typeValues = "";
15
+ const types = [];
16
+ Object.values(collections).forEach((collection) => {
17
+ const collectionName = collection.collection;
18
+ const typeName = pascalCase(collectionName);
19
+ types.push(`${collectionName}: ${typeName}[]`);
20
+ typeValues += `export type ${typeName} = {
21
+ `;
22
+ collection.fields.forEach((field) => {
23
+ if (field.meta?.interface?.startsWith("presentation-"))
24
+ return;
25
+ typeValues += " ";
26
+ typeValues += field.field.includes("-") ? `"${field.field}"` : field.field;
27
+ if (field.schema?.is_nullable)
28
+ typeValues += "?";
29
+ typeValues += ": ";
30
+ typeValues += getType(field);
31
+ typeValues += ";\n";
32
+ });
33
+ typeValues += "};\n\n";
16
34
  });
17
- if (ref) {
18
- const $ref = ref.$ref;
19
- const $refKey = $ref.split("/").pop();
20
- if ($refKey) {
21
- const $refSchema = `DirectusCollections['${schemas[$refKey]?.["x-collection"]}']`;
22
- if ($refSchema)
23
- return $refSchema;
24
- }
25
- }
26
- const firstValue = property.oneOf?.[0];
27
- if ("type" in firstValue) {
28
- const firstType = mapPropertyType(firstValue.type);
29
- if (firstType)
30
- return firstType;
31
- }
32
- console.error("Unknown schema for oneOf", name, property);
33
- return "";
35
+ typeValues += `export interface AllCollections {
36
+ ${types.map((x) => ` ${x};`).join("\n")}
37
+ };
38
+
39
+ interface UsersCollections {
40
+ ${types.filter((item) => !item.startsWith("directus_")).map((x) => ` ${x};`).join("\n")}
41
+ };
42
+
43
+ declare global {
44
+ interface DirectusCollections {
45
+ ${types.filter((item) => !item.startsWith("directus_")).map((x) => ` ${x};`).join("\n")}
46
+ };
47
+ }
48
+ `;
49
+ typeValues += "\n";
50
+ return typeValues;
34
51
  }
35
- function processProperty(schemas, name, property) {
36
- if ("type" in property) {
37
- if (property.type === "array" && property.items) {
38
- if (!property.items.oneOf)
39
- return processProperty(schemas, name, property.items);
40
- return `
41
- "${name}": ${processOneOfProperty(schemas, name, property.items)};
42
- `;
43
- } else {
44
- return `
45
- ${property.format ? `/* ${property.format} */` : ""}
46
- "${name}": ${mapPropertyType(property.type ?? "string")};
47
- `;
48
- }
49
- } else if ("oneOf" in property) {
50
- const value = processOneOfProperty(schemas, name, property);
51
- if (!value)
52
- return;
53
- const simpleTypes = ["string", "number", "boolean"];
54
- const valueType = simpleTypes.includes(value) ? value : `Single<${value}>`;
55
- return `
56
- "${name}": ${valueType};
57
- `;
52
+ function pascalCase(str) {
53
+ return str.split(" ").flatMap((x) => x.split("_")).flatMap((y) => y.split("-")).map((x) => x.charAt(0).toUpperCase() + x.slice(1)).join("");
54
+ }
55
+ function getType(field) {
56
+ let type = "";
57
+ if (field.relation && field.relation.type === "many") {
58
+ type = "any[]";
59
+ } else if (field.relation) {
60
+ type += field.relation.collection ? pascalCase(field.relation.collection) : "any";
61
+ if (field.relation.type === "many")
62
+ type += "[]";
63
+ } else {
64
+ if (["integer", "bigInteger", "float", "decimal"].includes(field.type))
65
+ type = "number";
66
+ else if (["boolean"].includes(field.type))
67
+ type = "boolean";
68
+ else if (["json", "csv"].includes(field.type))
69
+ type = "unknown";
70
+ else
71
+ type = "string";
58
72
  }
73
+ if (field.schema?.is_nullable) {
74
+ if (field.relation)
75
+ type = `${type} | null`;
76
+ else
77
+ type += " | null";
78
+ }
79
+ return type;
59
80
  }
60
- async function generateTypes(options) {
81
+ async function getCollections(options) {
61
82
  const directus = createDirectus(options.url).with(authentication("json", { autoRefresh: false })).with(rest());
62
83
  directus.setToken(options.token);
63
- const data = await directus.request(readOpenApiSpec());
64
- const types = [];
65
- const schemas = data.components.schemas;
66
- const schemaNames = [];
67
- Object.entries(schemas).forEach(([_, schema]) => {
68
- const schemaName = schema["x-collection"];
69
- if (!schemaName)
84
+ const rawCollections = await directus.request(readCollections());
85
+ const collections = {};
86
+ rawCollections.sort((a, b) => a.collection.localeCompare(b.collection)).forEach(
87
+ (collection) => collections[collection.collection] = { ...collection, fields: [] }
88
+ );
89
+ const fields = await directus.request(readFields());
90
+ fields.sort((a, b) => a.field.localeCompare(b.field)).forEach((field) => {
91
+ if (!collections[field.collection]) {
92
+ warn(`${field.collection} not found`);
70
93
  return;
71
- if (schema.type !== "object") {
72
- console.error(schemaName, "is not an object");
94
+ }
95
+ collections[field.collection].fields.push(field);
96
+ if (collections[field.collection].fields.length === 0)
97
+ delete collections[field.collection];
98
+ });
99
+ const relations = await directus.request(readRelations());
100
+ relations.forEach((relation) => {
101
+ if (!relation.meta) {
102
+ warn(`Relation on field '${relation.field}' in collection '${relation.collection}' has no meta. Maybe missing a relation inside directus_relations table.`);
73
103
  return;
74
104
  }
75
- if (schemaNames.includes(schemaName))
105
+ if (!relation.meta.one_collection) {
106
+ warn("No one collection");
76
107
  return;
77
- schemaNames.push(schemaName);
78
- const properties = [];
79
- Object.entries(schema.properties).forEach(([name, property]) => {
80
- const propertyType = processProperty(schemas, name, property);
81
- if (propertyType)
82
- properties.push(propertyType.trim());
83
- });
84
- types.push(`${snakeCase(schemaName)}: {
85
- ${properties.join("\n")}
86
- }[];
87
- `);
108
+ }
109
+ const oneField = collections[relation.meta.one_collection]?.fields.find(
110
+ (field) => field.field === relation.meta.one_field
111
+ );
112
+ const manyField = collections[relation.meta.many_collection]?.fields.find(
113
+ (field) => field.field === relation.meta.many_field
114
+ );
115
+ if (oneField) {
116
+ oneField.relation = {
117
+ type: "many",
118
+ collection: relation.meta.many_collection
119
+ };
120
+ }
121
+ if (manyField) {
122
+ manyField.relation = {
123
+ type: "one",
124
+ collection: relation.meta.one_collection
125
+ };
126
+ }
88
127
  });
89
- const exportProperties = types.join("\n");
90
- return `
91
- export type Single<T extends any[]> = T extends (infer U)[] ? U : never;
92
-
93
- export type DirectusCollections = {
94
- ${exportProperties}
95
- };
96
-
97
- export type DirectusCollectionUser = Single<DirectusCollections['directus_users']>;
98
-
99
- declare global {
100
- type Single = Single
101
- type DirectusCollections = DirectusCollections
102
- type DirectusCollectionUser = DirectusCollectionUser
128
+ return collections;
103
129
  }
104
130
 
105
- export {};
106
- `;
107
- }
108
-
109
- const configKey = "rolley";
131
+ const configKey = "directus";
132
+ const logger = useLogger("nuxt-directus-sdk");
110
133
  const module = defineNuxtModule({
111
134
  meta: {
112
135
  name,
@@ -120,9 +143,10 @@ const module = defineNuxtModule({
120
143
  defaults: {
121
144
  url: process.env.DIRECTUS_URL,
122
145
  adminToken: process.env.DIRECTUS_ADMIN_TOKEN,
123
- fetchUser: true,
124
146
  devtools: false,
125
- cookieNameToken: "directus_token",
147
+ fetchUser: true,
148
+ fetchUserParams: {},
149
+ cookieNameAccessToken: "directus_access_token",
126
150
  cookieNameRefreshToken: "directus_refresh_token",
127
151
  // Nuxt Cookies Docs @ https://nuxt.com/docs/api/composables/use-cookie
128
152
  cookieMaxAge: 900,
@@ -131,13 +155,14 @@ const module = defineNuxtModule({
131
155
  cookieSecure: false
132
156
  },
133
157
  async setup(options, nuxt) {
158
+ nuxt.options.runtimeConfig[configKey] = { adminToken: options.adminToken ?? "" };
134
159
  nuxt.options.runtimeConfig.public = nuxt.options.runtimeConfig.public || {};
135
160
  nuxt.options.runtimeConfig.public[configKey] = defu(nuxt.options.runtimeConfig.public[configKey], {
136
161
  url: options.url,
137
162
  fetchUser: options.fetchUser,
138
163
  fetchUserParams: options.fetchUserParams,
139
164
  devtools: options.devtools,
140
- cookieNameToken: options.cookieNameToken,
165
+ cookieNameAccessToken: options.cookieNameAccessToken,
141
166
  cookieNameRefreshToken: options.cookieNameRefreshToken,
142
167
  cookieMaxAge: options.cookieMaxAge,
143
168
  cookieMaxAgeRefreshToken: options.cookieMaxAgeRefreshToken,
@@ -166,20 +191,24 @@ const module = defineNuxtModule({
166
191
  });
167
192
  nitroConfig.alias[`#${configKey}`] = resolver.resolve("./runtime/server/services");
168
193
  });
169
- addTypeTemplate({
170
- filename: `types/${configKey}.d.ts`,
171
- getContents: () => [
172
- `declare module '#${configKey}' {`,
173
- ` const useDirectus: typeof import('${resolver.resolve("./runtime/server/services")}').useDirectus`,
174
- ` const useAdminDirectus: typeof import('${resolver.resolve("./runtime/server/services")}').useAdminDirectus`,
175
- ` const useDirectusUrl: typeof import('${resolver.resolve("./runtime/server/services")}').useDirectusUrl`,
176
- ` const useDirectusAccessToken: typeof import('${resolver.resolve("./runtime/server/services")}').useDirectusAccessToken`,
177
- "}"
178
- ].join("\n")
179
- });
180
- nuxt.hook("prepare:types", (options2) => {
181
- options2.references.push({ path: resolver.resolve(nuxt.options.buildDir, `types/${configKey}.d.ts`) });
182
- });
194
+ try {
195
+ const typesPath = addTypeTemplate({
196
+ filename: `types/${configKey}-server.d.ts`,
197
+ getContents: () => [
198
+ `declare module '#${configKey}-server' {`,
199
+ ` const useDirectus: typeof import('${resolver.resolve("./runtime/server/services")}').useDirectus`,
200
+ ` const useAdminDirectus: typeof import('${resolver.resolve("./runtime/server/services")}').useAdminDirectus`,
201
+ ` const useDirectusUrl: typeof import('${resolver.resolve("./runtime/server/services")}').useDirectusUrl`,
202
+ ` const useDirectusAccessToken: typeof import('${resolver.resolve("./runtime/server/services")}').useDirectusAccessToken`,
203
+ "}"
204
+ ].join("\n")
205
+ }).dst;
206
+ nuxt.hook("prepare:types", (options2) => {
207
+ options2.references.push({ path: typesPath });
208
+ });
209
+ } catch (error) {
210
+ logger.error(error.message);
211
+ }
183
212
  if (options.url) {
184
213
  const adminUrl = joinURL(options.url, "/admin/");
185
214
  logger.info(`Directus Admin URL: ${adminUrl}`);
@@ -200,11 +229,11 @@ const module = defineNuxtModule({
200
229
  logger.info("Generating Directus types");
201
230
  try {
202
231
  const typesPath = addTypeTemplate({
203
- filename: "types/directus.d.ts",
232
+ filename: `types/${configKey}.d.ts`,
204
233
  getContents() {
205
234
  return generateTypes({
206
- url: options.url ?? "",
207
- token: options.adminToken ?? ""
235
+ url: options.url,
236
+ token: options.adminToken
208
237
  });
209
238
  }
210
239
  }).dst;
@@ -1,21 +1,21 @@
1
1
  import type { ComputedRef, Ref } from '#imports';
2
- import type { DirectusCollectionUser } from '#build/types/directus';
3
- export declare function useDirectusUser(): Ref<any>;
2
+ import type { DirectusUsers } from '#build/types/directus';
3
+ export declare function useDirectusUser(): Ref<DirectusUsers | null>;
4
4
  export interface DirectusAuth {
5
- user: Ref<DirectusCollectionUser | null>;
5
+ user: Ref<DirectusUsers | null>;
6
6
  loggedIn: ComputedRef<boolean>;
7
7
  refreshTokens(): Promise<void>;
8
- fetchUser(): Promise<DirectusCollectionUser | null>;
9
- updateUser(data: Partial<DirectusCollectionUser>): Promise<DirectusCollectionUser | null>;
8
+ fetchUser(): Promise<DirectusUsers | null>;
9
+ updateUser(data: Partial<DirectusUsers>): Promise<DirectusUsers | null>;
10
10
  login(email: string, password: string): Promise<{
11
- user: DirectusCollectionUser | null;
11
+ user: DirectusUsers | null;
12
12
  access_token: string;
13
13
  refreshToken: string | null;
14
14
  expires: number;
15
15
  redirect(defaultPath?: string): void;
16
16
  }>;
17
17
  logout(): Promise<void>;
18
- register(data: Partial<DirectusCollectionUser>): Promise<DirectusCollectionUser>;
18
+ register(data: Partial<DirectusUsers>): Promise<DirectusUsers>;
19
19
  requestPasswordReset(email: string, resetUrl?: string | null | undefined): Promise<void>;
20
20
  resetPassword(token: string, password: string): Promise<void>;
21
21
  }
@@ -17,7 +17,7 @@ export function useDirectusAuth() {
17
17
  if (!tokens.refreshToken.value)
18
18
  throw new Error("No refresh token");
19
19
  await directus.refresh();
20
- user.value = await directus.request(readMe(config.public.rolley.fetchUserParams));
20
+ user.value = await directus.request(readMe(config.public.directus.fetchUserParams));
21
21
  } catch (e) {
22
22
  user.value = null;
23
23
  }
@@ -27,7 +27,7 @@ export function useDirectusAuth() {
27
27
  const currentUser = user.value;
28
28
  if (!currentUser?.id)
29
29
  throw new Error("No user available");
30
- user.value = await directus.request(updateMe(data, config.public.rolley.fetchUserParams));
30
+ user.value = await directus.request(updateMe(data, config.public.directus.fetchUserParams));
31
31
  return user.value;
32
32
  }
33
33
  async function login(email, password, options = {}) {
@@ -1,2 +1,4 @@
1
+ import type { AuthenticationClient, DirectusClient, RestClient, WebSocketClient } from '@directus/sdk';
2
+ import type { UsersCollections } from '#build/types/directus';
1
3
  export declare function useDirectusUrl(): string;
2
- export declare function useDirectus(token?: string): import("@directus/sdk/dist/client-e8d6bf91").D<DirectusCollections> & import("@directus/sdk/dist/login-0506af09").d<DirectusCollections> & import("@directus/sdk/dist/login-0506af09").f<DirectusCollections> & import("@directus/sdk/dist/output-35b496cf").d<DirectusCollections>;
4
+ export declare function useDirectus(token?: string): DirectusClient<UsersCollections> & AuthenticationClient<UsersCollections> & RestClient<UsersCollections> & WebSocketClient<UsersCollections>;
@@ -2,7 +2,7 @@ import { authentication, createDirectus, realtime, rest } from "@directus/sdk";
2
2
  import { useDirectusTokens } from "./tokens.mjs";
3
3
  import { useRuntimeConfig } from "#app";
4
4
  export function useDirectusUrl() {
5
- return useRuntimeConfig().public.rolley.url;
5
+ return useRuntimeConfig().public.directus.url;
6
6
  }
7
7
  function createDirectusStorage() {
8
8
  const tokens = useDirectusTokens();
@@ -1,6 +1,23 @@
1
- import type { DirectusThumbnailOptions } from '../types';
2
- export declare function uploadDirectusFile(file: File, folder?: string): Promise<Record<string, any>>;
1
+ import type { Query } from '@directus/sdk';
2
+ import type { AllCollections, DirectusFiles } from '#build/types/directus';
3
+ export type DirectusThumbnailFormat = 'jpg' | 'png' | 'webp' | 'tiff';
4
+ export type DirectusThumbnailFit = 'cover' | 'contain' | 'inside' | 'outside';
5
+ export interface DirectusThumbnailOptions {
6
+ width?: number;
7
+ height?: number;
8
+ quality?: number;
9
+ fit?: DirectusThumbnailFit;
10
+ format?: DirectusThumbnailFormat;
11
+ withoutEnlargement?: boolean;
12
+ token?: string;
13
+ }
14
+ interface FileUpload {
15
+ file: File;
16
+ data?: Record<keyof DirectusFiles, string>;
17
+ }
18
+ export declare function uploadDirectusFile(files: FileUpload[], query: Query<AllCollections, AllCollections['directus_files']>): Promise<DirectusFiles[]>;
3
19
  export declare function getDirectusAssetUrl(fileId: string, options?: {
4
20
  token?: string;
5
21
  }): string;
6
22
  export declare function getDirectusThumbnailUrl(fileId: string, options?: DirectusThumbnailOptions): string;
23
+ export {};
@@ -1,12 +1,17 @@
1
1
  import { uploadFiles } from "@directus/sdk";
2
2
  import { useDirectus, useDirectusUrl } from "./directus.mjs";
3
- export async function uploadDirectusFile(file, folder) {
3
+ export async function uploadDirectusFile(files, query) {
4
4
  const directus = useDirectus();
5
5
  const formData = new FormData();
6
- formData.set("file", file);
7
- if (folder)
8
- formData.set("folder", folder);
9
- return directus.request(uploadFiles(formData));
6
+ files.forEach(({ file, data }, i) => {
7
+ if (data) {
8
+ Object.entries(data).forEach(([key, value]) => {
9
+ formData.set(`file_${i + 1}_${key}`, value);
10
+ });
11
+ }
12
+ formData.set("file", file);
13
+ });
14
+ return await directus.request(uploadFiles(formData, query));
10
15
  }
11
16
  export function getDirectusAssetUrl(fileId, options) {
12
17
  const directusUrl = useDirectusUrl();
@@ -14,14 +14,14 @@ function directusCookie(name, cookieOptions) {
14
14
  return cookie;
15
15
  }
16
16
  export function useDirectusTokens() {
17
- const config = useRuntimeConfig().public.rolley;
17
+ const config = useRuntimeConfig().public.directus;
18
18
  const sharedOptions = {
19
19
  sameSite: config.cookieSameSite,
20
20
  secure: config.cookieSecure,
21
21
  domain: getCookieDomain()
22
22
  };
23
23
  function accessToken() {
24
- return directusCookie(config.cookieNameToken, {
24
+ return directusCookie(config.cookieNameAccessToken, {
25
25
  ...sharedOptions,
26
26
  maxAge: config.cookieMaxAge
27
27
  });
@@ -21,7 +21,7 @@ export default defineNuxtPlugin(async (nuxt) => {
21
21
  }
22
22
  }
23
23
  const config = useRuntimeConfig();
24
- if (config.public.rolley.fetchUser)
24
+ if (config.public.directus.fetchUser)
25
25
  await useDirectusAuth().fetchUser();
26
26
  addRouteMiddleware("auth", async (to) => {
27
27
  const user = useDirectusAuth().user;
@@ -1,5 +1,7 @@
1
+ import type { AuthenticationClient, DirectusClient, RestClient } from '@directus/sdk';
1
2
  import type { H3Event } from 'h3';
3
+ import type { UsersCollections } from '#build/types/directus';
2
4
  export declare function useDirectusAccessToken(event: H3Event): string | undefined;
3
5
  export declare function useDirectusUrl(): string;
4
- export declare function useDirectus(token?: string): import("@directus/sdk/dist/client-e8d6bf91").D<DirectusCollections> & import("@directus/sdk/dist/login-0506af09").d<DirectusCollections> & import("@directus/sdk/dist/login-0506af09").f<DirectusCollections>;
5
- export declare function useAdminDirectus(): import("@directus/sdk/dist/client-e8d6bf91").D<DirectusCollections> & import("@directus/sdk/dist/login-0506af09").d<DirectusCollections> & import("@directus/sdk/dist/login-0506af09").f<DirectusCollections>;
6
+ export declare function useDirectus(token?: string): DirectusClient<UsersCollections> & AuthenticationClient<UsersCollections> & RestClient<UsersCollections>;
7
+ export declare function useAdminDirectus(): DirectusClient<UsersCollections> & AuthenticationClient<UsersCollections> & RestClient<UsersCollections>;
@@ -2,10 +2,10 @@ import { authentication, createDirectus, rest } from "@directus/sdk";
2
2
  import { getCookie } from "h3";
3
3
  import { useRuntimeConfig } from "#imports";
4
4
  export function useDirectusAccessToken(event) {
5
- return getCookie(event, "directus_access_token");
5
+ return getCookie(event, useRuntimeConfig().public.directus.cookieNameAccessToken);
6
6
  }
7
7
  export function useDirectusUrl() {
8
- return useRuntimeConfig().public.rolley.url;
8
+ return useRuntimeConfig().public.directus.url;
9
9
  }
10
10
  export function useDirectus(token) {
11
11
  const url = useDirectusUrl();
@@ -17,12 +17,8 @@ export function useDirectus(token) {
17
17
  return directus;
18
18
  }
19
19
  export function useAdminDirectus() {
20
- const url = useDirectusUrl();
21
- if (!url)
22
- throw new Error("DIRECTUS_URL is not set in config options or .env file");
23
- if (!process.env.DIRECTUS_ADMIN_TOKEN)
20
+ const config = useRuntimeConfig().directus;
21
+ if (!config.adminToken)
24
22
  throw new Error("DIRECTUS_ADMIN_TOKEN is not set in config options or .env file");
25
- const directus = createDirectus(url).with(authentication("json", { autoRefresh: false })).with(rest());
26
- directus.setToken(process.env.DIRECTUS_ADMIN_TOKEN);
27
- return directus;
23
+ return useDirectus(config.adminToken);
28
24
  }
@@ -0,0 +1,7 @@
1
+ import type { Collections } from './generate.types';
2
+ export interface OASOptions {
3
+ url: string;
4
+ token: string;
5
+ }
6
+ export declare function generateTypes(options: OASOptions): Promise<string>;
7
+ export declare function getCollections(options: OASOptions): Promise<Collections>;
@@ -0,0 +1,123 @@
1
+ import { useLogger } from "@nuxt/kit";
2
+ import { authentication, createDirectus, readCollections, readFields, readRelations, rest } from "@directus/sdk";
3
+ function warn(message) {
4
+ useLogger(message);
5
+ }
6
+ export async function generateTypes(options) {
7
+ const collections = await getCollections(options);
8
+ let typeValues = "";
9
+ const types = [];
10
+ Object.values(collections).forEach((collection) => {
11
+ const collectionName = collection.collection;
12
+ const typeName = pascalCase(collectionName);
13
+ types.push(`${collectionName}: ${typeName}[]`);
14
+ typeValues += `export type ${typeName} = {
15
+ `;
16
+ collection.fields.forEach((field) => {
17
+ if (field.meta?.interface?.startsWith("presentation-"))
18
+ return;
19
+ typeValues += " ";
20
+ typeValues += field.field.includes("-") ? `"${field.field}"` : field.field;
21
+ if (field.schema?.is_nullable)
22
+ typeValues += "?";
23
+ typeValues += ": ";
24
+ typeValues += getType(field);
25
+ typeValues += ";\n";
26
+ });
27
+ typeValues += "};\n\n";
28
+ });
29
+ typeValues += `export interface AllCollections {
30
+ ${types.map((x) => ` ${x};`).join("\n")}
31
+ };
32
+
33
+ interface UsersCollections {
34
+ ${types.filter((item) => !item.startsWith("directus_")).map((x) => ` ${x};`).join("\n")}
35
+ };
36
+
37
+ declare global {
38
+ interface DirectusCollections {
39
+ ${types.filter((item) => !item.startsWith("directus_")).map((x) => ` ${x};`).join("\n")}
40
+ };
41
+ }
42
+ `;
43
+ typeValues += "\n";
44
+ return typeValues;
45
+ }
46
+ function pascalCase(str) {
47
+ return str.split(" ").flatMap((x) => x.split("_")).flatMap((y) => y.split("-")).map((x) => x.charAt(0).toUpperCase() + x.slice(1)).join("");
48
+ }
49
+ function getType(field) {
50
+ let type = "";
51
+ if (field.relation && field.relation.type === "many") {
52
+ type = "any[]";
53
+ } else if (field.relation) {
54
+ type += field.relation.collection ? pascalCase(field.relation.collection) : "any";
55
+ if (field.relation.type === "many")
56
+ type += "[]";
57
+ } else {
58
+ if (["integer", "bigInteger", "float", "decimal"].includes(field.type))
59
+ type = "number";
60
+ else if (["boolean"].includes(field.type))
61
+ type = "boolean";
62
+ else if (["json", "csv"].includes(field.type))
63
+ type = "unknown";
64
+ else
65
+ type = "string";
66
+ }
67
+ if (field.schema?.is_nullable) {
68
+ if (field.relation)
69
+ type = `${type} | null`;
70
+ else
71
+ type += " | null";
72
+ }
73
+ return type;
74
+ }
75
+ export async function getCollections(options) {
76
+ const directus = createDirectus(options.url).with(authentication("json", { autoRefresh: false })).with(rest());
77
+ directus.setToken(options.token);
78
+ const rawCollections = await directus.request(readCollections());
79
+ const collections = {};
80
+ rawCollections.sort((a, b) => a.collection.localeCompare(b.collection)).forEach(
81
+ (collection) => collections[collection.collection] = { ...collection, fields: [] }
82
+ );
83
+ const fields = await directus.request(readFields());
84
+ fields.sort((a, b) => a.field.localeCompare(b.field)).forEach((field) => {
85
+ if (!collections[field.collection]) {
86
+ warn(`${field.collection} not found`);
87
+ return;
88
+ }
89
+ collections[field.collection].fields.push(field);
90
+ if (collections[field.collection].fields.length === 0)
91
+ delete collections[field.collection];
92
+ });
93
+ const relations = await directus.request(readRelations());
94
+ relations.forEach((relation) => {
95
+ if (!relation.meta) {
96
+ warn(`Relation on field '${relation.field}' in collection '${relation.collection}' has no meta. Maybe missing a relation inside directus_relations table.`);
97
+ return;
98
+ }
99
+ if (!relation.meta.one_collection) {
100
+ warn("No one collection");
101
+ return;
102
+ }
103
+ const oneField = collections[relation.meta.one_collection]?.fields.find(
104
+ (field) => field.field === relation.meta.one_field
105
+ );
106
+ const manyField = collections[relation.meta.many_collection]?.fields.find(
107
+ (field) => field.field === relation.meta.many_field
108
+ );
109
+ if (oneField) {
110
+ oneField.relation = {
111
+ type: "many",
112
+ collection: relation.meta.many_collection
113
+ };
114
+ }
115
+ if (manyField) {
116
+ manyField.relation = {
117
+ type: "one",
118
+ collection: relation.meta.one_collection
119
+ };
120
+ }
121
+ });
122
+ return collections;
123
+ }
@@ -0,0 +1,13 @@
1
+ import type { Collection as DirectusCollection, Field as DirectusField } from '@directus/shared/types';
2
+ export type Field = DirectusField & {
3
+ relation?: {
4
+ type: 'many' | 'one';
5
+ collection: string;
6
+ };
7
+ };
8
+ export type Collection = DirectusCollection & {
9
+ fields: Field[];
10
+ };
11
+ export interface Collections {
12
+ [collection: string]: Collection;
13
+ }
@@ -1,38 +1 @@
1
- export type DirectusThumbnailFormat = 'jpg' | 'png' | 'webp' | 'tiff'
2
- export type DirectusThumbnailFit = 'cover' | 'contain' | 'inside' | 'outside'
3
-
4
- export interface DirectusThumbnailOptions {
5
- width?: number
6
- height?: number
7
- quality?: number
8
- fit?: DirectusThumbnailFit
9
- format?: DirectusThumbnailFormat
10
- withoutEnlargement?: boolean
11
- token?: string
12
- }
13
-
14
- export interface DirectusNotificationObject {
15
- id?: number
16
- timestamp?: string
17
- status?: 'inbox' | 'archived'
18
- recipient: Array<string> | string
19
- sender?: Array<string> | string
20
- subject: string
21
- message?: string
22
- collection?: string
23
- item?: string
24
- }
25
-
26
- export interface DirectusQueryParams {
27
- fields?: Array<string>
28
- sort?: string | Array<string>
29
- filter?: Record<string, unknown>
30
- limit?: number
31
- offset?: number
32
- page?: number
33
- alias?: string | Array<string>
34
- deep?: Record<string, unknown>
35
- search?: string
36
- meta?: 'total_count' | 'filter_count' | '*'
37
- }
38
-
1
+ export { generateTypes } from './generate';
@@ -0,0 +1 @@
1
+ export { generateTypes } from "./generate.mjs";
package/dist/types.d.mts CHANGED
@@ -2,13 +2,13 @@
2
2
  import { ModuleOptions } from './module'
3
3
 
4
4
  declare module '@nuxt/schema' {
5
- interface NuxtConfig { ['rolley']?: Partial<ModuleOptions> }
6
- interface NuxtOptions { ['rolley']?: ModuleOptions }
5
+ interface NuxtConfig { ['directus']?: Partial<ModuleOptions> }
6
+ interface NuxtOptions { ['directus']?: ModuleOptions }
7
7
  }
8
8
 
9
9
  declare module 'nuxt/schema' {
10
- interface NuxtConfig { ['rolley']?: Partial<ModuleOptions> }
11
- interface NuxtOptions { ['rolley']?: ModuleOptions }
10
+ interface NuxtConfig { ['directus']?: Partial<ModuleOptions> }
11
+ interface NuxtOptions { ['directus']?: ModuleOptions }
12
12
  }
13
13
 
14
14
 
package/dist/types.d.ts CHANGED
@@ -2,13 +2,13 @@
2
2
  import { ModuleOptions } from './module'
3
3
 
4
4
  declare module '@nuxt/schema' {
5
- interface NuxtConfig { ['rolley']?: Partial<ModuleOptions> }
6
- interface NuxtOptions { ['rolley']?: ModuleOptions }
5
+ interface NuxtConfig { ['directus']?: Partial<ModuleOptions> }
6
+ interface NuxtOptions { ['directus']?: ModuleOptions }
7
7
  }
8
8
 
9
9
  declare module 'nuxt/schema' {
10
- interface NuxtConfig { ['rolley']?: Partial<ModuleOptions> }
11
- interface NuxtOptions { ['rolley']?: ModuleOptions }
10
+ interface NuxtConfig { ['directus']?: Partial<ModuleOptions> }
11
+ interface NuxtOptions { ['directus']?: ModuleOptions }
12
12
  }
13
13
 
14
14
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "nuxt-directus-sdk",
3
3
  "type": "module",
4
- "version": "0.0.2",
4
+ "version": "0.0.3",
5
5
  "description": "A nuxt module that uses the directus SDK",
6
6
  "author": "Matthew Rollinson <matt@rolley.io>",
7
7
  "license": "MIT",
@@ -29,17 +29,19 @@
29
29
  },
30
30
  "dependencies": {
31
31
  "@directus/sdk": "^11.0.3",
32
+ "@directus/shared": "^9.24.0",
32
33
  "@nuxt/kit": "^3.7.1",
33
34
  "change-case": "^4.1.2",
34
35
  "defu": "^6.1.1",
36
+ "openapi-typescript": "^6.5.5",
35
37
  "parse-domain": "^7.0.1",
36
38
  "tippy.js": "^6.3.7",
37
39
  "ufo": "^1.1.1",
38
40
  "vue-toastification": "2.0.0-rc.5"
39
41
  },
40
42
  "devDependencies": {
43
+ "@antfu/eslint-config": "^0.41.0",
41
44
  "@nuxt/devtools": "latest",
42
- "@nuxt/eslint-config": "^0.2.0",
43
45
  "@nuxt/module-builder": "^0.5.1",
44
46
  "@nuxt/schema": "^3.7.1",
45
47
  "@nuxt/test-utils": "^3.7.1",
@@ -1,5 +0,0 @@
1
- import type { GenerateTypeOptions, SchemaProperty, SchemaPropertyOneOf, SchemaPropertyType, SchemasRecord } from './types';
2
- export declare function mapPropertyType(propertyType: SchemaPropertyType): "string" | "boolean" | "array" | "number";
3
- export declare function processOneOfProperty(schemas: SchemasRecord, name: string, property: SchemaPropertyOneOf): string | undefined;
4
- export declare function processProperty(schemas: SchemasRecord, name: string, property: SchemaProperty): string | undefined;
5
- export declare function generateTypes(options: GenerateTypeOptions): Promise<string>;
@@ -1,100 +0,0 @@
1
- import { snakeCase } from "change-case";
2
- import { authentication, createDirectus, readOpenApiSpec, rest } from "@directus/sdk";
3
- export function mapPropertyType(propertyType) {
4
- return propertyType === "integer" ? "number" : propertyType;
5
- }
6
- export function processOneOfProperty(schemas, name, property) {
7
- const ref = property.oneOf.find((item) => {
8
- return "$ref" in item;
9
- });
10
- if (ref) {
11
- const $ref = ref.$ref;
12
- const $refKey = $ref.split("/").pop();
13
- if ($refKey) {
14
- const $refSchema = `DirectusCollections['${schemas[$refKey]?.["x-collection"]}']`;
15
- if ($refSchema)
16
- return $refSchema;
17
- }
18
- }
19
- const firstValue = property.oneOf?.[0];
20
- if ("type" in firstValue) {
21
- const firstType = mapPropertyType(firstValue.type);
22
- if (firstType)
23
- return firstType;
24
- }
25
- console.error("Unknown schema for oneOf", name, property);
26
- return "";
27
- }
28
- export function processProperty(schemas, name, property) {
29
- if ("type" in property) {
30
- if (property.type === "array" && property.items) {
31
- if (!property.items.oneOf)
32
- return processProperty(schemas, name, property.items);
33
- return `
34
- "${name}": ${processOneOfProperty(schemas, name, property.items)};
35
- `;
36
- } else {
37
- return `
38
- ${property.format ? `/* ${property.format} */` : ""}
39
- "${name}": ${mapPropertyType(property.type ?? "string")};
40
- `;
41
- }
42
- } else if ("oneOf" in property) {
43
- const value = processOneOfProperty(schemas, name, property);
44
- if (!value)
45
- return;
46
- const simpleTypes = ["string", "number", "boolean"];
47
- const valueType = simpleTypes.includes(value) ? value : `Single<${value}>`;
48
- return `
49
- "${name}": ${valueType};
50
- `;
51
- }
52
- }
53
- export async function generateTypes(options) {
54
- const directus = createDirectus(options.url).with(authentication("json", { autoRefresh: false })).with(rest());
55
- directus.setToken(options.token);
56
- const data = await directus.request(readOpenApiSpec());
57
- const types = [];
58
- const schemas = data.components.schemas;
59
- const schemaNames = [];
60
- Object.entries(schemas).forEach(([_, schema]) => {
61
- const schemaName = schema["x-collection"];
62
- if (!schemaName)
63
- return;
64
- if (schema.type !== "object") {
65
- console.error(schemaName, "is not an object");
66
- return;
67
- }
68
- if (schemaNames.includes(schemaName))
69
- return;
70
- schemaNames.push(schemaName);
71
- const properties = [];
72
- Object.entries(schema.properties).forEach(([name, property]) => {
73
- const propertyType = processProperty(schemas, name, property);
74
- if (propertyType)
75
- properties.push(propertyType.trim());
76
- });
77
- types.push(`${snakeCase(schemaName)}: {
78
- ${properties.join("\n")}
79
- }[];
80
- `);
81
- });
82
- const exportProperties = types.join("\n");
83
- return `
84
- export type Single<T extends any[]> = T extends (infer U)[] ? U : never;
85
-
86
- export type DirectusCollections = {
87
- ${exportProperties}
88
- };
89
-
90
- export type DirectusCollectionUser = Single<DirectusCollections['directus_users']>;
91
-
92
- declare global {
93
- type Single = Single
94
- type DirectusCollections = DirectusCollections
95
- type DirectusCollectionUser = DirectusCollectionUser
96
- }
97
-
98
- export {};
99
- `;
100
- }
@@ -1,27 +0,0 @@
1
- export interface GenerateTypeOptions {
2
- url: string;
3
- token: string;
4
- collections?: string[];
5
- }
6
- export type SchemaPropertyType = 'string' | 'integer' | 'boolean' | 'array';
7
- export interface SchemaPropertyOneOfReference {
8
- $ref: string;
9
- }
10
- export type SchemaPropertyOneOfValue = SchemaPropertyOneOfReference | SchemaPropertySingle[];
11
- export interface SchemaPropertyOneOf {
12
- nullable: boolean;
13
- oneOf: SchemaPropertyOneOfValue[];
14
- }
15
- export interface SchemaPropertySingle {
16
- nullable: boolean;
17
- type?: SchemaPropertyType;
18
- format?: string;
19
- items?: SchemaPropertyOneOf;
20
- }
21
- export type SchemaProperty = SchemaPropertySingle | SchemaPropertyOneOf;
22
- export interface Schema {
23
- type: string;
24
- 'x-collection'?: string;
25
- properties: Record<string, SchemaProperty>;
26
- }
27
- export type SchemasRecord = Record<string, Schema>;