nextjs-cms 0.9.21 → 0.9.23

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 (190) hide show
  1. package/README.md +65 -13
  2. package/dist/api/actions/files.d.ts +30 -0
  3. package/dist/api/actions/files.d.ts.map +1 -0
  4. package/dist/api/actions/files.js +234 -0
  5. package/dist/api/actions/index.d.ts +4 -0
  6. package/dist/api/actions/index.d.ts.map +1 -0
  7. package/dist/api/actions/index.js +3 -0
  8. package/dist/api/actions/pages.d.ts +297 -0
  9. package/dist/api/actions/pages.d.ts.map +1 -0
  10. package/dist/api/actions/pages.js +1215 -0
  11. package/dist/api/actions/privileges.d.ts +25 -0
  12. package/dist/api/actions/privileges.d.ts.map +1 -0
  13. package/dist/api/actions/privileges.js +98 -0
  14. package/dist/api/client/index.d.ts +4 -0
  15. package/dist/api/client/index.d.ts.map +1 -0
  16. package/dist/api/client/index.js +3 -0
  17. package/dist/api/client.d.ts +30 -0
  18. package/dist/api/client.d.ts.map +1 -0
  19. package/dist/api/client.js +82 -0
  20. package/dist/api/index.d.ts +1 -938
  21. package/dist/api/index.d.ts.map +1 -1
  22. package/dist/api/index.js +0 -13
  23. package/dist/api/lib/serverActions.d.ts +3 -3
  24. package/dist/api/plugin/index.d.ts +7 -0
  25. package/dist/api/plugin/index.d.ts.map +1 -0
  26. package/dist/api/plugin/index.js +5 -0
  27. package/dist/api/root.d.ts +18 -1844
  28. package/dist/api/root.d.ts.map +1 -1
  29. package/dist/api/root.js +18 -83
  30. package/dist/api/routers/navigation.d.ts +3 -3
  31. package/dist/api/server/index.d.ts +8 -0
  32. package/dist/api/server/index.d.ts.map +1 -0
  33. package/dist/api/server/index.js +3 -0
  34. package/dist/api/server.d.ts +2748 -0
  35. package/dist/api/server.d.ts.map +1 -0
  36. package/dist/api/server.js +100 -0
  37. package/dist/api/trpc/client.d.ts +19 -3
  38. package/dist/api/trpc/client.d.ts.map +1 -1
  39. package/dist/api/trpc/client.js +55 -1
  40. package/dist/api/trpc/query-client.d.ts +3 -1
  41. package/dist/api/trpc/query-client.d.ts.map +1 -1
  42. package/dist/api/trpc/query-client.js +25 -20
  43. package/dist/api/trpc/root.d.ts +906 -0
  44. package/dist/api/trpc/root.d.ts.map +1 -0
  45. package/dist/api/trpc/root.js +47 -0
  46. package/dist/api/trpc/routers/accountSettings.d.ts +66 -0
  47. package/dist/api/trpc/routers/accountSettings.d.ts.map +1 -0
  48. package/dist/api/trpc/routers/accountSettings.js +200 -0
  49. package/dist/api/trpc/routers/admins.d.ts +112 -0
  50. package/dist/api/trpc/routers/admins.d.ts.map +1 -0
  51. package/dist/api/trpc/routers/admins.js +331 -0
  52. package/dist/api/trpc/routers/auth.d.ts +54 -0
  53. package/dist/api/trpc/routers/auth.d.ts.map +1 -0
  54. package/dist/api/trpc/routers/auth.js +50 -0
  55. package/dist/api/trpc/routers/categorySection.d.ts +105 -0
  56. package/dist/api/trpc/routers/categorySection.d.ts.map +1 -0
  57. package/dist/api/trpc/routers/categorySection.js +49 -0
  58. package/dist/api/trpc/routers/config.d.ts +48 -0
  59. package/dist/api/trpc/routers/config.d.ts.map +1 -0
  60. package/dist/api/trpc/routers/config.js +18 -0
  61. package/dist/api/trpc/routers/cpanel.d.ts +82 -0
  62. package/dist/api/trpc/routers/cpanel.d.ts.map +1 -0
  63. package/dist/api/trpc/routers/cpanel.js +216 -0
  64. package/dist/api/trpc/routers/fields.d.ts +35 -0
  65. package/dist/api/trpc/routers/fields.d.ts.map +1 -0
  66. package/dist/api/trpc/routers/fields.js +81 -0
  67. package/dist/api/trpc/routers/files.d.ts +34 -0
  68. package/dist/api/trpc/routers/files.d.ts.map +1 -0
  69. package/dist/api/trpc/routers/files.js +14 -0
  70. package/dist/api/trpc/routers/gallery.d.ts +35 -0
  71. package/dist/api/trpc/routers/gallery.d.ts.map +1 -0
  72. package/dist/api/trpc/routers/gallery.js +92 -0
  73. package/dist/api/trpc/routers/hasItemsSection.d.ts +194 -0
  74. package/dist/api/trpc/routers/hasItemsSection.d.ts.map +1 -0
  75. package/dist/api/trpc/routers/hasItemsSection.js +86 -0
  76. package/dist/api/trpc/routers/logs.d.ts +59 -0
  77. package/dist/api/trpc/routers/logs.d.ts.map +1 -0
  78. package/dist/api/trpc/routers/logs.js +79 -0
  79. package/dist/api/trpc/routers/navigation.d.ts +65 -0
  80. package/dist/api/trpc/routers/navigation.d.ts.map +1 -0
  81. package/dist/api/trpc/routers/navigation.js +11 -0
  82. package/dist/api/trpc/routers/simpleSection.d.ts +93 -0
  83. package/dist/api/trpc/routers/simpleSection.d.ts.map +1 -0
  84. package/dist/api/trpc/routers/simpleSection.js +54 -0
  85. package/dist/api/trpc/server.d.ts +2789 -5
  86. package/dist/api/trpc/server.d.ts.map +1 -1
  87. package/dist/api/trpc/server.js +91 -52
  88. package/dist/api/trpc/trpc.d.ts +111 -0
  89. package/dist/api/trpc/trpc.d.ts.map +1 -0
  90. package/dist/api/trpc/trpc.js +99 -0
  91. package/dist/api/trpc/utils/async-caller-proxy.d.ts +2 -0
  92. package/dist/api/trpc/utils/async-caller-proxy.d.ts.map +1 -0
  93. package/dist/api/trpc/utils/async-caller-proxy.js +38 -0
  94. package/dist/api/trpc/utils/refresh-token-link.d.ts +6 -0
  95. package/dist/api/trpc/utils/refresh-token-link.d.ts.map +1 -0
  96. package/dist/api/trpc/utils/refresh-token-link.js +81 -0
  97. package/dist/api/trpc/utils/router-types.d.ts +7 -0
  98. package/dist/api/trpc/utils/router-types.d.ts.map +1 -0
  99. package/dist/api/trpc/utils/router-types.js +0 -0
  100. package/dist/api/use-axios-private.d.ts +6 -0
  101. package/dist/api/use-axios-private.d.ts.map +1 -0
  102. package/dist/api/use-axios-private.js +57 -0
  103. package/dist/api/utils/async-caller-proxy.d.ts +2 -0
  104. package/dist/api/utils/async-caller-proxy.d.ts.map +1 -0
  105. package/dist/api/utils/async-caller-proxy.js +36 -0
  106. package/dist/api/utils/lazy-caller-proxy.d.ts +2 -0
  107. package/dist/api/utils/lazy-caller-proxy.d.ts.map +1 -0
  108. package/dist/api/utils/lazy-caller-proxy.js +36 -0
  109. package/dist/api/utils/router-types.d.ts +7 -0
  110. package/dist/api/utils/router-types.d.ts.map +1 -0
  111. package/dist/api/utils/router-types.js +0 -0
  112. package/dist/auth/hooks/index.d.ts +1 -2
  113. package/dist/auth/hooks/index.d.ts.map +1 -1
  114. package/dist/auth/hooks/index.js +1 -2
  115. package/dist/auth/react.d.ts +1 -2
  116. package/dist/auth/react.d.ts.map +1 -1
  117. package/dist/auth/react.js +1 -2
  118. package/dist/auth/trpc.d.ts +1 -1
  119. package/dist/auth/trpc.d.ts.map +1 -1
  120. package/dist/auth/trpc.js +0 -1
  121. package/dist/cli/lib/fix-master-admin.d.ts.map +1 -1
  122. package/dist/cli/lib/fix-master-admin.js +12 -25
  123. package/dist/cli/lib/update-sections.d.ts.map +1 -1
  124. package/dist/cli/lib/update-sections.js +90 -46
  125. package/dist/core/config/config-loader.d.ts +23 -7
  126. package/dist/core/config/config-loader.d.ts.map +1 -1
  127. package/dist/core/config/config-loader.js +26 -9
  128. package/dist/core/db/table-checker/MysqlTable.d.ts.map +1 -1
  129. package/dist/core/db/table-checker/MysqlTable.js +3 -1
  130. package/dist/core/fields/date-range.d.ts +4 -4
  131. package/dist/core/fields/select.d.ts +1 -1
  132. package/dist/core/sections/category.d.ts +8 -8
  133. package/dist/core/sections/hasItems.d.ts +8 -8
  134. package/dist/core/sections/section.d.ts +5 -5
  135. package/dist/core/sections/simple.d.ts +4 -4
  136. package/dist/core/types/index.d.ts +17 -0
  137. package/dist/core/types/index.d.ts.map +1 -1
  138. package/dist/index.d.ts +0 -1
  139. package/dist/index.d.ts.map +1 -1
  140. package/dist/index.js +0 -1
  141. package/dist/plugins/client.d.ts +19 -0
  142. package/dist/plugins/client.d.ts.map +1 -0
  143. package/dist/plugins/client.js +24 -0
  144. package/dist/plugins/define.d.ts +4 -0
  145. package/dist/plugins/define.d.ts.map +1 -0
  146. package/dist/plugins/define.js +3 -0
  147. package/dist/plugins/derive.d.ts +32 -0
  148. package/dist/plugins/derive.d.ts.map +1 -0
  149. package/dist/plugins/derive.js +77 -0
  150. package/dist/plugins/loader.d.ts +51 -7
  151. package/dist/plugins/loader.d.ts.map +1 -1
  152. package/dist/plugins/loader.js +111 -51
  153. package/dist/plugins/manifest.d.ts +28 -0
  154. package/dist/plugins/manifest.d.ts.map +1 -0
  155. package/dist/plugins/manifest.js +83 -0
  156. package/dist/plugins/prefetch.d.ts +16 -0
  157. package/dist/plugins/prefetch.d.ts.map +1 -0
  158. package/dist/plugins/prefetch.js +40 -0
  159. package/dist/plugins/registry.d.ts +22 -0
  160. package/dist/plugins/registry.d.ts.map +1 -0
  161. package/dist/plugins/registry.js +25 -0
  162. package/dist/plugins/server.d.ts +2 -0
  163. package/dist/plugins/server.d.ts.map +1 -1
  164. package/dist/plugins/server.js +2 -0
  165. package/dist/plugins/types.d.ts +9 -0
  166. package/dist/plugins/types.d.ts.map +1 -0
  167. package/dist/plugins/types.js +0 -0
  168. package/dist/translations/base/en.d.ts +5 -0
  169. package/dist/translations/base/en.d.ts.map +1 -1
  170. package/dist/translations/base/en.js +5 -0
  171. package/dist/translations/client.d.ts +64 -4
  172. package/dist/translations/client.d.ts.map +1 -1
  173. package/dist/translations/server.d.ts +64 -4
  174. package/dist/translations/server.d.ts.map +1 -1
  175. package/dist/utils/console-log.d.ts +18 -0
  176. package/dist/utils/console-log.d.ts.map +1 -0
  177. package/dist/utils/console-log.js +28 -0
  178. package/dist/utils/index.d.ts +1 -0
  179. package/dist/utils/index.d.ts.map +1 -1
  180. package/dist/utils/index.js +1 -0
  181. package/dist/utils/log.d.ts +18 -0
  182. package/dist/utils/log.d.ts.map +1 -0
  183. package/dist/utils/log.js +28 -0
  184. package/dist/validators/index.d.ts +1 -0
  185. package/dist/validators/index.d.ts.map +1 -1
  186. package/dist/validators/index.js +1 -0
  187. package/dist/validators/tags.d.ts +4 -0
  188. package/dist/validators/tags.d.ts.map +1 -0
  189. package/dist/validators/tags.js +8 -0
  190. package/package.json +36 -18
