create-elit 3.6.5 → 3.6.7

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 (76) hide show
  1. package/README.md +32 -68
  2. package/dist/index.js +121 -8
  3. package/dist/templates/{elit.config.ts → auth-fullstack-example/elit.config.ts} +51 -0
  4. package/dist/templates/auth-fullstack-example/package.json +26 -0
  5. package/dist/templates/auth-fullstack-example/src/native-screen.ts +10 -0
  6. package/dist/templates/auth-fullstack-example/wapkignore +10 -0
  7. package/dist/templates/auth-fullstack-example/wapkpatch +1 -0
  8. package/dist/templates/basic-example/README.md +39 -0
  9. package/dist/templates/basic-example/elit.config.ts +114 -0
  10. package/dist/templates/basic-example/gitignore +7 -0
  11. package/dist/templates/basic-example/package.json +26 -0
  12. package/dist/templates/basic-example/public/favicon.svg +22 -0
  13. package/dist/templates/basic-example/public/index.html +14 -0
  14. package/dist/templates/basic-example/src/client.ts +15 -0
  15. package/dist/templates/basic-example/src/main.ts +89 -0
  16. package/dist/templates/basic-example/src/mobile.ts +35 -0
  17. package/dist/templates/basic-example/src/styles.ts +273 -0
  18. package/dist/templates/basic-example/tsconfig.json +24 -0
  19. package/dist/templates/basic-example/wapkignore +10 -0
  20. package/dist/templates/basic-example/wapkpatch +1 -0
  21. package/dist/templates/todo-fullstack-example/README.md +39 -0
  22. package/dist/templates/todo-fullstack-example/databases/todo.ts +41 -0
  23. package/dist/templates/todo-fullstack-example/elit.config.ts +123 -0
  24. package/dist/templates/todo-fullstack-example/gitignore +7 -0
  25. package/dist/templates/todo-fullstack-example/package.json +26 -0
  26. package/dist/templates/todo-fullstack-example/public/favicon.svg +22 -0
  27. package/dist/templates/todo-fullstack-example/public/index.html +14 -0
  28. package/dist/templates/todo-fullstack-example/src/client.ts +15 -0
  29. package/dist/templates/todo-fullstack-example/src/components/AppFooter.ts +16 -0
  30. package/dist/templates/todo-fullstack-example/src/components/AppHeader.ts +23 -0
  31. package/dist/templates/todo-fullstack-example/src/main.ts +7 -0
  32. package/dist/templates/todo-fullstack-example/src/mobile.ts +36 -0
  33. package/dist/templates/todo-fullstack-example/src/pages/TodoPage.ts +491 -0
  34. package/dist/templates/todo-fullstack-example/src/router.ts +16 -0
  35. package/dist/templates/todo-fullstack-example/src/server.ts +226 -0
  36. package/dist/templates/todo-fullstack-example/src/styles.ts +768 -0
  37. package/dist/templates/todo-fullstack-example/src/todo-types.ts +19 -0
  38. package/dist/templates/todo-fullstack-example/src/web.ts +16 -0
  39. package/dist/templates/todo-fullstack-example/tsconfig.json +24 -0
  40. package/dist/templates/todo-fullstack-example/wapkignore +10 -0
  41. package/dist/templates/todo-fullstack-example/wapkpatch +1 -0
  42. package/package.json +1 -1
  43. package/dist/templates/package.json +0 -17
  44. package/dist/templates/src/client.test.ts +0 -292
  45. package/dist/templates/src/components/Footer.test.ts +0 -226
  46. package/dist/templates/src/components/Header.test.ts +0 -493
  47. package/dist/templates/src/pages/ChatListPage.test.ts +0 -603
  48. package/dist/templates/src/pages/ChatPage.test.ts +0 -530
  49. package/dist/templates/src/pages/ForgotPasswordPage.test.ts +0 -484
  50. package/dist/templates/src/pages/HomePage.test.ts +0 -601
  51. package/dist/templates/src/pages/LoginPage.test.ts +0 -619
  52. package/dist/templates/src/pages/PrivateChatPage.test.ts +0 -556
  53. package/dist/templates/src/pages/ProfilePage.test.ts +0 -628
  54. package/dist/templates/src/pages/RegisterPage.test.ts +0 -661
  55. /package/dist/templates/{README.md → auth-fullstack-example/README.md} +0 -0
  56. /package/dist/templates/{databases → auth-fullstack-example/databases}/users.ts +0 -0
  57. /package/dist/templates/{gitignore → auth-fullstack-example/gitignore} +0 -0
  58. /package/dist/templates/{public → auth-fullstack-example/public}/favicon.svg +0 -0
  59. /package/dist/templates/{public → auth-fullstack-example/public}/index.html +0 -0
  60. /package/dist/templates/{src → auth-fullstack-example/src}/client.ts +0 -0
  61. /package/dist/templates/{src → auth-fullstack-example/src}/components/Footer.ts +0 -0
  62. /package/dist/templates/{src → auth-fullstack-example/src}/components/Header.ts +0 -0
  63. /package/dist/templates/{src → auth-fullstack-example/src}/components/index.ts +0 -0
  64. /package/dist/templates/{src → auth-fullstack-example/src}/main.ts +0 -0
  65. /package/dist/templates/{src → auth-fullstack-example/src}/pages/ChatListPage.ts +0 -0
  66. /package/dist/templates/{src → auth-fullstack-example/src}/pages/ChatPage.ts +0 -0
  67. /package/dist/templates/{src → auth-fullstack-example/src}/pages/ForgotPasswordPage.ts +0 -0
  68. /package/dist/templates/{src → auth-fullstack-example/src}/pages/HomePage.ts +0 -0
  69. /package/dist/templates/{src → auth-fullstack-example/src}/pages/LoginPage.ts +0 -0
  70. /package/dist/templates/{src → auth-fullstack-example/src}/pages/PrivateChatPage.ts +0 -0
  71. /package/dist/templates/{src → auth-fullstack-example/src}/pages/ProfilePage.ts +0 -0
  72. /package/dist/templates/{src → auth-fullstack-example/src}/pages/RegisterPage.ts +0 -0
  73. /package/dist/templates/{src → auth-fullstack-example/src}/router.ts +0 -0
  74. /package/dist/templates/{src → auth-fullstack-example/src}/server.ts +0 -0
  75. /package/dist/templates/{src → auth-fullstack-example/src}/styles.ts +0 -0
  76. /package/dist/templates/{tsconfig.json → auth-fullstack-example/tsconfig.json} +0 -0
