@questpie/admin 3.0.4 → 3.0.6

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 (90) hide show
  1. package/README.md +99 -1
  2. package/dist/client/builder/types/field-types.d.mts +11 -0
  3. package/dist/client/components/blocks/block-editor-layout.mjs +2 -2
  4. package/dist/client/components/blocks/block-library-sidebar.mjs +89 -61
  5. package/dist/client/components/brand-logo.d.mts +25 -0
  6. package/dist/client/components/brand-logo.mjs +174 -0
  7. package/dist/client/components/media/media-grid.mjs +95 -78
  8. package/dist/client/components/primitives/select-multi.mjs +388 -368
  9. package/dist/client/components/primitives/select-single.mjs +344 -331
  10. package/dist/client/components/widgets/chart-widget.mjs +78 -62
  11. package/dist/client/components/widgets/progress-widget.mjs +39 -37
  12. package/dist/client/components/widgets/quick-actions-widget.mjs +111 -90
  13. package/dist/client/components/widgets/recent-items-widget.mjs +40 -38
  14. package/dist/client/components/widgets/table-widget.mjs +4 -3
  15. package/dist/client/components/widgets/timeline-widget.mjs +92 -74
  16. package/dist/client/components/widgets/value-widget.mjs +164 -144
  17. package/dist/client/create-admin-client.d.mts +7 -0
  18. package/dist/client/create-admin-client.mjs +25 -0
  19. package/dist/client/hooks/use-brand.d.mts +22 -0
  20. package/dist/client/hooks/use-brand.mjs +52 -0
  21. package/dist/client/hooks/use-server-actions.mjs +21 -16
  22. package/dist/client/preview/block-scope-context.d.mts +2 -2
  23. package/dist/client/preview/preview-banner.d.mts +2 -2
  24. package/dist/client/preview/preview-banner.mjs +75 -46
  25. package/dist/client/runtime/index.mjs +1 -1
  26. package/dist/client/runtime/provider.d.mts +4 -0
  27. package/dist/client/runtime/provider.mjs +38 -8
  28. package/dist/client/styles/base.css +4 -0
  29. package/dist/client/types/admin-config.d.mts +24 -0
  30. package/dist/client/views/auth/auth-layout.d.mts +6 -1
  31. package/dist/client/views/auth/auth-layout.mjs +116 -102
  32. package/dist/client/views/collection/auto-form-fields.mjs +2 -0
  33. package/dist/client/views/collection/field-renderer.mjs +3 -2
  34. package/dist/client/views/collection/table-view.mjs +26 -26
  35. package/dist/client/views/globals/global-form-view.mjs +908 -863
  36. package/dist/client/views/layout/admin-layout.mjs +151 -131
  37. package/dist/client/views/layout/admin-router.mjs +297 -180
  38. package/dist/client/views/layout/admin-sidebar.mjs +178 -156
  39. package/dist/client/views/pages/accept-invite-page.mjs +122 -144
  40. package/dist/client/views/pages/forgot-password-page.mjs +22 -30
  41. package/dist/client/views/pages/invite-page.mjs +24 -33
  42. package/dist/client/views/pages/login-page.mjs +24 -32
  43. package/dist/client/views/pages/reset-password-page.mjs +77 -92
  44. package/dist/client/views/pages/setup-page.mjs +73 -65
  45. package/dist/client.d.mts +6 -2
  46. package/dist/client.mjs +5 -2
  47. package/dist/index.d.mts +6 -2
  48. package/dist/index.mjs +5 -2
  49. package/dist/server/augmentation/dashboard.d.mts +23 -5
  50. package/dist/server/augmentation/form-layout.d.mts +10 -0
  51. package/dist/server/augmentation/index.d.mts +1 -1
  52. package/dist/server/augmentation.d.mts +1 -1
  53. package/dist/server/i18n/index.mjs +13 -7
  54. package/dist/server/i18n/messages/cs.mjs +391 -1
  55. package/dist/server/i18n/messages/de.mjs +389 -1
  56. package/dist/server/i18n/messages/en.mjs +102 -0
  57. package/dist/server/i18n/messages/es.mjs +389 -1
  58. package/dist/server/i18n/messages/fr.mjs +389 -1
  59. package/dist/server/i18n/messages/pl.mjs +393 -1
  60. package/dist/server/i18n/messages/pt.mjs +386 -1
  61. package/dist/server/i18n/messages/sk.mjs +133 -1
  62. package/dist/server/modules/admin/collections/account.d.mts +50 -50
  63. package/dist/server/modules/admin/collections/admin-locks.d.mts +53 -53
  64. package/dist/server/modules/admin/collections/admin-preferences.d.mts +39 -39
  65. package/dist/server/modules/admin/collections/admin-saved-views.d.mts +47 -47
  66. package/dist/server/modules/admin/collections/apikey.d.mts +68 -68
  67. package/dist/server/modules/admin/collections/assets.d.mts +20 -20
  68. package/dist/server/modules/admin/collections/session.d.mts +42 -42
  69. package/dist/server/modules/admin/collections/user.d.mts +32 -32
  70. package/dist/server/modules/admin/collections/verification.d.mts +36 -36
  71. package/dist/server/modules/admin/dto/admin-config.dto.mjs +19 -1
  72. package/dist/server/modules/admin/routes/admin-config.d.mts +2 -2
  73. package/dist/server/modules/admin/routes/execute-action.d.mts +9 -9
  74. package/dist/server/modules/admin/routes/execute-action.mjs +34 -28
  75. package/dist/server/modules/admin/routes/i18n-helpers.mjs +34 -0
  76. package/dist/server/modules/admin/routes/locales.d.mts +2 -2
  77. package/dist/server/modules/admin/routes/preview.d.mts +11 -11
  78. package/dist/server/modules/admin/routes/preview.mjs +25 -17
  79. package/dist/server/modules/admin/routes/reactive.d.mts +9 -9
  80. package/dist/server/modules/admin/routes/route-helpers.mjs +1 -1
  81. package/dist/server/modules/admin/routes/setup.mjs +10 -7
  82. package/dist/server/modules/admin/routes/translations.d.mts +4 -4
  83. package/dist/server/modules/admin/routes/widget-data.d.mts +5 -5
  84. package/dist/server/modules/admin-preferences/collections/saved-views.d.mts +23 -23
  85. package/dist/server.d.mts +4 -4
  86. package/dist/shared/preview-utils.d.mts +34 -1
  87. package/dist/shared/preview-utils.mjs +79 -1
  88. package/dist/shared.d.mts +2 -2
  89. package/dist/shared.mjs +2 -2
  90. package/package.json +3 -3
