easy-starter 1.2.0 → 2.0.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.
Files changed (38) hide show
  1. package/README.md +32 -80
  2. package/bin/index.js +219 -44
  3. package/package.json +20 -11
  4. package/template/.cursorrules +23 -0
  5. package/template/.github/workflows/deploy.yml +3 -0
  6. package/template/README.md +81 -24
  7. package/template/env +3 -2
  8. package/template/gitignore +1 -1
  9. package/template/index.html +15 -0
  10. package/template/package.json +8 -9
  11. package/template/public/images/icon-16.png +0 -0
  12. package/template/public/images/icon-180.png +0 -0
  13. package/template/public/images/icon-192.png +0 -0
  14. package/template/public/images/icon-32.png +0 -0
  15. package/template/public/images/icon-512.png +0 -0
  16. package/template/{src → public}/site.webmanifest +6 -12
  17. package/template/scripts/deploy.ts +3 -2
  18. package/template/server/index.tsx +248 -61
  19. package/template/server/mail.tsx +120 -0
  20. package/template/src/App.tsx +33 -7
  21. package/template/src/Router.tsx +11 -2
  22. package/template/src/index.tsx +28 -1
  23. package/template/src/pages/Index.tsx +45 -6
  24. package/template/src/pages/ResetPassword.tsx +126 -0
  25. package/template/src/pages/admin/Admin.tsx +360 -85
  26. package/template/src/pages/admin/AnalyticsTab.tsx +71 -0
  27. package/template/src/pages/admin/ErrorsTab.tsx +46 -0
  28. package/template/src/pages/admin/UsersTab.tsx +61 -0
  29. package/template/src/services/api.ts +5 -7
  30. package/template/src/services/common.ts +23 -0
  31. package/template/src/styles.css +460 -0
  32. package/template/tsconfig.json +2 -1
  33. package/template/types.ts +44 -3
  34. package/template/vite.config.ts +24 -0
  35. package/template/.parcelrc +0 -6
  36. package/template/src/images/icon.png +0 -0
  37. package/template/src/index.html +0 -16
  38. package/template/src/styles.scss +0 -292
@@ -0,0 +1,61 @@
1
+ import React from "react";
2
+
3
+ type UsersTabProps = {
4
+ users: any[];
5
+ loading: boolean;
6
+ errorMsg: string;
7
+ onRoleChange: (userId: string, role: "admin" | "user") => void;
8
+ };
9
+
10
+ export default function UsersTab({ users, loading, errorMsg, onRoleChange }: UsersTabProps) {
11
+ return (
12
+ <div>
13
+ <h3 style={{ marginBottom: 15 }}>User Management</h3>
14
+ {loading && <p>Loading users...</p>}
15
+ {errorMsg && <p style={{ color: "#ef4444" }}>{errorMsg}</p>}
16
+ {!loading && !errorMsg && (
17
+ <div style={{ overflowX: 'auto' }}>
18
+ <table style={{ width: '100%', borderCollapse: 'collapse', textAlign: 'left' }}>
19
+ <thead>
20
+ <tr style={{ borderBottom: '2px solid var(--border)' }}>
21
+ <th style={{ padding: 10 }}>Email</th>
22
+ <th style={{ padding: 10 }}>Name</th>
23
+ <th style={{ padding: 10 }}>Role</th>
24
+ <th style={{ padding: 10 }}>Actions</th>
25
+ </tr>
26
+ </thead>
27
+ <tbody>
28
+ {users.map((usr: any) => (
29
+ <tr key={usr._id} style={{ borderBottom: '1px solid var(--border)' }}>
30
+ <td style={{ padding: 10 }}>{usr.email}</td>
31
+ <td style={{ padding: 10 }}>{usr.name || "N/A"}</td>
32
+ <td style={{ padding: 10 }}>
33
+ <span style={{
34
+ padding: '2px 6px',
35
+ borderRadius: 4,
36
+ fontSize: '0.85em',
37
+ background: usr.role === 'admin' ? 'rgba(99, 102, 241, 0.2)' : 'rgba(255, 255, 255, 0.05)',
38
+ color: usr.role === 'admin' ? 'var(--primary-hover)' : 'var(--text-muted)'
39
+ }}>
40
+ {usr.role || "user"}
41
+ </span>
42
+ </td>
43
+ <td style={{ padding: 10 }}>
44
+ <select
45
+ value={usr.role || "user"}
46
+ onChange={(e) => onRoleChange(usr._id, e.target.value as any)}
47
+ style={{ padding: '4px 8px', background: 'var(--surface)', border: '1px solid var(--border)', color: 'var(--text)', borderRadius: 4 }}
48
+ >
49
+ <option value="user">User</option>
50
+ <option value="admin">Admin</option>
51
+ </select>
52
+ </td>
53
+ </tr>
54
+ ))}
55
+ </tbody>
56
+ </table>
57
+ </div>
58
+ )}
59
+ </div>
60
+ );
61
+ }
@@ -1,8 +1,11 @@
1
1
  import { useEffect } from "react";
