@questpie/admin 3.0.3 → 3.0.4
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.
- package/README.md +34 -5
- package/dist/client/blocks/block-renderer.d.mts +2 -2
- package/dist/client/blocks/block-renderer.mjs +4 -1
- package/dist/client/builder/types/action-types.d.mts +31 -3
- package/dist/client/builder/types/collection-types.d.mts +140 -0
- package/dist/client/builder/types/ui-config.d.mts +16 -2
- package/dist/client/builder/types/views.d.mts +57 -0
- package/dist/client/builder/types/widget-types.d.mts +5 -0
- package/dist/client/components/actions/action-button.mjs +137 -199
- package/dist/client/components/actions/action-dialog.mjs +198 -156
- package/dist/client/components/actions/confirmation-dialog.mjs +2 -2
- package/dist/client/components/actions/header-actions.mjs +52 -53
- package/dist/client/components/admin-link.d.mts +2 -2
- package/dist/client/components/auth/auth-loading.mjs +41 -18
- package/dist/client/components/blocks/block-fields-renderer.mjs +64 -28
- package/dist/client/components/blocks/block-insert-button.mjs +4 -4
- package/dist/client/components/blocks/block-item.mjs +2 -2
- package/dist/client/components/blocks/block-library-sidebar.mjs +2 -2
- package/dist/client/components/component-renderer.mjs +1 -1
- package/dist/client/components/fields/array-field.mjs +14 -14
- package/dist/client/components/fields/asset-preview-field.mjs +1 -1
- package/dist/client/components/fields/blocks-field/blocks-field.mjs +84 -104
- package/dist/client/components/fields/json-field.mjs +2 -2
- package/dist/client/components/fields/object-array-field.mjs +22 -22
- package/dist/client/components/fields/object-field.mjs +5 -5
- package/dist/client/components/fields/relation/displays/cards-display.mjs +16 -9
- package/dist/client/components/fields/relation/displays/chips-display.mjs +15 -12
- package/dist/client/components/fields/relation/displays/grid-display.mjs +15 -11
- package/dist/client/components/fields/relation/displays/list-display.mjs +33 -20
- package/dist/client/components/fields/relation/displays/table-display.mjs +62 -93
- package/dist/client/components/fields/relation/relation-items-display.mjs +1 -1
- package/dist/client/components/fields/relation-picker.mjs +7 -6
- package/dist/client/components/fields/relation-select.mjs +71 -47
- package/dist/client/components/fields/rich-text-editor/bubble-menu.mjs +392 -82
- package/dist/client/components/fields/rich-text-editor/extensions.mjs +54 -23
- package/dist/client/components/fields/rich-text-editor/image-popover.mjs +24 -50
- package/dist/client/components/fields/rich-text-editor/image-upload.mjs +66 -0
- package/dist/client/components/fields/rich-text-editor/index.d.mts +38 -0
- package/dist/client/components/fields/rich-text-editor/index.mjs +637 -376
- package/dist/client/components/fields/rich-text-editor/link-utils.mjs +26 -0
- package/dist/client/components/fields/rich-text-editor/presets.d.mts +10 -0
- package/dist/client/components/fields/rich-text-editor/slash-commands.mjs +27 -6
- package/dist/client/components/fields/rich-text-editor/toolbar.mjs +464 -346
- package/dist/client/components/fields/rich-text-editor/types.d.mts +77 -0
- package/dist/client/components/fields/upload-field.mjs +45 -49
- package/dist/client/components/filter-builder/columns-tab.mjs +69 -62
- package/dist/client/components/filter-builder/filter-builder-sheet.mjs +473 -308
- package/dist/client/components/filter-builder/filters-tab.mjs +109 -82
- package/dist/client/components/filter-builder/saved-views-tab.mjs +300 -198
- package/dist/client/components/history-sidebar.mjs +850 -340
- package/dist/client/components/layout/field-layout-renderer.mjs +6 -5
- package/dist/client/components/locale-switcher.mjs +8 -8
- package/dist/client/components/media/media-grid.mjs +12 -9
- package/dist/client/components/media/media-picker-dialog.mjs +242 -230
- package/dist/client/components/preview/live-preview-mode.mjs +1 -1
- package/dist/client/components/primitives/asset-preview.mjs +37 -22
- package/dist/client/components/primitives/date-input.mjs +212 -249
- package/dist/client/components/primitives/dropzone.mjs +192 -159
- package/dist/client/components/primitives/field-select-control.mjs +93 -0
- package/dist/client/components/primitives/select-multi.mjs +251 -230
- package/dist/client/components/primitives/select-single.mjs +345 -290
- package/dist/client/components/primitives/time-input.mjs +2 -2
- package/dist/client/components/sheets/resource-sheet.mjs +2 -0
- package/dist/client/components/ui/accordion.mjs +4 -4
- package/dist/client/components/ui/alert.mjs +3 -3
- package/dist/client/components/ui/badge.mjs +4 -4
- package/dist/client/components/ui/button.mjs +47 -37
- package/dist/client/components/ui/card.mjs +2 -2
- package/dist/client/components/ui/checkbox.mjs +1 -1
- package/dist/client/components/ui/command.mjs +5 -5
- package/dist/client/components/ui/dialog.mjs +3 -3
- package/dist/client/components/ui/drawer.mjs +1 -1
- package/dist/client/components/ui/dropdown-menu.mjs +157 -15
- package/dist/client/components/ui/empty-state.mjs +88 -59
- package/dist/client/components/ui/field.mjs +2 -2
- package/dist/client/components/ui/input-group.mjs +3 -3
- package/dist/client/components/ui/input.mjs +1 -1
- package/dist/client/components/ui/kbd.mjs +1 -1
- package/dist/client/components/ui/label.mjs +1 -1
- package/dist/client/components/ui/popover.mjs +19 -11
- package/dist/client/components/ui/scroll-fade.mjs +170 -0
- package/dist/client/components/ui/search-input.mjs +1 -1
- package/dist/client/components/ui/select.mjs +129 -27
- package/dist/client/components/ui/sheet.mjs +54 -34
- package/dist/client/components/ui/sidebar.mjs +15 -14
- package/dist/client/components/ui/skeleton.mjs +28 -12
- package/dist/client/components/ui/switch.mjs +2 -2
- package/dist/client/components/ui/table.mjs +82 -74
- package/dist/client/components/ui/tabs.mjs +26 -31
- package/dist/client/components/ui/textarea.mjs +1 -1
- package/dist/client/components/ui/tooltip.mjs +1 -1
- package/dist/client/components/widgets/chart-widget.mjs +134 -96
- package/dist/client/components/widgets/progress-widget.mjs +59 -34
- package/dist/client/components/widgets/quick-actions-widget.mjs +184 -113
- package/dist/client/components/widgets/recent-items-widget.mjs +144 -102
- package/dist/client/components/widgets/stats-widget.mjs +91 -72
- package/dist/client/components/widgets/table-widget.mjs +159 -246
- package/dist/client/components/widgets/timeline-widget.mjs +66 -43
- package/dist/client/components/widgets/value-widget.mjs +261 -152
- package/dist/client/components/widgets/widget-empty-state.mjs +88 -0
- package/dist/client/components/widgets/widget-skeletons.mjs +53 -20
- package/dist/client/contexts/focus-context.d.mts +2 -2
- package/dist/client/hooks/use-action.mjs +63 -55
- package/dist/client/hooks/use-audit-history.mjs +1 -65
- package/dist/client/hooks/use-collection-validation.mjs +36 -23
- package/dist/client/hooks/use-collection.mjs +96 -1
- package/dist/client/hooks/use-saved-views.mjs +70 -49
- package/dist/client/hooks/use-server-actions.mjs +59 -40
- package/dist/client/hooks/use-server-validation.mjs +156 -41
- package/dist/client/hooks/use-server-widget-data.mjs +1 -1
- package/dist/client/hooks/use-setup-status.d.mts +3 -3
- package/dist/client/hooks/use-setup-status.mjs +2 -2
- package/dist/client/hooks/use-transition-stage.mjs +2 -10
- package/dist/client/hooks/use-validation-error-map.mjs +31 -13
- package/dist/client/hooks/use-view-state.mjs +238 -174
- package/dist/client/i18n/date-locale.mjs +33 -0
- package/dist/client/i18n/hooks.mjs +17 -1
- package/dist/client/lib/utils.mjs +3 -2
- package/dist/client/preview/block-scope-context.d.mts +2 -2
- package/dist/client/preview/preview-banner.d.mts +2 -2
- package/dist/client/preview/preview-field.d.mts +4 -4
- package/dist/client/preview/preview-field.mjs +2 -2
- package/dist/client/runtime/provider.mjs +8 -1
- package/dist/client/runtime/translations-provider.mjs +1 -1
- package/dist/client/scope/picker.d.mts +2 -2
- package/dist/client/scope/provider.d.mts +2 -2
- package/dist/client/styles/base.css +1022 -0
- package/dist/client/styles/index.css +3 -589
- package/dist/client/utils/auto-expand-fields.mjs +4 -2
- package/dist/client/utils/keyboard-shortcuts.mjs +26 -0
- package/dist/client/utils/use-lazy-component.mjs +80 -0
- package/dist/client/views/auth/auth-layout.d.mts +18 -11
- package/dist/client/views/auth/auth-layout.mjs +291 -80
- package/dist/client/views/auth/forgot-password-form.d.mts +2 -2
- package/dist/client/views/auth/forgot-password-form.mjs +2 -2
- package/dist/client/views/auth/login-form.d.mts +2 -2
- package/dist/client/views/auth/login-form.mjs +1 -1
- package/dist/client/views/auth/reset-password-form.d.mts +2 -2
- package/dist/client/views/auth/reset-password-form.mjs +2 -2
- package/dist/client/views/auth/setup-form.d.mts +2 -2
- package/dist/client/views/collection/auto-form-fields.mjs +11 -9
- package/dist/client/views/collection/bulk-action-toolbar.mjs +173 -138
- package/dist/client/views/collection/cells/complex-cells.mjs +22 -22
- package/dist/client/views/collection/cells/primitive-cells.mjs +1 -1
- package/dist/client/views/collection/cells/relation-cells.mjs +147 -129
- package/dist/client/views/collection/cells/shared/asset-thumbnail.mjs +224 -278
- package/dist/client/views/collection/cells/shared/relation-chip.mjs +64 -36
- package/dist/client/views/collection/cells/upload-cells.mjs +199 -9
- package/dist/client/views/collection/columns/build-columns.mjs +29 -9
- package/dist/client/views/collection/columns/column-defaults.mjs +2 -2
- package/dist/client/views/collection/field-renderer.mjs +50 -89
- package/dist/client/views/collection/form-view.mjs +237 -227
- package/dist/client/views/collection/table-view.mjs +1162 -229
- package/dist/client/views/collection/view-skeletons.mjs +222 -79
- package/dist/client/views/common/global-search.mjs +29 -18
- package/dist/client/views/dashboard/dashboard-grid.mjs +678 -501
- package/dist/client/views/dashboard/dashboard-widget.mjs +6 -3
- package/dist/client/views/dashboard/widget-card.mjs +23 -14
- package/dist/client/views/globals/global-form-view.mjs +634 -589
- package/dist/client/views/layout/admin-layout-provider.mjs +67 -70
- package/dist/client/views/layout/admin-layout.d.mts +3 -6
- package/dist/client/views/layout/admin-layout.mjs +149 -172
- package/dist/client/views/layout/admin-router.mjs +747 -544
- package/dist/client/views/layout/admin-sidebar.d.mts +38 -1
- package/dist/client/views/layout/admin-sidebar.mjs +751 -591
- package/dist/client/views/layout/admin-theme.d.mts +10 -0
- package/dist/client/views/layout/admin-theme.mjs +84 -0
- package/dist/client/views/layout/admin-view-layout.mjs +161 -0
- package/dist/client/views/pages/accept-invite-page.d.mts +2 -2
- package/dist/client/views/pages/accept-invite-page.mjs +49 -26
- package/dist/client/views/pages/dashboard-page.d.mts +2 -2
- package/dist/client/views/pages/forgot-password-page.d.mts +2 -2
- package/dist/client/views/pages/forgot-password-page.mjs +2 -19
- package/dist/client/views/pages/invite-page.d.mts +2 -2
- package/dist/client/views/pages/invite-page.mjs +2 -19
- package/dist/client/views/pages/login-page.d.mts +1 -1
- package/dist/client/views/pages/login-page.mjs +4 -21
- package/dist/client/views/pages/reset-password-page.d.mts +2 -2
- package/dist/client/views/pages/reset-password-page.mjs +3 -20
- package/dist/client/views/pages/setup-page.d.mts +2 -2
- package/dist/client/views/pages/setup-page.mjs +3 -20
- package/dist/client.d.mts +6 -2
- package/dist/client.mjs +2 -1
- package/dist/components/rich-text/rich-text-renderer.d.mts +2 -2
- package/dist/index.d.mts +6 -2
- package/dist/index.mjs +2 -1
- package/dist/server/augmentation/dashboard.d.mts +67 -3
- package/dist/server/augmentation/form-layout.d.mts +21 -0
- package/dist/server/augmentation/index.d.mts +1 -1
- package/dist/server/codegen/admin-client-template.mjs +4 -0
- package/dist/server/fields/blocks.d.mts +1 -1
- package/dist/server/fields/blocks.mjs +12 -0
- package/dist/server/fields/rich-text.d.mts +1 -1
- package/dist/server/fields/rich-text.mjs +8 -0
- package/dist/server/i18n/index.mjs +17 -1
- package/dist/server/i18n/messages/cs.mjs +23 -0
- package/dist/server/i18n/messages/de.mjs +23 -0
- package/dist/server/i18n/messages/en.mjs +64 -1
- package/dist/server/i18n/messages/es.mjs +23 -0
- package/dist/server/i18n/messages/fr.mjs +23 -0
- package/dist/server/i18n/messages/pl.mjs +23 -0
- package/dist/server/i18n/messages/pt.mjs +23 -0
- package/dist/server/i18n/messages/sk.mjs +83 -1
- package/dist/server/modules/admin/block/introspection.mjs +4 -1
- package/dist/server/modules/admin/block/prefetch.mjs +12 -2
- package/dist/server/modules/admin/collections/account.d.mts +50 -50
- package/dist/server/modules/admin/collections/admin-locks.d.mts +54 -54
- package/dist/server/modules/admin/collections/admin-preferences.d.mts +39 -39
- package/dist/server/modules/admin/collections/admin-saved-views.d.mts +47 -47
- package/dist/server/modules/admin/collections/apikey.d.mts +68 -68
- package/dist/server/modules/admin/collections/assets.d.mts +20 -20
- package/dist/server/modules/admin/collections/assets.mjs +0 -1
- package/dist/server/modules/admin/collections/session.d.mts +42 -42
- package/dist/server/modules/admin/collections/user.d.mts +12 -0
- package/dist/server/modules/admin/collections/user.mjs +40 -9
- package/dist/server/modules/admin/collections/verification.d.mts +2 -2
- package/dist/server/modules/admin/dto/admin-config.dto.mjs +2 -0
- package/dist/server/modules/admin/factories.mjs +7 -18
- package/dist/server/modules/admin/index.d.mts +1 -1
- package/dist/server/modules/admin/routes/admin-config.d.mts +2 -2
- package/dist/server/modules/admin/routes/admin-config.mjs +34 -16
- package/dist/server/modules/admin/routes/execute-action.d.mts +9 -9
- package/dist/server/modules/admin/routes/execute-action.mjs +33 -0
- package/dist/server/modules/admin/routes/locales.d.mts +2 -2
- package/dist/server/modules/admin/routes/preview.d.mts +11 -11
- package/dist/server/modules/admin/routes/reactive.d.mts +9 -9
- package/dist/server/modules/admin/routes/setup.d.mts +10 -10
- package/dist/server/modules/admin/routes/setup.mjs +7 -7
- package/dist/server/modules/admin/routes/translations.d.mts +4 -4
- package/dist/server/modules/admin/routes/translations.mjs +5 -1
- package/dist/server/modules/admin/routes/widget-data.d.mts +5 -5
- package/dist/server/modules/admin-preferences/collections/admin-preferences.mjs +1 -1
- package/dist/server/modules/admin-preferences/collections/saved-views.d.mts +27 -27
- package/dist/server/modules/audit/.generated/module.d.mts +1 -1
- package/dist/server/modules/audit/.generated/module.mjs +1 -1
- package/dist/server/modules/audit/collections/audit-log.d.mts +2 -2
- package/dist/server/modules/audit/collections/audit-log.mjs +1 -1
- package/dist/server/modules/audit/config/app.mjs +99 -42
- package/dist/server/modules/audit/jobs/audit-cleanup.mjs +1 -1
- package/dist/server/plugin.mjs +4 -2
- package/dist/server/proxy-factories.d.mts +4 -3
- package/dist/server/proxy-factories.mjs +34 -8
- package/dist/shared/types/saved-views.types.d.mts +2 -0
- package/package.json +6 -4
- package/dist/client/components/fields/rich-text-editor/link-popover.mjs +0 -85
- package/dist/client/components/ui/spinner.mjs +0 -52
- package/dist/client/components/ui/toolbar.mjs +0 -136
- package/dist/client/contexts/breadcrumb-context.mjs +0 -60
- package/dist/client/views/layout/admin-topbar.mjs +0 -236
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as questpie135 from "questpie";
|
|
2
2
|
|
|
3
3
|
//#region src/server/modules/admin/routes/reactive.d.ts
|
|
4
4
|
|
|
@@ -13,7 +13,7 @@ import * as questpie143 from "questpie";
|
|
|
13
13
|
* Batch reactive endpoint.
|
|
14
14
|
* Executes multiple reactive handlers in a single request.
|
|
15
15
|
*/
|
|
16
|
-
declare const batchReactive:
|
|
16
|
+
declare const batchReactive: questpie135.JsonRouteDefinition<{
|
|
17
17
|
collection: string;
|
|
18
18
|
type: "collection" | "global";
|
|
19
19
|
requests: {
|
|
@@ -26,12 +26,12 @@ declare const batchReactive: questpie143.JsonRouteDefinition<{
|
|
|
26
26
|
}[];
|
|
27
27
|
formData?: Record<string, unknown> | undefined;
|
|
28
28
|
prevData?: Record<string, unknown> | null | undefined;
|
|
29
|
-
}, any,
|
|
29
|
+
}, any, questpie135.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:
|
|
34
|
+
declare const fieldOptions: questpie135.JsonRouteDefinition<{
|
|
35
35
|
collection: string;
|
|
36
36
|
type: "collection" | "global";
|
|
37
37
|
field: string;
|
|
@@ -40,12 +40,12 @@ declare const fieldOptions: questpie143.JsonRouteDefinition<{
|
|
|
40
40
|
page: number;
|
|
41
41
|
limit: number;
|
|
42
42
|
siblingData?: Record<string, unknown> | null | undefined;
|
|
43
|
-
}, any,
|
|
43
|
+
}, any, questpie135.JsonRouteParams>;
|
|
44
44
|
/**
|
|
45
45
|
* Reactive functions bundle.
|
|
46
46
|
*/
|
|
47
47
|
declare const reactiveFunctions: {
|
|
48
|
-
readonly batchReactive:
|
|
48
|
+
readonly batchReactive: questpie135.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,
|
|
62
|
-
readonly fieldOptions:
|
|
61
|
+
}, any, questpie135.JsonRouteParams>;
|
|
62
|
+
readonly fieldOptions: questpie135.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,
|
|
71
|
+
}, any, questpie135.JsonRouteParams>;
|
|
72
72
|
};
|
|
73
73
|
//#endregion
|
|
74
74
|
export { batchReactive, fieldOptions, reactiveFunctions };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as questpie143 from "questpie";
|
|
2
2
|
|
|
3
3
|
//#region src/server/modules/admin/routes/setup.d.ts
|
|
4
4
|
|
|
@@ -10,7 +10,7 @@ import * as questpie135 from "questpie";
|
|
|
10
10
|
* need an existing admin to create the first invitation.
|
|
11
11
|
*/
|
|
12
12
|
/**
|
|
13
|
-
* Check if setup is required (no users exist in the system).
|
|
13
|
+
* Check if setup is required (no admin users exist in the system).
|
|
14
14
|
*
|
|
15
15
|
* @example
|
|
16
16
|
* ```ts
|
|
@@ -20,12 +20,12 @@ import * as questpie135 from "questpie";
|
|
|
20
20
|
* }
|
|
21
21
|
* ```
|
|
22
22
|
*/
|
|
23
|
-
declare const isSetupRequired:
|
|
23
|
+
declare const isSetupRequired: questpie143.JsonRouteDefinition<Record<string, never>, any, questpie143.JsonRouteParams>;
|
|
24
24
|
/**
|
|
25
25
|
* Create the first admin user in the system.
|
|
26
|
-
* This function only works when no users exist (setup mode).
|
|
26
|
+
* This function only works when no admin users exist (setup mode).
|
|
27
27
|
*
|
|
28
|
-
* Security: Once any user exists, this function will refuse to create more users.
|
|
28
|
+
* Security: Once any admin user exists, this function will refuse to create more users.
|
|
29
29
|
* This prevents unauthorized admin creation after initial setup.
|
|
30
30
|
*
|
|
31
31
|
* @example
|
|
@@ -43,21 +43,21 @@ declare const isSetupRequired: questpie135.JsonRouteDefinition<Record<string, ne
|
|
|
43
43
|
* }
|
|
44
44
|
* ```
|
|
45
45
|
*/
|
|
46
|
-
declare const createFirstAdmin:
|
|
46
|
+
declare const createFirstAdmin: questpie143.JsonRouteDefinition<{
|
|
47
47
|
email: string;
|
|
48
48
|
password: string;
|
|
49
49
|
name: string;
|
|
50
|
-
}, any,
|
|
50
|
+
}, any, questpie143.JsonRouteParams>;
|
|
51
51
|
/**
|
|
52
52
|
* Bundle of setup-related functions.
|
|
53
53
|
*/
|
|
54
54
|
declare const setupFunctions: {
|
|
55
|
-
readonly isSetupRequired:
|
|
56
|
-
readonly createFirstAdmin:
|
|
55
|
+
readonly isSetupRequired: questpie143.JsonRouteDefinition<Record<string, never>, any, questpie143.JsonRouteParams>;
|
|
56
|
+
readonly createFirstAdmin: questpie143.JsonRouteDefinition<{
|
|
57
57
|
email: string;
|
|
58
58
|
password: string;
|
|
59
59
|
name: string;
|
|
60
|
-
}, any,
|
|
60
|
+
}, any, questpie143.JsonRouteParams>;
|
|
61
61
|
};
|
|
62
62
|
//#endregion
|
|
63
63
|
export { createFirstAdmin, isSetupRequired, setupFunctions };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { getApp } from "./route-helpers.mjs";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { route } from "questpie";
|
|
4
|
-
import { eq, sql as sql$1 } from "drizzle
|
|
4
|
+
import { eq, sql as sql$1 } from "questpie/drizzle";
|
|
5
5
|
|
|
6
6
|
//#region src/server/modules/admin/routes/setup.ts
|
|
7
7
|
/**
|
|
@@ -28,7 +28,7 @@ const createFirstAdminOutputSchema = z.object({
|
|
|
28
28
|
error: z.string().optional()
|
|
29
29
|
});
|
|
30
30
|
/**
|
|
31
|
-
* Check if setup is required (no users exist in the system).
|
|
31
|
+
* Check if setup is required (no admin users exist in the system).
|
|
32
32
|
*
|
|
33
33
|
* @example
|
|
34
34
|
* ```ts
|
|
@@ -41,13 +41,13 @@ const createFirstAdminOutputSchema = z.object({
|
|
|
41
41
|
const isSetupRequired = route().post().schema(isSetupRequiredSchema).outputSchema(isSetupRequiredOutputSchema).handler(async (ctx) => {
|
|
42
42
|
const app = getApp(ctx);
|
|
43
43
|
const userCollection = app.getCollectionConfig("user");
|
|
44
|
-
return { required: (await app.db.select({ count: sql$1`count(*)::int` }).from(userCollection.table))[0].count === 0 };
|
|
44
|
+
return { required: (await app.db.select({ count: sql$1`count(*)::int` }).from(userCollection.table).where(eq(userCollection.table.role, "admin")))[0].count === 0 };
|
|
45
45
|
});
|
|
46
46
|
/**
|
|
47
47
|
* Create the first admin user in the system.
|
|
48
|
-
* This function only works when no users exist (setup mode).
|
|
48
|
+
* This function only works when no admin users exist (setup mode).
|
|
49
49
|
*
|
|
50
|
-
* Security: Once any user exists, this function will refuse to create more users.
|
|
50
|
+
* Security: Once any admin user exists, this function will refuse to create more users.
|
|
51
51
|
* This prevents unauthorized admin creation after initial setup.
|
|
52
52
|
*
|
|
53
53
|
* @example
|
|
@@ -69,9 +69,9 @@ const createFirstAdmin = route().post().schema(createFirstAdminSchema).outputSch
|
|
|
69
69
|
const app = getApp(ctx);
|
|
70
70
|
const input = ctx.input;
|
|
71
71
|
const userCollection = app.getCollectionConfig("user");
|
|
72
|
-
if ((await app.db.select({ count: sql$1`count(*)::int` }).from(userCollection.table))[0].count > 0) return {
|
|
72
|
+
if ((await app.db.select({ count: sql$1`count(*)::int` }).from(userCollection.table).where(eq(userCollection.table.role, "admin")))[0].count > 0) return {
|
|
73
73
|
success: false,
|
|
74
|
-
error: "Setup already completed - users exist in the system"
|
|
74
|
+
error: "Setup already completed - admin users exist in the system"
|
|
75
75
|
};
|
|
76
76
|
try {
|
|
77
77
|
const signUpResult = await app.auth.api.signUpEmail({ body: {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as questpie464 from "questpie";
|
|
2
2
|
|
|
3
3
|
//#region src/server/modules/admin/routes/translations.d.ts
|
|
4
4
|
|
|
@@ -17,10 +17,10 @@ import * as questpie462 from "questpie";
|
|
|
17
17
|
* Bundle of translation-related functions.
|
|
18
18
|
*/
|
|
19
19
|
declare const translationFunctions: {
|
|
20
|
-
readonly getAdminTranslations:
|
|
20
|
+
readonly getAdminTranslations: questpie464.JsonRouteDefinition<{
|
|
21
21
|
locale: string;
|
|
22
|
-
}, any,
|
|
23
|
-
readonly getAdminLocales:
|
|
22
|
+
}, any, questpie464.JsonRouteParams>;
|
|
23
|
+
readonly getAdminLocales: questpie464.JsonRouteDefinition<Record<string, never> | undefined, any, questpie464.JsonRouteParams>;
|
|
24
24
|
};
|
|
25
25
|
//#endregion
|
|
26
26
|
export { translationFunctions };
|
|
@@ -29,7 +29,11 @@ function getAdminLocaleConfig(app) {
|
|
|
29
29
|
const getAdminTranslationsSchema = z.object({ locale: z.string() });
|
|
30
30
|
const messageValueSchema = z.union([z.string(), z.object({
|
|
31
31
|
one: z.string(),
|
|
32
|
-
other: z.string()
|
|
32
|
+
other: z.string(),
|
|
33
|
+
zero: z.string().optional(),
|
|
34
|
+
two: z.string().optional(),
|
|
35
|
+
few: z.string().optional(),
|
|
36
|
+
many: z.string().optional()
|
|
33
37
|
})]);
|
|
34
38
|
const getAdminTranslationsOutputSchema = z.object({
|
|
35
39
|
locale: z.string(),
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as questpie93 from "questpie";
|
|
2
2
|
|
|
3
3
|
//#region src/server/modules/admin/routes/widget-data.d.ts
|
|
4
4
|
|
|
@@ -20,13 +20,13 @@ import * as questpie69 from "questpie";
|
|
|
20
20
|
* const data = await client.routes.fetchWidgetData({ widgetId: "my-widget" });
|
|
21
21
|
* ```
|
|
22
22
|
*/
|
|
23
|
-
declare const fetchWidgetData:
|
|
23
|
+
declare const fetchWidgetData: questpie93.JsonRouteDefinition<{
|
|
24
24
|
widgetId: string;
|
|
25
|
-
}, any,
|
|
25
|
+
}, any, questpie93.JsonRouteParams>;
|
|
26
26
|
declare const widgetDataFunctions: {
|
|
27
|
-
readonly fetchWidgetData:
|
|
27
|
+
readonly fetchWidgetData: questpie93.JsonRouteDefinition<{
|
|
28
28
|
widgetId: string;
|
|
29
|
-
}, any,
|
|
29
|
+
}, any, questpie93.JsonRouteParams>;
|
|
30
30
|
};
|
|
31
31
|
//#endregion
|
|
32
32
|
export { fetchWidgetData, widgetDataFunctions };
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { FilterOperator, FilterRule, SortConfig, ViewConfiguration } from "../../../../shared/types/saved-views.types.mjs";
|
|
2
2
|
import * as questpie_shared15 from "questpie/shared";
|
|
3
|
-
import * as
|
|
3
|
+
import * as questpie107 from "questpie";
|
|
4
|
+
import * as questpie_src_server_modules_core_fields_email_js2 from "questpie/src/server/modules/core/fields/email.js";
|
|
5
|
+
import * as questpie_src_server_modules_core_fields_json_js2 from "questpie/src/server/modules/core/fields/json.js";
|
|
4
6
|
import * as drizzle_orm_pg_core22 from "drizzle-orm/pg-core";
|
|
5
7
|
import * as drizzle_orm5 from "drizzle-orm";
|
|
6
|
-
import * as questpie_src_server_modules_core_fields_email_js1 from "questpie/src/server/modules/core/fields/email.js";
|
|
7
|
-
import * as questpie_src_server_modules_core_fields_json_js1 from "questpie/src/server/modules/core/fields/json.js";
|
|
8
8
|
|
|
9
9
|
//#region src/server/modules/admin-preferences/collections/saved-views.d.ts
|
|
10
10
|
|
|
@@ -33,22 +33,22 @@ import * as questpie_src_server_modules_core_fields_json_js1 from "questpie/src/
|
|
|
33
33
|
* });
|
|
34
34
|
* ```
|
|
35
35
|
*/
|
|
36
|
-
declare const savedViewsCollection:
|
|
37
|
-
readonly text: typeof
|
|
38
|
-
readonly textarea: typeof
|
|
39
|
-
readonly email: typeof
|
|
40
|
-
readonly url: typeof
|
|
41
|
-
readonly number: typeof
|
|
42
|
-
readonly boolean: typeof
|
|
43
|
-
readonly date: typeof
|
|
44
|
-
readonly datetime: typeof
|
|
45
|
-
readonly time: typeof
|
|
46
|
-
readonly select: typeof
|
|
47
|
-
readonly upload: typeof
|
|
48
|
-
readonly relation: typeof
|
|
49
|
-
readonly object: typeof
|
|
50
|
-
readonly json: typeof
|
|
51
|
-
readonly from: typeof
|
|
36
|
+
declare const savedViewsCollection: questpie107.CollectionBuilder<questpie_shared15.Override<questpie_shared15.Override<questpie107.EmptyCollectionState<"admin_saved_views", undefined, {
|
|
37
|
+
readonly text: typeof questpie107.text;
|
|
38
|
+
readonly textarea: typeof questpie107.textarea;
|
|
39
|
+
readonly email: typeof questpie_src_server_modules_core_fields_email_js2.email;
|
|
40
|
+
readonly url: typeof questpie107.url;
|
|
41
|
+
readonly number: typeof questpie107.number;
|
|
42
|
+
readonly boolean: typeof questpie107.boolean;
|
|
43
|
+
readonly date: typeof questpie107.date;
|
|
44
|
+
readonly datetime: typeof questpie107.datetime;
|
|
45
|
+
readonly time: typeof questpie107.time;
|
|
46
|
+
readonly select: typeof questpie107.select;
|
|
47
|
+
readonly upload: typeof questpie107.upload;
|
|
48
|
+
readonly relation: typeof questpie107.relation;
|
|
49
|
+
readonly object: typeof questpie107.object;
|
|
50
|
+
readonly json: typeof questpie_src_server_modules_core_fields_json_js2.json;
|
|
51
|
+
readonly from: typeof questpie107.from;
|
|
52
52
|
}>, {
|
|
53
53
|
fields: {
|
|
54
54
|
readonly userId: drizzle_orm5.NotNull<drizzle_orm_pg_core22.PgVarcharBuilder<[string, ...string[]]>>;
|
|
@@ -59,31 +59,31 @@ declare const savedViewsCollection: questpie73.CollectionBuilder<questpie_shared
|
|
|
59
59
|
};
|
|
60
60
|
localized: readonly string[];
|
|
61
61
|
fieldDefinitions: {
|
|
62
|
-
readonly userId:
|
|
62
|
+
readonly userId: questpie107.FieldWithMethods<Omit<questpie107.TextFieldState, "notNull" | "column"> & {
|
|
63
63
|
notNull: true;
|
|
64
64
|
column: drizzle_orm5.NotNull<drizzle_orm_pg_core22.PgVarcharBuilder<[string, ...string[]]>>;
|
|
65
65
|
} & {
|
|
66
66
|
label: questpie_shared15.I18nText;
|
|
67
|
-
},
|
|
68
|
-
readonly collectionName:
|
|
67
|
+
}, questpie107.TextFieldMethods>;
|
|
68
|
+
readonly collectionName: questpie107.FieldWithMethods<Omit<questpie107.TextFieldState, "notNull" | "column"> & {
|
|
69
69
|
notNull: true;
|
|
70
70
|
column: drizzle_orm5.NotNull<drizzle_orm_pg_core22.PgVarcharBuilder<[string, ...string[]]>>;
|
|
71
71
|
} & {
|
|
72
72
|
label: questpie_shared15.I18nText;
|
|
73
|
-
},
|
|
74
|
-
readonly name:
|
|
73
|
+
}, questpie107.TextFieldMethods>;
|
|
74
|
+
readonly name: questpie107.FieldWithMethods<Omit<questpie107.TextFieldState, "notNull" | "column"> & {
|
|
75
75
|
notNull: true;
|
|
76
76
|
column: drizzle_orm5.NotNull<drizzle_orm_pg_core22.PgVarcharBuilder<[string, ...string[]]>>;
|
|
77
77
|
} & {
|
|
78
78
|
label: questpie_shared15.I18nText;
|
|
79
|
-
},
|
|
80
|
-
readonly configuration:
|
|
79
|
+
}, questpie107.TextFieldMethods>;
|
|
80
|
+
readonly configuration: questpie107.Field<Omit<questpie107.JsonFieldState, "notNull" | "column"> & {
|
|
81
81
|
notNull: true;
|
|
82
82
|
column: drizzle_orm5.NotNull<drizzle_orm_pg_core22.PgJsonbBuilder>;
|
|
83
83
|
} & {
|
|
84
84
|
label: questpie_shared15.I18nText;
|
|
85
85
|
}>;
|
|
86
|
-
readonly isDefault:
|
|
86
|
+
readonly isDefault: questpie107.Field<Omit<questpie107.BooleanFieldState, "column" | "hasDefault"> & {
|
|
87
87
|
hasDefault: true;
|
|
88
88
|
column: drizzle_orm5.HasDefault<drizzle_orm_pg_core22.PgBooleanBuilder>;
|
|
89
89
|
} & {
|
|
@@ -4,7 +4,7 @@ import * as questpie64 from "questpie";
|
|
|
4
4
|
|
|
5
5
|
//#region src/server/modules/audit/.generated/module.d.ts
|
|
6
6
|
interface AuditCollections {
|
|
7
|
-
|
|
7
|
+
admin_audit_log: typeof auditLogCollection;
|
|
8
8
|
}
|
|
9
9
|
interface AuditJobs {
|
|
10
10
|
auditCleanup: typeof auditCleanupJob;
|
|
@@ -6,7 +6,7 @@ import app_default from "../config/app.mjs";
|
|
|
6
6
|
//#region src/server/modules/audit/.generated/module.ts
|
|
7
7
|
const _module = {
|
|
8
8
|
name: "questpie-audit",
|
|
9
|
-
collections: { auditLogCollection },
|
|
9
|
+
collections: { admin_audit_log: auditLogCollection },
|
|
10
10
|
jobs: { auditCleanup: auditCleanupJob },
|
|
11
11
|
globals: {},
|
|
12
12
|
routes: {},
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import * as questpie_shared0 from "questpie/shared";
|
|
2
2
|
import * as questpie16 from "questpie";
|
|
3
|
-
import * as drizzle_orm_pg_core0 from "drizzle-orm/pg-core";
|
|
4
|
-
import * as drizzle_orm0 from "drizzle-orm";
|
|
5
3
|
import * as questpie_src_server_modules_core_fields_email_js0 from "questpie/src/server/modules/core/fields/email.js";
|
|
6
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
|
|
@@ -19,16 +19,36 @@ function isAuditDisabled(type, name) {
|
|
|
19
19
|
* Compute field-level changes between original and current data.
|
|
20
20
|
* Returns an object of `{ field: { from, to } }` or null if no meaningful changes.
|
|
21
21
|
*/
|
|
22
|
+
const SKIP_CHANGE_FIELDS = new Set([
|
|
23
|
+
"updatedAt",
|
|
24
|
+
"createdAt",
|
|
25
|
+
"id"
|
|
26
|
+
]);
|
|
27
|
+
function shouldSkipChangeField(key) {
|
|
28
|
+
return SKIP_CHANGE_FIELDS.has(key) || key.startsWith("_");
|
|
29
|
+
}
|
|
30
|
+
function makeFieldChangeMap(data, direction) {
|
|
31
|
+
if (!data) return null;
|
|
32
|
+
const changes = {};
|
|
33
|
+
for (const key of Object.keys(data)) {
|
|
34
|
+
if (shouldSkipChangeField(key)) continue;
|
|
35
|
+
const value = data[key];
|
|
36
|
+
if (value == null) continue;
|
|
37
|
+
changes[key] = direction === "create" ? {
|
|
38
|
+
from: null,
|
|
39
|
+
to: value
|
|
40
|
+
} : {
|
|
41
|
+
from: value,
|
|
42
|
+
to: null
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
return Object.keys(changes).length > 0 ? changes : null;
|
|
46
|
+
}
|
|
22
47
|
function computeChanges(original, current) {
|
|
23
48
|
if (!original) return null;
|
|
24
49
|
const changes = {};
|
|
25
|
-
const skipFields = new Set([
|
|
26
|
-
"updatedAt",
|
|
27
|
-
"createdAt",
|
|
28
|
-
"id"
|
|
29
|
-
]);
|
|
30
50
|
for (const key of Object.keys(current)) {
|
|
31
|
-
if (
|
|
51
|
+
if (shouldSkipChangeField(key)) continue;
|
|
32
52
|
const fromVal = original[key];
|
|
33
53
|
const toVal = current[key];
|
|
34
54
|
if (fromVal == null && toVal == null) continue;
|
|
@@ -85,24 +105,61 @@ function getResourceTypeLabel(type, name) {
|
|
|
85
105
|
* Generate a human-readable title for the audit log entry.
|
|
86
106
|
*/
|
|
87
107
|
function generateTitle(action, _resourceType, resourceTypeLabel, resourceLabel, userName) {
|
|
88
|
-
const user = userName || "Unknown";
|
|
89
108
|
const resource = resourceLabel || "(unnamed)";
|
|
90
|
-
return `${
|
|
109
|
+
return `${userName} ${{
|
|
91
110
|
create: "created",
|
|
92
111
|
update: "updated",
|
|
93
112
|
delete: "deleted",
|
|
94
113
|
transition: "changed status of"
|
|
95
114
|
}[action] || action} ${resourceTypeLabel} '${resource}'`;
|
|
96
115
|
}
|
|
116
|
+
function firstNonEmptyString(...values) {
|
|
117
|
+
for (const value of values) {
|
|
118
|
+
if (typeof value !== "string") continue;
|
|
119
|
+
const trimmed = value.trim();
|
|
120
|
+
if (trimmed.length > 0) return trimmed;
|
|
121
|
+
}
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
function resolveAuditActor(ctx) {
|
|
125
|
+
const user = ctx.session?.user;
|
|
126
|
+
const userId = user?.id != null ? String(user.id) : null;
|
|
127
|
+
const userName = firstNonEmptyString(user?.name, user?.email, userId);
|
|
128
|
+
if (userName) return {
|
|
129
|
+
actorType: "user",
|
|
130
|
+
userId,
|
|
131
|
+
userName
|
|
132
|
+
};
|
|
133
|
+
if (ctx.accessMode === "system") return {
|
|
134
|
+
actorType: "system",
|
|
135
|
+
userId: "system",
|
|
136
|
+
userName: "System"
|
|
137
|
+
};
|
|
138
|
+
return {
|
|
139
|
+
actorType: "anonymous",
|
|
140
|
+
userId: null,
|
|
141
|
+
userName: "Anonymous"
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
function buildAuditMetadata(ctx, actor, extra) {
|
|
145
|
+
return {
|
|
146
|
+
actorType: actor.actorType,
|
|
147
|
+
accessMode: ctx.accessMode ?? null,
|
|
148
|
+
...extra
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
function logAuditFailure(ctx, message, err) {
|
|
152
|
+
ctx.logger?.error?.(message, err);
|
|
153
|
+
}
|
|
97
154
|
async function collectionAfterChange(ctx) {
|
|
98
155
|
try {
|
|
99
156
|
const collections = ctx.collections ?? ctx.app?.collections;
|
|
100
157
|
if (isAuditDisabled("collection", ctx.collection)) return;
|
|
101
158
|
const action = ctx.operation === "create" ? "create" : "update";
|
|
102
|
-
const changes = ctx.operation === "update" ? computeChanges(ctx.original, ctx.data) :
|
|
159
|
+
const changes = ctx.operation === "update" ? computeChanges(ctx.original, ctx.data) : makeFieldChangeMap(ctx.data, "create");
|
|
103
160
|
if (ctx.operation === "update" && !changes) return;
|
|
104
161
|
const resourceLabel = extractLabel(ctx.data);
|
|
105
|
-
const
|
|
162
|
+
const actor = resolveAuditActor(ctx);
|
|
106
163
|
const resourceTypeLabel = getResourceTypeLabel("collection", ctx.collection);
|
|
107
164
|
await collections[AUDIT_LOG_COLLECTION].create({
|
|
108
165
|
action,
|
|
@@ -110,18 +167,18 @@ async function collectionAfterChange(ctx) {
|
|
|
110
167
|
resource: ctx.collection,
|
|
111
168
|
resourceId: ctx.data?.id ? String(ctx.data.id) : null,
|
|
112
169
|
resourceLabel,
|
|
113
|
-
userId:
|
|
114
|
-
userName,
|
|
170
|
+
userId: actor.userId,
|
|
171
|
+
userName: actor.userName,
|
|
115
172
|
locale: ctx.locale || null,
|
|
116
173
|
changes,
|
|
117
|
-
metadata:
|
|
118
|
-
title: generateTitle(action, "collection", resourceTypeLabel, resourceLabel, userName)
|
|
174
|
+
metadata: buildAuditMetadata(ctx, actor, { operation: ctx.operation }),
|
|
175
|
+
title: generateTitle(action, "collection", resourceTypeLabel, resourceLabel, actor.userName)
|
|
119
176
|
}, {
|
|
120
177
|
accessMode: "system",
|
|
121
178
|
db: ctx.db
|
|
122
179
|
});
|
|
123
180
|
} catch (err) {
|
|
124
|
-
|
|
181
|
+
logAuditFailure(ctx, `[Audit] Failed to log ${ctx.operation} for collection "${ctx.collection}":`, err);
|
|
125
182
|
}
|
|
126
183
|
}
|
|
127
184
|
async function collectionAfterDelete(ctx) {
|
|
@@ -129,7 +186,7 @@ async function collectionAfterDelete(ctx) {
|
|
|
129
186
|
const collections = ctx.collections ?? ctx.app?.collections;
|
|
130
187
|
if (isAuditDisabled("collection", ctx.collection)) return;
|
|
131
188
|
const resourceLabel = extractLabel(ctx.data);
|
|
132
|
-
const
|
|
189
|
+
const actor = resolveAuditActor(ctx);
|
|
133
190
|
const resourceTypeLabel = getResourceTypeLabel("collection", ctx.collection);
|
|
134
191
|
await collections[AUDIT_LOG_COLLECTION].create({
|
|
135
192
|
action: "delete",
|
|
@@ -137,18 +194,18 @@ async function collectionAfterDelete(ctx) {
|
|
|
137
194
|
resource: ctx.collection,
|
|
138
195
|
resourceId: ctx.data?.id ? String(ctx.data.id) : null,
|
|
139
196
|
resourceLabel,
|
|
140
|
-
userId:
|
|
141
|
-
userName,
|
|
197
|
+
userId: actor.userId,
|
|
198
|
+
userName: actor.userName,
|
|
142
199
|
locale: ctx.locale || null,
|
|
143
|
-
changes:
|
|
144
|
-
metadata:
|
|
145
|
-
title: generateTitle("delete", "collection", resourceTypeLabel, resourceLabel, userName)
|
|
200
|
+
changes: makeFieldChangeMap(ctx.data, "delete"),
|
|
201
|
+
metadata: buildAuditMetadata(ctx, actor, { operation: "delete" }),
|
|
202
|
+
title: generateTitle("delete", "collection", resourceTypeLabel, resourceLabel, actor.userName)
|
|
146
203
|
}, {
|
|
147
204
|
accessMode: "system",
|
|
148
205
|
db: ctx.db
|
|
149
206
|
});
|
|
150
207
|
} catch (err) {
|
|
151
|
-
|
|
208
|
+
logAuditFailure(ctx, `[Audit] Failed to log delete for collection "${ctx.collection}":`, err);
|
|
152
209
|
}
|
|
153
210
|
}
|
|
154
211
|
async function collectionAfterTransition(ctx) {
|
|
@@ -156,7 +213,7 @@ async function collectionAfterTransition(ctx) {
|
|
|
156
213
|
const collections = ctx.collections ?? ctx.app?.collections;
|
|
157
214
|
if (isAuditDisabled("collection", ctx.collection)) return;
|
|
158
215
|
const resourceLabel = extractLabel(ctx.data);
|
|
159
|
-
const
|
|
216
|
+
const actor = resolveAuditActor(ctx);
|
|
160
217
|
const resourceTypeLabel = getResourceTypeLabel("collection", ctx.collection);
|
|
161
218
|
await collections[AUDIT_LOG_COLLECTION].create({
|
|
162
219
|
action: "transition",
|
|
@@ -164,31 +221,31 @@ async function collectionAfterTransition(ctx) {
|
|
|
164
221
|
resource: ctx.collection,
|
|
165
222
|
resourceId: ctx.data?.id ? String(ctx.data.id) : null,
|
|
166
223
|
resourceLabel,
|
|
167
|
-
userId:
|
|
168
|
-
userName,
|
|
224
|
+
userId: actor.userId,
|
|
225
|
+
userName: actor.userName,
|
|
169
226
|
locale: ctx.locale || null,
|
|
170
227
|
changes: { stage: {
|
|
171
228
|
from: ctx.fromStage,
|
|
172
229
|
to: ctx.toStage
|
|
173
230
|
} },
|
|
174
|
-
metadata: {
|
|
231
|
+
metadata: buildAuditMetadata(ctx, actor, {
|
|
175
232
|
fromStage: ctx.fromStage,
|
|
176
233
|
toStage: ctx.toStage
|
|
177
|
-
},
|
|
178
|
-
title: generateTitle("transition", "collection", resourceTypeLabel, resourceLabel, userName)
|
|
234
|
+
}),
|
|
235
|
+
title: generateTitle("transition", "collection", resourceTypeLabel, resourceLabel, actor.userName)
|
|
179
236
|
}, {
|
|
180
237
|
accessMode: "system",
|
|
181
238
|
db: ctx.db
|
|
182
239
|
});
|
|
183
240
|
} catch (err) {
|
|
184
|
-
|
|
241
|
+
logAuditFailure(ctx, `[Audit] Failed to log transition for collection "${ctx.collection}":`, err);
|
|
185
242
|
}
|
|
186
243
|
}
|
|
187
244
|
async function globalAfterChange(ctx) {
|
|
188
245
|
try {
|
|
189
246
|
const collections = ctx.collections ?? ctx.app?.collections;
|
|
190
247
|
if (isAuditDisabled("global", ctx.global)) return;
|
|
191
|
-
const
|
|
248
|
+
const actor = resolveAuditActor(ctx);
|
|
192
249
|
const resourceTypeLabel = getResourceTypeLabel("global", ctx.global);
|
|
193
250
|
await collections[AUDIT_LOG_COLLECTION].create({
|
|
194
251
|
action: "update",
|
|
@@ -196,25 +253,25 @@ async function globalAfterChange(ctx) {
|
|
|
196
253
|
resource: ctx.global,
|
|
197
254
|
resourceId: null,
|
|
198
255
|
resourceLabel: ctx.global,
|
|
199
|
-
userId:
|
|
200
|
-
userName,
|
|
256
|
+
userId: actor.userId,
|
|
257
|
+
userName: actor.userName,
|
|
201
258
|
locale: ctx.locale || null,
|
|
202
259
|
changes: null,
|
|
203
|
-
metadata:
|
|
204
|
-
title: generateTitle("update", "global", resourceTypeLabel, ctx.global, userName)
|
|
260
|
+
metadata: buildAuditMetadata(ctx, actor, { operation: "update" }),
|
|
261
|
+
title: generateTitle("update", "global", resourceTypeLabel, ctx.global, actor.userName)
|
|
205
262
|
}, {
|
|
206
263
|
accessMode: "system",
|
|
207
264
|
db: ctx.db
|
|
208
265
|
});
|
|
209
266
|
} catch (err) {
|
|
210
|
-
|
|
267
|
+
logAuditFailure(ctx, `[Audit] Failed to log update for global "${ctx.global}":`, err);
|
|
211
268
|
}
|
|
212
269
|
}
|
|
213
270
|
async function globalAfterTransition(ctx) {
|
|
214
271
|
try {
|
|
215
272
|
const collections = ctx.collections ?? ctx.app?.collections;
|
|
216
273
|
if (isAuditDisabled("global", ctx.global)) return;
|
|
217
|
-
const
|
|
274
|
+
const actor = resolveAuditActor(ctx);
|
|
218
275
|
const resourceTypeLabel = getResourceTypeLabel("global", ctx.global);
|
|
219
276
|
await collections[AUDIT_LOG_COLLECTION].create({
|
|
220
277
|
action: "transition",
|
|
@@ -222,24 +279,24 @@ async function globalAfterTransition(ctx) {
|
|
|
222
279
|
resource: ctx.global,
|
|
223
280
|
resourceId: null,
|
|
224
281
|
resourceLabel: ctx.global,
|
|
225
|
-
userId:
|
|
226
|
-
userName,
|
|
282
|
+
userId: actor.userId,
|
|
283
|
+
userName: actor.userName,
|
|
227
284
|
locale: ctx.locale || null,
|
|
228
285
|
changes: { stage: {
|
|
229
286
|
from: ctx.fromStage,
|
|
230
287
|
to: ctx.toStage
|
|
231
288
|
} },
|
|
232
|
-
metadata: {
|
|
289
|
+
metadata: buildAuditMetadata(ctx, actor, {
|
|
233
290
|
fromStage: ctx.fromStage,
|
|
234
291
|
toStage: ctx.toStage
|
|
235
|
-
},
|
|
236
|
-
title: generateTitle("transition", "global", resourceTypeLabel, ctx.global, userName)
|
|
292
|
+
}),
|
|
293
|
+
title: generateTitle("transition", "global", resourceTypeLabel, ctx.global, actor.userName)
|
|
237
294
|
}, {
|
|
238
295
|
accessMode: "system",
|
|
239
296
|
db: ctx.db
|
|
240
297
|
});
|
|
241
298
|
} catch (err) {
|
|
242
|
-
|
|
299
|
+
logAuditFailure(ctx, `[Audit] Failed to log transition for global "${ctx.global}":`, err);
|
|
243
300
|
}
|
|
244
301
|
}
|
|
245
302
|
/**
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { AUDIT_LOG_COLLECTION } from "../collections/audit-log.mjs";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { job } from "questpie";
|
|
4
|
-
import { sql as sql$1 } from "drizzle
|
|
4
|
+
import { sql as sql$1 } from "questpie/drizzle";
|
|
5
5
|
|
|
6
6
|
//#region src/server/modules/audit/jobs/audit-cleanup.ts
|
|
7
7
|
/**
|