@tanglemedia/svelte-starter-directus-api 2.0.0 → 2.0.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.
|
@@ -1,14 +1,24 @@
|
|
|
1
|
-
import { type DirectusClient, type RestClient } from '@directus/sdk';
|
|
1
|
+
import { type AllCollections, type DirectusClient, type RegularCollections, type RestClient } from '@directus/sdk';
|
|
2
2
|
import { ApiAdapterAbstract, type AnyObject, type ApiAdapterRequestConfig, type ApiCreateManyQuery, type ApiDeleteManyQuery, type ApiId, type ApiResponse, type ApiUpdateManyQuery, type BaseApiMethods } from '@tanglemedia/svelte-starter-core';
|
|
3
3
|
import type { DirectusConfig, SchemaShape } from '../types/adapter.types';
|
|
4
4
|
export type AdapterClient<Schema extends SchemaShape = SchemaShape> = DirectusClient<Schema> & RestClient<Schema>;
|
|
5
|
-
export declare class DirectusApiAdapter<Schema extends SchemaShape = SchemaShape, Path extends
|
|
5
|
+
export declare class DirectusApiAdapter<Schema extends SchemaShape = SchemaShape, Path extends RegularCollections<Schema> = RegularCollections<Schema>> extends ApiAdapterAbstract<DirectusConfig, ApiAdapterRequestConfig, Path, AdapterClient> {
|
|
6
6
|
protected config: DirectusConfig;
|
|
7
7
|
private readonly directus;
|
|
8
8
|
constructor(config: DirectusConfig, directus: AdapterClient<Schema>);
|
|
9
9
|
getAdapterClient(): AdapterClient<Schema> | null;
|
|
10
|
-
normalizeMeta(
|
|
11
|
-
|
|
10
|
+
normalizeMeta(response: AnyObject): {
|
|
11
|
+
total?: undefined;
|
|
12
|
+
displayed?: undefined;
|
|
13
|
+
} | {
|
|
14
|
+
total: number;
|
|
15
|
+
displayed: number;
|
|
16
|
+
};
|
|
17
|
+
includeTotals(collection: AllCollections<Schema>, filters?: Record<string, unknown>): Promise<number | null>;
|
|
18
|
+
transformResponse<T, M extends object = AnyObject>(res: {
|
|
19
|
+
data: T;
|
|
20
|
+
meta?: AnyObject;
|
|
21
|
+
}, status?: number): Promise<ApiResponse<T, Response, M>>;
|
|
12
22
|
getConfig(configuration?: unknown): DirectusConfig;
|
|
13
23
|
request<T>(method: BaseApiMethods, url: string, query?: Record<string, unknown>): Promise<T>;
|
|
14
24
|
find<T>(collection: Path, query?: Record<string, unknown>): Promise<ApiResponse<T>>;
|
|
@@ -11,17 +11,36 @@ export class DirectusApiAdapter extends ApiAdapterAbstract {
|
|
|
11
11
|
getAdapterClient() {
|
|
12
12
|
return this.directus;
|
|
13
13
|
}
|
|
14
|
-
normalizeMeta(
|
|
14
|
+
normalizeMeta(response) {
|
|
15
|
+
const payload = response.data, meta = response.meta;
|
|
16
|
+
if (!meta) {
|
|
17
|
+
return {};
|
|
18
|
+
}
|
|
19
|
+
if (typeof meta.total === 'undefined') {
|
|
20
|
+
return {};
|
|
21
|
+
}
|
|
22
|
+
const displayed = Array.isArray(payload) ? payload.length : 0;
|
|
23
|
+
const total = Number(meta.total);
|
|
15
24
|
// todo: Transform or attempt to get meta information
|
|
16
25
|
// consider pulling count based on existing filters in order to determine pagination
|
|
17
|
-
return
|
|
26
|
+
return { total, displayed };
|
|
27
|
+
}
|
|
28
|
+
async includeTotals(collection, filters) {
|
|
29
|
+
if (true !== this.config.configuration.includeTotals) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
const data = await this.directus.request(aggregate(collection, {
|
|
33
|
+
aggregate: { count: '*' },
|
|
34
|
+
filters: filters || {}
|
|
35
|
+
}));
|
|
36
|
+
if (data && data.length === 1) {
|
|
37
|
+
return Number(data[0].count);
|
|
38
|
+
}
|
|
39
|
+
return 0;
|
|
18
40
|
}
|
|
19
41
|
async transformResponse(res, status = 200) {
|
|
20
|
-
// const payload = (await res.json()) as T;
|
|
21
42
|
return {
|
|
22
|
-
body: await this.envelopeResponse(res.data
|
|
23
|
-
// this.normalizeMeta(payload as AnyObject) as M
|
|
24
|
-
),
|
|
43
|
+
body: await this.envelopeResponse(res.data, (res.meta ? this.normalizeMeta(res) : {})),
|
|
25
44
|
status: status,
|
|
26
45
|
statusText: 'OK',
|
|
27
46
|
headers: {},
|
|
@@ -33,7 +52,7 @@ export class DirectusApiAdapter extends ApiAdapterAbstract {
|
|
|
33
52
|
// Add the 'configuration' property to the returned object
|
|
34
53
|
const config = {
|
|
35
54
|
...this.config,
|
|
36
|
-
configuration: configuration ?? {} // Use the provided configuration or an empty object if not provided
|
|
55
|
+
configuration: configuration ?? this.config.configuration ?? {} // Use the provided configuration or an empty object if not provided
|
|
37
56
|
};
|
|
38
57
|
return Object.assign(client, config);
|
|
39
58
|
}
|
|
@@ -55,37 +74,42 @@ export class DirectusApiAdapter extends ApiAdapterAbstract {
|
|
|
55
74
|
}
|
|
56
75
|
async find(collection, query) {
|
|
57
76
|
const response = await this.directus.request(readItems(collection, query));
|
|
58
|
-
|
|
77
|
+
const total = await this.includeTotals(collection, query.filter);
|
|
78
|
+
if (null === total) {
|
|
79
|
+
return this.transformResponse({ data: response });
|
|
80
|
+
}
|
|
81
|
+
// console.log('find meta', response, total)
|
|
82
|
+
return this.transformResponse({ data: response, meta: { total } });
|
|
59
83
|
}
|
|
60
84
|
async findOne(collection, key, query) {
|
|
61
|
-
const
|
|
62
|
-
return this.transformResponse(
|
|
85
|
+
const data = await this.directus.request(readItem(collection, key, query));
|
|
86
|
+
return this.transformResponse({ data });
|
|
63
87
|
}
|
|
64
88
|
async aggregate(collection, query) {
|
|
65
|
-
const
|
|
89
|
+
const data = await this.directus.request(aggregate(collection, {
|
|
66
90
|
aggregate: {
|
|
67
91
|
count: 'id'
|
|
68
92
|
},
|
|
69
93
|
query
|
|
70
94
|
}));
|
|
71
|
-
return this.transformResponse(
|
|
95
|
+
return this.transformResponse({ data });
|
|
72
96
|
}
|
|
73
97
|
async patch(collection, key, query) {
|
|
74
|
-
const
|
|
75
|
-
return this.transformResponse(
|
|
98
|
+
const data = await this.directus.request(updateItem(collection, key, query));
|
|
99
|
+
return this.transformResponse({ data });
|
|
76
100
|
}
|
|
77
101
|
async post(collection, data, query) {
|
|
78
102
|
const response = await this.directus.request(createItem(collection, data, query));
|
|
79
|
-
return this.transformResponse(response, 201);
|
|
103
|
+
return this.transformResponse({ data: response }, 201);
|
|
80
104
|
}
|
|
81
105
|
async delete(collection, key) {
|
|
82
|
-
const
|
|
83
|
-
return this.transformResponse(
|
|
106
|
+
const data = await this.directus.request(deleteItem(collection, key));
|
|
107
|
+
return this.transformResponse({ data }, 202);
|
|
84
108
|
}
|
|
85
109
|
async put(collection, key, payload) {
|
|
86
110
|
if (key) {
|
|
87
|
-
const
|
|
88
|
-
return this.transformResponse(
|
|
111
|
+
const data = await this.directus.request(updateItem(collection, key, payload));
|
|
112
|
+
return this.transformResponse({ data }, 201);
|
|
89
113
|
}
|
|
90
114
|
else {
|
|
91
115
|
console.error(`Error updating all ${collection}: no key specified`);
|
|
@@ -95,21 +119,21 @@ export class DirectusApiAdapter extends ApiAdapterAbstract {
|
|
|
95
119
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
96
120
|
async upload(path = '', data) {
|
|
97
121
|
const response = await this.directus.request(uploadFiles(data));
|
|
98
|
-
return this.transformResponse(response, 201);
|
|
122
|
+
return this.transformResponse({ data: response }, 201);
|
|
99
123
|
}
|
|
100
124
|
async createMany(path, body) {
|
|
101
|
-
const
|
|
102
|
-
return this.transformResponse(
|
|
125
|
+
const data = await this.directus.request(createItems(path, body.data));
|
|
126
|
+
return this.transformResponse({ data }, 200);
|
|
103
127
|
}
|
|
104
128
|
async updateMany(path, body) {
|
|
105
129
|
if (!body.ids) {
|
|
106
130
|
throw Error('You must provide an array of keys to update');
|
|
107
131
|
}
|
|
108
|
-
const
|
|
109
|
-
return this.transformResponse(
|
|
132
|
+
const data = await this.directus.request(updateItems(path, body.ids || [], body.data));
|
|
133
|
+
return this.transformResponse({ data }, 200);
|
|
110
134
|
}
|
|
111
135
|
async deleteMany(path, body) {
|
|
112
|
-
const
|
|
113
|
-
return this.transformResponse(
|
|
136
|
+
const data = await this.directus.request(deleteItems(path, body.ids));
|
|
137
|
+
return this.transformResponse({ data }, 201);
|
|
114
138
|
}
|
|
115
139
|
}
|
|
@@ -18,6 +18,7 @@ export type DirectusApiAdapterOptions = {
|
|
|
18
18
|
rest?: {
|
|
19
19
|
credentials?: RequestCredentials;
|
|
20
20
|
};
|
|
21
|
+
includeTotals?: boolean;
|
|
21
22
|
};
|
|
22
23
|
export type DirectusConfig = BaseApiAdapterConfig<DirectusApiAdapterOptions>;
|
|
23
24
|
export type SchemaShape = Record<string, object>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanglemedia/svelte-starter-directus-api",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"main": "src/index.ts",
|
|
5
5
|
"types": "src/index.ts",
|
|
6
6
|
"description": "directus API wrapper for all the directus sdk functionality",
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
}
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
|
+
"@directus/types": "^12.0.0",
|
|
25
26
|
"@sveltejs/adapter-auto": "^3.2.4",
|
|
26
27
|
"@sveltejs/package": "^2.3.4",
|
|
27
28
|
"@sveltejs/vite-plugin-svelte": "^3.1.2",
|
|
@@ -35,7 +36,7 @@
|
|
|
35
36
|
"vite": "^5.4.2",
|
|
36
37
|
"vitest": "^2.0.5",
|
|
37
38
|
"@internal/eslint-config": "0.0.0",
|
|
38
|
-
"@tanglemedia/svelte-starter-core": "0.2.
|
|
39
|
+
"@tanglemedia/svelte-starter-core": "0.2.1"
|
|
39
40
|
},
|
|
40
41
|
"dependencies": {
|
|
41
42
|
"@directus/sdk": "^17.0.0",
|
|
@@ -45,7 +46,7 @@
|
|
|
45
46
|
},
|
|
46
47
|
"peerDependencies": {
|
|
47
48
|
"@sveltejs/kit": ">=2 <3",
|
|
48
|
-
"@tanglemedia/svelte-starter-core": ">=0.2.
|
|
49
|
+
"@tanglemedia/svelte-starter-core": ">=0.2.1",
|
|
49
50
|
"svelte": ">=4 <5"
|
|
50
51
|
},
|
|
51
52
|
"scripts": {
|
|
@@ -9,7 +9,9 @@ import {
|
|
|
9
9
|
updateItem,
|
|
10
10
|
updateItems,
|
|
11
11
|
uploadFiles,
|
|
12
|
+
type AllCollections,
|
|
12
13
|
type DirectusClient,
|
|
14
|
+
type RegularCollections,
|
|
13
15
|
type RestClient
|
|
14
16
|
} from '@directus/sdk';
|
|
15
17
|
import {
|
|
@@ -30,7 +32,7 @@ export type AdapterClient<Schema extends SchemaShape = SchemaShape> = DirectusCl
|
|
|
30
32
|
|
|
31
33
|
export class DirectusApiAdapter<
|
|
32
34
|
Schema extends SchemaShape = SchemaShape,
|
|
33
|
-
Path extends
|
|
35
|
+
Path extends RegularCollections<Schema> = RegularCollections<Schema>
|
|
34
36
|
> extends ApiAdapterAbstract<DirectusConfig, ApiAdapterRequestConfig, Path, AdapterClient> {
|
|
35
37
|
constructor(
|
|
36
38
|
protected config: DirectusConfig,
|
|
@@ -43,22 +45,51 @@ export class DirectusApiAdapter<
|
|
|
43
45
|
return this.directus;
|
|
44
46
|
}
|
|
45
47
|
|
|
46
|
-
normalizeMeta(
|
|
48
|
+
normalizeMeta(response: AnyObject) {
|
|
49
|
+
const payload = response.data, meta = response.meta as Record<string, unknown>;
|
|
50
|
+
|
|
51
|
+
if (!meta) {
|
|
52
|
+
return {};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (typeof meta.total === 'undefined') {
|
|
56
|
+
return {};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const displayed = Array.isArray(payload) ? payload.length : 0;
|
|
60
|
+
|
|
61
|
+
const total = Number(meta.total);
|
|
62
|
+
|
|
47
63
|
// todo: Transform or attempt to get meta information
|
|
48
64
|
// consider pulling count based on existing filters in order to determine pagination
|
|
49
|
-
return
|
|
65
|
+
return { total, displayed };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async includeTotals(collection: AllCollections<Schema>, filters?: Record<string, unknown>) {
|
|
69
|
+
if (true !== this.config.configuration.includeTotals) {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const data = await this.directus.request(aggregate(collection, {
|
|
74
|
+
aggregate: { count: '*' },
|
|
75
|
+
filters: filters || {}
|
|
76
|
+
}));
|
|
77
|
+
|
|
78
|
+
if (data && data.length === 1) {
|
|
79
|
+
return Number(data[0].count);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return 0;
|
|
50
83
|
}
|
|
51
84
|
|
|
52
85
|
async transformResponse<T, M extends object = AnyObject>(
|
|
53
|
-
res: T,
|
|
86
|
+
res: {data: T, meta?: AnyObject},
|
|
54
87
|
status: number = 200
|
|
55
88
|
): Promise<ApiResponse<T, Response, M>> {
|
|
56
|
-
// const payload = (await res.json()) as T;
|
|
57
|
-
|
|
58
89
|
return {
|
|
59
90
|
body: await this.envelopeResponse<T, M>(
|
|
60
|
-
res.data
|
|
61
|
-
|
|
91
|
+
res.data,
|
|
92
|
+
(res.meta ? this.normalizeMeta(res as AnyObject) : {}) as M
|
|
62
93
|
),
|
|
63
94
|
status: status,
|
|
64
95
|
statusText: 'OK',
|
|
@@ -73,7 +104,7 @@ export class DirectusApiAdapter<
|
|
|
73
104
|
// Add the 'configuration' property to the returned object
|
|
74
105
|
const config: DirectusConfig = {
|
|
75
106
|
...this.config,
|
|
76
|
-
configuration: configuration ?? {} // Use the provided configuration or an empty object if not provided
|
|
107
|
+
configuration: configuration ?? this.config.configuration ?? {} // Use the provided configuration or an empty object if not provided
|
|
77
108
|
};
|
|
78
109
|
|
|
79
110
|
return Object.assign(client, config);
|
|
@@ -101,7 +132,13 @@ export class DirectusApiAdapter<
|
|
|
101
132
|
|
|
102
133
|
public async find<T>(collection: Path, query?: Record<string, unknown>): Promise<ApiResponse<T>> {
|
|
103
134
|
const response = await this.directus.request<T>(readItems(collection, query));
|
|
104
|
-
|
|
135
|
+
const total = await this.includeTotals(collection, query.filter);
|
|
136
|
+
if (null === total) {
|
|
137
|
+
return this.transformResponse({ data: response });
|
|
138
|
+
}
|
|
139
|
+
// console.log('find meta', response, total)
|
|
140
|
+
|
|
141
|
+
return this.transformResponse({ data: response, meta: { total } });
|
|
105
142
|
}
|
|
106
143
|
|
|
107
144
|
public async findOne<T>(
|
|
@@ -109,15 +146,15 @@ export class DirectusApiAdapter<
|
|
|
109
146
|
key?: ApiId,
|
|
110
147
|
query?: Record<string, unknown>
|
|
111
148
|
): Promise<ApiResponse<T>> {
|
|
112
|
-
const
|
|
113
|
-
return this.transformResponse(
|
|
149
|
+
const data = await this.directus.request<T>(readItem(collection, key, query));
|
|
150
|
+
return this.transformResponse({ data });
|
|
114
151
|
}
|
|
115
152
|
|
|
116
153
|
public async aggregate<T>(
|
|
117
154
|
collection: Path,
|
|
118
155
|
query?: Record<string, unknown>
|
|
119
156
|
): Promise<ApiResponse<T>> {
|
|
120
|
-
const
|
|
157
|
+
const data = await this.directus.request<T>(
|
|
121
158
|
aggregate(collection, {
|
|
122
159
|
aggregate: {
|
|
123
160
|
count: 'id'
|
|
@@ -125,7 +162,7 @@ export class DirectusApiAdapter<
|
|
|
125
162
|
query
|
|
126
163
|
})
|
|
127
164
|
);
|
|
128
|
-
return this.transformResponse(
|
|
165
|
+
return this.transformResponse({ data });
|
|
129
166
|
}
|
|
130
167
|
|
|
131
168
|
public async patch<T>(
|
|
@@ -133,8 +170,8 @@ export class DirectusApiAdapter<
|
|
|
133
170
|
key: ApiId,
|
|
134
171
|
query?: Record<string, unknown>
|
|
135
172
|
): Promise<ApiResponse<T>> {
|
|
136
|
-
const
|
|
137
|
-
return this.transformResponse(
|
|
173
|
+
const data = await this.directus.request<T>(updateItem(collection, key, query));
|
|
174
|
+
return this.transformResponse({ data });
|
|
138
175
|
}
|
|
139
176
|
|
|
140
177
|
public async post<T>(
|
|
@@ -143,18 +180,18 @@ export class DirectusApiAdapter<
|
|
|
143
180
|
query?: Record<string, unknown>
|
|
144
181
|
): Promise<ApiResponse<T>> {
|
|
145
182
|
const response = await this.directus.request<T>(createItem(collection, data, query));
|
|
146
|
-
return this.transformResponse(response, 201);
|
|
183
|
+
return this.transformResponse({ data: response }, 201);
|
|
147
184
|
}
|
|
148
185
|
|
|
149
186
|
public async delete<T>(collection: Path, key?: ApiId): Promise<ApiResponse<T>> {
|
|
150
|
-
const
|
|
151
|
-
return this.transformResponse(
|
|
187
|
+
const data = await this.directus.request<T>(deleteItem(collection, key));
|
|
188
|
+
return this.transformResponse({ data }, 202);
|
|
152
189
|
}
|
|
153
190
|
|
|
154
191
|
public async put<T>(collection: Path, key?: ApiId, payload?: AnyObject): Promise<ApiResponse<T>> {
|
|
155
192
|
if (key) {
|
|
156
|
-
const
|
|
157
|
-
return this.transformResponse(
|
|
193
|
+
const data = await this.directus.request<T>(updateItem(collection, key, payload));
|
|
194
|
+
return this.transformResponse({ data }, 201);
|
|
158
195
|
} else {
|
|
159
196
|
console.error(`Error updating all ${collection}: no key specified`);
|
|
160
197
|
throw new Error('No key specified');
|
|
@@ -164,24 +201,24 @@ export class DirectusApiAdapter<
|
|
|
164
201
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
165
202
|
public async upload<T>(path: string = '', data: FormData): Promise<ApiResponse<T>> {
|
|
166
203
|
const response = await this.directus.request<T>(uploadFiles(data));
|
|
167
|
-
return this.transformResponse(response, 201);
|
|
204
|
+
return this.transformResponse({ data: response }, 201);
|
|
168
205
|
}
|
|
169
206
|
|
|
170
207
|
async createMany<T, R = T>(path: Path, body: ApiCreateManyQuery<T>) {
|
|
171
|
-
const
|
|
172
|
-
return this.transformResponse<R[]>(
|
|
208
|
+
const data = await this.directus.request<T>(createItems(path, body.data));
|
|
209
|
+
return this.transformResponse<R[]>({ data }, 200);
|
|
173
210
|
}
|
|
174
211
|
|
|
175
212
|
async updateMany<T, R = T>(path: Path, body: ApiUpdateManyQuery<T>) {
|
|
176
213
|
if (!body.ids) {
|
|
177
214
|
throw Error('You must provide an array of keys to update');
|
|
178
215
|
}
|
|
179
|
-
const
|
|
180
|
-
return this.transformResponse<R[]>(
|
|
216
|
+
const data = await this.directus.request<T>(updateItems(path, body.ids || [], body.data));
|
|
217
|
+
return this.transformResponse<R[]>({ data }, 200);
|
|
181
218
|
}
|
|
182
219
|
|
|
183
220
|
async deleteMany<R = null>(path: Path, body: ApiDeleteManyQuery<ApiId>) {
|
|
184
|
-
const
|
|
185
|
-
return this.transformResponse<R>(
|
|
221
|
+
const data = await this.directus.request(deleteItems(path, body.ids));
|
|
222
|
+
return this.transformResponse<R>({ data } as R, 201);
|
|
186
223
|
}
|
|
187
224
|
}
|