2
2
  import { sendError } from "easy-analytics/client";
3
3
  import { setServerUrl, getUseAPIFrontend, getAPIFrontend, setHeaders } from "typed-client-server-api/hooks";
4
+
5
+ // --- SSR START ---
4
6
  import { useSSRHook } from "ssr-hook/client";
5
7
  import { setSSROrigin } from "ssr-hook";
8
+ // --- SSR END ---
6
9
 
7
10
  import { API } from "../../types";
8
11
 
@@ -14,13 +17,6 @@ export type UseSSRAPIType = {
14
17
  };
15
18
 
16
19
 
17
- if (process.env.NODE_ENV === "development") {
18
- // In development mode, the frontend (Parcel) and backend (Express) run on different ports.
19
- // We explicitly tell ssr-hook where the API backend is located.
20
- setSSROrigin("http://localhost:1111");
21
- setServerUrl("http://localhost:1111");
22
- }
23
-
24
20
  let authorization = "";
25
21
 
26
22
  setHeaders(() => ({
@@ -34,6 +30,7 @@ export function setAuthorizationHeader(newAuthorization: string) {
34
30
 
35
31
  export const api = getAPIFrontend<API>();
36
32
  export const useApi = getUseAPIFrontend<API>();
33
+ // --- SSR START ---
37
34
  export const useSSRApi = new Proxy({}, {
38
35
  get(target, prop: string) {
39
36
  return (params: any) => {
@@ -42,6 +39,7 @@ export const useSSRApi = new Proxy({}, {
42
39
  };
43
40
  }
44
41
  }) as UseSSRAPIType;
42
+ // --- SSR END ---
45
43
 
46
44
  export function handleError(error?: unknown, errorInfo?: any) {
47
45
  if (!error) return;
@@ -1,6 +1,12 @@
1
+ // --- SSR START ---
1
2
  import { useHeaders } from "ssr-hook";
3
+ // --- SSR END ---
2
4
  import { useTitle } from "easy-page-router/react";
3
5
 
6
+ // --- NO_SSR START ---
7
+ import { useEffect } from "react";
8
+ // --- NO_SSR END ---
9
+
4
10
  type UseHeadProps = {
5
11
  title: string;
6
12
  description: string;
@@ -10,6 +16,7 @@ type UseHeadProps = {
10
16
  };
11
17
 
12
18
  export function useHead({ title, description, image, canonical, lang }: UseHeadProps) {
19
+ // --- SSR START ---
13
20
  useHeaders({
14
21
  title,
15
22
  description,
@@ -17,5 +24,21 @@ export function useHead({ title, description, image, canonical, lang }: UseHeadP
17
24
  canonical: canonical || (typeof window !== "undefined" ? window.location.origin + window.location.pathname : ""),
18
25
  lang,
19
26
  });
27
+ // --- SSR END ---
28
+ // --- NO_SSR START ---
29
+ useEffect(() => {
30
+ if (typeof document !== "undefined") {
31
+ const metaDesc = document.querySelector('meta[name="description"]');
32
+ if (metaDesc) {
33
+ metaDesc.setAttribute("content", description);
34
+ } else {
35
+ const meta = document.createElement("meta");
36
+ meta.name = "description";
37
+ meta.content = description;
38
+ document.head.appendChild(meta);
39
+ }
40
+ }
41
+ }, [description]);
42
+ // --- NO_SSR END ---
20
43
  useTitle(title);
21
44
  }
@@ -0,0 +1,460 @@
1
+ /* --- AUTH START --- */
2
+ @import "easy-user-auth/style.css";
3
+ /* --- AUTH END --- */
4
+
5
+ /* Premium Dark Theme */
6
+ :root {
7
+ --bg: #09090b;
8
+ --surface: #18181b;
9
+ --primary: #6366f1; /* Indigo */
10
+ --primary-hover: #818cf8;
11
+ --text: #f4f4f5;
12
+ --text-muted: #a1a1aa;
13
+ --border: #27272a;
14
+ }
15
+
16
+ body {
17
+ font-family: 'Inter', system-ui, sans-serif;
18
+ background-color: var(--bg);
19
+ color: var(--text);
20
+ margin: 0;
21
+ padding: 0;
22
+ line-height: 1.6;
23
+ /* --- VIEWPORT START --- */
24
+ min-width: 600px;
25
+ /* --- VIEWPORT END --- */
26
+ }
27
+
28
+ a {
29
+ color: var(--primary);
30
+ text-decoration: none;
31
+ font-weight: bold;
32
+ transition: color 0.2s;
33
+
34
+ &:hover {
35
+ color: var(--primary-hover);
36
+ }
37
+ }
38
+
39
+ main {
40
+ max-width: 800px;
41
+ margin: 50px auto;
42
+ padding: 40px;
43
+ background: var(--surface);
44
+ border-radius: 16px;
45
+ box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5);
46
+ border: 1px solid var(--border);
47
+ }
48
+
49
+ header {
50
+ text-align: center;
51
+ margin-bottom: 40px;
52
+
53
+ h1 {
54
+ color: var(--primary);
55
+ }
56
+
57
+ p {
58
+ color: var(--text-muted);
59
+ }
60
+
61
+ figure {
62
+ width: 140px;
63
+ height: 140px;
64
+ margin: 0 auto 20px;
65
+ background-image: url("/images/icon.png");
66
+ background-size: contain;
67
+ background-repeat: no-repeat;
68
+ background-position: center;
69
+ }
70
+ }
71
+
72
+ section {
73
+ margin-top: 40px;
74
+ padding: 30px;
75
+ background: rgba(255, 255, 255, 0.02);
76
+ border-radius: 12px;
77
+ border: 1px solid var(--border);
78
+
79
+ ul {
80
+ list-style: none;
81
+ padding: 0;
82
+
83
+ li {
84
+ display: flex;
85
+ align-items: center;
86
+ justify-content: space-between;
87
+ padding: 15px 20px;
88
+ background: var(--bg);
89
+ border-radius: 8px;
90
+ margin-bottom: 12px;
91
+ border: 1px solid var(--border);
92
+ transition: transform 0.2s, border-color 0.2s;
93
+
94
+ &:hover {
95
+ transform: translateY(-2px);
96
+ border-color: var(--primary);
97
+ }
98
+
99
+ nav {
100
+ display: flex;
101
+ gap: 8px;
102
+ }
103
+ }
104
+ }
105
+
106
+ article {
107
+ padding: 0px 20px 10px;
108
+ background: var(--bg);
109
+ border-radius: 8px;
110
+ border: 1px solid var(--primary);
111
+ box-shadow: 0 0 15px rgba(99, 102, 241, 0.15);
112
+
113
+ h3 {
114
+ color: var(--primary);
115
+ }
116
+
117
+ p {
118
+ margin: 5px 0;
119
+ color: var(--text);
120
+ }
121
+ }
122
+
123
+ form {
124
+ display: flex;
125
+ gap: 12px;
126
+ flex-wrap: wrap;
127
+ }
128
+ }
129
+
130
+ /* Global Controls */
131
+ input {
132
+ padding: 12px 16px;
133
+ background: var(--bg);
134
+ border: 1px solid var(--border);
135
+ border-radius: 8px;
136
+ color: var(--text);
137
+ outline: none;
138
+ transition: border-color 0.2s;
139
+ flex: 1;
140
+ min-width: 150px;
141
+
142
+ &:focus {
143
+ border-color: var(--primary);
144
+ }
145
+ }
146
+
147
+ button {
148
+ padding: 12px 24px;
149
+ background: var(--primary);
150
+ color: #fff;
151
+ border: none;
152
+ border-radius: 8px;
153
+ cursor: pointer;
154
+ font-weight: bold;
155
+ transition: background 0.2s, transform 0.1s;
156
+
157
+ &:hover:not(:disabled) {
158
+ background: var(--primary-hover);
159
+ transform: scale(1.02);
160
+ }
161
+
162
+ &.btn-danger {
163
+ background: #ef4444;
164
+
165
+ &:hover:not(:disabled) {
166
+ background: #dc2626;
167
+ }
168
+ }
169
+ }
170
+
171
+ /* --- ADMIN START --- */
172
+ /* --- ADMIN DASHBOARD --- */
173
+ .admin-login {
174
+ padding: 40px;
175
+ max-width: 400px;
176
+ margin: 0 auto;
177
+ text-align: center;
178
+
179
+ h2 {
180
+ color: var(--text);
181
+ }
182
+
183
+ .back-link {
184
+ margin-bottom: 20px;
185
+ }
186
+
187
+ form {
188
+ display: flex;
189
+ flex-direction: column;
190
+ gap: 15px;
191
+ margin-top: 20px;
192
+ }
193
+ }
194
+
195
+ .admin-container {
196
+ padding: 40px;
197
+ max-width: 1200px;
198
+ margin: 0 auto;
199
+
200
+ .header {
201
+ display: flex;
202
+ justify-content: space-between;
203
+ align-items: center;
204
+ margin-bottom: 30px;
205
+
206
+ h2 {
207
+ margin: 0;
208
+ color: var(--text);
209
+ }
210
+
211
+ a {
212
+ color: var(--primary);
213
+ text-decoration: none;
214
+ font-weight: bold;
215
+ }
216
+ }
217
+
218
+ .controls {
219
+ display: flex;
220
+ gap: 15px;
221
+ align-items: center;
222
+ margin-bottom: 30px;
223
+ flex-wrap: wrap;
224
+
225
+ strong {
226
+ font-size: 1.1rem;
227
+ color: var(--text);
228
+ }
229
+
230
+ .btn-logout {
231
+ margin-left: auto;
232
+ background: #ef4444;
233
+
234
+ &:hover {
235
+ background: #dc2626;
236
+ }
237
+ }
238
+ }
239
+
240
+ .chart-container {
241
+ margin-bottom: 40px;
242
+ background: rgba(255, 255, 255, 0.02);
243
+ padding: 25px;
244
+ border-radius: 12px;
245
+ border: 1px solid var(--border);
246
+
247
+ h3 {
248
+ margin: 0 0 20px;
249
+ font-size: 1.1rem;
250
+ color: var(--text);
251
+ }
252
+
253
+ .chart {
254
+ display: flex;
255
+ align-items: flex-end;
256
+ height: 150px;
257
+ gap: 4px;
258
+
259
+ .bar-wrapper {
260
+ flex: 1;
261
+ display: flex;
262
+ flex-direction: column;
263
+ align-items: center;
264
+ justify-content: flex-end;
265
+ height: 100%;
266
+
267
+ .count {
268
+ font-size: 11px;
269
+ color: var(--text);
270
+ margin-bottom: 4px;
271
+ font-weight: bold;
272
+ }
273
+
274
+ .date {
275
+ font-size: 10px;
276
+ margin-top: 8px;
277
+ color: var(--text-muted);
278
+ }
279
+
280
+ .bar {
281
+ width: 100%;
282
+ max-width: 24px;
283
+ border-radius: 4px 4px 0 0;
284
+ transition: height 0.3s ease;
285
+ }
286
+
287
+ .bar.active {
288
+ background: var(--primary);
289
+ }
290
+ }
291
+ }
292
+ }
293
+
294
+ .grid {
295
+ display: grid;
296
+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
297
+ gap: 20px;
298
+ }
299
+ }
300
+ /* --- ADMIN END --- */
301
+
302
+ /* --- AUTH START --- */
303
+ /* --- EASY-USER-AUTH STYLING OVERRIDES --- */
304
+ .easy-user-auth-overlay {
305
+ position: fixed;
306
+ top: 0;
307
+ left: 0;
308
+ width: 100%;
309
+ height: 100%;
310
+ background: rgba(9, 9, 11, 0.8);
311
+ backdrop-filter: blur(8px);
312
+ display: flex;
313
+ align-items: center;
314
+ justify-content: center;
315
+ z-index: 1000;
316
+ }
317
+
318
+ .easy-user-auth-modal {
319
+ background: var(--surface);
320
+ border: 1px solid var(--border);
321
+ border-radius: 16px;
322
+ box-shadow: 0 20px 50px rgba(0, 0, 0, 0.6);
323
+ padding: 30px;
324
+ width: 100%;
325
+ max-width: 420px;
326
+ position: relative;
327
+ box-sizing: border-box;
328
+ }
329
+
330
+ .easy-user-auth-close-btn {
331
+ position: absolute;
332
+ top: 15px;
333
+ right: 20px;
334
+ background: transparent;
335
+ border: none;
336
+ font-size: 24px;
337
+ color: var(--text-muted);
338
+ cursor: pointer;
339
+ padding: 0;
340
+ transition: color 0.2s;
341
+
342
+ &:hover {
343
+ color: var(--text);
344
+ }
345
+ }
346
+
347
+ .easy-user-auth-tabs {
348
+ display: flex;
349
+ gap: 10px;
350
+ margin-bottom: 25px;
351
+ border-bottom: 1px solid var(--border);
352
+ padding-bottom: 10px;
353
+ }
354
+
355
+ .easy-user-auth-tab {
356
+ background: transparent;
357
+ border: none;
358
+ color: var(--text-muted);
359
+ font-size: 16px;
360
+ padding: 8px 12px;
361
+ cursor: pointer;
362
+ font-weight: 500;
363
+ transition: color 0.2s;
364
+
365
+ &:hover {
366
+ color: var(--text);
367
+ }
368
+
369
+ &.easy-user-auth-tab-active {
370
+ color: var(--primary);
371
+ border-bottom: 2px solid var(--primary);
372
+ font-weight: bold;
373
+ }
374
+ }
375
+
376
+ .easy-user-auth-form {
377
+ display: flex;
378
+ flex-direction: column;
379
+ gap: 20px;
380
+ }
381
+
382
+ .easy-user-auth-form-input {
383
+ display: flex;
384
+ flex-direction: column;
385
+ gap: 8px;
386
+ }
387
+
388
+ .easy-user-auth-label {
389
+ font-size: 14px;
390
+ color: var(--text-muted);
391
+ font-weight: 500;
392
+ }
393
+
394
+ .easy-user-auth-input {
395
+ width: 100%;
396
+ box-sizing: border-box;
397
+ }
398
+
399
+ .easy-user-auth-submit-btn {
400
+ width: 100%;
401
+ margin-top: 10px;
402
+ }
403
+
404
+ .easy-user-auth-back-btn {
405
+ width: 100%;
406
+ background: transparent;
407
+ border: 1px solid var(--border);
408
+ color: var(--text);
409
+
410
+ &:hover:not(:disabled) {
411
+ background: rgba(255, 255, 255, 0.05);
412
+ }
413
+ }
414
+
415
+ .easy-user-auth-forgot-link {
416
+ font-size: 14px;
417
+ color: var(--primary);
418
+ text-align: right;
419
+ align-self: flex-end;
420
+ cursor: pointer;
421
+ background: transparent;
422
+ border: none;
423
+ font-weight: bold;
424
+ padding: 0;
425
+
426
+ &:hover {
427
+ color: var(--primary-hover);
428
+ text-decoration: underline;
429
+ }
430
+ }
431
+
432
+ .easy-user-auth-title {
433
+ font-size: 20px;
434
+ font-weight: bold;
435
+ margin: 0 0 10px;
436
+ color: var(--text);
437
+ }
438
+
439
+ .easy-user-auth-text {
440
+ font-size: 14px;
441
+ color: var(--text-muted);
442
+ margin: 0 0 15px;
443
+ }
444
+
445
+ .easy-user-auth-alert {
446
+ padding: 12px;
447
+ border-radius: 8px;
448
+ font-size: 14px;
449
+ margin-bottom: 10px;
450
+ background: rgba(239, 68, 68, 0.1);
451
+ border: 1px solid rgba(239, 68, 68, 0.2);
452
+ color: #f87171;
453
+ }
454
+
455
+ .easy-user-auth-info {
456
+ font-size: 12px;
457
+ color: var(--text-muted);
458
+ margin-top: 4px;
459
+ }
460
+ /* --- AUTH END --- */
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "compilerOptions": {
3
3
  "target": "ES2022",
4
- "module": "CommonJS",
4
+ "module": "ESNext",
5
+ "moduleResolution": "Bundler",
5
6
  "lib": [
6
7
  "DOM",
7
8
  "DOM.Iterable",
package/template/types.ts CHANGED
@@ -1,16 +1,51 @@
1
- import { APIDefinition, Endpoint, Token } from "typed-client-server-api";
1
+ import { APIDefinition, Endpoint } from "typed-client-server-api";
2
+
3
+ // --- AUTH START ---
4
+ import { UserDB } from "easy-user-auth/types";
5
+
6
+ export type UserProfile = {
7
+ name: string;
8
+ role: "admin" | "user";
9
+ };
10
+ // --- AUTH END ---
11
+
12
+ // --- OGIMAGE START ---
13
+ export type OgImageRecord = {
14
+ dateCreated: string;
15
+ file: {
16
+ type: "EASY_DB_FILE";
17
+ url: string;
18
+ };
19
+ };
20
+ // --- OGIMAGE END ---
2
21
 
3
22
  // The API type defines the contract between your React frontend and Express backend.
4
23
  // Every property here represents an endpoint. Both the client and server use this
5
- // to ensure type safety. If you change a parameter here, TypeScript will immediately
6
- // warn you if you forgot to update the frontend or backend!
24
+ // to ensure type safety.
7
25
  export type API = APIDefinition<{
8
26
  getItems: Endpoint<{}, Item[]>;
9
27
  getItem: Endpoint<{ id: string }, Item>;
10
28
  addItem: Endpoint<Omit<Item, "_id">, string>;
11
29
  removeItem: Endpoint<{ id: string }, boolean>;
12
30
 
31
+ // --- ADMIN_NO_AUTH START ---
13
32
  getEasyAnalyticsData: Endpoint<{ password: string, month: string }, any[]>;
33
+ // --- ADMIN_NO_AUTH END ---
34
+ // --- ADMIN_WITH_AUTH START ---
35
+ getEasyAnalyticsData: Endpoint<{ month: string }, any[]>;
36
+ // --- ADMIN_WITH_AUTH END ---
37
+
38
+ // --- ADMIN_ERRORS_NO_AUTH START ---
39
+ getEasyAnalyticsErrors: Endpoint<{ password: string, month: string }, any[]>;
40
+ // --- ADMIN_ERRORS_NO_AUTH END ---
41
+ // --- ADMIN_ERRORS_WITH_AUTH START ---
42
+ getEasyAnalyticsErrors: Endpoint<{ month: string }, any[]>;
43
+ // --- ADMIN_ERRORS_WITH_AUTH END ---
44
+
45
+ // --- ADMIN_USERS START ---
46
+ getUsers: Endpoint<{}, { _id: string, email: string, name: string, role: "admin" | "user" }[]>;
47
+ updateUserRole: Endpoint<{ userId: string, role: "admin" | "user" }, boolean>;
48
+ // --- ADMIN_USERS END ---
14
49
  }>;
15
50
 
16
51
  export type Item = {
@@ -23,4 +58,10 @@ export type Item = {
23
58
  // Each property represents a 'table' (or a separate JSON file).
24
59
  export type Database = {
25
60
  item: Item;
61
+ // --- AUTH START ---
62
+ user: UserDB<UserProfile>;
63
+ // --- AUTH END ---
64
+ // --- OGIMAGE START ---
65
+ "og-image": OgImageRecord;
66
+ // --- OGIMAGE END ---
26
67
  };
@@ -0,0 +1,24 @@
1
+ import { defineConfig } from "vite";
2
+ import react from "@vitejs/plugin-react";
3
+ import { imagetools } from "vite-imagetools";
4
+
5
+ export default defineConfig({
6
+ plugins: [react(), imagetools()],
7
+ define: {
8
+ "process.env.NODE_ENV": JSON.stringify(process.env.NODE_ENV || "development"),
9
+ "global": "globalThis",
10
+ },
11
+ server: {
12
+ port: 5173,
13
+ proxy: {
14
+ "/api": {
15
+ target: "http://localhost:1111",
16
+ changeOrigin: true,
17
+ },
18
+ "/files": {
19
+ target: "http://localhost:1111",
20
+ changeOrigin: true,
21
+ },
22
+ },
23
+ },
24
+ });
@@ -1,6 +0,0 @@
1
- {
2
- "extends": "@parcel/config-default",
3
- "optimizers": {
4
- "*.html": []
5
- }
6
- }
Binary file