@@ -0,0 +1,226 @@
1
+ import { Database } from 'elit/database';
2
+ import { ServerRouter, json, type ServerRouteContext } from 'elit/server';
3
+ import { resolve } from 'path';
4
+ import type { TodoItem, TodoPriority, TodoSummary } from './todo-types';
5
+
6
+ const priorityWeight: Record<TodoPriority, number> = {
7
+ high: 0,
8
+ medium: 1,
9
+ low: 2
10
+ };
11
+
12
+ export const router = new ServerRouter();
13
+
14
+ const db = new Database({
15
+ dir: resolve(process.cwd(), 'databases'),
16
+ language: 'ts'
17
+ });
18
+
19
+ function normalizePriority(value: unknown): TodoPriority {
20
+ if (value === 'high' || value === 'low') {
21
+ return value;
22
+ }
23
+
24
+ return 'medium';
25
+ }
26
+
27
+ function summarizeTodos(items: TodoItem[]): TodoSummary {
28
+ const completed = items.filter((todo) => todo.completed).length;
29
+ const active = items.length - completed;
30
+ const highPriority = items.filter((todo) => !todo.completed && todo.priority === 'high').length;
31
+
32
+ return {
33
+ total: items.length,
34
+ active,
35
+ completed,
36
+ highPriority
37
+ };
38
+ }
39
+
40
+ function sortTodos(items: TodoItem[]): TodoItem[] {
41
+ return [...items].sort((left, right) =>
42
+ Number(left.completed) - Number(right.completed)
43
+ || priorityWeight[left.priority] - priorityWeight[right.priority]
44
+ || right.updatedAt.localeCompare(left.updatedAt)
45
+ );
46
+ }
47
+
48
+ async function readTodos(): Promise<TodoItem[]> {
49
+ const result = await db.execute(`
50
+ import { todos } from '@db/todo';
51
+ console.log(JSON.stringify(todos));
52
+ `);
53
+
54
+ const payload = result.logs.find((entry: { type: string }) => entry.type === 'log')?.args?.[0];
55
+
56
+ if (typeof payload === 'string') {
57
+ return sortTodos(JSON.parse(payload) as TodoItem[]);
58
+ }
59
+
60
+ if (Array.isArray(payload)) {
61
+ return sortTodos(payload as TodoItem[]);
62
+ }
63
+
64
+ return [];
65
+ }
66
+
67
+ function writeTodos(items: TodoItem[]): TodoItem[] {
68
+ const sortedTodos = sortTodos(items);
69
+ db.update('todo', 'todos', sortedTodos);
70
+ return sortedTodos;
71
+ }
72
+
73
+ function createTodoId(): string {
74
+ return `todo_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
75
+ }
76
+
77
+ function getTitle(body: any): string {
78
+ return typeof body?.title === 'string' ? body.title.trim() : '';
79
+ }
80
+
81
+ function getNotes(body: any): string {
82
+ return typeof body?.notes === 'string' ? body.notes.trim() : '';
83
+ }
84
+
85
+ function sendTodoPayload(ctx: ServerRouteContext, todos: TodoItem[], status = 200, extras: Record<string, unknown> = {}) {
86
+ return json(ctx.res, {
87
+ ...extras,
88
+ todos,
89
+ summary: summarizeTodos(todos)
90
+ }, status);
91
+ }
92
+
93
+ router.get('/api/health', async (ctx: ServerRouteContext) => {
94
+ json(ctx.res, {
95
+ ok: true,
96
+ storage: 'elit/database',
97
+ file: 'databases/todo.ts'
98
+ });
99
+ });
100
+
101
+ router.get('/api/todos', async (ctx: ServerRouteContext) => {
102
+ const todos = await readTodos();
103
+ sendTodoPayload(ctx, todos);
104
+ });
105
+
106
+ router.post('/api/todos', async (ctx: ServerRouteContext) => {
107
+ const title = getTitle(ctx.body);
108
+ const notes = getNotes(ctx.body);
109
+ const priority = normalizePriority(ctx.body?.priority);
110
+
111
+ if (!title) {
112
+ return json(ctx.res, { error: 'Add a task title before saving.' }, 400);
113
+ }
114
+
115
+ if (title.length > 120) {
116
+ return json(ctx.res, { error: 'Keep task titles under 120 characters.' }, 400);
117
+ }
118
+
119
+ if (notes.length > 280) {
120
+ return json(ctx.res, { error: 'Notes should stay under 280 characters.' }, 400);
121
+ }
122
+
123
+ const now = new Date().toISOString();
124
+ const todo: TodoItem = {
125
+ id: createTodoId(),
126
+ title,
127
+ notes,
128
+ priority,
129
+ completed: false,
130
+ createdAt: now,
131
+ updatedAt: now
132
+ };
133
+
134
+ const nextTodos = writeTodos([todo, ...(await readTodos())]);
135
+
136
+ return sendTodoPayload(ctx, nextTodos, 201, {
137
+ message: 'Task added to databases/todo.ts.',
138
+ todo
139
+ });
140
+ });
141
+
142
+ router.patch('/api/todos/:id', async (ctx: ServerRouteContext) => {
143
+ const todoId = ctx.params.id;
144
+ const currentTodos = await readTodos();
145
+ const todoIndex = currentTodos.findIndex((todo) => todo.id === todoId);
146
+
147
+ if (todoIndex === -1) {
148
+ return json(ctx.res, { error: 'Task not found.' }, 404);
149
+ }
150
+
151
+ const currentTodo = currentTodos[todoIndex];
152
+ const nextTitle = typeof ctx.body?.title === 'string' ? ctx.body.title.trim() : currentTodo.title;
153
+ const nextNotes = typeof ctx.body?.notes === 'string' ? ctx.body.notes.trim() : currentTodo.notes;
154
+ const nextPriority = ctx.body && 'priority' in ctx.body
155
+ ? normalizePriority(ctx.body.priority)
156
+ : currentTodo.priority;
157
+ const nextCompleted = typeof ctx.body?.completed === 'boolean'
158
+ ? ctx.body.completed
159
+ : currentTodo.completed;
160
+
161
+ if (!nextTitle) {
162
+ return json(ctx.res, { error: 'Task title cannot be empty.' }, 400);
163
+ }
164
+
165
+ if (nextTitle.length > 120) {
166
+ return json(ctx.res, { error: 'Keep task titles under 120 characters.' }, 400);
167
+ }
168
+
169
+ if (nextNotes.length > 280) {
170
+ return json(ctx.res, { error: 'Notes should stay under 280 characters.' }, 400);
171
+ }
172
+
173
+ const updatedTodo: TodoItem = {
174
+ ...currentTodo,
175
+ title: nextTitle,
176
+ notes: nextNotes,
177
+ priority: nextPriority,
178
+ completed: nextCompleted,
179
+ updatedAt: new Date().toISOString()
180
+ };
181
+
182
+ const nextTodos = writeTodos(currentTodos.map((todo) =>
183
+ todo.id === todoId ? updatedTodo : todo
184
+ ));
185
+
186
+ return sendTodoPayload(ctx, nextTodos, 200, {
187
+ message: updatedTodo.completed ? 'Task marked complete.' : 'Task updated.',
188
+ todo: updatedTodo
189
+ });
190
+ });
191
+
192
+ router.delete('/api/todos/completed', async (ctx: ServerRouteContext) => {
193
+ const currentTodos = await readTodos();
194
+ const nextTodos = currentTodos.filter((todo) => !todo.completed);
195
+
196
+ if (nextTodos.length === currentTodos.length) {
197
+ return json(ctx.res, { error: 'There are no completed tasks to clear.' }, 400);
198
+ }
199
+
200
+ const removedCount = currentTodos.length - nextTodos.length;
201
+ const savedTodos = writeTodos(nextTodos);
202
+
203
+ return sendTodoPayload(ctx, savedTodos, 200, {
204
+ message: `Cleared ${removedCount} completed task${removedCount === 1 ? '' : 's'}.`,
205
+ removedCount
206
+ });
207
+ });
208
+
209
+ router.delete('/api/todos/:id', async (ctx: ServerRouteContext) => {
210
+ const todoId = ctx.params.id;
211
+ const currentTodos = await readTodos();
212
+ const todo = currentTodos.find((entry) => entry.id === todoId);
213
+
214
+ if (!todo) {
215
+ return json(ctx.res, { error: 'Task not found.' }, 404);
216
+ }
217
+
218
+ const nextTodos = writeTodos(currentTodos.filter((entry) => entry.id !== todoId));
219
+
220
+ return sendTodoPayload(ctx, nextTodos, 200, {
221
+ message: 'Task removed from the board.',
222
+ todo
223
+ });
224
+ });
225
+
226
+ export const server = router;