@questpie/admin 3.5.2 → 3.5.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 +8 -0
- package/dist/client/blocks/block-renderer.d.mts +2 -2
- package/dist/client/builder/index.d.mts +1 -1
- package/dist/client/builder/types/collection-types.d.mts +89 -5
- package/dist/client/builder/types/common.d.mts +5 -0
- package/dist/client/builder/types/field-types.d.mts +41 -1
- package/dist/client/builder/view/view.d.mts +3 -2
- package/dist/client/components/actions/action-dialog.mjs +5 -0
- package/dist/client/components/admin-link.d.mts +2 -2
- package/dist/client/components/fields/boolean-field.mjs +2 -1
- package/dist/client/components/fields/date-field.mjs +2 -1
- package/dist/client/components/fields/datetime-field.mjs +2 -1
- package/dist/client/components/fields/email-field.mjs +2 -1
- package/dist/client/components/fields/field-utils.d.mts +11 -0
- package/dist/client/components/fields/field-utils.mjs +3 -1
- package/dist/client/components/fields/field-wrapper.mjs +3 -3
- package/dist/client/components/fields/number-field.mjs +2 -1
- package/dist/client/components/fields/object-field.mjs +2 -1
- package/dist/client/components/fields/relation/displays/types.mjs +3 -3
- package/dist/client/components/fields/rich-text-editor/bubble-menu.mjs +7 -0
- package/dist/client/components/fields/rich-text-editor/extensions.mjs +19 -2
- package/dist/client/components/fields/rich-text-editor/image-popover.mjs +6 -2
- package/dist/client/components/fields/rich-text-editor/image-upload.mjs +2 -1
- package/dist/client/components/fields/rich-text-editor/index.d.mts +5 -3
- package/dist/client/components/fields/rich-text-editor/index.mjs +38 -76
- package/dist/client/components/fields/rich-text-editor/slash-commands.mjs +30 -7
- package/dist/client/components/fields/rich-text-editor/toolbar.mjs +1 -312
- package/dist/client/components/fields/rich-text-editor/types.d.mts +4 -0
- package/dist/client/components/fields/rich-text-editor/types.mjs +1 -1
- package/dist/client/components/fields/rich-text-editor/utils.mjs +6 -12
- package/dist/client/components/fields/select-field.mjs +2 -1
- package/dist/client/components/fields/text-field.mjs +2 -1
- package/dist/client/components/fields/textarea-field.mjs +2 -1
- package/dist/client/components/fields/time-field.mjs +2 -1
- package/dist/client/components/filter-builder/filter-builder-sheet.mjs +75 -22
- package/dist/client/components/layout/field-layout-renderer.mjs +4 -4
- package/dist/client/components/media/media-grid.mjs +2 -1
- package/dist/client/components/primitives/asset-preview.mjs +4 -2
- package/dist/client/components/primitives/dropzone.d.mts +100 -0
- package/dist/client/components/primitives/field-select-control.mjs +2 -1
- package/dist/client/components/ui/button.d.mts +23 -0
- package/dist/client/components/ui/button.mjs +2 -2
- package/dist/client/components/ui/dropdown-menu.d.mts +49 -0
- package/dist/client/components/ui/dropdown-menu.mjs +7 -19
- package/dist/client/components/ui/popover.mjs +1 -1
- package/dist/client/components/ui/search-input.d.mts +56 -0
- package/dist/client/components/ui/select.mjs +2 -2
- package/dist/client/components/ui/sheet.d.mts +40 -0
- package/dist/client/components/ui/table.d.mts +49 -0
- package/dist/client/components/ui/table.mjs +15 -1
- package/dist/client/components/ui/tooltip.d.mts +21 -0
- package/dist/client/contexts/focus-context.d.mts +2 -2
- package/dist/client/hooks/query-access.d.mts +9 -0
- package/dist/client/hooks/query-access.mjs +20 -0
- package/dist/client/hooks/typed-hooks.d.mts +4 -2
- package/dist/client/hooks/typed-hooks.mjs +30 -29
- package/dist/client/hooks/use-admin-config.mjs +20 -1
- package/dist/client/hooks/use-autosave.mjs +91 -0
- package/dist/client/hooks/use-collection.mjs +65 -23
- package/dist/client/hooks/use-reactive-fields.d.mts +1 -0
- package/dist/client/hooks/use-reactive-fields.mjs +16 -1
- package/dist/client/hooks/use-server-actions.mjs +12 -1
- package/dist/client/hooks/use-upload.d.mts +40 -0
- package/dist/client/hooks/use-upload.mjs +4 -2
- package/dist/client/hooks/use-view-state.mjs +15 -7
- package/dist/client/i18n/hooks.d.mts +20 -0
- package/dist/client/lib/utils.d.mts +6 -0
- package/dist/client/lib/view-filter-utils.mjs +30 -0
- 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/runtime/provider.mjs +22 -3
- package/dist/client/scope/picker.d.mts +2 -2
- package/dist/client/scope/provider.d.mts +2 -2
- package/dist/client/styles/base.css +75 -79
- package/dist/client/utils/asset-url.mjs +27 -0
- package/dist/client/utils/build-field-definitions-from-schema.mjs +1 -0
- package/dist/client/views/auth/accept-invite-form.d.mts +2 -2
- package/dist/client/views/auth/auth-layout.d.mts +3 -3
- package/dist/client/views/auth/forgot-password-form.d.mts +2 -2
- package/dist/client/views/auth/login-form.d.mts +2 -2
- package/dist/client/views/auth/reset-password-form.d.mts +2 -2
- package/dist/client/views/auth/setup-form.d.mts +2 -2
- package/dist/client/views/collection/auto-form-fields.mjs +7 -6
- package/dist/client/views/collection/cells/primitive-cells.mjs +9 -6
- package/dist/client/views/collection/cells/shared/asset-thumbnail.d.mts +7 -0
- package/dist/client/views/collection/cells/shared/asset-thumbnail.mjs +3 -2
- package/dist/client/views/collection/cells/shared/cell-helpers.mjs +3 -2
- package/dist/client/views/collection/cells/upload-cells.mjs +2 -1
- package/dist/client/views/collection/columns/build-columns.mjs +3 -1
- package/dist/client/views/collection/document-view.d.mts +30 -0
- package/dist/client/views/collection/document-view.mjs +377 -0
- package/dist/client/views/collection/field-context.mjs +3 -2
- package/dist/client/views/collection/field-renderer.mjs +13 -5
- package/dist/client/views/collection/form-view.mjs +221 -282
- package/dist/client/views/collection/list-view.mjs +592 -190
- package/dist/client/views/collection/outline.mjs +44 -19
- package/dist/client/views/collection/quick-filter-bar.mjs +45 -0
- package/dist/client/views/collection/table-view.mjs +61 -17
- package/dist/client/views/globals/global-form-view.mjs +12 -9
- package/dist/client/views/layout/admin-layout-provider.mjs +4 -3
- package/dist/client/views/layout/admin-layout.mjs +108 -21
- package/dist/client/views/layout/admin-router.mjs +19 -3
- package/dist/client/views/layout/admin-sidebar.mjs +70 -20
- package/dist/client/views/layout/admin-theme.mjs +5 -4
- package/dist/client/views/layout/admin-view-layout.d.mts +36 -0
- package/dist/client/views/pages/accept-invite-page.d.mts +2 -2
- 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/invite-page.d.mts +2 -2
- package/dist/client/views/pages/login-page.d.mts +2 -2
- package/dist/client/views/pages/reset-password-page.d.mts +2 -2
- package/dist/client/views/pages/setup-page.d.mts +2 -2
- package/dist/client.d.mts +17 -2
- package/dist/client.mjs +17 -2
- package/dist/components/rich-text/rich-text-renderer.d.mts +5 -5
- package/dist/components/rich-text/rich-text-renderer.mjs +5 -2
- package/dist/factories.d.mts +4 -2
- package/dist/factories.mjs +2 -2
- package/dist/index.d.mts +17 -3
- package/dist/index.mjs +17 -2
- package/dist/modules/admin.d.mts +1 -1
- package/dist/server/adapters/index.d.mts +2 -0
- package/dist/server/adapters/nextjs.d.mts +1 -0
- package/dist/server/augmentation/actions.d.mts +9 -3
- package/dist/server/augmentation/dashboard.d.mts +11 -11
- package/dist/server/augmentation/form-layout.d.mts +16 -6
- package/dist/server/augmentation/index.d.mts +7 -0
- package/dist/server/augmentation/sidebar.d.mts +8 -8
- package/dist/server/augmentation/views.d.mts +4 -1
- package/dist/server/auth-helpers.d.mts +1 -0
- package/dist/server/codegen/admin-client-template.mjs +7 -6
- package/dist/server/fields/blocks.mjs +4 -1
- package/dist/server/fields/index.d.mts +1 -1
- package/dist/server/fields/reactive-runtime.mjs +3 -0
- package/dist/server/fields/rich-text.d.mts +16 -17
- package/dist/server/fields/rich-text.mjs +18 -7
- package/dist/server/i18n/messages/cs.mjs +2 -0
- package/dist/server/i18n/messages/de.mjs +2 -0
- package/dist/server/i18n/messages/en.mjs +4 -0
- package/dist/server/i18n/messages/es.mjs +2 -0
- package/dist/server/i18n/messages/fr.mjs +2 -0
- package/dist/server/i18n/messages/pl.mjs +2 -0
- package/dist/server/i18n/messages/pt.mjs +2 -0
- package/dist/server/i18n/messages/sk.mjs +2 -0
- package/dist/server/modules/admin/.generated/module.d.mts +1 -1
- package/dist/server/modules/admin/auth-helpers.mjs +7 -1
- package/dist/server/modules/admin/block/block-builder.d.mts +0 -8
- package/dist/server/modules/admin/block/introspection.d.mts +2 -2
- package/dist/server/modules/admin/block/introspection.mjs +28 -4
- package/dist/server/modules/admin/block/prefetch.d.mts +11 -0
- package/dist/server/modules/admin/block/prefetch.mjs +108 -27
- package/dist/server/modules/admin/client/.generated/module.d.mts +68 -67
- package/dist/server/modules/admin/client/.generated/module.mjs +2 -0
- package/dist/server/modules/admin/client/views/collection-document.d.mts +6 -0
- package/dist/server/modules/admin/client/views/collection-document.mjs +10 -0
- package/dist/server/modules/admin/collections/account.d.mts +53 -52
- package/dist/server/modules/admin/collections/admin-locks.d.mts +57 -56
- package/dist/server/modules/admin/collections/admin-preferences.d.mts +38 -37
- package/dist/server/modules/admin/collections/admin-saved-views.d.mts +50 -49
- package/dist/server/modules/admin/collections/apikey.d.mts +76 -67
- package/dist/server/modules/admin/collections/assets.d.mts +37 -36
- package/dist/server/modules/admin/collections/session.d.mts +42 -41
- package/dist/server/modules/admin/collections/user.d.mts +57 -56
- package/dist/server/modules/admin/collections/verification.d.mts +34 -33
- package/dist/server/modules/admin/dto/admin-config.dto.mjs +34 -4
- package/dist/server/modules/admin/factories.mjs +4 -34
- package/dist/server/modules/admin/index.d.mts +3 -3
- package/dist/server/modules/admin/routes/admin-config.d.mts +4 -2
- package/dist/server/modules/admin/routes/admin-config.mjs +56 -24
- package/dist/server/modules/admin/routes/execute-action.d.mts +9 -9
- package/dist/server/modules/admin/routes/execute-action.mjs +35 -9
- package/dist/server/modules/admin/routes/locales.mjs +1 -1
- package/dist/server/modules/admin/routes/preview.d.mts +11 -11
- package/dist/server/modules/admin/routes/preview.mjs +6 -5
- package/dist/server/modules/admin/routes/reactive.d.mts +9 -9
- package/dist/server/modules/admin/routes/reactive.mjs +2 -2
- package/dist/server/modules/admin/routes/route-helpers.d.mts +11 -7
- package/dist/server/modules/admin/routes/route-helpers.mjs +1 -1
- package/dist/server/modules/admin/routes/setup.d.mts +7 -7
- package/dist/server/modules/admin/routes/translations.d.mts +4 -4
- package/dist/server/modules/admin/routes/widget-data.d.mts +5 -5
- package/dist/server/modules/admin/routes/widget-data.mjs +12 -4
- package/dist/server/modules/admin-preferences/collections/saved-views.d.mts +45 -45
- package/dist/server/modules/audit/.generated/module.d.mts +6 -6
- package/dist/server/modules/audit/collections/audit-log.d.mts +81 -80
- package/dist/server/modules/audit/jobs/audit-cleanup.d.mts +2 -2
- package/dist/server/plugin.mjs +10 -5
- package/dist/server/proxy-factories.d.mts +8 -1
- package/dist/server/proxy-factories.mjs +33 -1
- package/dist/server.d.mts +3 -1
- package/dist/shared/types/index.d.mts +1 -0
- package/dist/shared/types/saved-views.types.d.mts +14 -7
- package/dist/shared.d.mts +3 -2
- package/package.json +5 -4
|
@@ -1,57 +1,58 @@
|
|
|
1
1
|
import * as questpie_shared67 from "questpie/shared";
|
|
2
|
-
import * as
|
|
2
|
+
import * as questpie430 from "questpie";
|
|
3
3
|
import * as questpie_src_server_modules_core_fields_email_js9 from "questpie/src/server/modules/core/fields/email.js";
|
|
4
4
|
import * as questpie_src_server_modules_core_fields_json_js9 from "questpie/src/server/modules/core/fields/json.js";
|
|
5
|
-
import * as
|
|
6
|
-
import * as
|
|
5
|
+
import * as drizzle_orm_pg_core144 from "drizzle-orm/pg-core";
|
|
6
|
+
import * as drizzle_orm80 from "drizzle-orm";
|
|
7
|
+
import * as questpie_src_server_collection_builder_types_js17 from "questpie/src/server/collection/builder/types.js";
|
|
7
8
|
|
|
8
9
|
//#region src/server/modules/admin/collections/verification.d.ts
|
|
9
|
-
declare const _default:
|
|
10
|
-
readonly text: typeof
|
|
11
|
-
readonly textarea: typeof
|
|
10
|
+
declare const _default: questpie430.CollectionBuilder<questpie_shared67.Override<questpie430.EmptyCollectionState<"verification", undefined, {
|
|
11
|
+
readonly text: typeof questpie430.text;
|
|
12
|
+
readonly textarea: typeof questpie430.textarea;
|
|
12
13
|
readonly email: typeof questpie_src_server_modules_core_fields_email_js9.email;
|
|
13
|
-
readonly url: typeof
|
|
14
|
-
readonly number: typeof
|
|
15
|
-
readonly boolean: typeof
|
|
16
|
-
readonly date: typeof
|
|
17
|
-
readonly datetime: typeof
|
|
18
|
-
readonly time: typeof
|
|
19
|
-
readonly select: typeof
|
|
20
|
-
readonly upload: typeof
|
|
21
|
-
readonly relation: typeof
|
|
22
|
-
readonly object: typeof
|
|
14
|
+
readonly url: typeof questpie430.url;
|
|
15
|
+
readonly number: typeof questpie430.number;
|
|
16
|
+
readonly boolean: typeof questpie430.boolean;
|
|
17
|
+
readonly date: typeof questpie430.date;
|
|
18
|
+
readonly datetime: typeof questpie430.datetime;
|
|
19
|
+
readonly time: typeof questpie430.time;
|
|
20
|
+
readonly select: typeof questpie430.select;
|
|
21
|
+
readonly upload: typeof questpie430.upload;
|
|
22
|
+
readonly relation: typeof questpie430.relation;
|
|
23
|
+
readonly object: typeof questpie430.object;
|
|
23
24
|
readonly json: typeof questpie_src_server_modules_core_fields_json_js9.json;
|
|
24
|
-
readonly from: typeof
|
|
25
|
+
readonly from: typeof questpie430.from;
|
|
25
26
|
}>, {
|
|
26
27
|
name: "verification";
|
|
27
28
|
fields: Record<string, any> & {
|
|
28
|
-
readonly identifier:
|
|
29
|
-
readonly value:
|
|
30
|
-
readonly expiresAt:
|
|
29
|
+
readonly identifier: drizzle_orm80.NotNull<drizzle_orm_pg_core144.PgVarcharBuilder<[string, ...string[]]>>;
|
|
30
|
+
readonly value: drizzle_orm80.NotNull<drizzle_orm_pg_core144.PgVarcharBuilder<[string, ...string[]]>>;
|
|
31
|
+
readonly expiresAt: drizzle_orm80.NotNull<drizzle_orm_pg_core144.PgTimestampBuilder>;
|
|
31
32
|
};
|
|
32
33
|
virtuals: undefined;
|
|
33
|
-
relations: Record<string,
|
|
34
|
+
relations: Record<string, questpie430.RelationConfig>;
|
|
34
35
|
indexes: Record<string, any>;
|
|
35
36
|
title: "identifier";
|
|
36
|
-
options:
|
|
37
|
+
options: questpie430.CollectionOptions & {
|
|
37
38
|
timestamps: true;
|
|
38
39
|
};
|
|
39
|
-
hooks:
|
|
40
|
-
access:
|
|
40
|
+
hooks: questpie_src_server_collection_builder_types_js17.CollectionHooksStorage;
|
|
41
|
+
access: questpie_src_server_collection_builder_types_js17.CollectionAccessStorage;
|
|
41
42
|
searchable: undefined;
|
|
42
43
|
fieldDefinitions: {
|
|
43
|
-
readonly identifier:
|
|
44
|
+
readonly identifier: questpie430.FieldWithMethods<Omit<questpie430.TextFieldState, "notNull" | "column"> & {
|
|
44
45
|
notNull: true;
|
|
45
|
-
column:
|
|
46
|
-
},
|
|
47
|
-
readonly value:
|
|
46
|
+
column: drizzle_orm80.NotNull<drizzle_orm_pg_core144.PgVarcharBuilder<[string, ...string[]]>>;
|
|
47
|
+
}, questpie430.TextFieldMethods>;
|
|
48
|
+
readonly value: questpie430.FieldWithMethods<Omit<questpie430.TextFieldState, "notNull" | "column"> & {
|
|
48
49
|
notNull: true;
|
|
49
|
-
column:
|
|
50
|
-
},
|
|
51
|
-
readonly expiresAt:
|
|
50
|
+
column: drizzle_orm80.NotNull<drizzle_orm_pg_core144.PgVarcharBuilder<[string, ...string[]]>>;
|
|
51
|
+
}, questpie430.TextFieldMethods>;
|
|
52
|
+
readonly expiresAt: questpie430.FieldWithMethods<Omit<questpie430.DatetimeFieldState, "notNull" | "column"> & {
|
|
52
53
|
notNull: true;
|
|
53
|
-
column:
|
|
54
|
-
},
|
|
54
|
+
column: drizzle_orm80.NotNull<drizzle_orm_pg_core144.PgTimestampBuilder>;
|
|
55
|
+
}, questpie430.DatetimeFieldMethods>;
|
|
55
56
|
};
|
|
56
57
|
upload: undefined;
|
|
57
58
|
output: {};
|
|
@@ -12,9 +12,18 @@ import { z } from "zod";
|
|
|
12
12
|
* They mirror the server augmentation types but are pure data
|
|
13
13
|
* (no functions, no callbacks, no non-serializable fields).
|
|
14
14
|
*/
|
|
15
|
+
function containsFunction(value, seen = /* @__PURE__ */ new WeakSet()) {
|
|
16
|
+
if (typeof value === "function") return true;
|
|
17
|
+
if (!value || typeof value !== "object") return false;
|
|
18
|
+
if (seen.has(value)) return false;
|
|
19
|
+
seen.add(value);
|
|
20
|
+
if (Array.isArray(value)) return value.some((item) => containsFunction(item, seen));
|
|
21
|
+
return Object.values(value).some((item) => containsFunction(item, seen));
|
|
22
|
+
}
|
|
23
|
+
const serializableUnknownSchema = z.unknown().refine((value) => !containsFunction(value), { message: "Functions cannot be serialized in admin config DTOs" });
|
|
15
24
|
const componentReferenceSchema = z.object({
|
|
16
25
|
type: z.string(),
|
|
17
|
-
props: z.record(z.string(),
|
|
26
|
+
props: z.record(z.string(), serializableUnknownSchema).optional()
|
|
18
27
|
});
|
|
19
28
|
const sidebarItemSchema = z.discriminatedUnion("type", [
|
|
20
29
|
z.object({
|
|
@@ -99,8 +108,8 @@ const dashboardConfigSchema = z.object({
|
|
|
99
108
|
rowHeight: z.union([z.number(), z.string()]).optional(),
|
|
100
109
|
gap: z.number().optional(),
|
|
101
110
|
realtime: z.boolean().optional(),
|
|
102
|
-
actions: z.array(
|
|
103
|
-
items: z.array(z.record(z.string(),
|
|
111
|
+
actions: z.array(serializableUnknownSchema).optional(),
|
|
112
|
+
items: z.array(z.record(z.string(), serializableUnknownSchema)).optional()
|
|
104
113
|
});
|
|
105
114
|
const brandLogoSchema = z.union([
|
|
106
115
|
z.string(),
|
|
@@ -120,6 +129,27 @@ const brandingConfigSchema = z.object({
|
|
|
120
129
|
tagline: i18nTextSchema.optional(),
|
|
121
130
|
favicon: z.string().optional()
|
|
122
131
|
});
|
|
132
|
+
const blockAdminSchema = z.object({
|
|
133
|
+
label: serializableUnknownSchema.optional(),
|
|
134
|
+
description: serializableUnknownSchema.optional(),
|
|
135
|
+
icon: componentReferenceSchema.optional(),
|
|
136
|
+
category: z.object({
|
|
137
|
+
label: serializableUnknownSchema,
|
|
138
|
+
icon: componentReferenceSchema.optional(),
|
|
139
|
+
order: z.number().optional()
|
|
140
|
+
}).optional(),
|
|
141
|
+
order: z.number().optional(),
|
|
142
|
+
hidden: z.boolean().optional()
|
|
143
|
+
});
|
|
144
|
+
const blockSchema = z.object({
|
|
145
|
+
name: z.string(),
|
|
146
|
+
admin: blockAdminSchema.optional(),
|
|
147
|
+
allowChildren: z.boolean().optional(),
|
|
148
|
+
maxChildren: z.number().optional(),
|
|
149
|
+
hasPrefetch: z.boolean(),
|
|
150
|
+
fields: z.record(z.string(), serializableUnknownSchema),
|
|
151
|
+
form: z.object({ fields: z.array(serializableUnknownSchema) }).optional()
|
|
152
|
+
});
|
|
123
153
|
/**
|
|
124
154
|
* Zod schema for the complete AdminConfigDTO.
|
|
125
155
|
* Can be used as the outputSchema for the getAdminConfig route.
|
|
@@ -129,7 +159,7 @@ const adminConfigDTOSchema = z.object({
|
|
|
129
159
|
sidebar: sidebarConfigSchema.optional(),
|
|
130
160
|
shell: adminShellConfigSchema.optional(),
|
|
131
161
|
branding: brandingConfigSchema.optional(),
|
|
132
|
-
blocks: z.record(z.string(),
|
|
162
|
+
blocks: z.record(z.string(), blockSchema).optional(),
|
|
133
163
|
collections: z.record(z.string(), collectionMetaSchema).optional(),
|
|
134
164
|
globals: z.record(z.string(), collectionMetaSchema).optional(),
|
|
135
165
|
uploads: uploadsConfigSchema.optional()
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createActionCallbackProxy } from "../../proxy-factories.mjs";
|
|
1
|
+
import { createActionCallbackProxy, createActionFieldBuilderProxy } from "../../proxy-factories.mjs";
|
|
2
2
|
import { CollectionBuilder } from "questpie";
|
|
3
3
|
|
|
4
4
|
//#region src/server/modules/admin/factories.ts
|
|
@@ -26,37 +26,6 @@ const _componentProxy = new Proxy({}, { get: (_, prop) => (...args) => ({
|
|
|
26
26
|
props: typeof args[0] === "string" ? { name: args[0] } : args[0] ?? {}
|
|
27
27
|
}) });
|
|
28
28
|
const _fieldRefProxy = new Proxy({}, { get: (_, prop) => String(prop) });
|
|
29
|
-
/**
|
|
30
|
-
* Field builder proxy for actions context.
|
|
31
|
-
* Supports `f.text().required().label({...})` chaining.
|
|
32
|
-
* Each method call returns a new proxy with accumulated properties.
|
|
33
|
-
*/
|
|
34
|
-
function _createFieldBuilderProxy() {
|
|
35
|
-
return new Proxy({}, { get: (_, prop) => {
|
|
36
|
-
if (typeof prop !== "string") return void 0;
|
|
37
|
-
return (...args) => {
|
|
38
|
-
const def = { type: prop };
|
|
39
|
-
if (Array.isArray(args[0])) def.options = args[0];
|
|
40
|
-
else if (args[0] && typeof args[0] === "object") Object.assign(def, args[0]);
|
|
41
|
-
else if (args[0] !== void 0) def.value = args[0];
|
|
42
|
-
return _chainable(def);
|
|
43
|
-
};
|
|
44
|
-
} });
|
|
45
|
-
}
|
|
46
|
-
function _chainable(def) {
|
|
47
|
-
return new Proxy(def, { get: (target, prop) => {
|
|
48
|
-
if (typeof prop !== "string") return Reflect.get(target, prop);
|
|
49
|
-
if (prop in target) return target[prop];
|
|
50
|
-
if (prop === "set") return (key, value) => _chainable({
|
|
51
|
-
...target,
|
|
52
|
-
[key]: value
|
|
53
|
-
});
|
|
54
|
-
return (...args) => _chainable({
|
|
55
|
-
...target,
|
|
56
|
-
[prop]: args.length === 0 ? true : args[0]
|
|
57
|
-
});
|
|
58
|
-
} });
|
|
59
|
-
}
|
|
60
29
|
const _actionBuilderProxy = createActionCallbackProxy();
|
|
61
30
|
const _simpleActionProxy = createActionCallbackProxy();
|
|
62
31
|
const _collExt = {
|
|
@@ -81,7 +50,8 @@ const _collExt = {
|
|
|
81
50
|
collectionTable: "collection-table"
|
|
82
51
|
}),
|
|
83
52
|
f: _fieldRefProxy,
|
|
84
|
-
a: _simpleActionProxy
|
|
53
|
+
a: _simpleActionProxy,
|
|
54
|
+
c: _componentProxy
|
|
85
55
|
}) : configOrFn
|
|
86
56
|
};
|
|
87
57
|
}
|
|
@@ -112,7 +82,7 @@ const _collExt = {
|
|
|
112
82
|
if (typeof configOrFn === "function") return configOrFn({
|
|
113
83
|
a: _actionBuilderProxy,
|
|
114
84
|
c: _componentProxy,
|
|
115
|
-
f:
|
|
85
|
+
f: createActionFieldBuilderProxy()
|
|
116
86
|
});
|
|
117
87
|
return configOrFn;
|
|
118
88
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
+
import { FilterOperator, FilterRule, SortConfig, ViewConfiguration } from "../../../shared/types/saved-views.types.mjs";
|
|
1
2
|
import { ExecuteActionRequest, ExecuteActionResponse, actionFunctions, executeAction, executeActionFn, getActionsConfig, getActionsConfigFn } from "./routes/execute-action.mjs";
|
|
2
3
|
import { PreviewTokenPayload, createPreviewFunctions, createPreviewTokenVerifier, verifyPreviewTokenDirect } from "./routes/preview.mjs";
|
|
3
4
|
import { batchReactive, fieldOptions, reactiveFunctions } from "./routes/reactive.mjs";
|
|
4
5
|
import { createFirstAdmin, isSetupRequired, setupFunctions } from "./routes/setup.mjs";
|
|
5
6
|
import { fetchWidgetData, widgetDataFunctions } from "./routes/widget-data.mjs";
|
|
6
7
|
import { AdminCollections, AdminComponents, AdminRoutes, AdminViews } from "./.generated/module.mjs";
|
|
7
|
-
import { FilterOperator, FilterRule, SortConfig, ViewConfiguration } from "../../../shared/types/saved-views.types.mjs";
|
|
8
8
|
import { savedViewsCollection } from "../admin-preferences/collections/saved-views.mjs";
|
|
9
9
|
import "./index.mjs";
|
|
10
10
|
import * as zod0 from "zod";
|
|
@@ -927,8 +927,8 @@ declare const adminModule: {
|
|
|
927
927
|
$Infer: {
|
|
928
928
|
body: {
|
|
929
929
|
permissions: {
|
|
930
|
-
readonly user?: ("
|
|
931
|
-
readonly session?: ("
|
|
930
|
+
readonly user?: ("create" | "update" | "list" | "set-role" | "ban" | "impersonate" | "impersonate-admins" | "delete" | "set-password" | "get")[] | undefined;
|
|
931
|
+
readonly session?: ("list" | "delete" | "revoke")[] | undefined;
|
|
932
932
|
};
|
|
933
933
|
} & {
|
|
934
934
|
userId?: string | undefined;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import "./route-helpers.mjs";
|
|
2
|
+
import * as questpie456 from "questpie";
|
|
2
3
|
|
|
3
4
|
//#region src/server/modules/admin/routes/admin-config.d.ts
|
|
4
5
|
|
|
@@ -7,7 +8,8 @@ import * as questpie454 from "questpie";
|
|
|
7
8
|
* Registered via module routes and exposed through the fetch handler.
|
|
8
9
|
*/
|
|
9
10
|
declare const adminConfigFunctions: {
|
|
10
|
-
readonly getAdminConfig:
|
|
11
|
+
readonly getAdminConfig: questpie456.JsonRouteDefinition<Record<string, never> | undefined, any, questpie456.JsonRouteParams>;
|
|
12
|
+
readonly getPublicAdminConfig: questpie456.JsonRouteDefinition<Record<string, never> | undefined, any, questpie456.JsonRouteParams>;
|
|
11
13
|
};
|
|
12
14
|
//#endregion
|
|
13
15
|
export { adminConfigFunctions };
|
|
@@ -3,7 +3,7 @@ import { introspectBlocks } from "../block/introspection.mjs";
|
|
|
3
3
|
import { adminConfigDTOSchema } from "../dto/admin-config.dto.mjs";
|
|
4
4
|
import { getAccessContext, getAdminConfig as getAdminConfig$1, getApp, getAppState, getCollectionState, getGlobalState } from "./route-helpers.mjs";
|
|
5
5
|
import { z } from "zod";
|
|
6
|
-
import { executeAccessRule, route } from "questpie";
|
|
6
|
+
import { executeAccessRule, route, shouldAutoAppendUnlistedSidebar } from "questpie";
|
|
7
7
|
|
|
8
8
|
//#region src/server/modules/admin/routes/admin-config.ts
|
|
9
9
|
/**
|
|
@@ -200,16 +200,28 @@ function buildAutoSidebar(collectionsMeta, globalsMeta) {
|
|
|
200
200
|
* Removes items referencing inaccessible collections/globals.
|
|
201
201
|
* Removes empty sections after filtering.
|
|
202
202
|
*/
|
|
203
|
-
function filterSidebarConfig(config, accessibleCollections, accessibleGlobals) {
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
203
|
+
function filterSidebarConfig(config, accessibleCollections, accessibleGlobals, hiddenCollections, hiddenGlobals) {
|
|
204
|
+
function filterSection(s) {
|
|
205
|
+
return {
|
|
206
|
+
...s,
|
|
207
|
+
items: (s.items ?? []).filter((item) => {
|
|
208
|
+
const rec = item;
|
|
209
|
+
if (item.type === "collection") {
|
|
210
|
+
const collection$1 = rec.collection;
|
|
211
|
+
if (hiddenCollections.has(collection$1)) return false;
|
|
212
|
+
return accessibleCollections.has(collection$1);
|
|
213
|
+
}
|
|
214
|
+
if (item.type === "global") {
|
|
215
|
+
const global = rec.global;
|
|
216
|
+
if (hiddenGlobals.has(global)) return false;
|
|
217
|
+
return accessibleGlobals.has(global);
|
|
218
|
+
}
|
|
219
|
+
return true;
|
|
220
|
+
}),
|
|
221
|
+
sections: (s.sections ?? []).map(filterSection).filter((sub) => (sub.items?.length ?? 0) > 0 || (sub.sections?.length ?? 0) > 0)
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
return { sections: config.sections.map(filterSection).filter((s) => (s.items?.length ?? 0) > 0 || (s.sections?.length ?? 0) > 0) };
|
|
213
225
|
}
|
|
214
226
|
/**
|
|
215
227
|
* Collect all collection and global names referenced in a sidebar config.
|
|
@@ -502,6 +514,11 @@ async function processDashboardItems(items, accessibleCollections, accessCtx) {
|
|
|
502
514
|
}
|
|
503
515
|
const getAdminConfigSchema = z.object({}).optional();
|
|
504
516
|
const getAdminConfigOutputSchema = adminConfigDTOSchema;
|
|
517
|
+
function buildPublicAdminConfig(adminCfg) {
|
|
518
|
+
const response = {};
|
|
519
|
+
if (adminCfg.branding) response.branding = adminCfg.branding;
|
|
520
|
+
return stripUndefinedDeep(response);
|
|
521
|
+
}
|
|
505
522
|
/**
|
|
506
523
|
* Get admin configuration including dashboard, sidebar, blocks,
|
|
507
524
|
* and collection/global metadata.
|
|
@@ -523,7 +540,7 @@ const getAdminConfigOutputSchema = adminConfigDTOSchema;
|
|
|
523
540
|
* const config = await client.routes.getAdminConfig({});
|
|
524
541
|
* ```
|
|
525
542
|
*/
|
|
526
|
-
const getAdminConfig = route().post().schema(getAdminConfigSchema).outputSchema(getAdminConfigOutputSchema).handler(async (ctx) => {
|
|
543
|
+
const getAdminConfig = route().post().access((ctx) => ctx.session?.user?.role === "admin").schema(getAdminConfigSchema).outputSchema(getAdminConfigOutputSchema).handler(async (ctx) => {
|
|
527
544
|
const app = getApp(ctx);
|
|
528
545
|
const appState = getAppState(app);
|
|
529
546
|
const adminCfg = getAdminConfig$1(app);
|
|
@@ -557,27 +574,42 @@ const getAdminConfig = route().post().schema(getAdminConfigSchema).outputSchema(
|
|
|
557
574
|
let sidebarConfig;
|
|
558
575
|
if (isLegacySidebarConfig(adminCfg.sidebar)) sidebarConfig = adminCfg.sidebar;
|
|
559
576
|
else sidebarConfig = mergeSidebarContributions(normalizeSidebarContributions(adminCfg.sidebar));
|
|
560
|
-
const
|
|
561
|
-
const
|
|
562
|
-
const
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
const
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
577
|
+
const hiddenCollections = new Set(Object.entries(allCollectionsMeta).filter(([, meta]) => meta.hidden).map(([name]) => name));
|
|
578
|
+
const hiddenGlobals = new Set(Object.entries(allGlobalsMeta).filter(([, meta]) => meta.hidden).map(([name]) => name));
|
|
579
|
+
const filteredSidebar = filterSidebarConfig(sidebarConfig, accessibleCollections, accessibleGlobals, hiddenCollections, hiddenGlobals);
|
|
580
|
+
if (shouldAutoAppendUnlistedSidebar(adminCfg, sidebarConfig)) {
|
|
581
|
+
const referenced = collectSidebarReferences(sidebarConfig);
|
|
582
|
+
const unlistedSidebar = buildAutoSidebar(Object.fromEntries(Object.entries(filteredCollectionsMeta).filter(([name, meta]) => !referenced.collections.has(name) && !meta.hidden)), Object.fromEntries(Object.entries(filteredGlobalsMeta).filter(([name, meta]) => !referenced.globals.has(name) && !meta.hidden)));
|
|
583
|
+
const mergedSections = [...filteredSidebar.sections];
|
|
584
|
+
for (const unlistedSection of unlistedSidebar.sections) {
|
|
585
|
+
const existing = mergedSections.find((s) => s.id === unlistedSection.id);
|
|
586
|
+
if (existing) existing.items = [...existing.items ?? [], ...unlistedSection.items ?? []];
|
|
587
|
+
else mergedSections.push(unlistedSection);
|
|
588
|
+
}
|
|
589
|
+
response.sidebar = { sections: mergedSections };
|
|
590
|
+
} else response.sidebar = filteredSidebar;
|
|
570
591
|
} else response.sidebar = buildAutoSidebar(filteredCollectionsMeta, filteredGlobalsMeta);
|
|
571
|
-
if (appState.blocks && Object.keys(appState.blocks).length > 0) response.blocks = introspectBlocks(appState.blocks);
|
|
592
|
+
if (accessCtx.session && appState.blocks && Object.keys(appState.blocks).length > 0) response.blocks = introspectBlocks(appState.blocks);
|
|
572
593
|
response.collections = filteredCollectionsMeta;
|
|
573
594
|
response.globals = filteredGlobalsMeta;
|
|
574
595
|
return stripUndefinedDeep(response);
|
|
575
596
|
});
|
|
576
597
|
/**
|
|
598
|
+
* Get public admin bootstrap configuration for unauthenticated auth pages.
|
|
599
|
+
*
|
|
600
|
+
* This intentionally exposes only branding. Full admin config, sidebar,
|
|
601
|
+
* dashboard, blocks, upload collections, and resource metadata stay behind
|
|
602
|
+
* getAdminConfig's admin-session guard.
|
|
603
|
+
*/
|
|
604
|
+
const getPublicAdminConfig = route().post().access(true).schema(getAdminConfigSchema).outputSchema(getAdminConfigOutputSchema).handler(async (ctx) => buildPublicAdminConfig(getAdminConfig$1(getApp(ctx))));
|
|
605
|
+
/**
|
|
577
606
|
* Admin config route handlers.
|
|
578
607
|
* Registered via module routes and exposed through the fetch handler.
|
|
579
608
|
*/
|
|
580
|
-
const adminConfigFunctions = {
|
|
609
|
+
const adminConfigFunctions = {
|
|
610
|
+
getAdminConfig,
|
|
611
|
+
getPublicAdminConfig
|
|
612
|
+
};
|
|
581
613
|
|
|
582
614
|
//#endregion
|
|
583
615
|
export { adminConfigFunctions };
|
|
@@ -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
|
|
4
|
+
import * as questpie64 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:
|
|
59
|
+
declare const executeActionFn: questpie64.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,
|
|
66
|
+
}, any, questpie64.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:
|
|
71
|
+
declare const getActionsConfigFn: questpie64.JsonRouteDefinition<{
|
|
72
72
|
collection: string;
|
|
73
|
-
}, any,
|
|
73
|
+
}, any, questpie64.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:
|
|
79
|
+
executeAction: questpie64.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,
|
|
87
|
-
getActionsConfig:
|
|
86
|
+
}, any, questpie64.JsonRouteParams>;
|
|
87
|
+
getActionsConfig: questpie64.JsonRouteDefinition<{
|
|
88
88
|
collection: string;
|
|
89
|
-
}, any,
|
|
89
|
+
}, any, questpie64.JsonRouteParams>;
|
|
90
90
|
};
|
|
91
91
|
//#endregion
|
|
92
92
|
export { ExecuteActionRequest, ExecuteActionResponse, actionFunctions, executeAction, executeActionFn, getActionsConfig, getActionsConfigFn };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { getApp, getCollection, getCollectionCrud, getCollectionCruds, getGlobalCruds, getSession } from "./route-helpers.mjs";
|
|
2
2
|
import { translateAdminMessage } from "./i18n-helpers.mjs";
|
|
3
3
|
import { z } from "zod";
|
|
4
|
-
import { route } from "questpie";
|
|
4
|
+
import { extractAppServices, route, runWithContext } from "questpie";
|
|
5
5
|
|
|
6
6
|
//#region src/server/modules/admin/routes/execute-action.ts
|
|
7
7
|
/**
|
|
@@ -137,12 +137,18 @@ async function executeAction(app, request, session) {
|
|
|
137
137
|
success: false,
|
|
138
138
|
result: {
|
|
139
139
|
type: "error",
|
|
140
|
-
toast: { message: validationError }
|
|
140
|
+
toast: { message: validationError.message },
|
|
141
|
+
errors: validationError.errors
|
|
141
142
|
}
|
|
142
143
|
};
|
|
143
144
|
}
|
|
144
145
|
try {
|
|
145
146
|
const appRec = app;
|
|
147
|
+
const services = extractAppServices(app, {
|
|
148
|
+
db: appRec.db,
|
|
149
|
+
session,
|
|
150
|
+
locale
|
|
151
|
+
});
|
|
146
152
|
const context = {
|
|
147
153
|
data: data || {},
|
|
148
154
|
itemId,
|
|
@@ -153,9 +159,16 @@ async function executeAction(app, request, session) {
|
|
|
153
159
|
db: appRec.db,
|
|
154
160
|
session,
|
|
155
161
|
locale,
|
|
156
|
-
t
|
|
162
|
+
t,
|
|
163
|
+
workflows: services.workflows
|
|
157
164
|
};
|
|
158
|
-
const result = await
|
|
165
|
+
const result = await runWithContext({
|
|
166
|
+
app,
|
|
167
|
+
db: appRec.db,
|
|
168
|
+
session,
|
|
169
|
+
locale,
|
|
170
|
+
accessMode: "user"
|
|
171
|
+
}, () => customAction.handler(context));
|
|
159
172
|
return {
|
|
160
173
|
success: result.type === "success" || result.type === "redirect",
|
|
161
174
|
result
|
|
@@ -182,7 +195,8 @@ async function executeBuiltinAction(app, params) {
|
|
|
182
195
|
const crudContext = {
|
|
183
196
|
db: appRec.db,
|
|
184
197
|
session: params.session,
|
|
185
|
-
locale: params.locale
|
|
198
|
+
locale: params.locale,
|
|
199
|
+
accessMode: "user"
|
|
186
200
|
};
|
|
187
201
|
try {
|
|
188
202
|
switch (actionId) {
|
|
@@ -420,8 +434,20 @@ function isFieldRequired(field$1) {
|
|
|
420
434
|
* Returns error message if validation fails, null if valid.
|
|
421
435
|
*/
|
|
422
436
|
function validateActionFormData(fields, data, t) {
|
|
423
|
-
|
|
424
|
-
|
|
437
|
+
const errors = {};
|
|
438
|
+
for (const [fieldName, fieldConfig] of Object.entries(fields)) {
|
|
439
|
+
if (isFieldDefinition(fieldConfig)) {
|
|
440
|
+
const result = fieldConfig.toZodSchema().safeParse(data[fieldName]);
|
|
441
|
+
if (!result.success) errors[fieldName] = result.error.issues[0]?.message || t("action.fieldRequired", { field: fieldName });
|
|
442
|
+
continue;
|
|
443
|
+
}
|
|
444
|
+
if (isFieldRequired(fieldConfig) && (data[fieldName] === void 0 || data[fieldName] === null)) errors[fieldName] = t("action.fieldRequired", { field: fieldName });
|
|
445
|
+
}
|
|
446
|
+
const firstError = Object.values(errors)[0];
|
|
447
|
+
return firstError ? {
|
|
448
|
+
message: firstError,
|
|
449
|
+
errors
|
|
450
|
+
} : null;
|
|
425
451
|
}
|
|
426
452
|
const executeActionRequestSchema = z.object({
|
|
427
453
|
collection: z.string(),
|
|
@@ -454,7 +480,7 @@ const getActionsConfigResponseSchema = z.object({
|
|
|
454
480
|
* });
|
|
455
481
|
* ```
|
|
456
482
|
*/
|
|
457
|
-
const executeActionFn = route().post().schema(executeActionRequestSchema).outputSchema(executeActionResponseSchema).handler(async (ctx) => {
|
|
483
|
+
const executeActionFn = route().post().access((ctx) => ctx.session?.user?.role === "admin").schema(executeActionRequestSchema).outputSchema(executeActionResponseSchema).handler(async (ctx) => {
|
|
458
484
|
const app = getApp(ctx);
|
|
459
485
|
const session = getSession(ctx);
|
|
460
486
|
return executeAction(app, ctx.input, session);
|
|
@@ -463,7 +489,7 @@ const executeActionFn = route().post().schema(executeActionRequestSchema).output
|
|
|
463
489
|
* Get actions configuration for a collection.
|
|
464
490
|
* Returns action definitions without handlers for client rendering.
|
|
465
491
|
*/
|
|
466
|
-
const getActionsConfigFn = route().post().schema(getActionsConfigRequestSchema).outputSchema(getActionsConfigResponseSchema).handler((ctx) => {
|
|
492
|
+
const getActionsConfigFn = route().post().access((ctx) => ctx.session?.user?.role === "admin").schema(getActionsConfigRequestSchema).outputSchema(getActionsConfigResponseSchema).handler((ctx) => {
|
|
467
493
|
return getActionsConfig(getApp(ctx), ctx.input.collection);
|
|
468
494
|
});
|
|
469
495
|
/**
|
|
@@ -39,7 +39,7 @@ const getContentLocalesOutputSchema = z.object({
|
|
|
39
39
|
* // }
|
|
40
40
|
* ```
|
|
41
41
|
*/
|
|
42
|
-
const getContentLocales = route().post().schema(getContentLocalesSchema).outputSchema(getContentLocalesOutputSchema).handler(async (ctx) => {
|
|
42
|
+
const getContentLocales = route().post().access(true).schema(getContentLocalesSchema).outputSchema(getContentLocalesOutputSchema).handler(async (ctx) => {
|
|
43
43
|
const localeConfig = getApp(ctx).config.locale;
|
|
44
44
|
if (!localeConfig) return {
|
|
45
45
|
locales: [{
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as questpie72 from "questpie";
|
|
2
2
|
|
|
3
3
|
//#region src/server/modules/admin/routes/preview.d.ts
|
|
4
4
|
|
|
@@ -25,13 +25,13 @@ interface PreviewTokenPayload {
|
|
|
25
25
|
* @returns Object with preview functions
|
|
26
26
|
*/
|
|
27
27
|
declare function createPreviewFunctions(secret?: PreviewSecretSource): {
|
|
28
|
-
mintPreviewToken:
|
|
28
|
+
mintPreviewToken: questpie72.JsonRouteDefinition<{
|
|
29
29
|
path: string;
|
|
30
30
|
ttlMs?: number | undefined;
|
|
31
|
-
}, any,
|
|
32
|
-
verifyPreviewToken:
|
|
31
|
+
}, any, questpie72.JsonRouteParams>;
|
|
32
|
+
verifyPreviewToken: questpie72.JsonRouteDefinition<{
|
|
33
33
|
token: string;
|
|
34
|
-
}, any,
|
|
34
|
+
}, any, questpie72.JsonRouteParams>;
|
|
35
35
|
};
|
|
36
36
|
/**
|
|
37
37
|
* Verify a preview token without RPC.
|
|
@@ -68,18 +68,18 @@ declare function createPreviewTokenVerifier(secret: string): (token: string) =>
|
|
|
68
68
|
* Used by the `adminModule` to register preview RPC functions.
|
|
69
69
|
*/
|
|
70
70
|
declare const previewFunctions: {
|
|
71
|
-
getPreviewUrl:
|
|
71
|
+
getPreviewUrl: questpie72.JsonRouteDefinition<{
|
|
72
72
|
collection: string;
|
|
73
73
|
record: Record<string, unknown>;
|
|
74
74
|
locale?: string | undefined;
|
|
75
|
-
}, any,
|
|
76
|
-
mintPreviewToken:
|
|
75
|
+
}, any, questpie72.JsonRouteParams>;
|
|
76
|
+
mintPreviewToken: questpie72.JsonRouteDefinition<{
|
|
77
77
|
path: string;
|
|
78
78
|
ttlMs?: number | undefined;
|
|
79
|
-
}, any,
|
|
80
|
-
verifyPreviewToken:
|
|
79
|
+
}, any, questpie72.JsonRouteParams>;
|
|
80
|
+
verifyPreviewToken: questpie72.JsonRouteDefinition<{
|
|
81
81
|
token: string;
|
|
82
|
-
}, any,
|
|
82
|
+
}, any, questpie72.JsonRouteParams>;
|
|
83
83
|
};
|
|
84
84
|
//#endregion
|
|
85
85
|
export { PreviewTokenPayload, createPreviewFunctions, createPreviewTokenVerifier, previewFunctions, verifyPreviewTokenDirect };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { hasAdminRole } from "../auth-helpers.mjs";
|
|
2
|
+
import { getApp, getCollectionState, getLocale } from "./route-helpers.mjs";
|
|
2
3
|
import { translateAdminMessage } from "./i18n-helpers.mjs";
|
|
3
4
|
import { z } from "zod";
|
|
4
5
|
import { ApiError, route } from "questpie";
|
|
@@ -103,11 +104,11 @@ const DEFAULT_TTL_MS = 3600 * 1e3;
|
|
|
103
104
|
*/
|
|
104
105
|
function createPreviewFunctions(secret = defaultPreviewSecret) {
|
|
105
106
|
return {
|
|
106
|
-
mintPreviewToken: route().post().schema(mintPreviewTokenSchema).outputSchema(mintPreviewTokenOutputSchema).handler(async (ctx) => {
|
|
107
|
+
mintPreviewToken: route().post().access((ctx) => ctx.session?.user?.role === "admin").schema(mintPreviewTokenSchema).outputSchema(mintPreviewTokenOutputSchema).handler(async (ctx) => {
|
|
107
108
|
const { input } = ctx;
|
|
108
109
|
const locale = getLocale(ctx);
|
|
109
110
|
const t = (key, params) => translateAdminMessage(locale, key, params);
|
|
110
|
-
if (!
|
|
111
|
+
if (!hasAdminRole(ctx)) throw ApiError.unauthorized(t("preview.adminSessionRequired"));
|
|
111
112
|
const { path, ttlMs = DEFAULT_TTL_MS } = input;
|
|
112
113
|
const expiresAt = Date.now() + ttlMs;
|
|
113
114
|
const payload = {
|
|
@@ -210,11 +211,11 @@ const getPreviewUrlOutputSchema = z.object({
|
|
|
210
211
|
* // Returns: "/about?preview=true"
|
|
211
212
|
* ```
|
|
212
213
|
*/
|
|
213
|
-
const getPreviewUrl = route().post().schema(getPreviewUrlSchema).outputSchema(getPreviewUrlOutputSchema).handler(async (ctx) => {
|
|
214
|
+
const getPreviewUrl = route().post().access((ctx) => ctx.session?.user?.role === "admin").schema(getPreviewUrlSchema).outputSchema(getPreviewUrlOutputSchema).handler(async (ctx) => {
|
|
214
215
|
const { input } = ctx;
|
|
215
216
|
const messageLocale = getLocale(ctx) ?? input.locale;
|
|
216
217
|
const t = (key, params) => translateAdminMessage(messageLocale, key, params);
|
|
217
|
-
if (!
|
|
218
|
+
if (!hasAdminRole(ctx)) return {
|
|
218
219
|
url: null,
|
|
219
220
|
error: t("preview.adminSessionRequired")
|
|
220
221
|
};
|