@@ -0,0 +1,331 @@
1
+ import { router, privateProcedure } from '../trpc.js';
2
+ import * as z from 'zod';
3
+ import { getAdminsList, getAllPrivileges, isAccessAllowed } from '../../actions/privileges.js';
4
+ import { db } from '../../../db/client.js';
5
+ import { AccessTokensTable, AdminPrivilegesTable, AdminsTable } from '../../../db/schema.js';
6
+ import { eq } from 'drizzle-orm';
7
+ import { TRPCError } from '@trpc/server';
8
+ import bcrypt from 'bcrypt';
9
+ import { customAlphabet } from 'nanoid';
10
+ import getString from '../../../translations/index.js';
11
+ import path from 'path';
12
+ import fs from 'fs';
13
+ import { getCMSConfig } from '../../../core/config/index.js';
14
+ import { getRequestMetadataFromHeaders, recordLog } from '../../../logging/index.js';
15
+ export const adminsRouter = router({
16
+ list: privateProcedure.query(async ({ ctx }) => {
17
+ const accessAllowed = await isAccessAllowed({
18
+ sectionName: 'admins',
19
+ userId: ctx.session.user.id,
20
+ });
21
+ if (!accessAllowed) {
22
+ return {
23
+ error: {
24
+ message: getString('sectionNotFound', ctx.session.user.language),
25
+ },
26
+ };
27
+ }
28
+ const data = await Promise.all([getAdminsList(), getAllPrivileges(ctx.session)]);
29
+ const adminList = data[0];
30
+ const privileges = data[1];
31
+ return {
32
+ admins: adminList,
33
+ privileges: privileges,
34
+ };
35
+ }),
36
+ get: privateProcedure.input(z.string()).query(async (opts) => {
37
+ const accessAllowed = await isAccessAllowed({
38
+ sectionName: 'admins',
39
+ userId: opts.ctx.session.user.id,
40
+ });
41
+ if (!accessAllowed) {
42
+ throw new TRPCError({
43
+ code: 'NOT_FOUND',
44
+ message: getString('sectionNotFound', opts.ctx.session.user.language),
45
+ });
46
+ }
47
+ const data = await Promise.all([
48
+ db
49
+ .select({
50
+ id: AdminsTable.id,
51
+ user: AdminsTable.user,
52
+ })
53
+ .from(AdminsTable)
54
+ .where(eq(AdminsTable.id, opts.input)),
55
+ db
56
+ .select({
57
+ sectionName: AdminPrivilegesTable.sectionName,
58
+ operations: AdminPrivilegesTable.operations,
59
+ publisher: AdminPrivilegesTable.publisher,
60
+ })
61
+ .from(AdminPrivilegesTable)
62
+ .where(eq(AdminPrivilegesTable.adminId, opts.input)),
63
+ getAllPrivileges(opts.ctx.session),
64
+ ]);
65
+ const adminRows = data[0];
66
+ const adminRoles = data[1];
67
+ const allRoles = data[2];
68
+ const adminData = adminRows[0];
69
+ if (!adminData) {
70
+ throw new TRPCError({
71
+ code: 'BAD_REQUEST',
72
+ message: 'Admin not found',
73
+ });
74
+ }
75
+ return {
76
+ admin: adminData,
77
+ adminRoles: adminRoles,
78
+ allRoles: allRoles,
79
+ };
80
+ }),
81
+ create: privateProcedure
82
+ .input(z.object({
83
+ username: z.string(),
84
+ password: z.string(),
85
+ privileges: z.array(z.object({
86
+ sectionName: z.string(),
87
+ publisher: z.boolean().nullable(),
88
+ operations: z.string(),
89
+ })),
90
+ }))
91
+ .mutation(async ({ ctx, input }) => {
92
+ const requestMetadata = getRequestMetadataFromHeaders(ctx.headers);
93
+ const accessAllowed = await isAccessAllowed({
94
+ sectionName: 'admins',
95
+ userId: ctx.session.user.id,
96
+ });
97
+ if (!accessAllowed) {
98
+ throw new TRPCError({
99
+ code: 'NOT_FOUND',
100
+ message: getString('sectionNotFound', ctx.session.user.language),
101
+ });
102
+ }
103
+ /**
104
+ * First, let's check if the username already exists
105
+ */
106
+ const usernameExists = await db.select().from(AdminsTable).where(eq(AdminsTable.user, input.username));
107
+ /**
108
+ * If the username already exists, throw an error
109
+ */
110
+ if (usernameExists.length > 0) {
111
+ throw new TRPCError({
112
+ code: 'BAD_REQUEST',
113
+ message: getString('adminAlreadyExists', ctx.session.user.language),
114
+ });
115
+ }
116
+ /**
117
+ * Let's filter the privileges to remove the ones that has operations set to 'none'
118
+ */
119
+ const filteredPrivileges = input.privileges.filter((privilege) => privilege.operations !== 'none');
120
+ /**
121
+ * If the filtered privileges are empty, throw an error
122
+ */
123
+ if (filteredPrivileges.length === 0) {
124
+ throw new TRPCError({
125
+ code: 'BAD_REQUEST',
126
+ message: getString('selectAtLeastOnePrivilege', ctx.session.user.language),
127
+ });
128
+ }
129
+ /**
130
+ * Hash password with bcrypt
131
+ */
132
+ const hashedPassword = await bcrypt.hash(input.password, 10);
133
+ const id = customAlphabet('1234567890', 25)();
134
+ /**
135
+ * Now, let's prepare the rows to be inserted into the admin_privileges table
136
+ */
137
+ const rows = filteredPrivileges.map((privilege) => ({
138
+ adminId: id,
139
+ sectionName: privilege.sectionName,
140
+ operations: privilege.operations,
141
+ publisher: privilege.publisher,
142
+ }));
143
+ /**
144
+ * Insert admin and privileges atomically
145
+ */
146
+ await db.transaction(async (tx) => {
147
+ await tx.insert(AdminsTable).values({
148
+ id: id,
149
+ pass: hashedPassword,
150
+ user: input.username,
151
+ });
152
+ await tx.insert(AdminPrivilegesTable).values(rows);
153
+ });
154
+ await recordLog({
155
+ eventType: 'admin.section.create',
156
+ actorId: ctx.session.user.id,
157
+ actorUsername: ctx.session.user.name ?? null,
158
+ entityType: 'admin',
159
+ entityId: id,
160
+ entityLabel: input.username,
161
+ sectionName: 'admins',
162
+ metadata: {
163
+ privileges: rows.map((privilege) => ({
164
+ sectionName: privilege.sectionName,
165
+ operations: privilege.operations,
166
+ publisher: privilege.publisher,
167
+ })),
168
+ },
169
+ requestMetadata,
170
+ });
171
+ return {
172
+ status: 'success',
173
+ id,
174
+ };
175
+ }),
176
+ update: privateProcedure
177
+ .input(z.object({
178
+ id: z.string(),
179
+ privileges: z.array(z.object({
180
+ sectionName: z.string(),
181
+ publisher: z.boolean().nullable(),
182
+ operations: z.string(),
183
+ })),
184
+ }))
185
+ .mutation(async ({ ctx, input }) => {
186
+ const requestMetadata = getRequestMetadataFromHeaders(ctx.headers);
187
+ const accessAllowed = await isAccessAllowed({
188
+ sectionName: 'admins',
189
+ userId: ctx.session.user.id,
190
+ });
191
+ if (!accessAllowed) {
192
+ throw new TRPCError({
193
+ code: 'NOT_FOUND',
194
+ message: getString('sectionNotFound', ctx.session.user.language),
195
+ });
196
+ }
197
+ /**
198
+ * First, let's check if the admin exists
199
+ */
200
+ const adminRows = await db.select().from(AdminsTable).where(eq(AdminsTable.id, input.id));
201
+ const admin = adminRows[0];
202
+ /**
203
+ * If the admin doens't exist, throw an error
204
+ */
205
+ if (!admin) {
206
+ throw new TRPCError({
207
+ code: 'BAD_REQUEST',
208
+ message: getString('adminDoesNotExist', ctx.session.user.language),
209
+ });
210
+ }
211
+ /**
212
+ * Let's filter the privileges to remove the ones that has operations set to 'none'
213
+ */
214
+ const filteredPrivileges = input.privileges.filter((privilege) => privilege.operations !== 'none');
215
+ /**
216
+ * If the filtered privileges are empty, throw an error
217
+ */
218
+ if (filteredPrivileges.length === 0) {
219
+ throw new TRPCError({
220
+ code: 'BAD_REQUEST',
221
+ message: getString('selectAtLeastOnePrivilege', ctx.session.user.language),
222
+ });
223
+ }
224
+ /**
225
+ * Now, let's prepare the rows to be inserted into the admin_privileges table
226
+ */
227
+ const rows = filteredPrivileges.map((privilege) => ({
228
+ adminId: input.id,
229
+ sectionName: privilege.sectionName,
230
+ operations: privilege.operations,
231
+ publisher: privilege.publisher,
232
+ }));
233
+ /**
234
+ * Delete and then insert the privileges into the admin_privileges table atomically
235
+ */
236
+ await db.transaction(async (tx) => {
237
+ await tx.delete(AdminPrivilegesTable).where(eq(AdminPrivilegesTable.adminId, input.id));
238
+ await tx.insert(AdminPrivilegesTable).values(rows);
239
+ });
240
+ await recordLog({
241
+ eventType: 'admin.section.update',
242
+ actorId: ctx.session.user.id,
243
+ actorUsername: ctx.session.user.name ?? null,
244
+ entityType: 'admin',
245
+ entityId: input.id,
246
+ entityLabel: admin.user ?? null,
247
+ sectionName: 'admins',
248
+ metadata: {
249
+ privileges: rows.map((privilege) => ({
250
+ sectionName: privilege.sectionName,
251
+ operations: privilege.operations,
252
+ publisher: privilege.publisher,
253
+ })),
254
+ },
255
+ requestMetadata,
256
+ });
257
+ return {
258
+ status: 'success',
259
+ };
260
+ }),
261
+ remove: privateProcedure
262
+ .input(z.object({
263
+ id: z.string(),
264
+ }))
265
+ .mutation(async ({ ctx, input }) => {
266
+ const requestMetadata = getRequestMetadataFromHeaders(ctx.headers);
267
+ const accessAllowed = await isAccessAllowed({
268
+ sectionName: 'admins',
269
+ userId: ctx.session.user.id,
270
+ });
271
+ if (!accessAllowed) {
272
+ throw new TRPCError({
273
+ code: 'NOT_FOUND',
274
+ message: getString('sectionNotFound', ctx.session.user.language),
275
+ });
276
+ }
277
+ const uploadsFolder = (await getCMSConfig()).media.upload.path;
278
+ /**
279
+ * Check if the admin is not the master admin
280
+ */
281
+ if (input.id === '1') {
282
+ throw new TRPCError({
283
+ code: 'BAD_REQUEST',
284
+ message: getString('masterAdminCannotBeDeleted', ctx.session.user.language),
285
+ });
286
+ }
287
+ /**
288
+ * Check if the admin exists
289
+ */
290
+ const adminResult = await db.select().from(AdminsTable).where(eq(AdminsTable.id, input.id));
291
+ const admin = adminResult[0];
292
+ if (!admin) {
293
+ throw new TRPCError({
294
+ code: 'BAD_REQUEST',
295
+ message: getString('adminNotFound', ctx.session.user.language),
296
+ });
297
+ }
298
+ /**
299
+ * Delete privileges, access tokens, and admin row atomically.
300
+ * Access tokens must be deleted before the admin row due to FK constraint.
301
+ */
302
+ await db.transaction(async (tx) => {
303
+ await tx.delete(AdminPrivilegesTable).where(eq(AdminPrivilegesTable.adminId, input.id));
304
+ await tx.delete(AccessTokensTable).where(eq(AccessTokensTable.adminId, input.id));
305
+ await tx.delete(AdminsTable).where(eq(AdminsTable.id, input.id));
306
+ });
307
+ /**
308
+ * Remove the admin avatar. Failure here must not undo the DB deletion above,
309
+ * so swallow filesystem errors (file may already be missing).
310
+ */
311
+ if (admin.coverphoto) {
312
+ await fs.promises
313
+ .rm(path.join(uploadsFolder, '.thumbs', 'admins', admin.coverphoto), { force: true })
314
+ .catch(() => { });
315
+ }
316
+ await recordLog({
317
+ eventType: 'admin.section.delete',
318
+ actorId: ctx.session.user.id,
319
+ actorUsername: ctx.session.user.name ?? null,
320
+ entityType: 'admin',
321
+ entityId: input.id,
322
+ entityLabel: admin.user ?? null,
323
+ sectionName: 'admins',
324
+ metadata: {
325
+ hadAvatar: Boolean(admin.coverphoto),
326
+ },
327
+ requestMetadata,
328
+ });
329
+ return true;
330
+ }),
331
+ });
@@ -0,0 +1,54 @@
1
+ import * as z from 'zod';
2
+ export declare const authRouter: import("@trpc/server").TRPCBuiltRouter<{
3
+ ctx: {
4
+ headers: Headers;
5
+ db: import("drizzle-orm/mysql2").MySql2Database<typeof import("../../../db/schema.js")> & {
6
+ $client: import("mysql2/promise").Pool;
7
+ };
8
+ session: import("../../../index.js").Session | null;
9
+ };
10
+ meta: object;
11
+ errorShape: {
12
+ data: {
13
+ zodError: z.core.$ZodFlattenedError<unknown, string> | null;
14
+ code: import("@trpc/server").TRPC_ERROR_CODE_KEY;
15
+ httpStatus: number;
16
+ path?: string;
17
+ stack?: string;
18
+ };
19
+ message: string;
20
+ code: import("@trpc/server").TRPC_ERROR_CODE_NUMBER;
21
+ };
22
+ transformer: true;
23
+ }, import("@trpc/server").TRPCDecorateCreateRouterOptions<{
24
+ login: import("@trpc/server").TRPCMutationProcedure<{
25
+ input: {
26
+ username: string;
27
+ password: string;
28
+ };
29
+ output: {
30
+ status: number;
31
+ session: {
32
+ user: {
33
+ id: string;
34
+ name: string;
35
+ language: string;
36
+ };
37
+ };
38
+ user: {
39
+ id: string;
40
+ username: string;
41
+ lang: string;
42
+ avatar: string | null;
43
+ };
44
+ accessToken: string;
45
+ };
46
+ meta: object;
47
+ }>;
48
+ logout: import("@trpc/server").TRPCMutationProcedure<{
49
+ input: void;
50
+ output: boolean;
51
+ meta: object;
52
+ }>;
53
+ }>>;
54
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../../src/api/trpc/routers/auth.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,CAAC,MAAM,KAAK,CAAA;AAKxB,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDrB,CAAA"}
@@ -0,0 +1,50 @@
1
+ import { privateProcedure, publicProcedure, router } from '../trpc.js';
2
+ import * as z from 'zod';
3
+ import { TRPCError } from '@trpc/server';
4
+ import { deleteSession, login } from '../../../auth/lib/index.js';
5
+ import { getRequestMetadataFromHeaders, recordLog } from '../../../logging/index.js';
6
+ export const authRouter = router({
7
+ login: publicProcedure
8
+ .input(z.object({
9
+ username: z.string(),
10
+ password: z.string(),
11
+ }))
12
+ .mutation(async (opts) => {
13
+ try {
14
+ const requestMetadata = getRequestMetadataFromHeaders(opts.ctx.headers);
15
+ const result = await login(opts.input);
16
+ await recordLog({
17
+ eventType: 'auth.login',
18
+ actorId: result.user?.id ?? null,
19
+ actorUsername: result.user?.username ?? null,
20
+ entityType: 'admin',
21
+ entityId: result.user?.id ?? null,
22
+ entityLabel: result.user?.username ?? null,
23
+ sectionName: 'auth',
24
+ requestMetadata,
25
+ });
26
+ return result;
27
+ }
28
+ catch (error) {
29
+ throw new TRPCError({
30
+ code: 'BAD_REQUEST',
31
+ message: error.message,
32
+ });
33
+ }
34
+ }),
35
+ logout: privateProcedure.mutation(async (opts) => {
36
+ const requestMetadata = getRequestMetadataFromHeaders(opts.ctx.headers);
37
+ const result = await deleteSession(opts.ctx.session);
38
+ await recordLog({
39
+ eventType: 'auth.logout',
40
+ actorId: opts.ctx.session.user.id,
41
+ actorUsername: opts.ctx.session.user.name ?? null,
42
+ entityType: 'admin',
43
+ entityId: opts.ctx.session.user.id,
44
+ entityLabel: opts.ctx.session.user.name ?? null,
45
+ sectionName: 'auth',
46
+ requestMetadata,
47
+ });
48
+ return result;
49
+ }),
50
+ });
@@ -0,0 +1,105 @@
1
+ import * as z from 'zod';
2
+ export declare const categorySectionRouter: import("@trpc/server").TRPCBuiltRouter<{
3
+ ctx: {
4
+ headers: Headers;
5
+ db: import("drizzle-orm/mysql2").MySql2Database<typeof import("../../../db/schema.js")> & {
6
+ $client: import("mysql2/promise").Pool;
7
+ };
8
+ session: import("../../../index.js").Session | null;
9
+ };
10
+ meta: object;
11
+ errorShape: {
12
+ data: {
13
+ zodError: z.core.$ZodFlattenedError<unknown, string> | null;
14
+ code: import("@trpc/server").TRPC_ERROR_CODE_KEY;
15
+ httpStatus: number;
16
+ path?: string;
17
+ stack?: string;
18
+ };
19
+ message: string;
20
+ code: import("@trpc/server").TRPC_ERROR_CODE_NUMBER;
21
+ };
22
+ transformer: true;
23
+ }, import("@trpc/server").TRPCDecorateCreateRouterOptions<{
24
+ get: import("@trpc/server").TRPCQueryProcedure<{
25
+ input: {
26
+ sectionName: string;
27
+ };
28
+ output: {
29
+ error: {
30
+ message: string;
31
+ };
32
+ section?: undefined;
33
+ data?: undefined;
34
+ } | {
35
+ section: {
36
+ tableName: string;
37
+ sectionName: string;
38
+ title: {
39
+ section: string;
40
+ singular: string;
41
+ plural: string;
42
+ };
43
+ };
44
+ data: {
45
+ options: {
46
+ value: string | number;
47
+ label: string;
48
+ }[] | undefined;
49
+ required: boolean;
50
+ name: string;
51
+ label: string;
52
+ value: {
53
+ value: string | number;
54
+ label: string;
55
+ }[] | undefined;
56
+ parentId: string | number | undefined;
57
+ level: number;
58
+ depth: number | undefined;
59
+ sectionName: string;
60
+ allowRecursiveDelete: boolean | undefined;
61
+ };
62
+ error?: undefined;
63
+ };
64
+ meta: object;
65
+ }>;
66
+ getChildren: import("@trpc/server").TRPCMutationProcedure<{
67
+ input: {
68
+ sectionName: string;
69
+ parentId: string | number | undefined;
70
+ level: number;
71
+ };
72
+ output: {
73
+ error: {
74
+ message: string;
75
+ };
76
+ options?: undefined;
77
+ parentId?: undefined;
78
+ level?: undefined;
79
+ } | {
80
+ options: null;
81
+ parentId: string | number;
82
+ level: number;
83
+ error?: undefined;
84
+ } | {
85
+ options: {
86
+ value: any;
87
+ label: any;
88
+ }[];
89
+ parentId: string | number;
90
+ level: number;
91
+ error?: undefined;
92
+ } | undefined;
93
+ meta: object;
94
+ }>;
95
+ deleteItem: import("@trpc/server").TRPCMutationProcedure<{
96
+ input: {
97
+ sectionName: string;
98
+ sectionItemId: string | number;
99
+ deleteChildren?: boolean | undefined;
100
+ };
101
+ output: boolean;
102
+ meta: object;
103
+ }>;
104
+ }>>;
105
+ //# sourceMappingURL=categorySection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"categorySection.d.ts","sourceRoot":"","sources":["../../../../src/api/trpc/routers/categorySection.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,CAAC,MAAM,KAAK,CAAA;AAKxB,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4DhC,CAAA"}
@@ -0,0 +1,49 @@
1
+ import { privateProcedure, router } from '../trpc.js';
2
+ import * as z from 'zod';
3
+ import { deleteSectionItem, getCategorySection, getCategorySectionChildren } from '../../actions/pages.js';
4
+ import { getRequestMetadataFromHeaders } from '../../../logging/index.js';
5
+ import { TRPCError } from '@trpc/server';
6
+ export const categorySectionRouter = router({
7
+ get: privateProcedure
8
+ .input(z.object({
9
+ sectionName: z.string(),
10
+ }))
11
+ .query(async ({ ctx, input }) => {
12
+ return await getCategorySection(ctx.session, input.sectionName);
13
+ }),
14
+ getChildren: privateProcedure
15
+ .input(z.object({
16
+ sectionName: z.string(),
17
+ parentId: z.number().or(z.string()).or(z.undefined()),
18
+ level: z.number(),
19
+ }))
20
+ .mutation(async ({ ctx, input }) => {
21
+ if (input.parentId === undefined) {
22
+ return undefined;
23
+ }
24
+ return await getCategorySectionChildren({
25
+ session: ctx.session,
26
+ sectionName: input.sectionName,
27
+ id: input.parentId,
28
+ level: input.level,
29
+ });
30
+ }),
31
+ deleteItem: privateProcedure
32
+ .input(z.object({
33
+ sectionName: z.string(),
34
+ sectionItemId: z.number().or(z.string()),
35
+ deleteChildren: z.boolean().optional(),
36
+ }))
37
+ .mutation(async ({ ctx, input }) => {
38
+ const requestMetadata = getRequestMetadataFromHeaders(ctx.headers);
39
+ const result = await deleteSectionItem(ctx.session, input.sectionName, input.sectionItemId, input.deleteChildren, requestMetadata);
40
+ if (result && typeof result === 'object' && 'error' in result) {
41
+ const message = result.error?.message ?? 'Failed to delete section item';
42
+ throw new TRPCError({
43
+ code: 'BAD_REQUEST',
44
+ message,
45
+ });
46
+ }
47
+ return result;
48
+ }),
49
+ });
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Config router. Exposes non-sensitive config (e.g. i18n) to authenticated clients.
3
+ */
4
+ export declare const configRouter: import("@trpc/server").TRPCBuiltRouter<{
5
+ ctx: {
6
+ headers: Headers;
7
+ db: import("drizzle-orm/mysql2").MySql2Database<typeof import("../../../db/schema.js")> & {
8
+ $client: import("mysql2/promise").Pool;
9
+ };
10
+ session: import("../../../index.js").Session | null;
11
+ };
12
+ meta: object;
13
+ errorShape: {
14
+ data: {
15
+ zodError: import("zod").ZodFlattenedError<unknown, string> | null;
16
+ code: import("@trpc/server").TRPC_ERROR_CODE_KEY;
17
+ httpStatus: number;
18
+ path?: string;
19
+ stack?: string;
20
+ };
21
+ message: string;
22
+ code: import("@trpc/server").TRPC_ERROR_CODE_NUMBER;
23
+ };
24
+ transformer: true;
25
+ }, import("@trpc/server").TRPCDecorateCreateRouterOptions<{
26
+ getI18n: import("@trpc/server").TRPCQueryProcedure<{
27
+ input: void;
28
+ output: {
29
+ supportedLanguages: readonly string[];
30
+ fallbackLanguage: string;
31
+ };
32
+ meta: object;
33
+ }>;
34
+ getLocalization: import("@trpc/server").TRPCQueryProcedure<{
35
+ input: void;
36
+ output: {
37
+ enabled: boolean;
38
+ locales: {
39
+ code: string;
40
+ label: string;
41
+ rtl?: boolean;
42
+ }[];
43
+ defaultLocale: string;
44
+ } | null;
45
+ meta: object;
46
+ }>;
47
+ }>>;
48
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../../src/api/trpc/routers/config.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mBAa61c,CAAC;;;;;;GADr3c,CAAA"}
@@ -0,0 +1,18 @@
1
+ import { privateProcedure, router } from '../trpc.js';
2
+ import { getCMSConfig } from '../../../core/config/index.js';
3
+ /**
4
+ * Config router. Exposes non-sensitive config (e.g. i18n) to authenticated clients.
5
+ */
6
+ export const configRouter = router({
7
+ getI18n: privateProcedure.query(async () => {
8
+ const config = await getCMSConfig();
9
+ return {
10
+ supportedLanguages: config.i18n.supportedLanguages,
11
+ fallbackLanguage: config.i18n.fallbackLanguage,
12
+ };
13
+ }),
14
+ getLocalization: privateProcedure.query(async () => {
15
+ const config = await getCMSConfig();
16
+ return config.localization;
17
+ }),
18
+ });