create-ng-tailwind 3.1.0 → 4.1.0
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.
Potentially problematic release.
This version of create-ng-tailwind might be problematic. Click here for more details.
- package/CHANGELOG.md +96 -341
- package/README.md +111 -157
- package/lib/cli/index.js +74 -3
- package/lib/cli/interactive.js +26 -1
- package/lib/managers/ProjectManager.js +2 -5
- package/lib/templates/base/components.js +243 -0
- package/lib/templates/base/index.js +207 -0
- package/lib/templates/base/infrastructure.js +314 -0
- package/lib/templates/base/linting.js +359 -0
- package/lib/templates/base/pwa.js +103 -0
- package/lib/templates/base/services.js +362 -0
- package/lib/templates/blog/app.js +250 -0
- package/lib/templates/blog/components.js +360 -0
- package/lib/templates/blog/i18n.js +77 -0
- package/lib/templates/blog/index.js +126 -0
- package/lib/templates/blog/pages.js +554 -0
- package/lib/templates/blog/services.js +390 -0
- package/lib/templates/dashboard/app.js +320 -0
- package/lib/templates/dashboard/charts.js +305 -0
- package/lib/templates/dashboard/components.js +410 -0
- package/lib/templates/dashboard/i18n.js +340 -0
- package/lib/templates/dashboard/index.js +141 -0
- package/lib/templates/dashboard/layout.js +310 -0
- package/lib/templates/dashboard/pages.js +681 -0
- package/lib/templates/ecommerce/app.js +315 -0
- package/lib/templates/ecommerce/components.js +496 -0
- package/lib/templates/ecommerce/i18n.js +389 -0
- package/lib/templates/ecommerce/index.js +152 -0
- package/lib/templates/ecommerce/layout.js +270 -0
- package/lib/templates/ecommerce/pages.js +969 -0
- package/lib/templates/ecommerce/services.js +300 -0
- package/lib/templates/index.js +12 -0
- package/lib/templates/landing/index.js +1117 -0
- package/lib/templates/portfolio/index.js +1160 -0
- package/lib/templates/saas/index.js +1371 -0
- package/lib/templates/starter/app.js +364 -0
- package/lib/templates/starter/i18n.js +856 -0
- package/lib/templates/starter/index.js +52 -4060
- package/lib/templates/starter/layout.js +852 -0
- package/lib/templates/starter/pages.js +1241 -0
- package/lib/utils/nodeCompat.js +85 -0
- package/package.json +1 -1
- package/lib/templates/starter/features.js +0 -867
- package/lib/utils/ai-config.js +0 -641
- /package/lib/templates/{starter → base}/advanced-features.js +0 -0
- /package/lib/templates/{starter → base}/seo-assets.js +0 -0
- /package/lib/templates/{starter → base}/seo-features.js +0 -0
- /package/lib/templates/{starter → base}/ui-features.js +0 -0
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
const fs = require('fs-extra');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Setup PWA (Progressive Web App) configuration
|
|
6
|
+
*/
|
|
7
|
+
async function setupPWA(config) {
|
|
8
|
+
// Create manifest.json
|
|
9
|
+
const manifest = {
|
|
10
|
+
name: config.projectName,
|
|
11
|
+
short_name: config.projectName,
|
|
12
|
+
theme_color: '#3b82f6',
|
|
13
|
+
background_color: '#ffffff',
|
|
14
|
+
display: 'standalone',
|
|
15
|
+
scope: '/',
|
|
16
|
+
start_url: '/',
|
|
17
|
+
description: `${config.projectName} - Built with Angular and Tailwind CSS`,
|
|
18
|
+
icons: [
|
|
19
|
+
{
|
|
20
|
+
src: 'assets/icons/android-chrome-192x192.svg',
|
|
21
|
+
sizes: '192x192',
|
|
22
|
+
type: 'image/svg+xml',
|
|
23
|
+
purpose: 'maskable any',
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
src: 'assets/icons/android-chrome-512x512.svg',
|
|
27
|
+
sizes: '512x512',
|
|
28
|
+
type: 'image/svg+xml',
|
|
29
|
+
purpose: 'maskable any',
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
// Write manifest to public directory (new Angular structure)
|
|
35
|
+
await fs.ensureDir(path.join(config.fullPath, 'public'));
|
|
36
|
+
await fs.writeFile(
|
|
37
|
+
path.join(config.fullPath, 'public/manifest.webmanifest'),
|
|
38
|
+
JSON.stringify(manifest, null, 2)
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
// Create ngsw-config.json (Service Worker configuration)
|
|
42
|
+
const ngswConfig = {
|
|
43
|
+
$schema: './node_modules/@angular/service-worker/config/schema.json',
|
|
44
|
+
index: '/index.html',
|
|
45
|
+
assetGroups: [
|
|
46
|
+
{
|
|
47
|
+
name: 'app',
|
|
48
|
+
installMode: 'prefetch',
|
|
49
|
+
resources: {
|
|
50
|
+
files: ['/favicon.ico', '/index.html', '/manifest.webmanifest', '/*.css', '/*.js'],
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
name: 'assets',
|
|
55
|
+
installMode: 'lazy',
|
|
56
|
+
updateMode: 'prefetch',
|
|
57
|
+
resources: {
|
|
58
|
+
files: [
|
|
59
|
+
'/assets/**',
|
|
60
|
+
'/*.(svg|cur|jpg|jpeg|png|apng|webp|avif|gif|otf|ttf|woff|woff2)',
|
|
61
|
+
],
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
],
|
|
65
|
+
dataGroups: [
|
|
66
|
+
{
|
|
67
|
+
name: 'api',
|
|
68
|
+
urls: ['https://api.example.com/**'],
|
|
69
|
+
cacheConfig: {
|
|
70
|
+
maxSize: 100,
|
|
71
|
+
maxAge: '1h',
|
|
72
|
+
timeout: '10s',
|
|
73
|
+
strategy: 'freshness',
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
],
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
await fs.writeFile(
|
|
80
|
+
path.join(config.fullPath, 'ngsw-config.json'),
|
|
81
|
+
JSON.stringify(ngswConfig, null, 2)
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
// Update index.html to include PWA assets
|
|
85
|
+
const indexPath = path.join(config.fullPath, 'src/index.html');
|
|
86
|
+
let indexContent = await fs.readFile(indexPath, 'utf8');
|
|
87
|
+
|
|
88
|
+
// Add manifest link and theme color meta tag if not present
|
|
89
|
+
if (!indexContent.includes('manifest.webmanifest')) {
|
|
90
|
+
indexContent = indexContent.replace(
|
|
91
|
+
'</head>',
|
|
92
|
+
` <link rel="manifest" href="manifest.webmanifest">
|
|
93
|
+
<meta name="theme-color" content="#3b82f6">
|
|
94
|
+
<link rel="apple-touch-icon" href="assets/icons/apple-touch-icon.svg">
|
|
95
|
+
</head>`
|
|
96
|
+
);
|
|
97
|
+
await fs.writeFile(indexPath, indexContent);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
module.exports = {
|
|
102
|
+
setupPWA,
|
|
103
|
+
};
|
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
const fs = require('fs-extra');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Create API Service
|
|
6
|
+
*/
|
|
7
|
+
async function createApiService(config) {
|
|
8
|
+
const apiService = `import { Injectable, inject } from '@angular/core';
|
|
9
|
+
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
|
|
10
|
+
import { Observable, throwError } from 'rxjs';
|
|
11
|
+
import { catchError, retry } from 'rxjs/operators';
|
|
12
|
+
|
|
13
|
+
import { ApiResponse } from '@shared/models/api-response.interface';
|
|
14
|
+
|
|
15
|
+
@Injectable({
|
|
16
|
+
providedIn: 'root'
|
|
17
|
+
})
|
|
18
|
+
export class ApiService {
|
|
19
|
+
private http = inject(HttpClient);
|
|
20
|
+
private readonly baseUrl = 'https://api.example.com'; // Configure your API URL
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Generic GET request
|
|
24
|
+
*/
|
|
25
|
+
get<T>(endpoint: string): Observable<ApiResponse<T>> {
|
|
26
|
+
return this.http.get<ApiResponse<T>>(\`\${this.baseUrl}/\${endpoint}\`)
|
|
27
|
+
.pipe(
|
|
28
|
+
retry(1),
|
|
29
|
+
catchError(this.handleError)
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Generic POST request
|
|
35
|
+
*/
|
|
36
|
+
post<T, D = unknown>(endpoint: string, data: D): Observable<ApiResponse<T>> {
|
|
37
|
+
return this.http.post<ApiResponse<T>>(\`\${this.baseUrl}/\${endpoint}\`, data)
|
|
38
|
+
.pipe(
|
|
39
|
+
catchError(this.handleError)
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Generic PUT request
|
|
45
|
+
*/
|
|
46
|
+
put<T, D = unknown>(endpoint: string, data: D): Observable<ApiResponse<T>> {
|
|
47
|
+
return this.http.put<ApiResponse<T>>(\`\${this.baseUrl}/\${endpoint}\`, data)
|
|
48
|
+
.pipe(
|
|
49
|
+
catchError(this.handleError)
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Generic DELETE request
|
|
55
|
+
*/
|
|
56
|
+
delete<T>(endpoint: string): Observable<ApiResponse<T>> {
|
|
57
|
+
return this.http.delete<ApiResponse<T>>(\`\${this.baseUrl}/\${endpoint}\`)
|
|
58
|
+
.pipe(
|
|
59
|
+
catchError(this.handleError)
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Handle HTTP errors
|
|
65
|
+
*/
|
|
66
|
+
private handleError(error: HttpErrorResponse) {
|
|
67
|
+
let errorMessage = 'An unknown error occurred';
|
|
68
|
+
|
|
69
|
+
if (error.error instanceof ErrorEvent) {
|
|
70
|
+
// Client-side error
|
|
71
|
+
errorMessage = error.error.message;
|
|
72
|
+
} else {
|
|
73
|
+
// Server-side error
|
|
74
|
+
errorMessage = error.error?.message || \`Server returned code: \${error.status}, error message is: \${error.message}\`;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
console.error('API Error:', errorMessage);
|
|
78
|
+
return throwError(() => new Error(errorMessage));
|
|
79
|
+
}
|
|
80
|
+
}`;
|
|
81
|
+
|
|
82
|
+
await fs.writeFile(
|
|
83
|
+
path.join(config.fullPath, 'src/app/core/services/api.service.ts'),
|
|
84
|
+
apiService
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Create Auth Service
|
|
90
|
+
*/
|
|
91
|
+
async function createAuthService(config) {
|
|
92
|
+
const authService = `import { Injectable, inject } from '@angular/core';
|
|
93
|
+
import { HttpClient } from '@angular/common/http';
|
|
94
|
+
import { Router } from '@angular/router';
|
|
95
|
+
import { BehaviorSubject, Observable, throwError } from 'rxjs';
|
|
96
|
+
import { catchError, tap } from 'rxjs/operators';
|
|
97
|
+
import { environment } from '@environments/environment';
|
|
98
|
+
import { StorageService } from './storage.service';
|
|
99
|
+
|
|
100
|
+
interface User {
|
|
101
|
+
id: string;
|
|
102
|
+
email: string;
|
|
103
|
+
firstName: string;
|
|
104
|
+
lastName: string;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
interface AuthResponse {
|
|
108
|
+
token: string;
|
|
109
|
+
user: User;
|
|
110
|
+
refreshToken?: string;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
interface LoginCredentials {
|
|
114
|
+
email: string;
|
|
115
|
+
password: string;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
interface RegisterData {
|
|
119
|
+
email: string;
|
|
120
|
+
password: string;
|
|
121
|
+
firstName: string;
|
|
122
|
+
lastName: string;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
@Injectable({
|
|
126
|
+
providedIn: 'root'
|
|
127
|
+
})
|
|
128
|
+
export class AuthService {
|
|
129
|
+
private http = inject(HttpClient);
|
|
130
|
+
private router = inject(Router);
|
|
131
|
+
private storage = inject(StorageService);
|
|
132
|
+
|
|
133
|
+
private readonly API_URL = environment.apiUrl;
|
|
134
|
+
|
|
135
|
+
// Reactive state
|
|
136
|
+
private _isAuthenticated$ = new BehaviorSubject<boolean>(this.hasValidToken());
|
|
137
|
+
private _currentUser$ = new BehaviorSubject<User | null>(this.getCurrentUserFromStorage());
|
|
138
|
+
|
|
139
|
+
// Public observables
|
|
140
|
+
public readonly isAuthenticated$ = this._isAuthenticated$.asObservable();
|
|
141
|
+
public readonly currentUser$ = this._currentUser$.asObservable();
|
|
142
|
+
|
|
143
|
+
constructor() {
|
|
144
|
+
// Initialize authentication state on service creation
|
|
145
|
+
this.checkAuthenticationStatus();
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
login(credentials: LoginCredentials): Observable<AuthResponse> {
|
|
149
|
+
// For demo purposes, simulate login
|
|
150
|
+
if (credentials.email === 'demo@example.com' && credentials.password === 'password') {
|
|
151
|
+
const mockResponse: AuthResponse = {
|
|
152
|
+
token: 'mock_jwt_token_12345',
|
|
153
|
+
user: {
|
|
154
|
+
id: '1',
|
|
155
|
+
email: 'demo@example.com',
|
|
156
|
+
firstName: 'Demo',
|
|
157
|
+
lastName: 'User'
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
// Store auth data
|
|
162
|
+
this.storage.setItem(environment.auth.tokenKey, mockResponse.token);
|
|
163
|
+
this.storage.setItem('current_user', JSON.stringify(mockResponse.user));
|
|
164
|
+
|
|
165
|
+
// Update reactive state
|
|
166
|
+
this._isAuthenticated$.next(true);
|
|
167
|
+
this._currentUser$.next(mockResponse.user);
|
|
168
|
+
|
|
169
|
+
return new Observable(subscriber => {
|
|
170
|
+
setTimeout(() => {
|
|
171
|
+
subscriber.next(mockResponse);
|
|
172
|
+
subscriber.complete();
|
|
173
|
+
}, 1000);
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Real API call would be:
|
|
178
|
+
return this.http.post<AuthResponse>(\`\${this.API_URL}/auth/login\`, credentials)
|
|
179
|
+
.pipe(
|
|
180
|
+
tap(response => {
|
|
181
|
+
// Store tokens
|
|
182
|
+
this.storage.setItem(environment.auth.tokenKey, response.token);
|
|
183
|
+
this.storage.setItem('current_user', JSON.stringify(response.user));
|
|
184
|
+
if (response.refreshToken) {
|
|
185
|
+
this.storage.setItem(environment.auth.refreshTokenKey, response.refreshToken);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Update reactive state
|
|
189
|
+
this._isAuthenticated$.next(true);
|
|
190
|
+
this._currentUser$.next(response.user);
|
|
191
|
+
}),
|
|
192
|
+
catchError(error => throwError(() => error))
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
logout(): void {
|
|
197
|
+
this.storage.removeItem(environment.auth.tokenKey);
|
|
198
|
+
this.storage.removeItem(environment.auth.refreshTokenKey);
|
|
199
|
+
this.storage.removeItem('current_user');
|
|
200
|
+
|
|
201
|
+
// Update reactive state
|
|
202
|
+
this._isAuthenticated$.next(false);
|
|
203
|
+
this._currentUser$.next(null);
|
|
204
|
+
|
|
205
|
+
this.router.navigate(['/auth/login']);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
register(userData: RegisterData): Observable<AuthResponse> {
|
|
209
|
+
return this.http.post<AuthResponse>(\`\${this.API_URL}/auth/register\`, userData)
|
|
210
|
+
.pipe(
|
|
211
|
+
tap(response => {
|
|
212
|
+
// Store auth data after successful registration
|
|
213
|
+
this.storage.setItem(environment.auth.tokenKey, response.token);
|
|
214
|
+
this.storage.setItem('current_user', JSON.stringify(response.user));
|
|
215
|
+
|
|
216
|
+
// Update reactive state
|
|
217
|
+
this._isAuthenticated$.next(true);
|
|
218
|
+
this._currentUser$.next(response.user);
|
|
219
|
+
}),
|
|
220
|
+
catchError(error => throwError(() => error))
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Synchronous authentication check
|
|
225
|
+
isAuthenticated(): boolean {
|
|
226
|
+
return this.hasValidToken();
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
private hasValidToken(): boolean {
|
|
230
|
+
const token = this.storage.getItem(environment.auth.tokenKey);
|
|
231
|
+
return !!token && !this.isTokenExpired(token);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
private isTokenExpired(token: string): boolean {
|
|
235
|
+
// For demo token, always return false
|
|
236
|
+
if (token === 'mock_jwt_token_12345') {
|
|
237
|
+
return false;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
try {
|
|
241
|
+
const payload = JSON.parse(atob(token.split('.')[1]));
|
|
242
|
+
const now = Date.now() / 1000;
|
|
243
|
+
return payload.exp < now;
|
|
244
|
+
} catch {
|
|
245
|
+
return true;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
private getCurrentUserFromStorage(): User | null {
|
|
250
|
+
try {
|
|
251
|
+
const userStr = this.storage.getItem('current_user');
|
|
252
|
+
return userStr ? JSON.parse(userStr) : null;
|
|
253
|
+
} catch {
|
|
254
|
+
return null;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
private checkAuthenticationStatus(): void {
|
|
259
|
+
const isAuth = this.hasValidToken();
|
|
260
|
+
const user = this.getCurrentUserFromStorage();
|
|
261
|
+
|
|
262
|
+
this._isAuthenticated$.next(isAuth);
|
|
263
|
+
this._currentUser$.next(user);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
getToken(): string | null {
|
|
267
|
+
return this.storage.getItem(environment.auth.tokenKey);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// Get current user synchronously
|
|
271
|
+
getCurrentUser(): User | null {
|
|
272
|
+
return this._currentUser$.getValue();
|
|
273
|
+
}
|
|
274
|
+
}`;
|
|
275
|
+
|
|
276
|
+
await fs.writeFile(
|
|
277
|
+
path.join(config.fullPath, 'src/app/core/services/auth.service.ts'),
|
|
278
|
+
authService
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Create Storage Service
|
|
284
|
+
*/
|
|
285
|
+
async function createStorageService(config) {
|
|
286
|
+
const storageService = `import { Injectable, inject, PLATFORM_ID } from '@angular/core';
|
|
287
|
+
import { isPlatformBrowser } from '@angular/common';
|
|
288
|
+
|
|
289
|
+
@Injectable({
|
|
290
|
+
providedIn: 'root'
|
|
291
|
+
})
|
|
292
|
+
export class StorageService {
|
|
293
|
+
private platformId = inject(PLATFORM_ID);
|
|
294
|
+
private isBrowser = isPlatformBrowser(this.platformId);
|
|
295
|
+
|
|
296
|
+
setItem(key: string, value: string): void {
|
|
297
|
+
if (!this.isBrowser) {
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
try {
|
|
301
|
+
localStorage.setItem(key, value);
|
|
302
|
+
} catch (error) {
|
|
303
|
+
console.error('Error storing to localStorage:', error);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
getItem(key: string): string | null {
|
|
308
|
+
if (!this.isBrowser) {
|
|
309
|
+
return null;
|
|
310
|
+
}
|
|
311
|
+
try {
|
|
312
|
+
return localStorage.getItem(key);
|
|
313
|
+
} catch (error) {
|
|
314
|
+
console.error('Error retrieving from localStorage:', error);
|
|
315
|
+
return null;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
removeItem(key: string): void {
|
|
320
|
+
if (!this.isBrowser) {
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
try {
|
|
324
|
+
localStorage.removeItem(key);
|
|
325
|
+
} catch (error) {
|
|
326
|
+
console.error('Error removing from localStorage:', error);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
clear(): void {
|
|
331
|
+
if (!this.isBrowser) {
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
try {
|
|
335
|
+
localStorage.clear();
|
|
336
|
+
} catch (error) {
|
|
337
|
+
console.error('Error clearing localStorage:', error);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}`;
|
|
341
|
+
|
|
342
|
+
await fs.writeFile(
|
|
343
|
+
path.join(config.fullPath, 'src/app/core/services/storage.service.ts'),
|
|
344
|
+
storageService
|
|
345
|
+
);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* Create all core services
|
|
350
|
+
*/
|
|
351
|
+
async function createCoreServices(config) {
|
|
352
|
+
await createApiService(config);
|
|
353
|
+
await createAuthService(config);
|
|
354
|
+
await createStorageService(config);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
module.exports = {
|
|
358
|
+
createApiService,
|
|
359
|
+
createAuthService,
|
|
360
|
+
createStorageService,
|
|
361
|
+
createCoreServices,
|
|
362
|
+
};
|