@questpie/admin 3.2.7 → 3.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (135) hide show
  1. package/README.md +4 -6
  2. package/dist/client/blocks/block-renderer.d.mts +2 -2
  3. package/dist/client/builder/admin-types.d.mts +3 -3
  4. package/dist/client/builder/types/action-types.d.mts +1 -1
  5. package/dist/client/builder/types/collection-types.d.mts +59 -2
  6. package/dist/client/components/blocks/block-editor-provider.mjs +13 -0
  7. package/dist/client/components/fields/array-field.mjs +105 -122
  8. package/dist/client/components/fields/asset-preview-field.mjs +1 -1
  9. package/dist/client/components/fields/blocks-field/blocks-field.mjs +1 -1
  10. package/dist/client/components/fields/boolean-field.mjs +1 -1
  11. package/dist/client/components/fields/date-field.mjs +1 -1
  12. package/dist/client/components/fields/datetime-field.mjs +1 -1
  13. package/dist/client/components/fields/email-field.mjs +1 -1
  14. package/dist/client/components/fields/field-wrapper.mjs +44 -15
  15. package/dist/client/components/fields/number-field.mjs +1 -1
  16. package/dist/client/components/fields/object-array-field.mjs +179 -149
  17. package/dist/client/components/fields/object-field.mjs +96 -87
  18. package/dist/client/components/fields/relation-picker.mjs +1 -1
  19. package/dist/client/components/fields/relation-select.mjs +1 -1
  20. package/dist/client/components/fields/rich-text-editor/index.mjs +1 -1
  21. package/dist/client/components/fields/select-field.mjs +1 -1
  22. package/dist/client/components/fields/text-field.mjs +1 -1
  23. package/dist/client/components/fields/textarea-field.mjs +1 -1
  24. package/dist/client/components/fields/time-field.mjs +1 -1
  25. package/dist/client/components/fields/upload-field.mjs +1 -1
  26. package/dist/client/components/history-sidebar.mjs +10 -4
  27. package/dist/client/components/structured-diff.mjs +367 -0
  28. package/dist/client/components/ui/sidebar.mjs +1 -1
  29. package/dist/client/hooks/use-field-options.mjs +34 -15
  30. package/dist/client/hooks/use-transition-stage.mjs +2 -2
  31. package/dist/client/modules/admin.d.mts +3 -0
  32. package/dist/client/modules/admin.mjs +3 -0
  33. package/dist/client/preview/block-scope-context.d.mts +2 -2
  34. package/dist/client/preview/preview-banner.d.mts +2 -2
  35. package/dist/client/preview/preview-field.d.mts +4 -4
  36. package/dist/client/utils/auto-expand-fields.mjs +1 -1
  37. package/dist/client/views/collection/auto-form-fields.mjs +23 -19
  38. package/dist/client/views/collection/cells/complex-cells.mjs +1 -1
  39. package/dist/client/views/collection/columns/build-columns.mjs +1 -1
  40. package/dist/client/views/collection/columns/column-defaults.mjs +17 -4
  41. package/dist/client/views/collection/field-renderer.mjs +19 -7
  42. package/dist/client/views/collection/form-view.mjs +10 -6
  43. package/dist/client/views/collection/list-view.mjs +830 -0
  44. package/dist/client/views/collection/outline.mjs +363 -0
  45. package/dist/client/views/collection/table-view.mjs +25 -16
  46. package/dist/client/views/globals/global-form-view.mjs +47 -27
  47. package/dist/client/views/layout/admin-layout.d.mts +15 -1
  48. package/dist/client/views/layout/admin-layout.mjs +95 -31
  49. package/dist/client/views/layout/admin-sidebar.mjs +2 -2
  50. package/dist/client.d.mts +6 -6
  51. package/dist/client.mjs +1 -1
  52. package/dist/components/rich-text/rich-text-renderer.d.mts +2 -2
  53. package/dist/factories.d.mts +19 -0
  54. package/dist/factories.mjs +11 -0
  55. package/dist/fields.d.mts +4 -0
  56. package/dist/fields.mjs +5 -0
  57. package/dist/index.d.mts +6 -6
  58. package/dist/index.mjs +1 -1
  59. package/dist/modules/admin.d.mts +10 -0
  60. package/dist/modules/admin.mjs +9 -0
  61. package/dist/modules/audit.d.mts +5 -0
  62. package/dist/modules/audit.mjs +5 -0
  63. package/dist/server/augmentation/form-layout.d.mts +57 -2
  64. package/dist/server/augmentation/index.d.mts +3 -1
  65. package/dist/server/augmentation/shell.d.mts +48 -0
  66. package/dist/server/augmentation.d.mts +2 -1
  67. package/dist/server/codegen/admin-client-template.mjs +11 -4
  68. package/dist/server/fields/blocks.d.mts +9 -2
  69. package/dist/server/fields/blocks.mjs +1 -1
  70. package/dist/server/fields/index.d.mts +2 -2
  71. package/dist/server/fields/index.mjs +2 -2
  72. package/dist/server/fields/rich-text.d.mts +9 -2
  73. package/dist/server/fields/rich-text.mjs +1 -1
  74. package/dist/server/i18n/messages/cs.mjs +8 -0
  75. package/dist/server/i18n/messages/de.mjs +8 -0
  76. package/dist/server/i18n/messages/en.mjs +8 -0
  77. package/dist/server/i18n/messages/es.mjs +8 -0
  78. package/dist/server/i18n/messages/fr.mjs +8 -0
  79. package/dist/server/i18n/messages/pl.mjs +8 -0
  80. package/dist/server/i18n/messages/pt.mjs +8 -0
  81. package/dist/server/i18n/messages/sk.mjs +8 -0
  82. package/dist/server/modules/admin/.generated/module.d.mts +24 -19
  83. package/dist/server/modules/admin/.generated/module.mjs +5 -1
  84. package/dist/server/modules/admin/.generated/registries.d.mts +6 -4
  85. package/dist/server/modules/admin/client/.generated/module.d.mts +70 -70
  86. package/dist/server/modules/admin/client/.generated/module.mjs +3 -1
  87. package/dist/server/modules/admin/client/views/collection-form.d.mts +6 -0
  88. package/dist/server/modules/admin/client/views/collection-table.d.mts +6 -0
  89. package/dist/server/modules/admin/client/views/global-form.d.mts +6 -0
  90. package/dist/server/modules/admin/client/views/list-view.d.mts +6 -0
  91. package/dist/server/modules/admin/client/views/list-view.mjs +10 -0
  92. package/dist/server/modules/admin/collections/account.d.mts +50 -50
  93. package/dist/server/modules/admin/collections/admin-locks.d.mts +54 -54
  94. package/dist/server/modules/admin/collections/admin-preferences.d.mts +39 -39
  95. package/dist/server/modules/admin/collections/admin-saved-views.d.mts +47 -47
  96. package/dist/server/modules/admin/collections/apikey.d.mts +39 -39
  97. package/dist/server/modules/admin/collections/assets.d.mts +39 -39
  98. package/dist/server/modules/admin/collections/session.d.mts +42 -42
  99. package/dist/server/modules/admin/collections/user.d.mts +63 -63
  100. package/dist/server/modules/admin/collections/verification.d.mts +36 -36
  101. package/dist/server/modules/admin/dto/admin-config.dto.mjs +17 -0
  102. package/dist/server/modules/admin/index.d.mts +30 -31
  103. package/dist/server/modules/admin/routes/admin-config.d.mts +2 -17
  104. package/dist/server/modules/admin/routes/admin-config.mjs +21 -5
  105. package/dist/server/modules/admin/routes/execute-action.d.mts +9 -9
  106. package/dist/server/modules/admin/routes/execute-action.mjs +18 -12
  107. package/dist/server/modules/admin/routes/i18n-helpers.d.mts +4 -0
  108. package/dist/server/modules/admin/routes/locales.d.mts +2 -2
  109. package/dist/server/modules/admin/routes/preview.d.mts +24 -19
  110. package/dist/server/modules/admin/routes/preview.mjs +83 -62
  111. package/dist/server/modules/admin/routes/reactive.d.mts +9 -9
  112. package/dist/server/modules/admin/routes/route-helpers.mjs +36 -1
  113. package/dist/server/modules/admin/routes/setup.d.mts +7 -14
  114. package/dist/server/modules/admin/routes/setup.mjs +16 -3
  115. package/dist/server/modules/admin/routes/translations.d.mts +4 -4
  116. package/dist/server/modules/admin/routes/widget-data.d.mts +5 -5
  117. package/dist/server/modules/admin/views/list-view.d.mts +8 -0
  118. package/dist/server/modules/admin/views/list-view.mjs +7 -0
  119. package/dist/server/modules/admin-preferences/collections/saved-views.d.mts +41 -41
  120. package/dist/server/modules/audit/.generated/module.d.mts +6 -6
  121. package/dist/server/modules/audit/collections/audit-log.d.mts +87 -80
  122. package/dist/server/modules/audit/collections/audit-log.mjs +7 -2
  123. package/dist/server/modules/audit/config/localize-title.mjs +67 -0
  124. package/dist/server/modules/audit/index.d.mts +3 -2
  125. package/dist/server/modules/audit/jobs/audit-cleanup.d.mts +2 -2
  126. package/dist/server/modules/audit/log-audit-entry.d.mts +85 -0
  127. package/dist/server/modules/audit/log-audit-entry.mjs +125 -0
  128. package/dist/server/plugin.d.mts +1 -1
  129. package/dist/server/plugin.mjs +31 -31
  130. package/dist/server.d.mts +6 -4
  131. package/dist/server.mjs +9 -8
  132. package/dist/shared/preview-utils.d.mts +4 -4
  133. package/dist/shared/preview-utils.mjs +5 -7
  134. package/package.json +13 -3
  135. package/dist/client/hooks/use-audit-history.mjs +0 -38
