nextjs-cms 0.9.37 → 0.9.38

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 (115) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +279 -279
  3. package/dist/api/actions/files.d.ts.map +1 -1
  4. package/dist/api/actions/pages.d.ts +1 -0
  5. package/dist/api/actions/pages.d.ts.map +1 -1
  6. package/dist/api/actions/pages.js +1 -0
  7. package/dist/api/axios/axiosInstance.d.ts +2 -0
  8. package/dist/api/axios/axiosInstance.d.ts.map +1 -0
  9. package/dist/api/axios/axiosInstance.js +8 -0
  10. package/dist/api/index.d.ts +975 -0
  11. package/dist/api/index.d.ts.map +1 -0
  12. package/dist/api/index.js +13 -0
  13. package/dist/api/lib/serverActions.d.ts +374 -0
  14. package/dist/api/lib/serverActions.d.ts.map +1 -0
  15. package/dist/api/lib/serverActions.js +1445 -0
  16. package/dist/api/root.d.ts +1917 -0
  17. package/dist/api/root.d.ts.map +1 -0
  18. package/dist/api/root.js +115 -0
  19. package/dist/api/routers/accountSettings.d.ts +66 -0
  20. package/dist/api/routers/accountSettings.d.ts.map +1 -0
  21. package/dist/api/routers/accountSettings.js +202 -0
  22. package/dist/api/routers/admins.d.ts +112 -0
  23. package/dist/api/routers/admins.d.ts.map +1 -0
  24. package/dist/api/routers/admins.js +323 -0
  25. package/dist/api/routers/auth.d.ts +54 -0
  26. package/dist/api/routers/auth.d.ts.map +1 -0
  27. package/dist/api/routers/auth.js +50 -0
  28. package/dist/api/routers/categorySection.d.ts +105 -0
  29. package/dist/api/routers/categorySection.d.ts.map +1 -0
  30. package/dist/api/routers/categorySection.js +49 -0
  31. package/dist/api/routers/config.d.ts +48 -0
  32. package/dist/api/routers/config.d.ts.map +1 -0
  33. package/dist/api/routers/config.js +18 -0
  34. package/dist/api/routers/cpanel.d.ts +82 -0
  35. package/dist/api/routers/cpanel.d.ts.map +1 -0
  36. package/dist/api/routers/cpanel.js +216 -0
  37. package/dist/api/routers/fields.d.ts +35 -0
  38. package/dist/api/routers/fields.d.ts.map +1 -0
  39. package/dist/api/routers/fields.js +81 -0
  40. package/dist/api/routers/files.d.ts +34 -0
  41. package/dist/api/routers/files.d.ts.map +1 -0
  42. package/dist/api/routers/files.js +14 -0
  43. package/dist/api/routers/gallery.d.ts +34 -0
  44. package/dist/api/routers/gallery.d.ts.map +1 -0
  45. package/dist/api/routers/gallery.js +64 -0
  46. package/dist/api/routers/hasItemsSection.d.ts +219 -0
  47. package/dist/api/routers/hasItemsSection.d.ts.map +1 -0
  48. package/dist/api/routers/hasItemsSection.js +86 -0
  49. package/dist/api/routers/logs.d.ts +59 -0
  50. package/dist/api/routers/logs.d.ts.map +1 -0
  51. package/dist/api/routers/logs.js +76 -0
  52. package/dist/api/routers/navigation.d.ts +50 -0
  53. package/dist/api/routers/navigation.d.ts.map +1 -0
  54. package/dist/api/routers/navigation.js +11 -0
  55. package/dist/api/routers/simpleSection.d.ts +105 -0
  56. package/dist/api/routers/simpleSection.d.ts.map +1 -0
  57. package/dist/api/routers/simpleSection.js +54 -0
  58. package/dist/api/trpc/root.d.ts +41 -7
  59. package/dist/api/trpc/root.d.ts.map +1 -1
  60. package/dist/api/trpc/routers/config.d.ts.map +1 -1
  61. package/dist/api/trpc/routers/hasItemsSection.d.ts.map +1 -1
  62. package/dist/api/trpc/routers/logs.d.ts +37 -4
  63. package/dist/api/trpc/routers/logs.d.ts.map +1 -1
  64. package/dist/api/trpc/routers/logs.js +92 -43
  65. package/dist/api/trpc/routers/navigation.d.ts +1 -0
  66. package/dist/api/trpc/routers/navigation.d.ts.map +1 -1
  67. package/dist/api/trpc/routers/simpleSection.d.ts.map +1 -1
  68. package/dist/api/trpc/server.d.ts +123 -21
  69. package/dist/api/trpc/server.d.ts.map +1 -1
  70. package/dist/api/trpc.d.ts +111 -0
  71. package/dist/api/trpc.d.ts.map +1 -0
  72. package/dist/api/trpc.js +99 -0
  73. package/dist/auth/axios/axiosInstance.d.ts +2 -0
  74. package/dist/auth/axios/axiosInstance.d.ts.map +1 -0
  75. package/dist/auth/axios/axiosInstance.js +8 -0
  76. package/dist/auth/hooks/useAxiosPrivate.d.ts +5 -0
  77. package/dist/auth/hooks/useAxiosPrivate.d.ts.map +1 -0
  78. package/dist/auth/hooks/useAxiosPrivate.js +74 -0
  79. package/dist/auth/trpc.d.ts +6 -0
  80. package/dist/auth/trpc.d.ts.map +1 -0
  81. package/dist/auth/trpc.js +82 -0
  82. package/dist/cli/lib/db-config.js +10 -10
  83. package/dist/cli/lib/update-sections.js +24 -24
  84. package/dist/core/config/config-loader.d.ts +2 -2
  85. package/dist/core/db/table-checker/MysqlTable.js +10 -10
  86. package/dist/core/factories/section-factory-with-esbuild.js +9 -9
  87. package/dist/core/factories/section-factory-with-jiti.js +9 -9
  88. package/dist/core/fields/dateRange.d.ts +115 -0
  89. package/dist/core/fields/dateRange.d.ts.map +1 -0
  90. package/dist/core/fields/dateRange.js +149 -0
  91. package/dist/logging/event-labels.d.ts +11 -0
  92. package/dist/logging/event-labels.d.ts.map +1 -0
  93. package/dist/logging/event-labels.js +14 -0
  94. package/dist/logging/log.d.ts +1 -1
  95. package/dist/logging/log.d.ts.map +1 -1
  96. package/dist/translations/base/en.d.ts +33 -0
  97. package/dist/translations/base/en.d.ts.map +1 -1
  98. package/dist/translations/base/en.js +33 -0
  99. package/dist/translations/client.d.ts +400 -4
  100. package/dist/translations/client.d.ts.map +1 -1
  101. package/dist/translations/locale-cookie.d.ts +24 -0
  102. package/dist/translations/locale-cookie.d.ts.map +1 -0
  103. package/dist/translations/locale-cookie.js +44 -0
  104. package/dist/translations/locale-utils.d.ts +8 -0
  105. package/dist/translations/locale-utils.d.ts.map +1 -0
  106. package/dist/translations/locale-utils.js +11 -0
  107. package/dist/translations/localization.d.ts +40 -0
  108. package/dist/translations/localization.d.ts.map +1 -0
  109. package/dist/translations/localization.js +48 -0
  110. package/dist/translations/server.d.ts +400 -4
  111. package/dist/translations/server.d.ts.map +1 -1
  112. package/dist/validators/dateRange.d.ts +11 -0
  113. package/dist/validators/dateRange.d.ts.map +1 -0
  114. package/dist/validators/dateRange.js +16 -0
  115. package/package.json +6 -2