@@ -1,7 +1,7 @@
1
1
  import { ServerActionDefinition, ServerActionResult } from "../../../augmentation/actions.mjs";
2
2
  import "../../../augmentation.mjs";
3
3
  import { App } from "./route-helpers.mjs";
4
- import * as questpie69 from "questpie";
4
+ import * as questpie135 from "questpie";
5
5
 
6
6
  //#region src/server/modules/admin/routes/execute-action.d.ts
7
7
 
@@ -56,37 +56,37 @@ declare function executeAction(app: App, request: ExecuteActionRequest, session?
56
56
  * });
57
57
  * ```
58
58
  */
59
- declare const executeActionFn: questpie69.JsonRouteDefinition<{
59
+ declare const executeActionFn: questpie135.JsonRouteDefinition<{
60
60
  collection: string;
61
61
  actionId: string;
62
62
  itemId?: string | undefined;
63
63
  itemIds?: string[] | undefined;
64
64
  data?: Record<string, unknown> | undefined;
65
65
  locale?: string | undefined;
66
- }, any, questpie69.JsonRouteParams>;
66
+ }, any, questpie135.JsonRouteParams>;
67
67
  /**
68
68
  * Get actions configuration for a collection.
69
69
  * Returns action definitions without handlers for client rendering.
70
70
  */
71
- declare const getActionsConfigFn: questpie69.JsonRouteDefinition<{
71
+ declare const getActionsConfigFn: questpie135.JsonRouteDefinition<{
72
72
  collection: string;
73
- }, any, questpie69.JsonRouteParams>;
73
+ }, any, questpie135.JsonRouteParams>;
74
74
  /**
75
75
  * QUESTPIE functions for action execution.
76
76
  * These are registered on the `adminModule`.
77
77
  */
78
78
  declare const actionFunctions: {
79
- executeAction: questpie69.JsonRouteDefinition<{
79
+ executeAction: questpie135.JsonRouteDefinition<{
80
80
  collection: string;
81
81
  actionId: string;
82
82
  itemId?: string | undefined;
83
83
  itemIds?: string[] | undefined;
84
84
  data?: Record<string, unknown> | undefined;
85
85
  locale?: string | undefined;
86
- }, any, questpie69.JsonRouteParams>;
87
- getActionsConfig: questpie69.JsonRouteDefinition<{
86
+ }, any, questpie135.JsonRouteParams>;
87
+ getActionsConfig: questpie135.JsonRouteDefinition<{
88
88
  collection: string;
89
- }, any, questpie69.JsonRouteParams>;
89
+ }, any, questpie135.JsonRouteParams>;
90
90
  };
91
91
  //#endregion
92
92
  export { ExecuteActionRequest, ExecuteActionResponse, actionFunctions, executeAction, executeActionFn, getActionsConfig, getActionsConfigFn };
@@ -1,4 +1,5 @@
1
1
  import { getApp, getAppState, getSession } from "./route-helpers.mjs";
2
+ import { translateAdminMessage } from "./i18n-helpers.mjs";
2
3
  import { z } from "zod";
3
4
  import { route } from "questpie";
4
5
 
@@ -98,9 +99,10 @@ function serializeActionFormFields(fields) {
98
99
  async function executeAction(app, request, session) {
99
100
  const { collection: collectionSlug, actionId, itemId, itemIds, data, locale } = request;
100
101
  const collection$1 = getAppState(app).collections?.[collectionSlug];
102
+ const t = (key, params) => translateAdminMessage(locale, key, params);
101
103
  if (!collection$1) return {
102
104
  success: false,
103
- error: `Collection "${collectionSlug}" not found`
105
+ error: t("action.collectionNotFound", { collection: collectionSlug })
104
106
  };
105
107
  const actionsConfig = (collection$1.state || collection$1).adminActions;
106
108
  if ((actionsConfig?.builtin || [
@@ -124,10 +126,13 @@ async function executeAction(app, request, session) {
124
126
  const customAction = actionsConfig?.custom?.find((a) => a.id === actionId);
125
127
  if (!customAction) return {
126
128
  success: false,
127
- error: `Action "${actionId}" not found on collection "${collectionSlug}"`
129
+ error: t("action.notFound", {
130
+ action: actionId,
131
+ collection: collectionSlug
132
+ })
128
133
  };
129
134
  if (customAction.form) {
130
- const validationError = validateActionFormData(customAction.form.fields, data || {});
135
+ const validationError = validateActionFormData(customAction.form.fields, data || {}, t);
131
136
  if (validationError) return {
132
137
  success: false,
133
138
  result: {
@@ -160,7 +165,7 @@ async function executeAction(app, request, session) {
160
165
  success: false,
161
166
  result: {
162
167
  type: "error",
163
- toast: { message: error instanceof Error ? error.message : "Action execution failed" }
168
+ toast: { message: error instanceof Error ? error.message : t("action.executionFailed") }
164
169
  }
165
170
  };
166
171
  }
@@ -169,7 +174,8 @@ async function executeAction(app, request, session) {
169
174
  * Execute a built-in action.
170
175
  */
171
176
  async function executeBuiltinAction(app, params) {
172
- const { collectionSlug, actionId, itemId, itemIds, data } = params;
177
+ const { collectionSlug, actionId, itemId, itemIds, data, locale } = params;
178
+ const t = (key, messageParams) => translateAdminMessage(locale, key, messageParams);
173
179
  const appRec = app;
174
180
  const collectionCrud = appRec.api?.collections?.[collectionSlug];
175
181
  const crudContext = {
@@ -185,7 +191,7 @@ async function executeBuiltinAction(app, params) {
185
191
  success: true,
186
192
  result: {
187
193
  type: "success",
188
- toast: { message: "Item created successfully" },
194
+ toast: { message: t("action.itemCreated") },
189
195
  effects: {
190
196
  invalidate: [collectionSlug],
191
197
  redirect: `/admin/collections/${collectionSlug}/${result.id}`
@@ -198,7 +204,7 @@ async function executeBuiltinAction(app, params) {
198
204
  success: false,
199
205
  result: {
200
206
  type: "error",
201
- toast: { message: "Item ID is required for save action" }
207
+ toast: { message: t("action.itemIdRequired.save") }
202
208
  }
203
209
  };
204
210
  await appRec.update(collectionSlug, itemId, data || {});
@@ -206,7 +212,7 @@ async function executeBuiltinAction(app, params) {
206
212
  success: true,
207
213
  result: {
208
214
  type: "success",
209
- toast: { message: "Item saved successfully" },
215
+ toast: { message: t("action.itemSaved") },
210
216
  effects: { invalidate: [collectionSlug] }
211
217
  }
212
218
  };
@@ -215,7 +221,7 @@ async function executeBuiltinAction(app, params) {
215
221
  success: false,
216
222
  result: {
217
223
  type: "error",
218
- toast: { message: "Item ID is required for delete action" }
224
+ toast: { message: t("action.itemIdRequired.delete") }
219
225
  }
220
226
  };
221
227
  await appRec.delete(collectionSlug, itemId);
@@ -223,7 +229,7 @@ async function executeBuiltinAction(app, params) {
223
229
  success: true,
224
230
  result: {
225
231
  type: "success",
226
- toast: { message: "Item deleted successfully" },
232
+ toast: { message: t("action.itemDeleted") },
227
233
  effects: {
228
234
  invalidate: [collectionSlug],
229
235
  redirect: `/admin/collections/${collectionSlug}`
@@ -235,7 +241,7 @@ async function executeBuiltinAction(app, params) {
235
241
  success: false,
236
242
  result: {
237
243
  type: "error",
238
- toast: { message: "Item IDs are required for bulk delete action" }
244
+ toast: { message: t("action.itemIdsRequired.bulkDelete") }
239
245
  }
240
246
  };
241
247
  await Promise.all(itemIds.map((id) => appRec.delete(collectionSlug, id)));
@@ -243,7 +249,7 @@ async function executeBuiltinAction(app, params) {
243
249
  success: true,
244
250
  result: {
245
251
  type: "success",
246
- toast: { message: `${itemIds.length} items deleted successfully` },
252
+ toast: { message: t("action.itemsDeleted", { count: itemIds.length }) },
247
253
  effects: { invalidate: [collectionSlug] }
248
254
  }
249
255
  };
@@ -252,7 +258,7 @@ async function executeBuiltinAction(app, params) {
252
258
  success: false,
253
259
  result: {
254
260
  type: "error",
255
- toast: { message: "Item ID is required for restore action" }
261
+ toast: { message: t("action.itemIdRequired.restore") }
256
262
  }
257
263
  };
258
264
  if (typeof appRec.restore === "function") await appRec.restore(collectionSlug, itemId);
@@ -261,14 +267,14 @@ async function executeBuiltinAction(app, params) {
261
267
  success: false,
262
268
  result: {
263
269
  type: "error",
264
- toast: { message: "Restore is not supported for this collection" }
270
+ toast: { message: t("action.restoreUnsupported") }
265
271
  }
266
272
  };
267
273
  return {
268
274
  success: true,
269
275
  result: {
270
276
  type: "success",
271
- toast: { message: "Item restored successfully" },
277
+ toast: { message: t("action.itemRestored") },
272
278
  effects: {
273
279
  invalidate: [collectionSlug],
274
280
  redirect: `/admin/collections/${collectionSlug}/${itemId}`
@@ -280,7 +286,7 @@ async function executeBuiltinAction(app, params) {
280
286
  success: false,
281
287
  result: {
282
288
  type: "error",
283
- toast: { message: "Item IDs are required for bulk restore action" }
289
+ toast: { message: t("action.itemIdsRequired.bulkRestore") }
284
290
  }
285
291
  };
286
292
  if (typeof appRec.restore === "function") await Promise.all(itemIds.map((id) => appRec.restore(collectionSlug, id)));
@@ -296,7 +302,7 @@ async function executeBuiltinAction(app, params) {
296
302
  success: true,
297
303
  result: {
298
304
  type: "success",
299
- toast: { message: `${itemIds.length} items restored successfully` },
305
+ toast: { message: t("action.itemsRestored", { count: itemIds.length }) },
300
306
  effects: { invalidate: [collectionSlug] }
301
307
  }
302
308
  };
@@ -305,7 +311,7 @@ async function executeBuiltinAction(app, params) {
305
311
  success: false,
306
312
  result: {
307
313
  type: "error",
308
- toast: { message: "Item ID is required for duplicate action" }
314
+ toast: { message: t("action.itemIdRequired.duplicate") }
309
315
  }
310
316
  };
311
317
  const original = await appRec.findById(collectionSlug, itemId);
@@ -313,7 +319,7 @@ async function executeBuiltinAction(app, params) {
313
319
  success: false,
314
320
  result: {
315
321
  type: "error",
316
- toast: { message: "Item not found" }
322
+ toast: { message: t("action.itemNotFound") }
317
323
  }
318
324
  };
319
325
  const { id, createdAt, updatedAt, ...duplicateData } = original;
@@ -322,7 +328,7 @@ async function executeBuiltinAction(app, params) {
322
328
  success: true,
323
329
  result: {
324
330
  type: "success",
325
- toast: { message: "Item duplicated successfully" },
331
+ toast: { message: t("action.itemDuplicated") },
326
332
  effects: {
327
333
  invalidate: [collectionSlug],
328
334
  redirect: `/admin/collections/${collectionSlug}/${duplicated.id}`
@@ -335,7 +341,7 @@ async function executeBuiltinAction(app, params) {
335
341
  success: false,
336
342
  result: {
337
343
  type: "error",
338
- toast: { message: "Item ID is required for transition action" }
344
+ toast: { message: t("action.itemIdRequired.transition") }
339
345
  }
340
346
  };
341
347
  const stage = data?.stage;
@@ -343,7 +349,7 @@ async function executeBuiltinAction(app, params) {
343
349
  success: false,
344
350
  result: {
345
351
  type: "error",
346
- toast: { message: "Target stage is required for transition action" }
352
+ toast: { message: t("action.targetStageRequired") }
347
353
  }
348
354
  };
349
355
  if (collectionCrud?.transitionStage) {
@@ -358,14 +364,14 @@ async function executeBuiltinAction(app, params) {
358
364
  success: false,
359
365
  result: {
360
366
  type: "error",
361
- toast: { message: "Workflow transitions are not supported for this collection" }
367
+ toast: { message: t("action.workflowUnsupported") }
362
368
  }
363
369
  };
364
370
  return {
365
371
  success: true,
366
372
  result: {
367
373
  type: "success",
368
- toast: { message: `Transitioned to "${stage}" successfully` },
374
+ toast: { message: t("workflow.transitionSuccess", { stage }) },
369
375
  effects: { invalidate: [collectionSlug] }
370
376
  }
371
377
  };
@@ -374,7 +380,7 @@ async function executeBuiltinAction(app, params) {
374
380
  success: false,
375
381
  result: {
376
382
  type: "error",
377
- toast: { message: `Unknown built-in action: ${actionId}` }
383
+ toast: { message: t("action.unknownBuiltin", { action: actionId }) }
378
384
  }
379
385
  };
380
386
  }
@@ -384,7 +390,7 @@ async function executeBuiltinAction(app, params) {
384
390
  success: false,
385
391
  result: {
386
392
  type: "error",
387
- toast: { message: error instanceof Error ? error.message : "Action execution failed" }
393
+ toast: { message: error instanceof Error ? error.message : t("action.executionFailed") }
388
394
  }
389
395
  };
390
396
  }
@@ -406,8 +412,8 @@ function isFieldRequired(field$1) {
406
412
  * Validate form data against action form fields.
407
413
  * Returns error message if validation fails, null if valid.
408
414
  */
409
- function validateActionFormData(fields, data) {
410
- for (const [fieldName, fieldConfig] of Object.entries(fields)) if (isFieldRequired(fieldConfig) && !data[fieldName]) return `Field "${fieldName}" is required`;
415
+ function validateActionFormData(fields, data, t) {
416
+ for (const [fieldName, fieldConfig] of Object.entries(fields)) if (isFieldRequired(fieldConfig) && !data[fieldName]) return t("action.fieldRequired", { field: fieldName });
411
417
  return null;
412
418
  }
413
419
  const executeActionRequestSchema = z.object({
@@ -0,0 +1,34 @@
1
+ import { getAdminMessagesForLocale } from "../../../i18n/index.mjs";
2
+
3
+ //#region src/server/modules/admin/routes/i18n-helpers.ts
4
+ function getPluralCount(params) {
5
+ if (!params) return 1;
6
+ for (const key of [
7
+ "count",
8
+ "total",
9
+ "length"
10
+ ]) if (typeof params[key] === "number") return params[key];
11
+ return 1;
12
+ }
13
+ function selectMessage(value, locale, params) {
14
+ if (typeof value === "string") return value;
15
+ const count = getPluralCount(params);
16
+ try {
17
+ return value[new Intl.PluralRules(locale).select(count)] ?? value.other;
18
+ } catch {
19
+ return count === 1 ? value.one : value.other;
20
+ }
21
+ }
22
+ function interpolate(template, params) {
23
+ if (!params) return template;
24
+ return template.replace(/\{\{\s*(\w+)\s*\}\}/g, (_, key) => params[key] === void 0 ? `{{${key}}}` : String(params[key]));
25
+ }
26
+ function translateAdminMessage(locale, key, params) {
27
+ const resolvedLocale = locale ?? "en";
28
+ const message = getAdminMessagesForLocale(resolvedLocale)[key];
29
+ if (message === void 0) return key;
30
+ return interpolate(selectMessage(message, resolvedLocale, params), params);
31
+ }
32
+
33
+ //#endregion
34
+ export { translateAdminMessage };
@@ -1,4 +1,4 @@
1
- import * as questpie462 from "questpie";
1
+ import * as questpie268 from "questpie";
2
2
 
3
3
  //#region src/server/modules/admin/routes/locales.d.ts
4
4
 
@@ -12,7 +12,7 @@ import * as questpie462 from "questpie";
12
12
  * Bundle of locale-related functions.
13
13
  */
14
14
  declare const localeFunctions: {
15
- readonly getContentLocales: questpie462.JsonRouteDefinition<Record<string, never> | undefined, any, questpie462.JsonRouteParams>;
15
+ readonly getContentLocales: questpie268.JsonRouteDefinition<Record<string, never> | undefined, any, questpie268.JsonRouteParams>;
16
16
  };
17
17
  //#endregion
18
18
  export { localeFunctions };
@@ -1,4 +1,4 @@
1
- import * as questpie97 from "questpie";
1
+ import * as questpie117 from "questpie";
2
2
 
3
3
  //#region src/server/modules/admin/routes/preview.d.ts
4
4
 
@@ -21,13 +21,13 @@ interface PreviewTokenPayload {
21
21
  * @returns Object with preview functions
22
22
  */
23
23
  declare function createPreviewFunctions(secret: string): {
24
- mintPreviewToken: questpie97.JsonRouteDefinition<{
24
+ mintPreviewToken: questpie117.JsonRouteDefinition<{
25
25
  path: string;
26
26
  ttlMs?: number | undefined;
27
- }, any, questpie97.JsonRouteParams>;
28
- verifyPreviewToken: questpie97.JsonRouteDefinition<{
27
+ }, any, questpie117.JsonRouteParams>;
28
+ verifyPreviewToken: questpie117.JsonRouteDefinition<{
29
29
  token: string;
30
- }, any, questpie97.JsonRouteParams>;
30
+ }, any, questpie117.JsonRouteParams>;
31
31
  };
32
32
  /**
33
33
  * Verify a preview token without RPC.
@@ -63,18 +63,18 @@ declare function createPreviewTokenVerifier(secret?: string): (token: string) =>
63
63
  * Used by the `adminModule` to register preview RPC functions.
64
64
  */
65
65
  declare const previewFunctions: {
66
- getPreviewUrl: questpie97.JsonRouteDefinition<{
66
+ getPreviewUrl: questpie117.JsonRouteDefinition<{
67
67
  collection: string;
68
68
  record: Record<string, unknown>;
69
69
  locale?: string | undefined;
70
- }, any, questpie97.JsonRouteParams>;
71
- mintPreviewToken: questpie97.JsonRouteDefinition<{
70
+ }, any, questpie117.JsonRouteParams>;
71
+ mintPreviewToken: questpie117.JsonRouteDefinition<{
72
72
  path: string;
73
73
  ttlMs?: number | undefined;
74
- }, any, questpie97.JsonRouteParams>;
75
- verifyPreviewToken: questpie97.JsonRouteDefinition<{
74
+ }, any, questpie117.JsonRouteParams>;
75
+ verifyPreviewToken: questpie117.JsonRouteDefinition<{
76
76
  token: string;
77
- }, any, questpie97.JsonRouteParams>;
77
+ }, any, questpie117.JsonRouteParams>;
78
78
  };
79
79
  //#endregion
80
80
  export { PreviewTokenPayload, createPreviewFunctions, createPreviewTokenVerifier, previewFunctions, verifyPreviewTokenDirect };
@@ -1,5 +1,6 @@
1
- import { getApp, getCollectionState, getSession } from "./route-helpers.mjs";
2
1
  import { getPreviewSecret } from "../../../../shared/preview-utils.mjs";
2
+ import { getApp, getCollectionState, getLocale, getSession } from "./route-helpers.mjs";
3
+ import { translateAdminMessage } from "./i18n-helpers.mjs";
3
4
  import { z } from "zod";
4
5
  import { ApiError, route } from "questpie";
5
6
  import { createHmac, timingSafeEqual } from "node:crypto";
@@ -23,7 +24,7 @@ function base64UrlDecode(input) {
23
24
  return Buffer.from(base64, "base64").toString("utf8");
24
25
  }
25
26
  const mintPreviewTokenSchema = z.object({
26
- path: z.string().min(1, "Path is required"),
27
+ path: z.string().min(1),
27
28
  ttlMs: z.number().positive().optional()
28
29
  });
29
30
  const mintPreviewTokenOutputSchema = z.object({
@@ -50,7 +51,9 @@ function createPreviewFunctions(secret) {
50
51
  return {
51
52
  mintPreviewToken: route().post().schema(mintPreviewTokenSchema).outputSchema(mintPreviewTokenOutputSchema).handler(async (ctx) => {
52
53
  const { input } = ctx;
53
- if (!getSession(ctx)) throw ApiError.unauthorized("Admin session required");
54
+ const locale = getLocale(ctx);
55
+ const t = (key, params) => translateAdminMessage(locale, key, params);
56
+ if (!getSession(ctx)) throw ApiError.unauthorized(t("preview.adminSessionRequired"));
54
57
  const { path, ttlMs = DEFAULT_TTL_MS } = input;
55
58
  const expiresAt = Date.now() + ttlMs;
56
59
  const payload = {
@@ -63,37 +66,40 @@ function createPreviewFunctions(secret) {
63
66
  expiresAt
64
67
  };
65
68
  }),
66
- verifyPreviewToken: route().post().schema(verifyPreviewTokenSchema).outputSchema(verifyPreviewTokenOutputSchema).handler(async ({ input }) => {
69
+ verifyPreviewToken: route().post().schema(verifyPreviewTokenSchema).outputSchema(verifyPreviewTokenOutputSchema).handler(async (ctx) => {
70
+ const { input } = ctx;
71
+ const locale = getLocale(ctx);
72
+ const t = (key, params) => translateAdminMessage(locale, key, params);
67
73
  const { token } = input;
68
74
  const [encodedPayload, signature] = token.split(".");
69
75
  if (!encodedPayload || !signature) return {
70
76
  valid: false,
71
- error: "Invalid token format"
77
+ error: t("preview.invalidTokenFormat")
72
78
  };
73
79
  const expectedSignature = signPayload(encodedPayload);
74
80
  const signatureBuffer = Uint8Array.from(Buffer.from(signature));
75
81
  const expectedBuffer = Uint8Array.from(Buffer.from(expectedSignature));
76
82
  if (signatureBuffer.length !== expectedBuffer.length) return {
77
83
  valid: false,
78
- error: "Invalid signature"
84
+ error: t("preview.invalidSignature")
79
85
  };
80
86
  if (!timingSafeEqual(signatureBuffer, expectedBuffer)) return {
81
87
  valid: false,
82
- error: "Invalid signature"
88
+ error: t("preview.invalidSignature")
83
89
  };
84
90
  try {
85
91
  const payload = JSON.parse(base64UrlDecode(encodedPayload));
86
92
  if (!payload?.exp || typeof payload.exp !== "number") return {
87
93
  valid: false,
88
- error: "Invalid payload"
94
+ error: t("preview.invalidPayload")
89
95
  };
90
96
  if (payload.exp < Date.now()) return {
91
97
  valid: false,
92
- error: "Token expired"
98
+ error: t("preview.tokenExpired")
93
99
  };
94
100
  if (!payload.path || typeof payload.path !== "string") return {
95
101
  valid: false,
96
- error: "Invalid path"
102
+ error: t("preview.invalidPath")
97
103
  };
98
104
  return {
99
105
  valid: true,
@@ -102,7 +108,7 @@ function createPreviewFunctions(secret) {
102
108
  } catch {
103
109
  return {
104
110
  valid: false,
105
- error: "Invalid payload"
111
+ error: t("preview.invalidPayload")
106
112
  };
107
113
  }
108
114
  })
@@ -160,7 +166,7 @@ function createPreviewTokenVerifier(secret) {
160
166
  };
161
167
  }
162
168
  const getPreviewUrlSchema = z.object({
163
- collection: z.string().min(1, "Collection name is required"),
169
+ collection: z.string().min(1),
164
170
  record: z.record(z.string(), z.unknown()),
165
171
  locale: z.string().optional()
166
172
  });
@@ -186,24 +192,26 @@ const getPreviewUrlOutputSchema = z.object({
186
192
  */
187
193
  const getPreviewUrl = route().post().schema(getPreviewUrlSchema).outputSchema(getPreviewUrlOutputSchema).handler(async (ctx) => {
188
194
  const { input } = ctx;
195
+ const messageLocale = getLocale(ctx) ?? input.locale;
196
+ const t = (key, params) => translateAdminMessage(messageLocale, key, params);
189
197
  if (!getSession(ctx)) return {
190
198
  url: null,
191
- error: "Unauthorized: Admin session required"
199
+ error: t("preview.adminSessionRequired")
192
200
  };
193
201
  const { collection: collectionName, record, locale } = input;
194
202
  const collection$1 = getApp(ctx).getCollections()[collectionName];
195
203
  if (!collection$1) return {
196
204
  url: null,
197
- error: `Collection '${collectionName}' not found`
205
+ error: t("preview.collectionNotFound", { collection: collectionName })
198
206
  };
199
207
  const previewConfig = getCollectionState(collection$1).adminPreview;
200
208
  if (!previewConfig?.url) return {
201
209
  url: null,
202
- error: "No preview URL configured for this collection"
210
+ error: t("preview.noUrlConfigured")
203
211
  };
204
212
  if (previewConfig.enabled === false) return {
205
213
  url: null,
206
- error: "Preview is disabled for this collection"
214
+ error: t("preview.disabledForCollection")
207
215
  };
208
216
  try {
209
217
  return { url: previewConfig.url({
@@ -213,7 +221,7 @@ const getPreviewUrl = route().post().schema(getPreviewUrlSchema).outputSchema(ge
213
221
  } catch (err) {
214
222
  return {
215
223
  url: null,
216
- error: `Failed to generate preview URL: ${err instanceof Error ? err.message : "Unknown error"}`
224
+ error: t("preview.generateUrlFailed", { message: err instanceof Error ? err.message : t("error.unknown") })
217
225
  };
218
226
  }
219
227
  });
@@ -1,4 +1,4 @@
1
- import * as questpie135 from "questpie";
1
+ import * as questpie127 from "questpie";
2
2
 
3
3
  //#region src/server/modules/admin/routes/reactive.d.ts
4
4
 
@@ -13,7 +13,7 @@ import * as questpie135 from "questpie";
13
13
  * Batch reactive endpoint.
14
14
  * Executes multiple reactive handlers in a single request.
15
15
  */
16
- declare const batchReactive: questpie135.JsonRouteDefinition<{
16
+ declare const batchReactive: questpie127.JsonRouteDefinition<{
17
17
  collection: string;
18
18
  type: "collection" | "global";
19
19
  requests: {
@@ -26,12 +26,12 @@ declare const batchReactive: questpie135.JsonRouteDefinition<{
26
26
  }[];
27
27
  formData?: Record<string, unknown> | undefined;
28
28
  prevData?: Record<string, unknown> | null | undefined;
29
- }, any, questpie135.JsonRouteParams>;
29
+ }, any, questpie127.JsonRouteParams>;
30
30
  /**
31
31
  * Dynamic options endpoint.
32
32
  * Fetches options for select/relation fields with search and pagination.
33
33
  */
34
- declare const fieldOptions: questpie135.JsonRouteDefinition<{
34
+ declare const fieldOptions: questpie127.JsonRouteDefinition<{
35
35
  collection: string;
36
36
  type: "collection" | "global";
37
37
  field: string;
@@ -40,12 +40,12 @@ declare const fieldOptions: questpie135.JsonRouteDefinition<{
40
40
  page: number;
41
41
  limit: number;
42
42
  siblingData?: Record<string, unknown> | null | undefined;
43
- }, any, questpie135.JsonRouteParams>;
43
+ }, any, questpie127.JsonRouteParams>;
44
44
  /**
45
45
  * Reactive functions bundle.
46
46
  */
47
47
  declare const reactiveFunctions: {
48
- readonly batchReactive: questpie135.JsonRouteDefinition<{
48
+ readonly batchReactive: questpie127.JsonRouteDefinition<{
49
49
  collection: string;
50
50
  type: "collection" | "global";
51
51
  requests: {
@@ -58,8 +58,8 @@ declare const reactiveFunctions: {
58
58
  }[];
59
59
  formData?: Record<string, unknown> | undefined;
60
60
  prevData?: Record<string, unknown> | null | undefined;
61
- }, any, questpie135.JsonRouteParams>;
62
- readonly fieldOptions: questpie135.JsonRouteDefinition<{
61
+ }, any, questpie127.JsonRouteParams>;
62
+ readonly fieldOptions: questpie127.JsonRouteDefinition<{
63
63
  collection: string;
64
64
  type: "collection" | "global";
65
65
  field: string;
@@ -68,7 +68,7 @@ declare const reactiveFunctions: {
68
68
  page: number;
69
69
  limit: number;
70
70
  siblingData?: Record<string, unknown> | null | undefined;
71
- }, any, questpie135.JsonRouteParams>;
71
+ }, any, questpie127.JsonRouteParams>;
72
72
  };
73
73
  //#endregion
74
74
  export { batchReactive, fieldOptions, reactiveFunctions };
@@ -73,4 +73,4 @@ function buildServerContext(ctx) {
73
73
  }
74
74
 
75
75
  //#endregion
76
- export { buildServerContext, getAccessContext, getAdminConfig, getApp, getAppState, getCollectionState, getGlobalState, getSession };
76
+ export { buildServerContext, getAccessContext, getAdminConfig, getApp, getAppState, getCollectionState, getGlobalState, getLocale, getSession };
@@ -1,4 +1,5 @@
1
- import { getApp } from "./route-helpers.mjs";
1
+ import { getApp, getLocale } from "./route-helpers.mjs";
2
+ import { translateAdminMessage } from "./i18n-helpers.mjs";
2
3
  import { z } from "zod";
3
4
  import { route } from "questpie";
4
5
  import { eq, sql as sql$1 } from "questpie/drizzle";
@@ -14,9 +15,9 @@ import { eq, sql as sql$1 } from "questpie/drizzle";
14
15
  const isSetupRequiredSchema = z.object({});
15
16
  const isSetupRequiredOutputSchema = z.object({ required: z.boolean() });
16
17
  const createFirstAdminSchema = z.object({
17
- email: z.string().email("Invalid email address"),
18
- password: z.string().min(8, "Password must be at least 8 characters"),
19
- name: z.string().min(2, "Name must be at least 2 characters")
18
+ email: z.string().email(),
19
+ password: z.string().min(8),
20
+ name: z.string().min(2)
20
21
  });
21
22
  const createFirstAdminOutputSchema = z.object({
22
23
  success: z.boolean(),
@@ -67,11 +68,13 @@ const isSetupRequired = route().post().schema(isSetupRequiredSchema).outputSchem
67
68
  */
68
69
  const createFirstAdmin = route().post().schema(createFirstAdminSchema).outputSchema(createFirstAdminOutputSchema).handler(async (ctx) => {
69
70
  const app = getApp(ctx);
71
+ const locale = getLocale(ctx);
72
+ const t = (key, params) => translateAdminMessage(locale, key, params);
70
73
  const input = ctx.input;
71
74
  const userCollection = app.getCollectionConfig("user");
72
75
  if ((await app.db.select({ count: sql$1`count(*)::int` }).from(userCollection.table).where(eq(userCollection.table.role, "admin")))[0].count > 0) return {
73
76
  success: false,
74
- error: "Setup already completed - admin users exist in the system"
77
+ error: t("auth.setupAlreadyCompleted")
75
78
  };
76
79
  try {
77
80
  const signUpResult = await app.auth.api.signUpEmail({ body: {
@@ -81,7 +84,7 @@ const createFirstAdmin = route().post().schema(createFirstAdminSchema).outputSch
81
84
  } });
82
85
  if (!signUpResult.user) return {
83
86
  success: false,
84
- error: "Failed to create user account"
87
+ error: t("auth.failedToCreateUserAccount")
85
88
  };
86
89
  await app.db.update(userCollection.table).set({
87
90
  role: "admin",
@@ -98,7 +101,7 @@ const createFirstAdmin = route().post().schema(createFirstAdminSchema).outputSch
98
101
  } catch (error) {
99
102
  return {
100
103
  success: false,
101
- error: error instanceof Error ? error.message : "An unexpected error occurred"
104
+ error: error instanceof Error ? error.message : t("error.unexpectedError")
102
105
  };
103
106
  }
104
107
  });