@@ -1,13 +1,18 @@
1
- import * as questpie_shared6 from "questpie/shared";
2
- import * as questpie98 from "questpie";
3
- import * as questpie_src_server_modules_core_fields_email_js2 from "questpie/src/server/modules/core/fields/email.js";
4
- import * as questpie_src_server_modules_core_fields_json_js2 from "questpie/src/server/modules/core/fields/json.js";
5
- import * as drizzle_orm_pg_core9 from "drizzle-orm/pg-core";
6
- import * as drizzle_orm9 from "drizzle-orm";
1
+ import * as questpie_shared0 from "questpie/shared";
2
+ import * as questpie21 from "questpie";
3
+ import * as questpie_src_server_modules_core_fields_email_js0 from "questpie/src/server/modules/core/fields/email.js";
4
+ import * as questpie_src_server_modules_core_fields_json_js0 from "questpie/src/server/modules/core/fields/json.js";
5
+ import * as drizzle_orm_pg_core0 from "drizzle-orm/pg-core";
6
+ import * as drizzle_orm0 from "drizzle-orm";
7
7
  import * as questpie_src_server_fields_operators_builtin_js0 from "questpie/src/server/fields/operators/builtin.js";
8
8
 
9
9
  //#region src/server/modules/audit/collections/audit-log.d.ts