@@ -0,0 +1,219 @@
1
+ import * as z from 'zod';
2
+ export declare const hasItemsSectionRouter: 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
+ listItems: import("@trpc/server").TRPCQueryProcedure<{
25
+ input: {
26
+ sectionName: string;
27
+ page?: number | undefined;
28
+ q?: string | undefined;
29
+ };
30
+ output: {
31
+ error: {
32
+ message: string;
33
+ };
34
+ section?: undefined;
35
+ items?: undefined;
36
+ totalCount?: undefined;
37
+ } | {
38
+ section: {
39
+ hasSearch: boolean;
40
+ name: string;
41
+ title: string;
42
+ };
43
+ items: (Record<string, any> | {
44
+ id: string | number;
45
+ headingTitle: string;
46
+ coverPhoto: string | null;
47
+ createdAt: string;
48
+ createdBy: string;
49
+ permission: number;
50
+ })[];
51
+ totalCount: any;
52
+ error?: undefined;
53
+ };
54
+ meta: object;
55
+ }>;
56
+ newItem: import("@trpc/server").TRPCQueryProcedure<{
57
+ input: {
58
+ sectionName: string;
59
+ };
60
+ output: {
61
+ error: {
62
+ message: any;
63
+ };
64
+ section?: undefined;
65
+ inputGroups?: undefined;
66
+ defaultLocale?: undefined;
67
+ } | {
68
+ section: {
69
+ name: string;
70
+ title: {
71
+ section: string;
72
+ singular: string;
73
+ plural: string;
74
+ };
75
+ gallery: {
76
+ db: {
77
+ tableName: string;
78
+ referenceIdentifierField: string;
79
+ photoNameField: string;
80
+ metaField: string;
81
+ };
82
+ watermark?: boolean;
83
+ thumbnail?: {
84
+ width: number;
85
+ height: number;
86
+ fit: "cover" | "contain";
87
+ quality: number;
88
+ };
89
+ } | undefined;
90
+ variants: import("../../core/types/index.js").Variant[] | undefined;
91
+ configFile: string;
92
+ };
93
+ inputGroups: {
94
+ groupId: number;
95
+ groupTitle: string;
96
+ groupOrder: number;
97
+ inputs: {
98
+ type: import("../../core/types/index.js").FieldType;
99
+ name: string;
100
+ label: string;
101
+ required: boolean;
102
+ localized?: boolean;
103
+ conditionalFields: import("../../core/types/index.js").ConditionalField[];
104
+ readonly: boolean;
105
+ defaultValue: any;
106
+ value: any;
107
+ }[];
108
+ }[] | undefined;
109
+ defaultLocale: {
110
+ code: string;
111
+ label: string;
112
+ rtl?: boolean;
113
+ } | null;
114
+ error?: undefined;
115
+ };
116
+ meta: object;
117
+ }>;
118
+ editItem: import("@trpc/server").TRPCQueryProcedure<{
119
+ input: {
120
+ sectionName: string;
121
+ sectionItemId: string | number;
122
+ locale?: string | undefined;
123
+ };
124
+ output: {
125
+ section: {
126
+ name: string;
127
+ title: {
128
+ section: string;
129
+ singular: string;
130
+ plural: string;
131
+ };
132
+ gallery: {
133
+ db: {
134
+ tableName: string;
135
+ referenceIdentifierField: string;
136
+ photoNameField: string;
137
+ metaField: string;
138
+ };
139
+ watermark?: boolean;
140
+ thumbnail?: {
141
+ width: number;
142
+ height: number;
143
+ fit: "cover" | "contain";
144
+ quality: number;
145
+ };
146
+ } | undefined;
147
+ variants: import("../../core/types/index.js").Variant[] | undefined;
148
+ configFile: string;
149
+ };
150
+ inputGroups: {
151
+ groupId: number;
152
+ groupTitle: string;
153
+ groupOrder: number;
154
+ inputs: {
155
+ type: import("../../core/types/index.js").FieldType;
156
+ name: string;
157
+ label: string;
158
+ required: boolean;
159
+ localized?: boolean;
160
+ conditionalFields: import("../../core/types/index.js").ConditionalField[];
161
+ readonly: boolean;
162
+ defaultValue: any;
163
+ value: any;
164
+ }[];
165
+ }[] | undefined;
166
+ gallery: {
167
+ referenceId: string;
168
+ photo: string;
169
+ meta: any;
170
+ }[];
171
+ localization: {
172
+ defaultLocale: {
173
+ code: string;
174
+ label: string;
175
+ rtl?: boolean;
176
+ };
177
+ currentLocale: {
178
+ code: string;
179
+ label: string;
180
+ rtl?: boolean;
181
+ };
182
+ existingTranslations: string[];
183
+ locales: {
184
+ code: string;
185
+ label: string;
186
+ rtl?: boolean;
187
+ }[];
188
+ } | null;
189
+ error?: undefined;
190
+ } | {
191
+ error: {
192
+ message: any;
193
+ };
194
+ section?: undefined;
195
+ inputGroups?: undefined;
196
+ gallery?: undefined;
197
+ localization?: undefined;
198
+ };
199
+ meta: object;
200
+ }>;
201
+ deleteItem: import("@trpc/server").TRPCMutationProcedure<{
202
+ input: {
203
+ sectionName: string;
204
+ sectionItemId: string | number;
205
+ };
206
+ output: boolean;
207
+ meta: object;
208
+ }>;
209
+ deleteLocaleTranslation: import("@trpc/server").TRPCMutationProcedure<{
210
+ input: {
211
+ sectionName: string;
212
+ sectionItemId: string | number;
213
+ locale: string;
214
+ };
215
+ output: boolean;
216
+ meta: object;
217
+ }>;
218
+ }>>;
219
+ //# sourceMappingURL=hasItemsSection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hasItemsSection.d.ts","sourceRoot":"","sources":["../../../src/api/routers/hasItemsSection.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,CAAC,MAAM,KAAK,CAAA;AAcxB,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uBAwGykwC,CAAC;;;;;uBAAyE,CAAC;;;;;;uBAA8G,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GADnywC,CAAA"}
@@ -0,0 +1,86 @@
1
+ import { privateProcedure, router } from '../trpc.js';
2
+ import * as z from 'zod';
3
+ import { createEditPage, createNewPage, deleteLocaleTranslation, deleteSectionItem, getBrowsePage, } from '../lib/serverActions.js';
4
+ import { getRequestMetadataFromHeaders } from '../../logging/index.js';
5
+ import { TRPCError } from '@trpc/server';
6
+ import { getCMSConfig } from '../../core/config/index.js';
7
+ import { resolveLocale } from '../../core/localization/index.js';
8
+ import getString from '../../translations/index.js';
9
+ export const hasItemsSectionRouter = router({
10
+ listItems: privateProcedure
11
+ .input(z.object({
12
+ sectionName: z.string(),
13
+ page: z.number().optional(),
14
+ q: z.string().optional(),
15
+ }))
16
+ .query(async ({ ctx, input }) => {
17
+ return await getBrowsePage(ctx.session, input.sectionName, input.page, input.q);
18
+ }),
19
+ newItem: privateProcedure
20
+ .input(z.object({
21
+ sectionName: z.string(),
22
+ }))
23
+ .query(async ({ ctx, input }) => {
24
+ return await createNewPage(ctx.session, input.sectionName);
25
+ }),
26
+ editItem: privateProcedure
27
+ .input(z.object({
28
+ sectionName: z.string(),
29
+ sectionItemId: z.number().or(z.string()),
30
+ locale: z.string().optional(),
31
+ }))
32
+ .query(async ({ ctx, input }) => {
33
+ return await createEditPage(ctx.session, input.sectionName, input.sectionItemId, input.locale);
34
+ }),
35
+ deleteItem: privateProcedure
36
+ .input(z.object({ sectionName: z.string(), sectionItemId: z.number().or(z.string()) }))
37
+ .mutation(async ({ ctx, input }) => {
38
+ const requestMetadata = getRequestMetadataFromHeaders(ctx.headers);
39
+ const result = await deleteSectionItem(ctx.session, input.sectionName, input.sectionItemId, undefined, 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
+ deleteLocaleTranslation: privateProcedure
50
+ .input(z.object({
51
+ sectionName: z.string(),
52
+ sectionItemId: z.number().or(z.string()),
53
+ locale: z.string(),
54
+ }))
55
+ .mutation(async ({ ctx, input }) => {
56
+ const cmsConfig = await getCMSConfig();
57
+ const localeResult = resolveLocale({
58
+ localization: cmsConfig.localization,
59
+ locale: input.locale,
60
+ });
61
+ if (!localeResult.resolvedLocale) {
62
+ if (localeResult.localizationEnabled === false) {
63
+ throw new TRPCError({
64
+ code: 'BAD_REQUEST',
65
+ message: getString('localizationNotEnabledForSection', ctx.session.user.language),
66
+ });
67
+ }
68
+ throw new TRPCError({
69
+ code: 'BAD_REQUEST',
70
+ message: getString('invalidLocale', ctx.session.user.language, {
71
+ locale: input.locale,
72
+ locales: localeResult.availableLocales.map((l) => l.code).join(', '),
73
+ }),
74
+ });
75
+ }
76
+ const result = await deleteLocaleTranslation(ctx.session, input.sectionName, input.sectionItemId, localeResult.resolvedLocale.code);
77
+ if (result && typeof result === 'object' && 'error' in result) {
78
+ const message = result.error?.message ?? 'Failed to delete locale translation';
79
+ throw new TRPCError({
80
+ code: 'BAD_REQUEST',
81
+ message,
82
+ });
83
+ }
84
+ return result;
85
+ }),
86
+ });
@@ -0,0 +1,59 @@
1
+ import * as z from 'zod';
2
+ export declare const logsRouter: 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
+ list: import("@trpc/server").TRPCQueryProcedure<{
25
+ input: {
26
+ limit?: number | undefined;
27
+ offset?: number | undefined;
28
+ eventType?: string | undefined;
29
+ actorId?: string | undefined;
30
+ sectionName?: string | undefined;
31
+ entityType?: string | undefined;
32
+ entityId?: string | undefined;
33
+ from?: string | undefined;
34
+ to?: string | undefined;
35
+ } | undefined;
36
+ output: {
37
+ items: {
38
+ id: number;
39
+ eventType: string;
40
+ actorId: string | null;
41
+ actorUsername: string | null;
42
+ entityType: string | null;
43
+ entityId: string | null;
44
+ entityLabel: string | null;
45
+ sectionName: string | null;
46
+ metadata: string | null;
47
+ ipAddress: string | null;
48
+ userAgent: string | null;
49
+ source: string | null;
50
+ createdAt: Date;
51
+ }[];
52
+ total: number;
53
+ limit: number;
54
+ offset: number;
55
+ };
56
+ meta: object;
57
+ }>;
58
+ }>>;
59
+ //# sourceMappingURL=logs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logs.d.ts","sourceRoot":"","sources":["../../../src/api/routers/logs.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,CAAC,MAAM,KAAK,CAAA;AAqBxB,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8DrB,CAAA"}
@@ -0,0 +1,76 @@
1
+ import { TRPCError } from '@trpc/server';
2
+ import { and, desc, eq, gte, lte, sql } from 'drizzle-orm';
3
+ import * as z from 'zod';
4
+ import { db } from '../../db/client.js';
5
+ import { LogsTable } from '../../db/schema.js';
6
+ import { isAccessAllowed } from '../lib/serverActions.js';
7
+ import { privateProcedure, router } from '../trpc.js';
8
+ import getString from '../../translations/index.js';
9
+ const listInputSchema = z
10
+ .object({
11
+ limit: z.number().min(1).max(200).optional(),
12
+ offset: z.number().min(0).optional(),
13
+ eventType: z.string().optional(),
14
+ actorId: z.string().optional(),
15
+ sectionName: z.string().optional(),
16
+ entityType: z.string().optional(),
17
+ entityId: z.string().optional(),
18
+ from: z.string().datetime().optional(),
19
+ to: z.string().datetime().optional(),
20
+ })
21
+ .optional();
22
+ export const logsRouter = router({
23
+ list: privateProcedure.input(listInputSchema).query(async ({ ctx, input }) => {
24
+ const accessAllowed = await isAccessAllowed({
25
+ sectionName: 'log',
26
+ userId: ctx.session.user.id,
27
+ });
28
+ if (!accessAllowed) {
29
+ throw new TRPCError({
30
+ code: 'NOT_FOUND',
31
+ message: getString('sectionNotFound', ctx.session.user.language),
32
+ });
33
+ }
34
+ const limit = input?.limit ?? 50;
35
+ const offset = input?.offset ?? 0;
36
+ const conditions = [];
37
+ if (input?.eventType) {
38
+ conditions.push(eq(LogsTable.eventType, input.eventType));
39
+ }
40
+ if (input?.actorId) {
41
+ conditions.push(eq(LogsTable.actorId, input.actorId));
42
+ }
43
+ if (input?.sectionName) {
44
+ conditions.push(eq(LogsTable.sectionName, input.sectionName));
45
+ }
46
+ if (input?.entityType) {
47
+ conditions.push(eq(LogsTable.entityType, input.entityType));
48
+ }
49
+ if (input?.entityId) {
50
+ conditions.push(eq(LogsTable.entityId, input.entityId));
51
+ }
52
+ if (input?.from) {
53
+ conditions.push(gte(LogsTable.createdAt, new Date(input.from)));
54
+ }
55
+ if (input?.to) {
56
+ conditions.push(lte(LogsTable.createdAt, new Date(input.to)));
57
+ }
58
+ const whereClause = conditions.length > 0 ? and(...conditions) : undefined;
59
+ let listQuery = db.select().from(LogsTable).$dynamic();
60
+ let countQuery = db.select({ count: sql `count(*)` }).from(LogsTable).$dynamic();
61
+ if (whereClause) {
62
+ listQuery = listQuery.where(whereClause);
63
+ countQuery = countQuery.where(whereClause);
64
+ }
65
+ const [rows, totalRows] = await Promise.all([
66
+ listQuery.orderBy(desc(LogsTable.createdAt)).limit(limit).offset(offset),
67
+ countQuery,
68
+ ]);
69
+ return {
70
+ items: rows,
71
+ total: totalRows[0]?.count ?? 0,
72
+ limit,
73
+ offset,
74
+ };
75
+ }),
76
+ });