@tanglemedia/svelte-starter-directus-api 0.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.
package/README.md ADDED
@@ -0,0 +1,3 @@
1
+ # Directus-api
2
+
3
+ _This package is experimental and is meant for internal use only._
package/dist/auth.d.ts ADDED
@@ -0,0 +1,15 @@
1
+ import type { DirectusClient, RestClient } from '@directus/sdk';
2
+ declare class ApiAuthDirectus {
3
+ private baseURL;
4
+ private directus;
5
+ constructor(baseURL: string);
6
+ private init;
7
+ getConfig<T extends object>(): DirectusClient<T> & RestClient<object>;
8
+ refresh<T>(): Promise<T>;
9
+ getToken<T>(): Promise<T>;
10
+ login<T>(email: string, password: string): Promise<T>;
11
+ logout<T>(): Promise<T>;
12
+ getCurrentUser<T>(fields?: string[] | null): Promise<T>;
13
+ updateCurrentUser<T>(data: object): Promise<T>;
14
+ }
15
+ export { ApiAuthDirectus };
package/dist/auth.js ADDED
@@ -0,0 +1,117 @@
1
+ import { createDirectus, rest, authentication, refresh, readMe, updateMe } from '@directus/sdk';
2
+ import { browser } from '$app/environment';
3
+ const localDirectusStorage = (storageKey = 'access_token_directus') => {
4
+ if (!browser || !window.localStorage) {
5
+ console.warn('Defaulting to memory storage');
6
+ return {
7
+ get: async () => null,
8
+ set: async (value) => { }
9
+ };
10
+ }
11
+ const storage = window.localStorage;
12
+ return {
13
+ get: async () => {
14
+ const data = storage.getItem(storageKey);
15
+ return data ? JSON.parse(data) : null;
16
+ },
17
+ set: async (value) => {
18
+ if (value === null) {
19
+ storage.removeItem(storageKey);
20
+ }
21
+ else {
22
+ storage.setItem(storageKey, JSON.stringify(value));
23
+ }
24
+ }
25
+ };
26
+ };
27
+ const authenticationConfig = {
28
+ storage: localDirectusStorage(),
29
+ autoRefresh: true,
30
+ msRefreshBeforeExpires: 30000,
31
+ credentials: 'include'
32
+ };
33
+ class ApiAuthDirectus {
34
+ baseURL;
35
+ directus;
36
+ constructor(baseURL) {
37
+ this.baseURL = baseURL;
38
+ this.init();
39
+ }
40
+ init() {
41
+ try {
42
+ this.directus = createDirectus(this.baseURL).with(rest({ credentials: 'include' })).with(authentication('json', authenticationConfig));
43
+ }
44
+ catch (error) {
45
+ console.error(`Error initializing Directus:`, error);
46
+ throw error;
47
+ }
48
+ }
49
+ getConfig() {
50
+ return this.directus;
51
+ }
52
+ async refresh() {
53
+ try {
54
+ const response = await this.directus.request(refresh());
55
+ return response;
56
+ }
57
+ catch (error) {
58
+ console.error(`Error refreshing :`, error);
59
+ throw error;
60
+ }
61
+ }
62
+ async getToken() {
63
+ try {
64
+ const response = await this.directus.getToken();
65
+ return response;
66
+ }
67
+ catch (error) {
68
+ console.error(`Error refreshing :`, error);
69
+ throw error;
70
+ }
71
+ }
72
+ async login(email, password) {
73
+ try {
74
+ const response = await this.directus.login(email, password);
75
+ return response;
76
+ }
77
+ catch (error) {
78
+ console.error(`Error login :`, error);
79
+ throw error;
80
+ }
81
+ }
82
+ async logout() {
83
+ try {
84
+ const response = await this.directus.logout();
85
+ return response;
86
+ }
87
+ catch (error) {
88
+ console.error(`Error refreshing :`, error);
89
+ throw error;
90
+ }
91
+ }
92
+ async getCurrentUser(fields = null) {
93
+ try {
94
+ if (!this.getToken())
95
+ await this.refresh();
96
+ const response = await this.directus.request(readMe({ fields: fields ? fields : ['*', 'roles.*'] }));
97
+ return response;
98
+ }
99
+ catch (error) {
100
+ console.error(`Error refreshing :`, error);
101
+ throw error;
102
+ }
103
+ }
104
+ async updateCurrentUser(data) {
105
+ try {
106
+ if (!this.getToken())
107
+ await this.refresh();
108
+ const response = await this.directus.request(updateMe(data));
109
+ return response;
110
+ }
111
+ catch (error) {
112
+ console.error(`Error refreshing :`, error);
113
+ throw error;
114
+ }
115
+ }
116
+ }
117
+ export { ApiAuthDirectus };
@@ -0,0 +1,20 @@
1
+ import type { ApiAdapterInterface, ApiAdapterRequestConfig, AnyObject, BaseApiAdapterConfig } from '@tanglemedia/svelte-starter-core';
2
+ type BaseApiMethods = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
3
+ type ApiId = string | number;
4
+ declare class ApiClientDirectus implements ApiAdapterInterface {
5
+ private baseURL;
6
+ private directus;
7
+ constructor(baseURL: string);
8
+ private init;
9
+ getConfig<T extends object>(configuration?: unknown): BaseApiAdapterConfig;
10
+ request<T>(method: BaseApiMethods, url: string, queryParams?: Record<string, any>): Promise<T>;
11
+ find<T>(collection: string, queryParams?: Record<string, unknown>): Promise<T>;
12
+ findOne<T>(collection: string, key?: ApiId, queryParams?: Record<string, unknown>): Promise<T>;
13
+ aggregate<T>(collection: string, queryParams?: Record<string, unknown>): Promise<T>;
14
+ patch<T>(collection: string, key: ApiId, queryParams?: Record<string, unknown>): Promise<T>;
15
+ post<T>(collection: string, data: AnyObject, queryParams?: Record<string, unknown>): Promise<T>;
16
+ delete<T>(collection: string, key?: ApiId): Promise<T>;
17
+ put<T>(collection: string, payload: AnyObject, config?: ApiAdapterRequestConfig, key?: ApiId): Promise<T>;
18
+ upload<T>(path: string | undefined, data: FormData): Promise<T>;
19
+ }
20
+ export { ApiClientDirectus };
package/dist/client.js ADDED
@@ -0,0 +1,161 @@
1
+ import { createDirectus, rest, authentication, readItems, readItem, updateItem, updateItems, createItem, createItems, deleteItem, deleteItems, aggregate, uploadFiles } from '@directus/sdk';
2
+ import { browser } from '$app/environment';
3
+ const localDirectusStorage = (storageKey = 'access_token_directus') => {
4
+ if (!browser || !window.localStorage) {
5
+ console.warn('Defaulting to memory storage');
6
+ return {
7
+ get: async () => null,
8
+ set: async (value) => { }
9
+ };
10
+ }
11
+ const storage = window.localStorage;
12
+ return {
13
+ get: async () => {
14
+ const data = storage.getItem(storageKey);
15
+ return data ? JSON.parse(data) : null;
16
+ },
17
+ set: async (value) => { }
18
+ };
19
+ };
20
+ const authenticationConfig = {
21
+ storage: localDirectusStorage(),
22
+ autoRefresh: true,
23
+ msRefreshBeforeExpires: 30000,
24
+ credentials: 'include'
25
+ };
26
+ class ApiClientDirectus {
27
+ baseURL;
28
+ directus;
29
+ constructor(baseURL) {
30
+ this.baseURL = baseURL;
31
+ this.init();
32
+ }
33
+ init() {
34
+ try {
35
+ this.directus = createDirectus(this.baseURL).with(rest({ credentials: 'include' })).with(authentication('json', authenticationConfig));
36
+ }
37
+ catch (error) {
38
+ console.error(`Error initializing Directus:`, error);
39
+ throw error;
40
+ }
41
+ }
42
+ getConfig(configuration) {
43
+ // return this.directus as DirectusClient<T> & RestClient<object>;
44
+ const client = this.directus;
45
+ // Add the 'configuration' property to the returned object
46
+ const config = {
47
+ configuration: configuration ?? {} // Use the provided configuration or an empty object if not provided
48
+ };
49
+ return Object.assign(client, config);
50
+ }
51
+ async request(method, url, queryParams) {
52
+ try {
53
+ const response = await this.directus.request(() => {
54
+ const params = JSON.stringify(queryParams);
55
+ return {
56
+ path: `${url}?${params}`,
57
+ method: method
58
+ };
59
+ });
60
+ return response;
61
+ }
62
+ catch (error) {
63
+ console.error(`Error request:`, error);
64
+ throw error;
65
+ }
66
+ }
67
+ async find(collection, queryParams) {
68
+ console.log('in find');
69
+ try {
70
+ // console.log(`Find ${collection}`)
71
+ const response = await this.directus.request(readItems(collection, queryParams));
72
+ return response;
73
+ }
74
+ catch (error) {
75
+ console.error(`Error fetching all ${collection}:`, error);
76
+ throw error;
77
+ }
78
+ }
79
+ async findOne(collection, key, queryParams) {
80
+ try {
81
+ const response = await this.directus.request(readItem(collection, key, queryParams));
82
+ return response;
83
+ }
84
+ catch (error) {
85
+ console.error(`Error fetching ${collection}:`, error);
86
+ throw error;
87
+ }
88
+ }
89
+ async aggregate(collection, queryParams) {
90
+ try {
91
+ const response = await this.directus.request(aggregate(collection, {
92
+ aggregate: {
93
+ count: 'id'
94
+ },
95
+ queryParams
96
+ }));
97
+ return response;
98
+ }
99
+ catch (error) {
100
+ console.error(`Error fetching total of ${collection}:`, error);
101
+ throw error;
102
+ }
103
+ }
104
+ async patch(collection, key, queryParams) {
105
+ try {
106
+ const response = await this.directus.request(updateItem(collection, key, queryParams));
107
+ return response;
108
+ }
109
+ catch (error) {
110
+ console.error(`Error updating all ${collection}:`, error);
111
+ throw error;
112
+ }
113
+ }
114
+ async post(collection, data, queryParams) {
115
+ try {
116
+ const response = await this.directus.request(createItem(collection, data, queryParams));
117
+ return response;
118
+ }
119
+ catch (error) {
120
+ console.error(`Error creating items ${collection}:`, error);
121
+ throw error;
122
+ }
123
+ }
124
+ async delete(collection, key) {
125
+ try {
126
+ const response = await this.directus.request(deleteItem(collection, key));
127
+ return response;
128
+ }
129
+ catch (error) {
130
+ console.error(`Error deleting items ${collection}:`, error);
131
+ throw error;
132
+ }
133
+ }
134
+ async put(collection, payload, config, key) {
135
+ try {
136
+ if (key) {
137
+ const response = await this.directus.request(updateItem(collection, key, payload));
138
+ return response;
139
+ }
140
+ else {
141
+ console.error(`Error updating all ${collection}: no key specified`);
142
+ throw new Error('No key specified');
143
+ }
144
+ }
145
+ catch (error) {
146
+ console.error(`Error updating all ${collection}:`, error);
147
+ throw error;
148
+ }
149
+ }
150
+ async upload(path = '', data) {
151
+ try {
152
+ const response = await this.directus.request(uploadFiles(data));
153
+ return response;
154
+ }
155
+ catch (error) {
156
+ console.error(`Error uploading file:`, error);
157
+ throw error;
158
+ }
159
+ }
160
+ }
161
+ export { ApiClientDirectus };
@@ -0,0 +1,4 @@
1
+ export * from './static';
2
+ export * from './client';
3
+ export * from './auth';
4
+ export * from './load-directus-api-povider';
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export * from './static';
2
+ export * from './client';
3
+ export * from './auth';
4
+ export * from './load-directus-api-povider';
@@ -0,0 +1,9 @@
1
+ import { type ApiAdapterProviderInterface, type ApiAdapterInterface, type ApiAdapterRequestConfig, type BaseApiAdapterConfig, type Config, type ApiConfigSchema } from '@tanglemedia/svelte-starter-core';
2
+ declare class LoadDirectusApiProvider implements ApiAdapterProviderInterface {
3
+ private readonly configLoader;
4
+ constructor(configLoader: () => Promise<Config<{
5
+ api?: ApiConfigSchema;
6
+ }>>);
7
+ loadAdapter(key?: string | undefined): Promise<ApiAdapterInterface<BaseApiAdapterConfig, ApiAdapterRequestConfig, string>>;
8
+ }
9
+ export { LoadDirectusApiProvider };
@@ -0,0 +1,43 @@
1
+ import { ApiClientDirectus } from './client';
2
+ import { ApiStaticDirectus } from './static';
3
+ import {} from '@tanglemedia/svelte-starter-core';
4
+ class LoadDirectusApiProvider {
5
+ configLoader;
6
+ constructor(configLoader) {
7
+ this.configLoader = configLoader;
8
+ }
9
+ async loadAdapter(key) {
10
+ const conf = await this.configLoader();
11
+ const config = (p) => conf.config(p);
12
+ const apiAdapterKey = key || config('api.default');
13
+ const directusType = config(`api.adapters.${apiAdapterKey}.type`) || 'client';
14
+ console.log(`api.apaters.${apiAdapterKey}.type`);
15
+ if (!apiAdapterKey) {
16
+ throw new Error(`No adapter key specified`);
17
+ }
18
+ console.log(apiAdapterKey);
19
+ console.log(directusType);
20
+ if (directusType) {
21
+ if (directusType === 'client') {
22
+ const protocol = config(`api.adapters.${apiAdapterKey}.protocol`) || '';
23
+ const host = config(`api.adapters.${apiAdapterKey}.host`) || '';
24
+ return new ApiClientDirectus(`${protocol}://${host}`.trim());
25
+ }
26
+ else {
27
+ console.log('static');
28
+ const protocol = config(`api.adapters.${apiAdapterKey}.protocol`) || '';
29
+ const host = config(`api.adapters.${apiAdapterKey}.host`) || '';
30
+ const accessToken = config(`api.adapters.${apiAdapterKey}.access_token`) || '';
31
+ return new ApiStaticDirectus(`${protocol}://${host}`.trim(), accessToken);
32
+ }
33
+ }
34
+ else {
35
+ console.log('client');
36
+ const protocol = config(`api.adapters.${apiAdapterKey}.protocol`) || '';
37
+ const host = config(`api.adapters.${apiAdapterKey}.host`) || '';
38
+ return new ApiClientDirectus(`${protocol}://${host}`.trim());
39
+ }
40
+ console.log('This should be unreachable');
41
+ }
42
+ }
43
+ export { LoadDirectusApiProvider };
@@ -0,0 +1,31 @@
1
+ import type { ApiAdapterInterface, ApiAdapterRequestConfig, AnyObject, BaseApiAdapterConfig } from '@tanglemedia/svelte-starter-core';
2
+ type BaseApiMethods = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
3
+ type ApiId = string | number;
4
+ declare class ApiStaticDirectus implements ApiAdapterInterface {
5
+ private baseURL;
6
+ private directusAccessToken;
7
+ private directus;
8
+ constructor(baseURL: string, directusAccessToken: string);
9
+ private init;
10
+ getConfig<T extends object>(configuration?: unknown): BaseApiAdapterConfig;
11
+ request<T>(method: BaseApiMethods, url: string, queryParams?: Record<string, any>): Promise<T>;
12
+ createUser(data: {
13
+ email: string;
14
+ password: string;
15
+ first_name: string;
16
+ last_name: string;
17
+ role: string;
18
+ } | object): Promise<{
19
+ message: string;
20
+ type: string;
21
+ }>;
22
+ find<T>(collection: string, queryParams?: Record<string, any>): Promise<T>;
23
+ findOne<T>(collection: string, key: ApiId, queryParams?: Record<string, any>): Promise<T>;
24
+ aggregate<T>(collection: string, queryParams?: Record<string, any>): Promise<T>;
25
+ patch<T>(collection: string, key: ApiId, queryParams?: Record<string, any>): Promise<T>;
26
+ post<T>(collection: string, data: AnyObject, queryParams?: Record<string, any>): Promise<T>;
27
+ delete<T>(collection: string, keys: ApiId): Promise<T>;
28
+ put<T>(collection: string, payload: AnyObject, config?: ApiAdapterRequestConfig, key?: ApiId): Promise<T>;
29
+ upload<T>(path: string | undefined, data: FormData): Promise<T>;
30
+ }
31
+ export { ApiStaticDirectus };
package/dist/static.js ADDED
@@ -0,0 +1,149 @@
1
+ import { createDirectus, rest, staticToken, readItems, readItem, updateItem, updateItems, createItem, createUser, deleteItem, aggregate, uploadFiles } from '@directus/sdk';
2
+ class ApiStaticDirectus {
3
+ baseURL;
4
+ directusAccessToken;
5
+ directus;
6
+ constructor(baseURL, directusAccessToken) {
7
+ this.baseURL = baseURL;
8
+ this.directusAccessToken = directusAccessToken;
9
+ this.init();
10
+ }
11
+ init() {
12
+ try {
13
+ this.directus = createDirectus(this.baseURL)
14
+ .with(rest())
15
+ .with(staticToken(this.directusAccessToken));
16
+ }
17
+ catch (error) {
18
+ console.error(`Error initializing Directus admin:`, error);
19
+ throw error;
20
+ }
21
+ }
22
+ getConfig(configuration) {
23
+ // return this.directus as DirectusClient<T> & RestClient<object>;
24
+ const client = this.directus;
25
+ // Add the 'configuration' property to the returned object
26
+ const config = {
27
+ configuration: configuration ?? {} // Use the provided configuration or an empty object if not provided
28
+ };
29
+ return Object.assign(client, config);
30
+ }
31
+ async request(method, url, queryParams) {
32
+ try {
33
+ const response = await this.directus.request(() => {
34
+ const params = JSON.stringify(queryParams);
35
+ return {
36
+ path: `${url}?${params}`,
37
+ method: method
38
+ };
39
+ });
40
+ return response;
41
+ }
42
+ catch (error) {
43
+ console.error(`Error request:`, error);
44
+ throw error;
45
+ }
46
+ }
47
+ async createUser(data) {
48
+ try {
49
+ await this.directus.request(createUser(data));
50
+ return { message: 'You have successfully registered your account', type: 'success' };
51
+ }
52
+ catch (error) {
53
+ console.error(`Error creating a user:`, error);
54
+ throw error;
55
+ }
56
+ }
57
+ async find(collection, queryParams) {
58
+ try {
59
+ const response = await this.directus.request(readItems(collection, queryParams));
60
+ return response;
61
+ }
62
+ catch (error) {
63
+ console.error(`Error fetching all ${collection}:`, error);
64
+ throw error;
65
+ }
66
+ }
67
+ async findOne(collection, key, queryParams) {
68
+ try {
69
+ const response = await this.directus.request(readItem(collection, key, queryParams));
70
+ return response;
71
+ }
72
+ catch (error) {
73
+ console.error(`Error fetching ${collection}:`, error);
74
+ throw error;
75
+ }
76
+ }
77
+ async aggregate(collection, queryParams) {
78
+ try {
79
+ const response = await this.directus.request(aggregate(collection, {
80
+ aggregate: {
81
+ count: 'id'
82
+ },
83
+ queryParams
84
+ }));
85
+ return response;
86
+ }
87
+ catch (error) {
88
+ console.error(`Error fetching total of ${collection}:`, error);
89
+ throw error;
90
+ }
91
+ }
92
+ async patch(collection, key, queryParams) {
93
+ try {
94
+ const response = await this.directus.request(updateItems(collection, key, queryParams));
95
+ return response;
96
+ }
97
+ catch (error) {
98
+ console.error(`Error updating all ${collection}:`, error);
99
+ throw error;
100
+ }
101
+ }
102
+ async post(collection, data, queryParams) {
103
+ try {
104
+ const response = await this.directus.request(createItem(collection, data, queryParams));
105
+ return response;
106
+ }
107
+ catch (error) {
108
+ console.error(`Error creating items ${collection}:`, error);
109
+ throw error;
110
+ }
111
+ }
112
+ async delete(collection, keys) {
113
+ try {
114
+ const response = await this.directus.request(deleteItem(collection, key));
115
+ return response;
116
+ }
117
+ catch (error) {
118
+ console.error(`Error deleting items ${collection}:`, error);
119
+ throw error;
120
+ }
121
+ }
122
+ async put(collection, payload, config, key) {
123
+ try {
124
+ if (key) {
125
+ const response = await this.directus.request(updateItem(collection, key, payload));
126
+ return response;
127
+ }
128
+ else {
129
+ console.error(`Error updating all ${collection}: no key specified`);
130
+ throw new Error('No key specified');
131
+ }
132
+ }
133
+ catch (error) {
134
+ console.error(`Error updating all ${collection}:`, error);
135
+ throw error;
136
+ }
137
+ }
138
+ async upload(path = '', data) {
139
+ try {
140
+ const response = await this.directus.request(uploadFiles(data));
141
+ return response;
142
+ }
143
+ catch (error) {
144
+ console.error(`Error uploading file:`, error);
145
+ throw error;
146
+ }
147
+ }
148
+ }
149
+ export { ApiStaticDirectus };
package/package.json ADDED
@@ -0,0 +1,65 @@
1
+ {
2
+ "name": "@tanglemedia/svelte-starter-directus-api",
3
+ "version": "0.0.1",
4
+ "main": "src/index.ts",
5
+ "types": "src/index.ts",
6
+ "description": "directus API wrapper for all the directus sdk functionality",
7
+ "type": "module",
8
+ "module": "src/index.ts",
9
+ "svelte": "src/index.ts",
10
+ "license": "MIT",
11
+ "files": [
12
+ "dist",
13
+ "src",
14
+ "!tests"
15
+ ],
16
+ "exports": {
17
+ ".": {
18
+ "types": "./dist/index.d.ts",
19
+ "svelte": "./dist/index.js",
20
+ "import": "./dist/index.js",
21
+ "default": "./dist/index.js"
22
+ }
23
+ },
24
+ "devDependencies": {
25
+ "@sveltejs/adapter-auto": "^2.1.1",
26
+ "@sveltejs/package": "^2.2.2",
27
+ "@testing-library/jest-dom": "^6.1.4",
28
+ "@testing-library/svelte": "^4.0.5",
29
+ "@vitest/coverage-v8": "^0.34.6",
30
+ "jsdom": "^22.1.0",
31
+ "msw": "^2.0.8",
32
+ "svelte": "^4.2.7",
33
+ "svelte-check": "^3.6.0",
34
+ "vite": "^4.5.0",
35
+ "vitest": "^0.34.6",
36
+ "eslint-config-custom": "0.0.0"
37
+ },
38
+ "dependencies": {
39
+ "@directus/sdk": "^13.0.2",
40
+ "@tanglemedia/svelte-starter-core": "^0.0.5",
41
+ "flowbite-svelte": "^0.44.19",
42
+ "fontawesome-svelte": "^2.0.1",
43
+ "svelte-fa": "^3.0.4",
44
+ "tailwind-merge": "^2.0.0"
45
+ },
46
+ "peerDependencies": {
47
+ "@sveltejs/kit": ">=1.20 <2",
48
+ "svelte": ">=4 <5"
49
+ },
50
+ "babelMacros": {
51
+ "fontawesome-svg-core": {
52
+ "license": "free"
53
+ }
54
+ },
55
+ "scripts": {
56
+ "build": "svelte-package --input ./src --output ./dist",
57
+ "dev": "npm run build -- --watch",
58
+ "lint": "prettier --check --ignore-path=../../.prettierignore . && eslint \".\" --ignore-path=../../.prettierignore",
59
+ "format": "prettier --write --ignore-path=../../.prettierignore . && eslint \".\" --ignore-path=../../.prettierignore",
60
+ "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
61
+ "test": "vitest",
62
+ "test:debug": "vitest --test-timeout=0 --reporter=verbose --coverage",
63
+ "clean": "rimraf ./dist && rimraf ./coverage"
64
+ }
65
+ }
package/src/auth.ts ADDED
@@ -0,0 +1,133 @@
1
+ import {
2
+ createDirectus,
3
+ rest,
4
+ authentication,
5
+ refresh,
6
+ readMe,
7
+ updateMe
8
+ } from '@directus/sdk';
9
+ import type { AuthenticationData, AuthenticationConfig } from '@directus/sdk';
10
+
11
+ import type { DirectusClient, RestClient } from '@directus/sdk';
12
+
13
+ import { browser } from '$app/environment';
14
+
15
+ const localDirectusStorage = (storageKey: string = 'access_token_directus') => {
16
+ if (!browser || !window.localStorage) {
17
+ console.warn('Defaulting to memory storage');
18
+ return {
19
+ get: async (): Promise<AuthenticationData | null> => null,
20
+ set: async (value: AuthenticationData | null): Promise<void> => {}
21
+ };
22
+ }
23
+
24
+ const storage = window.localStorage;
25
+
26
+ return {
27
+ get: async (): Promise<AuthenticationData | null> => {
28
+ const data = storage.getItem(storageKey);
29
+ return data ? (JSON.parse(data) as AuthenticationData) : null;
30
+ },
31
+ set: async (value: AuthenticationData | null): Promise<void> => {
32
+ if (value === null) {
33
+ storage.removeItem(storageKey);
34
+ } else {
35
+ storage.setItem(storageKey, JSON.stringify(value));
36
+ }
37
+ }
38
+ };
39
+ };
40
+
41
+ const authenticationConfig: AuthenticationConfig = {
42
+ storage: localDirectusStorage(),
43
+ autoRefresh: true,
44
+ msRefreshBeforeExpires: 30000,
45
+ credentials: 'include'
46
+ };
47
+
48
+ class ApiAuthDirectus {
49
+ private baseURL: string;
50
+ private directus: DirectusClient<object> & RestClient<object>;
51
+
52
+ constructor(baseURL: string) {
53
+ this.baseURL = baseURL;
54
+ this.init();
55
+ }
56
+
57
+ private init<T extends object>(): void {
58
+ try {
59
+ this.directus = createDirectus<T>(this.baseURL).with(rest({credentials: 'include'})).with(authentication('json', authenticationConfig))
60
+ } catch (error) {
61
+ console.error(`Error initializing Directus:`, error);
62
+ throw error;
63
+ }
64
+ }
65
+
66
+ public getConfig<T extends object>(): DirectusClient<T> & RestClient<object> {
67
+ return this.directus as DirectusClient<T> & RestClient<object>;
68
+ }
69
+
70
+ public async refresh<T>(): Promise<T> {
71
+ try {
72
+ const response = await this.directus.request<T>(refresh());
73
+ return response;
74
+ } catch (error) {
75
+ console.error(`Error refreshing :`, error);
76
+ throw error;
77
+ }
78
+ }
79
+
80
+ public async getToken<T>(): Promise<T> {
81
+ try {
82
+ const response = await this.directus.getToken();
83
+ return response;
84
+ } catch (error) {
85
+ console.error(`Error refreshing :`, error);
86
+ throw error;
87
+ }
88
+ }
89
+
90
+ public async login<T>(email: string, password: string): Promise<T> {
91
+ try {
92
+ const response = await this.directus.login(email, password);
93
+ return response;
94
+ } catch (error) {
95
+ console.error(`Error login :`, error);
96
+ throw error;
97
+ }
98
+ }
99
+
100
+ public async logout<T>(): Promise<T> {
101
+ try {
102
+ const response = await this.directus.logout();
103
+ return response;
104
+ } catch (error) {
105
+ console.error(`Error refreshing :`, error);
106
+ throw error;
107
+ }
108
+ }
109
+
110
+ public async getCurrentUser<T>(fields: string[] | null = null): Promise<T> {
111
+ try {
112
+ if (!this.getToken()) await this.refresh();
113
+ const response = await this.directus.request<T>(readMe({fields: fields ? fields : ['*', 'roles.*']}));
114
+ return response;
115
+ } catch (error) {
116
+ console.error(`Error refreshing :`, error);
117
+ throw error;
118
+ }
119
+ }
120
+
121
+ public async updateCurrentUser<T>(data: object): Promise<T> {
122
+ try {
123
+ if (!this.getToken()) await this.refresh();
124
+ const response = await this.directus.request<T>(updateMe(data));
125
+ return response;
126
+ } catch (error) {
127
+ console.error(`Error refreshing :`, error);
128
+ throw error;
129
+ }
130
+ }
131
+ }
132
+
133
+ export { ApiAuthDirectus };
package/src/client.ts ADDED
@@ -0,0 +1,196 @@
1
+ import {
2
+ createDirectus,
3
+ rest,
4
+ authentication,
5
+ readItems,
6
+ readItem,
7
+ updateItem,
8
+ updateItems,
9
+ createItem,
10
+ createItems,
11
+ deleteItem,
12
+ deleteItems,
13
+ aggregate,
14
+ uploadFiles
15
+ } from '@directus/sdk';
16
+ import type { AuthenticationData, AuthenticationConfig } from '@directus/sdk';
17
+
18
+ import type { DirectusClient, RestClient } from '@directus/sdk';
19
+
20
+ import type { ApiAdapterInterface, ApiAdapterRequestConfig, AnyObject, BaseApiAdapterConfig } from '@tanglemedia/svelte-starter-core';
21
+
22
+ import { browser } from '$app/environment';
23
+
24
+ const localDirectusStorage = (storageKey: string = 'access_token_directus') => {
25
+ if (!browser || !window.localStorage) {
26
+ console.warn('Defaulting to memory storage');
27
+ return {
28
+ get: async (): Promise<AuthenticationData | null> => null,
29
+ set: async (value: AuthenticationData | null): Promise<void> => {}
30
+ };
31
+ }
32
+
33
+ const storage = window.localStorage;
34
+
35
+ return {
36
+ get: async (): Promise<AuthenticationData | null> => {
37
+ const data = storage.getItem(storageKey);
38
+ return data ? (JSON.parse(data) as AuthenticationData) : null;
39
+ },
40
+ set: async (value: AuthenticationData | null): Promise<void> => {}
41
+ };
42
+ };
43
+
44
+ const authenticationConfig: AuthenticationConfig = {
45
+ storage: localDirectusStorage(),
46
+ autoRefresh: true,
47
+ msRefreshBeforeExpires: 30000,
48
+ credentials: 'include'
49
+ };
50
+
51
+ type BaseApiMethods = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
52
+
53
+ type ApiId = string | number;
54
+
55
+ class ApiClientDirectus implements ApiAdapterInterface {
56
+ private baseURL: string;
57
+ private directus: DirectusClient<object> & RestClient<object>;
58
+
59
+ constructor(baseURL: string) {
60
+ this.baseURL = baseURL;
61
+ this.init();
62
+ }
63
+
64
+ private init<T extends object>(): void {
65
+ try {
66
+ this.directus = createDirectus<T>(this.baseURL).with(rest({credentials: 'include'})).with(authentication('json', authenticationConfig))
67
+ } catch (error) {
68
+ console.error(`Error initializing Directus:`, error);
69
+ throw error;
70
+ }
71
+ }
72
+
73
+ public getConfig<T extends object>(configuration?: unknown): BaseApiAdapterConfig {
74
+ // return this.directus as DirectusClient<T> & RestClient<object>;
75
+ const client = this.directus as DirectusClient<T> & RestClient<object>;
76
+
77
+ // Add the 'configuration' property to the returned object
78
+ const config: BaseApiAdapterConfig = {
79
+ configuration: configuration ?? {} // Use the provided configuration or an empty object if not provided
80
+ };
81
+
82
+ return Object.assign(client, config);
83
+ }
84
+
85
+ public async request<T>(method: BaseApiMethods, url: string, queryParams?: Record<string, any>): Promise<T> {
86
+ try {
87
+ const response = await this.directus.request<T>(() => {
88
+ const params = JSON.stringify(queryParams);
89
+ return {
90
+ path: `${url}?${params}`,
91
+ method: method
92
+ };
93
+ });
94
+ return response;
95
+ } catch (error) {
96
+ console.error(`Error request:`, error);
97
+ throw error;
98
+ }
99
+ }
100
+
101
+ public async find<T>(collection: string, queryParams?: Record<string, unknown>): Promise<T> {
102
+ console.log('in find')
103
+ try {
104
+ // console.log(`Find ${collection}`)
105
+ const response = await this.directus.request<T>(readItems(collection, queryParams));
106
+ return response;
107
+ } catch (error) {
108
+ console.error(`Error fetching all ${collection}:`, error);
109
+ throw error;
110
+ }
111
+ }
112
+
113
+ public async findOne<T>(collection: string, key?: ApiId, queryParams?: Record<string, unknown>): Promise<T> {
114
+ try {
115
+ const response = await this.directus.request<T>(readItem(collection, key, queryParams));
116
+ return response;
117
+ } catch (error) {
118
+ console.error(`Error fetching ${collection}:`, error);
119
+ throw error;
120
+ }
121
+ }
122
+
123
+ public async aggregate<T>(collection: string, queryParams?: Record<string, unknown>): Promise<T> {
124
+ try {
125
+ const response = await this.directus.request<T>(aggregate(collection, {
126
+ aggregate: {
127
+ count: 'id'
128
+ },
129
+ queryParams
130
+ }));
131
+ return response;
132
+ } catch (error) {
133
+ console.error(`Error fetching total of ${collection}:`, error);
134
+ throw error;
135
+ }
136
+ }
137
+
138
+ public async patch<T>(collection: string, key: ApiId, queryParams?: Record<string, unknown>): Promise<T> {
139
+ try {
140
+ const response = await this.directus.request<T>(updateItem(collection, key, queryParams));
141
+ return response;
142
+ } catch (error) {
143
+ console.error(`Error updating all ${collection}:`, error);
144
+ throw error;
145
+ }
146
+ }
147
+
148
+ public async post<T>(collection: string, data: AnyObject, queryParams?: Record<string, unknown>): Promise<T> {
149
+ try {
150
+ const response = await this.directus.request<T>(createItem(collection, data, queryParams));
151
+ return response;
152
+ } catch (error) {
153
+ console.error(`Error creating items ${collection}:`, error);
154
+ throw error;
155
+ }
156
+ }
157
+
158
+ public async delete<T>(collection: string, key?: ApiId): Promise<T> {
159
+ try {
160
+ const response = await this.directus.request<T>(deleteItem(collection, key));
161
+ return response;
162
+ } catch (error) {
163
+ console.error(`Error deleting items ${collection}:`, error);
164
+ throw error;
165
+ }
166
+ }
167
+
168
+ public async put<T>(collection: string, payload: AnyObject, config?: ApiAdapterRequestConfig, key?: ApiId): Promise<T> {
169
+ try {
170
+ if(key){
171
+ const response = await this.directus.request<T>(updateItem(collection, key, payload));
172
+ return response;
173
+ }else {
174
+ console.error(`Error updating all ${collection}: no key specified`);
175
+ throw new Error('No key specified');
176
+ }
177
+ } catch (error) {
178
+ console.error(`Error updating all ${collection}:`, error);
179
+ throw error;
180
+ }
181
+ }
182
+
183
+
184
+ public async upload<T>(path: string = '', data: FormData): Promise<T> {
185
+ try {
186
+ const response = await this.directus.request<T>(uploadFiles(data));
187
+ return response;
188
+ } catch (error) {
189
+ console.error(`Error uploading file:`, error);
190
+ throw error;
191
+ }
192
+ }
193
+
194
+ }
195
+
196
+ export { ApiClientDirectus };
package/src/index.ts ADDED
@@ -0,0 +1,4 @@
1
+ export * from './static';
2
+ export * from './client';
3
+ export * from './auth';
4
+ export * from './load-directus-api-povider';
@@ -0,0 +1,47 @@
1
+ import { ApiClientDirectus } from './client';
2
+ import { ApiStaticDirectus } from './static';
3
+ import { type ApiAdapterProviderInterface, type ApiAdapterInterface, type ApiAdapterRequestConfig, type BaseApiAdapterConfig, type Config, type ApiConfigSchema } from '@tanglemedia/svelte-starter-core';
4
+
5
+ class LoadDirectusApiProvider implements ApiAdapterProviderInterface {
6
+
7
+ constructor(
8
+ private readonly configLoader: () => Promise<Config<{ api?: ApiConfigSchema }>>,
9
+ ) { }
10
+
11
+ async loadAdapter(key?: string | undefined): Promise<ApiAdapterInterface<BaseApiAdapterConfig, ApiAdapterRequestConfig, string>> {
12
+ const conf = await this.configLoader();
13
+ const config = (p: string) => conf.config(p);
14
+
15
+ const apiAdapterKey = key || (config('api.default') as string);
16
+ const directusType = (config(`api.adapters.${apiAdapterKey}.type`) as string) || 'client';
17
+ console.log(`api.apaters.${apiAdapterKey}.type`)
18
+
19
+ if (!apiAdapterKey) {
20
+ throw new Error(`No adapter key specified`);
21
+ }
22
+ console.log(apiAdapterKey)
23
+ console.log(directusType)
24
+ if (directusType) {
25
+ if (directusType === 'client') {
26
+ const protocol: string = config(`api.adapters.${apiAdapterKey}.protocol`) || '';
27
+ const host: string = config(`api.adapters.${apiAdapterKey}.host`) || '';
28
+ return new ApiClientDirectus(`${protocol}://${host}`.trim());
29
+ } else {
30
+ console.log('static');
31
+ const protocol: string = config(`api.adapters.${apiAdapterKey}.protocol`) || '';
32
+ const host: string = config(`api.adapters.${apiAdapterKey}.host`) || '';
33
+ const accessToken: string = config(`api.adapters.${apiAdapterKey}.access_token`) || '';
34
+ return new ApiStaticDirectus(`${protocol}://${host}`.trim(), accessToken);
35
+ }
36
+ } else {
37
+ console.log('client');
38
+ const protocol: string = config(`api.adapters.${apiAdapterKey}.protocol`) || '';
39
+ const host: string = config(`api.adapters.${apiAdapterKey}.host`) || '';
40
+ return new ApiClientDirectus(`${protocol}://${host}`.trim());
41
+ }
42
+
43
+ console.log('This should be unreachable')
44
+ }
45
+ }
46
+
47
+ export { LoadDirectusApiProvider }
package/src/static.ts ADDED
@@ -0,0 +1,176 @@
1
+ import {
2
+ createDirectus,
3
+ rest,
4
+ staticToken,
5
+ readItems,
6
+ readItem,
7
+ updateItem,
8
+ updateItems,
9
+ createItem,
10
+ createUser,
11
+ deleteItem,
12
+ aggregate,
13
+ uploadFiles
14
+ } from '@directus/sdk';
15
+
16
+ import type { DirectusClient, RestClient, StaticTokenClient } from '@directus/sdk';
17
+
18
+ import type { ApiAdapterInterface, ApiAdapterRequestConfig, AnyObject, BaseApiAdapterConfig } from '@tanglemedia/svelte-starter-core';
19
+
20
+ type BaseApiMethods = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
21
+
22
+ type ApiId = string | number;
23
+
24
+ class ApiStaticDirectus implements ApiAdapterInterface {
25
+ private baseURL: string;
26
+ private directusAccessToken: string;
27
+ private directus: DirectusClient<any> & RestClient<object> & StaticTokenClient<object>;
28
+
29
+ constructor(baseURL: string, directusAccessToken: string) {
30
+ this.baseURL = baseURL;
31
+ this.directusAccessToken = directusAccessToken;
32
+ this.init();
33
+ }
34
+
35
+ private init<T extends object>(): void {
36
+ try {
37
+ this.directus = createDirectus<T>(this.baseURL)
38
+ .with(rest())
39
+ .with(staticToken(this.directusAccessToken));
40
+ } catch (error) {
41
+ console.error(`Error initializing Directus admin:`, error);
42
+ throw error;
43
+ }
44
+ }
45
+
46
+ public getConfig<T extends object>(configuration?: unknown): BaseApiAdapterConfig {
47
+ // return this.directus as DirectusClient<T> & RestClient<object>;
48
+ const client = this.directus as DirectusClient<T> & RestClient<object>;
49
+
50
+ // Add the 'configuration' property to the returned object
51
+ const config: BaseApiAdapterConfig = {
52
+ configuration: configuration ?? {} // Use the provided configuration or an empty object if not provided
53
+ };
54
+
55
+ return Object.assign(client, config);
56
+ }
57
+
58
+ public async request<T>(method: BaseApiMethods, url: string, queryParams?: Record<string, any>): Promise<T> {
59
+ try {
60
+ const response = await this.directus.request<T>(() => {
61
+ const params = JSON.stringify(queryParams);
62
+ return {
63
+ path: `${url}?${params}`,
64
+ method: method
65
+ };
66
+ });
67
+ return response;
68
+ } catch (error) {
69
+ console.error(`Error request:`, error);
70
+ throw error;
71
+ }
72
+ }
73
+
74
+ public async createUser(data: {email: string, password: string, first_name: string, last_name: string, role: string} | object): Promise<{ message: string; type: string; }> {
75
+ try {
76
+ await this.directus.request(createUser(data));
77
+
78
+ return { message: 'You have successfully registered your account', type: 'success' };
79
+ } catch (error) {
80
+ console.error(`Error creating a user:`, error);
81
+ throw error;
82
+ }
83
+ }
84
+
85
+ public async find<T>(collection: string, queryParams?: Record<string, any>): Promise<T> {
86
+ try {
87
+ const response = await this.directus.request<T>(readItems(collection, queryParams));
88
+ return response;
89
+ } catch (error) {
90
+ console.error(`Error fetching all ${collection}:`, error);
91
+ throw error;
92
+ }
93
+ }
94
+
95
+ public async findOne<T>(collection: string, key: ApiId, queryParams?: Record<string, any>): Promise<T> {
96
+ try {
97
+ const response = await this.directus.request<T>(readItem(collection, key, queryParams));
98
+ return response;
99
+ } catch (error) {
100
+ console.error(`Error fetching ${collection}:`, error);
101
+ throw error;
102
+ }
103
+ }
104
+
105
+ public async aggregate<T>(collection: string, queryParams?: Record<string, any>): Promise<T> {
106
+ try {
107
+ const response = await this.directus.request<T>(aggregate(collection, {
108
+ aggregate: {
109
+ count: 'id'
110
+ },
111
+ queryParams
112
+ }));
113
+ return response;
114
+ } catch (error) {
115
+ console.error(`Error fetching total of ${collection}:`, error);
116
+ throw error;
117
+ }
118
+ }
119
+
120
+ public async patch<T>(collection: string, key: ApiId, queryParams?: Record<string, any>): Promise<T> {
121
+ try {
122
+ const response = await this.directus.request<T>(updateItems(collection, key, queryParams));
123
+ return response;
124
+ } catch (error) {
125
+ console.error(`Error updating all ${collection}:`, error);
126
+ throw error;
127
+ }
128
+ }
129
+
130
+ public async post<T>(collection: string, data: AnyObject, queryParams?: Record<string, any>): Promise<T> {
131
+ try {
132
+ const response = await this.directus.request<T>(createItem(collection, data, queryParams));
133
+ return response;
134
+ } catch (error) {
135
+ console.error(`Error creating items ${collection}:`, error);
136
+ throw error;
137
+ }
138
+ }
139
+
140
+ public async delete<T>(collection: string, keys: ApiId): Promise<T> {
141
+ try {
142
+ const response = await this.directus.request<T>(deleteItem(collection, key));
143
+ return response;
144
+ } catch (error) {
145
+ console.error(`Error deleting items ${collection}:`, error);
146
+ throw error;
147
+ }
148
+ }
149
+
150
+ public async put<T>(collection: string, payload: AnyObject, config?: ApiAdapterRequestConfig, key?: ApiId): Promise<T> {
151
+ try {
152
+ if(key){
153
+ const response = await this.directus.request<T>(updateItem(collection, key, payload));
154
+ return response;
155
+ }else {
156
+ console.error(`Error updating all ${collection}: no key specified`);
157
+ throw new Error('No key specified');
158
+ }
159
+ } catch (error) {
160
+ console.error(`Error updating all ${collection}:`, error);
161
+ throw error;
162
+ }
163
+ }
164
+
165
+ public async upload<T>(path: string = '', data: FormData): Promise<T> {
166
+ try {
167
+ const response = await this.directus.request<T>(uploadFiles(data));
168
+ return response;
169
+ } catch (error) {
170
+ console.error(`Error uploading file:`, error);
171
+ throw error;
172
+ }
173
+ }
174
+ }
175
+
176
+ export { ApiStaticDirectus };