10
-
10
+ /**
11
+ * The collection slug used by the audit log.
12
+ * Exported so hooks and jobs can reference the collection dynamically
13
+ * instead of hardcoding the name.
14
+ */
15
+ declare const AUDIT_LOG_COLLECTION: "admin_audit_log";
11
16
  /**
12
17
  * Audit Log Collection
13
18
  *
@@ -19,140 +24,142 @@ import * as questpie_src_server_fields_operators_builtin_js0 from "questpie/src/
19
24
  * - update: disallowed
20
25
  * - read: allowed (for admin UI display)
21
26
  */
22
- declare const auditLogCollection: questpie98.CollectionBuilder<questpie_shared6.Override<questpie_shared6.Override<questpie_shared6.Override<questpie_shared6.Override<questpie_shared6.Override<questpie98.EmptyCollectionState<"admin_audit_log", undefined, {
23
- readonly text: typeof questpie98.text;
24
- readonly textarea: typeof questpie98.textarea;
25
- readonly email: typeof questpie_src_server_modules_core_fields_email_js2.email;
26
- readonly url: typeof questpie98.url;
27
- readonly number: typeof questpie98.number;
28
- readonly boolean: typeof questpie98.boolean;
29
- readonly date: typeof questpie98.date;
30
- readonly datetime: typeof questpie98.datetime;
31
- readonly time: typeof questpie98.time;
32
- readonly select: typeof questpie98.select;
33
- readonly upload: typeof questpie98.upload;
34
- readonly relation: typeof questpie98.relation;
35
- readonly object: typeof questpie98.object;
36
- readonly json: typeof questpie_src_server_modules_core_fields_json_js2.json;
37
- readonly from: typeof questpie98.from;
27
+ declare const auditLogCollection: questpie21.CollectionBuilder<questpie_shared0.Override<questpie_shared0.Override<questpie_shared0.Override<questpie_shared0.Override<questpie_shared0.Override<questpie_shared0.Override<questpie21.EmptyCollectionState<"admin_audit_log", undefined, {
28
+ readonly text: typeof questpie21.text;
29
+ readonly textarea: typeof questpie21.textarea;
30
+ readonly email: typeof questpie_src_server_modules_core_fields_email_js0.email;
31
+ readonly url: typeof questpie21.url;
32
+ readonly number: typeof questpie21.number;
33
+ readonly boolean: typeof questpie21.boolean;
34
+ readonly date: typeof questpie21.date;
35
+ readonly datetime: typeof questpie21.datetime;
36
+ readonly time: typeof questpie21.time;
37
+ readonly select: typeof questpie21.select;
38
+ readonly upload: typeof questpie21.upload;
39
+ readonly relation: typeof questpie21.relation;
40
+ readonly object: typeof questpie21.object;
41
+ readonly json: typeof questpie_src_server_modules_core_fields_json_js0.json;
42
+ readonly from: typeof questpie21.from;
38
43
  }>, {
39
44
  fields: {
40
- readonly action: drizzle_orm9.NotNull<drizzle_orm_pg_core9.PgVarcharBuilder<[string, ...string[]]>>;
41
- readonly resourceType: drizzle_orm9.NotNull<drizzle_orm_pg_core9.PgVarcharBuilder<[string, ...string[]]>>;
42
- readonly resource: drizzle_orm9.NotNull<drizzle_orm_pg_core9.PgVarcharBuilder<[string, ...string[]]>>;
43
- readonly resourceId: drizzle_orm_pg_core9.PgVarcharBuilder<[string, ...string[]]>;
44
- readonly resourceLabel: drizzle_orm_pg_core9.PgVarcharBuilder<[string, ...string[]]>;
45
- readonly userId: drizzle_orm_pg_core9.PgVarcharBuilder<[string, ...string[]]>;
46
- readonly userName: drizzle_orm_pg_core9.PgVarcharBuilder<[string, ...string[]]>;
47
- readonly locale: drizzle_orm_pg_core9.PgVarcharBuilder<[string, ...string[]]>;
48
- readonly changes: drizzle_orm_pg_core9.PgJsonbBuilder;
49
- readonly metadata: drizzle_orm_pg_core9.PgJsonbBuilder;
50
- readonly title: drizzle_orm_pg_core9.PgVarcharBuilder<[string, ...string[]]>;
45
+ readonly action: drizzle_orm0.NotNull<drizzle_orm_pg_core0.PgVarcharBuilder<[string, ...string[]]>>;
46
+ readonly resourceType: drizzle_orm0.NotNull<drizzle_orm_pg_core0.PgVarcharBuilder<[string, ...string[]]>>;
47
+ readonly resource: drizzle_orm0.NotNull<drizzle_orm_pg_core0.PgVarcharBuilder<[string, ...string[]]>>;
48
+ readonly resourceId: drizzle_orm_pg_core0.PgVarcharBuilder<[string, ...string[]]>;
49
+ readonly resourceLabel: drizzle_orm_pg_core0.PgVarcharBuilder<[string, ...string[]]>;
50
+ readonly userId: drizzle_orm_pg_core0.PgVarcharBuilder<[string, ...string[]]>;
51
+ readonly userName: drizzle_orm_pg_core0.PgVarcharBuilder<[string, ...string[]]>;
52
+ readonly locale: drizzle_orm_pg_core0.PgVarcharBuilder<[string, ...string[]]>;
53
+ readonly changes: drizzle_orm_pg_core0.PgJsonbBuilder;
54
+ readonly metadata: drizzle_orm_pg_core0.PgJsonbBuilder;
55
+ readonly title: drizzle_orm_pg_core0.PgVarcharBuilder<[string, ...string[]]>;
51
56
  };
52
57
  localized: readonly string[];
53
58
  fieldDefinitions: {
54
59
  /** Action performed: create, update, delete, transition, custom */
55
- readonly action: questpie98.FieldWithMethods<Omit<questpie98.TextFieldState, "notNull" | "column"> & {
60
+ readonly action: questpie21.FieldWithMethods<Omit<questpie21.TextFieldState, "notNull" | "column"> & {
56
61
  notNull: true;
57
- column: drizzle_orm9.NotNull<drizzle_orm_pg_core9.PgVarcharBuilder<[string, ...string[]]>>;
62
+ column: drizzle_orm0.NotNull<drizzle_orm_pg_core0.PgVarcharBuilder<[string, ...string[]]>>;
58
63
  } & {
59
- label: questpie_shared6.I18nText;
60
- }, questpie98.TextFieldMethods>;
64
+ label: questpie_shared0.I18nText;
65
+ }, questpie21.TextFieldMethods>;
61
66
  /** Resource type: collection, global, auth, system, custom */
62
- readonly resourceType: questpie98.FieldWithMethods<Omit<questpie98.TextFieldState, "notNull" | "column"> & {
67
+ readonly resourceType: questpie21.FieldWithMethods<Omit<questpie21.TextFieldState, "notNull" | "column"> & {
63
68
  notNull: true;
64
- column: drizzle_orm9.NotNull<drizzle_orm_pg_core9.PgVarcharBuilder<[string, ...string[]]>>;
69
+ column: drizzle_orm0.NotNull<drizzle_orm_pg_core0.PgVarcharBuilder<[string, ...string[]]>>;
65
70
  } & {
66
- label: questpie_shared6.I18nText;
67
- }, questpie98.TextFieldMethods>;
71
+ label: questpie_shared0.I18nText;
72
+ }, questpie21.TextFieldMethods>;
68
73
  /** Resource slug (collection/global name) */
69
- readonly resource: questpie98.FieldWithMethods<Omit<questpie98.TextFieldState, "notNull" | "column"> & {
74
+ readonly resource: questpie21.FieldWithMethods<Omit<questpie21.TextFieldState, "notNull" | "column"> & {
70
75
  notNull: true;
71
- column: drizzle_orm9.NotNull<drizzle_orm_pg_core9.PgVarcharBuilder<[string, ...string[]]>>;
76
+ column: drizzle_orm0.NotNull<drizzle_orm_pg_core0.PgVarcharBuilder<[string, ...string[]]>>;
72
77
  } & {
73
- label: questpie_shared6.I18nText;
74
- }, questpie98.TextFieldMethods>;
78
+ label: questpie_shared0.I18nText;
79
+ }, questpie21.TextFieldMethods>;
75
80
  /** ID of the specific record (null for globals) */
76
- readonly resourceId: questpie98.FieldWithMethods<questpie98.DefaultFieldState & {
81
+ readonly resourceId: questpie21.FieldWithMethods<questpie21.DefaultFieldState & {
77
82
  type: "text";
78
83
  data: string;
79
- column: drizzle_orm_pg_core9.PgVarcharBuilder<[string, ...string[]]>;
84
+ column: drizzle_orm_pg_core0.PgVarcharBuilder<[string, ...string[]]>;
80
85
  operators: typeof questpie_src_server_fields_operators_builtin_js0.stringOps;
81
86
  } & {
82
- label: questpie_shared6.I18nText;
83
- }, questpie98.TextFieldMethods>;
87
+ label: questpie_shared0.I18nText;
88
+ }, questpie21.TextFieldMethods>;
84
89
  /** Denormalized display label for the affected record */
85
- readonly resourceLabel: questpie98.FieldWithMethods<questpie98.DefaultFieldState & {
90
+ readonly resourceLabel: questpie21.FieldWithMethods<questpie21.DefaultFieldState & {
86
91
  type: "text";
87
92
  data: string;
88
- column: drizzle_orm_pg_core9.PgVarcharBuilder<[string, ...string[]]>;
93
+ column: drizzle_orm_pg_core0.PgVarcharBuilder<[string, ...string[]]>;
89
94
  operators: typeof questpie_src_server_fields_operators_builtin_js0.stringOps;
90
95
  } & {
91
- label: questpie_shared6.I18nText;
92
- }, questpie98.TextFieldMethods>;
96
+ label: questpie_shared0.I18nText;
97
+ }, questpie21.TextFieldMethods>;
93
98
  /** User who performed the action */
94
- readonly userId: questpie98.FieldWithMethods<questpie98.DefaultFieldState & {
99
+ readonly userId: questpie21.FieldWithMethods<questpie21.DefaultFieldState & {
95
100
  type: "text";
96
101
  data: string;
97
- column: drizzle_orm_pg_core9.PgVarcharBuilder<[string, ...string[]]>;
102
+ column: drizzle_orm_pg_core0.PgVarcharBuilder<[string, ...string[]]>;
98
103
  operators: typeof questpie_src_server_fields_operators_builtin_js0.stringOps;
99
104
  } & {
100
- label: questpie_shared6.I18nText;
101
- }, questpie98.TextFieldMethods>;
105
+ label: questpie_shared0.I18nText;
106
+ }, questpie21.TextFieldMethods>;
102
107
  /** Denormalized user display name */
103
- readonly userName: questpie98.FieldWithMethods<questpie98.DefaultFieldState & {
108
+ readonly userName: questpie21.FieldWithMethods<questpie21.DefaultFieldState & {
104
109
  type: "text";
105
110
  data: string;
106
- column: drizzle_orm_pg_core9.PgVarcharBuilder<[string, ...string[]]>;
111
+ column: drizzle_orm_pg_core0.PgVarcharBuilder<[string, ...string[]]>;
107
112
  operators: typeof questpie_src_server_fields_operators_builtin_js0.stringOps;
108
113
  } & {
109
- label: questpie_shared6.I18nText;
110
- }, questpie98.TextFieldMethods>;
114
+ label: questpie_shared0.I18nText;
115
+ }, questpie21.TextFieldMethods>;
111
116
  /** Locale context of the operation */
112
- readonly locale: questpie98.FieldWithMethods<questpie98.DefaultFieldState & {
117
+ readonly locale: questpie21.FieldWithMethods<questpie21.DefaultFieldState & {
113
118
  type: "text";
114
119
  data: string;
115
- column: drizzle_orm_pg_core9.PgVarcharBuilder<[string, ...string[]]>;
120
+ column: drizzle_orm_pg_core0.PgVarcharBuilder<[string, ...string[]]>;
116
121
  operators: typeof questpie_src_server_fields_operators_builtin_js0.stringOps;
117
122
  } & {
118
- label: questpie_shared6.I18nText;
119
- }, questpie98.TextFieldMethods>;
123
+ label: questpie_shared0.I18nText;
124
+ }, questpie21.TextFieldMethods>;
120
125
  /** Field-level diffs: { field: { from, to } } or null */
121
- readonly changes: questpie98.Field<questpie98.DefaultFieldState & {
126
+ readonly changes: questpie21.Field<questpie21.DefaultFieldState & {
122
127
  type: "json";
123
- data: questpie98.JsonValue;
124
- column: drizzle_orm_pg_core9.PgJsonbBuilder;
128
+ data: questpie21.JsonValue;
129
+ column: drizzle_orm_pg_core0.PgJsonbBuilder;
125
130
  operators: typeof questpie_src_server_fields_operators_builtin_js0.basicOps;
126
131
  } & {
127
- label: questpie_shared6.I18nText;
132
+ label: questpie_shared0.I18nText;
128
133
  }>;
129
134
  /** Extra context metadata */
130
- readonly metadata: questpie98.Field<questpie98.DefaultFieldState & {
135
+ readonly metadata: questpie21.Field<questpie21.DefaultFieldState & {
131
136
  type: "json";
132
- data: questpie98.JsonValue;
133
- column: drizzle_orm_pg_core9.PgJsonbBuilder;
137
+ data: questpie21.JsonValue;
138
+ column: drizzle_orm_pg_core0.PgJsonbBuilder;
134
139
  operators: typeof questpie_src_server_fields_operators_builtin_js0.basicOps;
135
140
  } & {
136
- label: questpie_shared6.I18nText;
141
+ label: questpie_shared0.I18nText;
137
142
  }>;
138
143
  /** Human-readable title: "User Action ResourceType 'ResourceLabel'" */
139
- readonly title: questpie98.FieldWithMethods<questpie98.DefaultFieldState & {
144
+ readonly title: questpie21.FieldWithMethods<questpie21.DefaultFieldState & {
140
145
  type: "text";
141
146
  data: string;
142
- column: drizzle_orm_pg_core9.PgVarcharBuilder<[string, ...string[]]>;
147
+ column: drizzle_orm_pg_core0.PgVarcharBuilder<[string, ...string[]]>;
143
148
  operators: typeof questpie_src_server_fields_operators_builtin_js0.stringOps;
144
149
  } & {
145
- label: questpie_shared6.I18nText;
146
- }, questpie98.TextFieldMethods>;
150
+ label: questpie_shared0.I18nText;
151
+ }, questpie21.TextFieldMethods>;
147
152
  };
148
153
  }>, {
149
154
  options: {
150
155
  timestamps: true;
151
156
  };
152
157
  }>, {
153
- indexes: drizzle_orm_pg_core9.IndexBuilder[];
158
+ indexes: drizzle_orm_pg_core0.IndexBuilder[];
154
159
  }>, {
155
160
  access: Record<string, any>;
161
+ }>, {
162
+ hooks: Record<string, any>;
156
163
  }> & Record<"admin", {
157
164
  label: {
158
165
  key: string;
@@ -211,4 +218,4 @@ declare const auditLogCollection: questpie98.CollectionBuilder<questpie_shared6.
211
218
  })[];
212
219
  }>>;
213
220
  //#endregion
214
- export { auditLogCollection };
221
+ export { AUDIT_LOG_COLLECTION, auditLogCollection };
@@ -1,4 +1,5 @@
1
- import { collection } from "questpie";
1
+ import { localizeAuditTitle } from "../config/localize-title.mjs";
2
+ import { collection, tryGetContext } from "questpie";
2
3
  import { index } from "questpie/drizzle-pg-core";
3
4
 
4
5
  //#region src/server/modules/audit/collections/audit-log.ts
@@ -41,7 +42,11 @@ const auditLogCollection = collection(AUDIT_LOG_COLLECTION).fields(({ f }) => ({
41
42
  update: false,
42
43
  delete: false,
43
44
  read: true
44
- }).set("admin", {
45
+ }).hooks({ afterRead: ({ data, locale }) => {
46
+ if (!data) return;
47
+ const localized = localizeAuditTitle(data, locale, tryGetContext()?.app);
48
+ if (localized) data.title = localized;
49
+ } }).set("admin", {
45
50
  label: { key: "audit.collection.label" },
46
51
  icon: {
47
52
  type: "icon",
@@ -0,0 +1,67 @@
1
+ import { getAdminMessagesForLocale } from "../../../i18n/index.mjs";
2
+ import { isI18nTranslationKey, resolveI18nText } from "questpie/shared";
3
+
4
+ //#region src/server/modules/audit/config/localize-title.ts
5
+ function lookupMessage(messages, key) {
6
+ const value = messages[key];
7
+ if (typeof value === "string") return value;
8
+ if (value && typeof value === "object") {
9
+ const plural = value.other;
10
+ if (typeof plural === "string") return plural;
11
+ }
12
+ return null;
13
+ }
14
+ function makeTranslator(messages) {
15
+ return (key) => lookupMessage(messages, key) ?? key;
16
+ }
17
+ function getResourceLabel(app, resourceType, resource) {
18
+ if (!app) return null;
19
+ if (resourceType === "collection") {
20
+ const config = app.getCollectionConfig?.(resource);
21
+ return config?.state?.admin?.label ?? config?.state?.label ?? null;
22
+ }
23
+ if (resourceType === "global") {
24
+ const config = app.getGlobals?.()?.[resource];
25
+ return config?.state?.admin?.label ?? config?.state?.label ?? null;
26
+ }
27
+ return null;
28
+ }
29
+ function resolveLabel(label, locale, t) {
30
+ if (label == null) return null;
31
+ if (isI18nTranslationKey(label)) {
32
+ const resolved = t(label.key);
33
+ return resolved === label.key ? label.fallback ?? null : resolved;
34
+ }
35
+ return resolveI18nText(label, locale, t);
36
+ }
37
+ function interpolate(template, values) {
38
+ return template.replace(/\{\{\s*(\w+)\s*\}\}/g, (_m, k) => values[k] ?? `{{${k}}}`);
39
+ }
40
+ /**
41
+ * Recompute the audit log title in the viewer's locale.
42
+ * Returns null when no locale is provided so the caller can keep the stored value.
43
+ */
44
+ function localizeAuditTitle(data, locale, app) {
45
+ if (!locale) return null;
46
+ const messages = getAdminMessagesForLocale(locale);
47
+ const t = makeTranslator(messages);
48
+ const action = String(data.action ?? "");
49
+ const resourceType = String(data.resourceType ?? "");
50
+ const resource = String(data.resource ?? "");
51
+ const userName = String(data.userName ?? "");
52
+ const actionText = lookupMessage(messages, `audit.action.${action}`) ?? action;
53
+ const resourceTypeText = lookupMessage(messages, `audit.resourceType.${resourceType}`) ?? resourceType;
54
+ const resourceName = resolveLabel(getResourceLabel(app, resourceType, resource), locale, t) ?? resource;
55
+ const rawLabel = typeof data.resourceLabel === "string" && data.resourceLabel.length > 0 ? data.resourceLabel : null;
56
+ const unnamed = lookupMessage(messages, "audit.unnamed") ?? "(unnamed)";
57
+ const resourceLabel = rawLabel ? `'${rawLabel}'` : unnamed;
58
+ return interpolate(lookupMessage(messages, "audit.title.template") ?? "{{userName}} {{action}} {{resourceType}} {{resourceLabel}}", {
59
+ userName,
60
+ action: actionText,
61
+ resourceType: `${resourceTypeText} ${resourceName}`,
62
+ resourceLabel
63
+ });
64
+ }
65
+
66
+ //#endregion
67
+ export { localizeAuditTitle };
@@ -1,2 +1,3 @@
1
- import { auditLogCollection } from "./collections/audit-log.mjs";
2
- import { AuditModule, _module } from "./.generated/module.mjs";
1
+ import { AUDIT_LOG_COLLECTION, auditLogCollection } from "./collections/audit-log.mjs";
2
+ import { AuditModule, _module } from "./.generated/module.mjs";
3
+ import { AuditActorType, AuditContext, LogAuditEntryOptions, logAuditEntry } from "./log-audit-entry.mjs";
@@ -1,4 +1,4 @@
1
- import * as questpie461 from "questpie";
1
+ import * as questpie151 from "questpie";
2
2
 
3
3
  //#region src/server/modules/audit/jobs/audit-cleanup.d.ts
4
4
 
@@ -6,7 +6,7 @@ import * as questpie461 from "questpie";
6
6
  * Audit log cleanup job.
7
7
  * Runs daily (via cron) to delete entries older than the configured retention period.
8
8
  */
9
- declare const auditCleanupJob: questpie461.JobDefinition<{
9
+ declare const auditCleanupJob: questpie151.JobDefinition<{
10
10
  retentionDays: number;
11
11
  }, void, "audit-cleanup">;
12
12
  //#endregion
@@ -0,0 +1,85 @@
1
+ //#region src/server/modules/audit/log-audit-entry.d.ts
2
+ /**
3
+ * Options for a custom audit log entry.
4
+ */
5
+ type AuditActorType = "anonymous" | "system" | "user" | (string & {});
6
+ interface LogAuditEntryOptions {
7
+ /** Action performed (e.g., "create", "bulk-email", "archive", "migrate"). */
8
+ action: string;
9
+ /**
10
+ * Category of the affected resource.
11
+ * Built-in: "collection" | "global"
12
+ * Custom: "system" | "job" | "webhook" | any string
13
+ */
14
+ resourceType: string;
15
+ /** Resource identifier (e.g., collection slug, job name). */
16
+ resource: string;
17
+ /** Optional ID of a specific record. */
18
+ resourceId?: string | null;
19
+ /** Display label for the affected resource (e.g., record title, job description). */
20
+ resourceLabel?: string | null;
21
+ /** Override actor user name (auto-resolved from session when omitted). */
22
+ userName?: string;
23
+ /** Override actor user ID (auto-resolved from session when omitted). */
24
+ userId?: string | null;
25
+ /** Override actor category stored in metadata. */
26
+ actorType?: AuditActorType;
27
+ /** Locale context of the operation. */
28
+ locale?: string | null;
29
+ /** Field-level changes, or arbitrary structured data. */
30
+ changes?: Record<string, unknown> | null;
31
+ /** Extra metadata (e.g., job payload, webhook source). */
32
+ metadata?: Record<string, unknown> | null;
33
+ }
34
+ /**
35
+ * Audit context — pass the hook/job context directly.
36
+ * Needs `collections` (or `app.collections`) and optionally `session`, `db`.
37
+ */
38
+ interface AuditContext {
39
+ collections?: Record<string, any>;
40
+ app?: {
41
+ collections?: Record<string, any>;
42
+ getCollectionConfig?: (slug: string) => any;
43
+ getGlobals?: () => Record<string, any>;
44
+ };
45
+ session?: {
46
+ user?: Record<string, unknown> | null;
47
+ } | null;
48
+ accessMode?: string;
49
+ db?: unknown;
50
+ logger?: {
51
+ error?: (...args: any[]) => void;
52
+ };
53
+ }
54
+ /**
55
+ * Write a custom audit log entry.
56
+ *
57
+ * Use this in jobs, custom actions, webhooks, or anywhere you want
58
+ * to record a meaningful event in the audit trail.
59
+ *
60
+ * @example
61
+ * ```ts
62
+ * import { logAuditEntry } from "@questpie/admin/server";
63
+ *
64
+ * // Inside a job handler:
65
+ * await logAuditEntry(ctx, {
66
+ * action: "bulk-email",
67
+ * resourceType: "system",
68
+ * resource: "newsletter",
69
+ * resourceLabel: "Q1 Campaign",
70
+ * metadata: { sentCount: 1234, jobId: ctx.id },
71
+ * });
72
+ *
73
+ * // Inside a collection hook with session:
74
+ * await logAuditEntry(ctx, {
75
+ * action: "export",
76
+ * resourceType: "collection",
77
+ * resource: "orders",
78
+ * resourceLabel: "Monthly export",
79
+ * changes: { format: { from: null, to: "csv" } },
80
+ * });
81
+ * ```
82
+ */
83
+ declare function logAuditEntry(ctx: AuditContext, options: LogAuditEntryOptions): Promise<void>;
84
+ //#endregion
85
+ export { AuditActorType, AuditContext, LogAuditEntryOptions, logAuditEntry };
@@ -0,0 +1,125 @@
1
+ import { AUDIT_LOG_COLLECTION } from "./collections/audit-log.mjs";
2
+ import { tryGetContext } from "questpie";
3
+
4
+ //#region src/server/modules/audit/log-audit-entry.ts
5
+ function resolveCollections(ctx) {
6
+ return ctx.collections ?? ctx.app?.collections ?? null;
7
+ }
8
+ function resolveActor(ctx) {
9
+ const user = ctx.session?.user;
10
+ const userId = user?.id != null ? String(user.id) : null;
11
+ for (const candidate of [
12
+ user?.name,
13
+ user?.email,
14
+ userId
15
+ ]) if (typeof candidate === "string" && candidate.trim().length > 0) return {
16
+ actorType: "user",
17
+ userId,
18
+ userName: candidate.trim()
19
+ };
20
+ if (ctx.accessMode === "system") return {
21
+ actorType: "system",
22
+ userId: "system",
23
+ userName: "System"
24
+ };
25
+ return {
26
+ actorType: "anonymous",
27
+ userId: null,
28
+ userName: "Anonymous"
29
+ };
30
+ }
31
+ function getResourceTypeLabel(ctx, resourceType, resource) {
32
+ const stored = tryGetContext();
33
+ const app = ctx.app ?? stored?.app;
34
+ if (!app) return resource;
35
+ if (resourceType === "collection") {
36
+ const config = app.getCollectionConfig?.(resource);
37
+ const label = config?.state?.admin?.label ?? config?.state?.label;
38
+ if (typeof label === "string") return label;
39
+ return resource;
40
+ }
41
+ if (resourceType === "global") {
42
+ const config = app.getGlobals?.()?.[resource];
43
+ const label = config?.state?.admin?.label ?? config?.state?.label;
44
+ if (typeof label === "string") return label;
45
+ return resource;
46
+ }
47
+ return resource;
48
+ }
49
+ function resolveActorType(actor, options, userId) {
50
+ if (options.actorType) return options.actorType;
51
+ if (options.userId !== void 0 || options.userName !== void 0) return userId && userId !== "system" ? "user" : "system";
52
+ return actor.actorType;
53
+ }
54
+ /**
55
+ * Write a custom audit log entry.
56
+ *
57
+ * Use this in jobs, custom actions, webhooks, or anywhere you want
58
+ * to record a meaningful event in the audit trail.
59
+ *
60
+ * @example
61
+ * ```ts
62
+ * import { logAuditEntry } from "@questpie/admin/server";
63
+ *
64
+ * // Inside a job handler:
65
+ * await logAuditEntry(ctx, {
66
+ * action: "bulk-email",
67
+ * resourceType: "system",
68
+ * resource: "newsletter",
69
+ * resourceLabel: "Q1 Campaign",
70
+ * metadata: { sentCount: 1234, jobId: ctx.id },
71
+ * });
72
+ *
73
+ * // Inside a collection hook with session:
74
+ * await logAuditEntry(ctx, {
75
+ * action: "export",
76
+ * resourceType: "collection",
77
+ * resource: "orders",
78
+ * resourceLabel: "Monthly export",
79
+ * changes: { format: { from: null, to: "csv" } },
80
+ * });
81
+ * ```
82
+ */
83
+ async function logAuditEntry(ctx, options) {
84
+ const collections = resolveCollections(ctx);
85
+ if (!collections?.[AUDIT_LOG_COLLECTION]) {
86
+ ctx.logger?.error?.("[Audit] Cannot write audit entry — audit log collection not available");
87
+ return;
88
+ }
89
+ const actor = resolveActor(ctx);
90
+ const userName = options.userName ?? actor.userName;
91
+ const userId = options.userId !== void 0 ? options.userId : actor.userId;
92
+ const actorType = resolveActorType(actor, options, userId);
93
+ const resourceTypeLabel = getResourceTypeLabel(ctx, options.resourceType, options.resource);
94
+ const resourceLabel = options.resourceLabel ?? null;
95
+ const label = resourceLabel || "(unnamed)";
96
+ const title = `${userName} ${{
97
+ create: "created",
98
+ update: "updated",
99
+ delete: "deleted",
100
+ transition: "changed status of"
101
+ }[options.action] || options.action} ${resourceTypeLabel} '${label}'`;
102
+ await collections[AUDIT_LOG_COLLECTION].create({
103
+ action: options.action,
104
+ resourceType: options.resourceType,
105
+ resource: options.resource,
106
+ resourceId: options.resourceId ?? null,
107
+ resourceLabel,
108
+ userId,
109
+ userName,
110
+ locale: options.locale ?? null,
111
+ changes: options.changes ?? null,
112
+ metadata: {
113
+ actorType,
114
+ accessMode: ctx.accessMode ?? "system",
115
+ ...options.metadata ?? {}
116
+ },
117
+ title
118
+ }, {
119
+ accessMode: "system",
120
+ db: ctx.db
121
+ });
122
+ }
123
+
124
+ //#endregion
125
+ export { logAuditEntry };
@@ -1,4 +1,4 @@
1
- import { CodegenPlugin } from "questpie";
1
+ import { CodegenPlugin } from "questpie/codegen";
2
2
 
3
3
  //#region src/server/plugin.d.ts
4
4