@hywax/cms 2.1.0 → 3.0.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 (44) hide show
  1. package/.nuxt/cms/{input-uplora-image.ts → form-uplora-image.ts} +2 -9
  2. package/.nuxt/cms/http-statuses.ts +59 -0
  3. package/.nuxt/cms/index.ts +4 -4
  4. package/.nuxt/cms.css +3 -3
  5. package/dist/module.d.mts +5 -2
  6. package/dist/module.json +1 -1
  7. package/dist/module.mjs +75 -44
  8. package/dist/runtime/components/DatePicker.vue +13 -1
  9. package/dist/runtime/components/FormPanel.vue +2 -0
  10. package/dist/runtime/components/{InputSeo.d.vue.ts → FormSeo.d.vue.ts} +10 -8
  11. package/dist/runtime/components/{InputSeo.vue → FormSeo.vue} +18 -8
  12. package/dist/runtime/components/{InputSeo.vue.d.ts → FormSeo.vue.d.ts} +10 -8
  13. package/dist/runtime/components/{InputSlug.vue.d.ts → FormSlug.d.vue.ts} +8 -7
  14. package/dist/runtime/components/{InputSlug.vue → FormSlug.vue} +15 -6
  15. package/dist/runtime/components/{InputSlug.d.vue.ts → FormSlug.vue.d.ts} +8 -7
  16. package/dist/runtime/components/FormUploraImage.d.vue.ts +43 -0
  17. package/dist/runtime/components/FormUploraImage.vue +172 -0
  18. package/dist/runtime/components/FormUploraImage.vue.d.ts +43 -0
  19. package/dist/runtime/components/TablePreviewLink.vue +1 -2
  20. package/dist/runtime/editor/uplora-image/EditorUploraImageNode.vue +2 -2
  21. package/dist/runtime/server/api/uplora/[id].delete.js +1 -1
  22. package/dist/runtime/server/api/uplora/index.post.js +2 -4
  23. package/dist/runtime/server/errors/HttpError.d.ts +8 -0
  24. package/dist/runtime/server/errors/HttpError.js +7 -0
  25. package/dist/runtime/server/errors/index.d.ts +1 -1
  26. package/dist/runtime/server/errors/index.js +1 -1
  27. package/dist/runtime/server/utils/http.d.ts +43 -0
  28. package/dist/runtime/server/utils/http.js +86 -0
  29. package/dist/runtime/server/utils/validation.js +6 -7
  30. package/dist/runtime/types/index.d.ts +3 -3
  31. package/dist/runtime/types/index.js +3 -3
  32. package/package.json +5 -4
  33. package/.nuxt/cms/http-codes.ts +0 -8
  34. package/dist/runtime/components/InputUploraImage.d.vue.ts +0 -40
  35. package/dist/runtime/components/InputUploraImage.vue +0 -181
  36. package/dist/runtime/components/InputUploraImage.vue.d.ts +0 -40
  37. package/dist/runtime/server/errors/InternalHttpError.d.ts +0 -8
  38. package/dist/runtime/server/errors/InternalHttpError.js +0 -7
  39. package/dist/runtime/server/utils/errors.d.ts +0 -8
  40. package/dist/runtime/server/utils/errors.js +0 -57
  41. package/dist/runtime/server/utils/httpHandler.d.ts +0 -10
  42. package/dist/runtime/server/utils/httpHandler.js +0 -15
  43. /package/.nuxt/cms/{input-seo.ts → form-seo.ts} +0 -0
  44. /package/.nuxt/cms/{input-slug.ts → form-slug.ts} +0 -0
@@ -0,0 +1,43 @@
1
+ import type { AppConfig } from '@nuxt/schema';
2
+ import type { ComponentConfig } from '../types';
3
+ import theme from '#build/cms/form-uplora-image';
4
+ type FormUploraImage = ComponentConfig<typeof theme, AppConfig, 'formUploraImage'>;
5
+ export interface FormUploraImageModelValue {
6
+ image?: string;
7
+ alt?: string;
8
+ color?: string;
9
+ lqip?: string;
10
+ }
11
+ export interface FormUploraImageProps {
12
+ showExtensions?: boolean;
13
+ id?: string;
14
+ name?: string;
15
+ label?: string;
16
+ disabled?: boolean;
17
+ as?: any;
18
+ class?: any;
19
+ nested?: boolean;
20
+ ui?: FormUploraImage['slots'];
21
+ }
22
+ export interface FormUploraImageEmits {
23
+ upload: [FormUploraImageModelValue];
24
+ delete: [];
25
+ }
26
+ declare const _default: typeof __VLS_export;
27
+ export default _default;
28
+ declare const __VLS_export: import("vue").DefineComponent<FormUploraImageProps & {
29
+ modelValue?: FormUploraImageModelValue;
30
+ }, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
31
+ delete: () => any;
32
+ "update:modelValue": (value: FormUploraImageModelValue) => any;
33
+ upload: (args_0: FormUploraImageModelValue) => any;
34
+ }, string, import("vue").PublicProps, Readonly<FormUploraImageProps & {
35
+ modelValue?: FormUploraImageModelValue;
36
+ }> & Readonly<{
37
+ onDelete?: (() => any) | undefined;
38
+ "onUpdate:modelValue"?: ((value: FormUploraImageModelValue) => any) | undefined;
39
+ onUpload?: ((args_0: FormUploraImageModelValue) => any) | undefined;
40
+ }>, {
41
+ showExtensions: boolean;
42
+ nested: boolean;
43
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
@@ -0,0 +1,172 @@
1
+ <template>
2
+ <UForm
3
+ :name="name"
4
+ :schema="schema"
5
+ :class="ui.root({ class: [props.ui?.root, props.class] })"
6
+ :validate-on="['change']"
7
+ :nested="nested"
8
+ >
9
+ <UFormField name="image" :label="label">
10
+ <div :class="ui.base({ class: [props.ui?.base] })">
11
+ <template v-if="modelValue.image">
12
+ <UPopover :content="{ align: 'center', side: 'top', sideOffset: 8 }" :ui="{ content: 'p-1' }">
13
+ <CUploraImage
14
+ :image="modelValue.image"
15
+ :alt="modelValue.alt"
16
+ :color="modelValue.color"
17
+ :lqip="modelValue.lqip"
18
+ />
19
+
20
+ <template #content>
21
+ <div class="flex items-center gap-0.5">
22
+ <UButton
23
+ color="neutral"
24
+ size="sm"
25
+ variant="ghost"
26
+ :icon="appConfig.ui.icons.refresh"
27
+ @click="resetState()"
28
+ />
29
+
30
+ <ButtonDeleteConfirm
31
+ color="error"
32
+ size="sm"
33
+ variant="ghost"
34
+ label=""
35
+ :icon="appConfig.ui.icons.trash"
36
+ @confirm="deleteExecute(modelValue.image)"
37
+ />
38
+ </div>
39
+ </template>
40
+ </UPopover>
41
+ </template>
42
+ <div v-else :id="id" :class="ui.uploader({ class: [props.ui?.uploader] })">
43
+ <template v-if="uploadStatus === 'pending'">
44
+ <UIcon :name="appConfig.ui.icons.loading" :class="ui.uploaderPendingIcon({ class: [props.ui?.uploaderPendingIcon] })" />
45
+ </template>
46
+ <template v-else-if="uploadStatus === 'idle'">
47
+ <button
48
+ type="button"
49
+ :class="ui.uploaderIdleButton({ class: [props.ui?.uploaderIdleButton] })"
50
+ :disabled="disabled"
51
+ v-bind="ariaAttrs"
52
+ @click="open"
53
+ >
54
+ <UAvatar :icon="appConfig.ui.icons.image" size="lg" />
55
+
56
+ <p :class="ui.uploaderIdleText({ class: [props.ui?.uploaderIdleText] })">
57
+ Загрузить изображение
58
+ </p>
59
+ <p :class="ui.uploaderIdleExtensions({ class: [props.ui?.uploaderIdleExtensions] })">
60
+ {{ extensions }}
61
+ </p>
62
+ </button>
63
+ </template>
64
+ <template v-else-if="uploadStatus === 'error'">
65
+ <p :class="ui.uploaderErrorText({ class: [props.ui?.uploaderErrorText] })">
66
+ Произошла ошибка при загрузке изображения
67
+ </p>
68
+ <div :class="ui.uploaderErrorActions({ class: [props.ui?.uploaderErrorActions] })">
69
+ <UButton
70
+ label="Отменить"
71
+ variant="ghost"
72
+ color="neutral"
73
+ @click="resetUpload"
74
+ />
75
+ <UButton
76
+ label="Повторить"
77
+ variant="soft"
78
+ color="neutral"
79
+ @click="uploadExecute"
80
+ />
81
+ </div>
82
+ </template>
83
+ </div>
84
+ </div>
85
+ </UFormField>
86
+ <UFormField name="alt">
87
+ <UInput
88
+ v-model="modelValue.alt"
89
+ placeholder="Введите описание..."
90
+ variant="none"
91
+ size="xs"
92
+ :ui="{ base: 'text-center' }"
93
+ />
94
+ </UFormField>
95
+ </UForm>
96
+ </template>
97
+
98
+ <script>
99
+ import theme from "#build/cms/form-uplora-image";
100
+ import { useAppConfig, useFormField, useUploraDelete, useUploraUpload } from "#imports";
101
+ import { imagesExtensions } from "@uplora/formats";
102
+ import { computed, useId } from "vue";
103
+ import { z } from "zod";
104
+ import { tv } from "../tv";
105
+ import ButtonDeleteConfirm from "./ButtonDeleteConfirm.vue";
106
+ </script>
107
+
108
+ <script setup>
109
+ const props = defineProps({
110
+ showExtensions: { type: Boolean, required: false, default: true },
111
+ id: { type: String, required: false },
112
+ name: { type: String, required: false },
113
+ label: { type: String, required: false },
114
+ disabled: { type: Boolean, required: false },
115
+ as: { type: null, required: false },
116
+ class: { type: null, required: false },
117
+ nested: { type: Boolean, required: false, default: true },
118
+ ui: { type: null, required: false }
119
+ });
120
+ const emit = defineEmits(["upload", "delete"]);
121
+ const modelValue = defineModel({ type: Object, ...{
122
+ default: () => ({
123
+ image: void 0,
124
+ alt: void 0,
125
+ lqip: void 0,
126
+ color: void 0
127
+ })
128
+ } });
129
+ const appConfig = useAppConfig();
130
+ const schema = z.object({
131
+ image: z.string().min(1),
132
+ alt: z.string().min(1),
133
+ lqip: z.string().min(1).optional(),
134
+ color: z.string().min(1).optional()
135
+ });
136
+ const extensions = computed(() => imagesExtensions.filter((extension) => extension !== "jpeg").join(", "));
137
+ const { id: _id, disabled, emitFormChange, emitFormInput, ariaAttrs } = useFormField(props);
138
+ const id = _id.value ?? useId();
139
+ const { open, execute: uploadExecute, status: uploadStatus, reset: resetUpload, onUploaded } = useUploraUpload({
140
+ accept: "image/*"
141
+ });
142
+ const { execute: deleteExecute, onDeleted } = useUploraDelete();
143
+ function resetState() {
144
+ modelValue.value = {
145
+ image: void 0,
146
+ alt: void 0,
147
+ lqip: void 0,
148
+ color: void 0
149
+ };
150
+ emitFormChange();
151
+ emitFormInput();
152
+ }
153
+ onUploaded((file) => {
154
+ modelValue.value = {
155
+ ...modelValue.value,
156
+ image: file.id,
157
+ lqip: file.lqip,
158
+ color: file.color
159
+ };
160
+ emit("upload", modelValue.value);
161
+ emitFormChange();
162
+ emitFormInput();
163
+ });
164
+ onDeleted(() => {
165
+ resetUpload();
166
+ resetState();
167
+ emit("delete");
168
+ });
169
+ const ui = computed(() => tv({ extend: tv(theme), ...appConfig.cms?.formUploraImage || {} })({
170
+ disabled: disabled.value
171
+ }));
172
+ </script>
@@ -0,0 +1,43 @@
1
+ import type { AppConfig } from '@nuxt/schema';
2
+ import type { ComponentConfig } from '../types';
3
+ import theme from '#build/cms/form-uplora-image';
4
+ type FormUploraImage = ComponentConfig<typeof theme, AppConfig, 'formUploraImage'>;
5
+ export interface FormUploraImageModelValue {
6
+ image?: string;
7
+ alt?: string;
8
+ color?: string;
9
+ lqip?: string;
10
+ }
11
+ export interface FormUploraImageProps {
12
+ showExtensions?: boolean;
13
+ id?: string;
14
+ name?: string;
15
+ label?: string;
16
+ disabled?: boolean;
17
+ as?: any;
18
+ class?: any;
19
+ nested?: boolean;
20
+ ui?: FormUploraImage['slots'];
21
+ }
22
+ export interface FormUploraImageEmits {
23
+ upload: [FormUploraImageModelValue];
24
+ delete: [];
25
+ }
26
+ declare const _default: typeof __VLS_export;
27
+ export default _default;
28
+ declare const __VLS_export: import("vue").DefineComponent<FormUploraImageProps & {
29
+ modelValue?: FormUploraImageModelValue;
30
+ }, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
31
+ delete: () => any;
32
+ "update:modelValue": (value: FormUploraImageModelValue) => any;
33
+ upload: (args_0: FormUploraImageModelValue) => any;
34
+ }, string, import("vue").PublicProps, Readonly<FormUploraImageProps & {
35
+ modelValue?: FormUploraImageModelValue;
36
+ }> & Readonly<{
37
+ onDelete?: (() => any) | undefined;
38
+ "onUpdate:modelValue"?: ((value: FormUploraImageModelValue) => any) | undefined;
39
+ onUpload?: ((args_0: FormUploraImageModelValue) => any) | undefined;
40
+ }>, {
41
+ showExtensions: boolean;
42
+ nested: boolean;
43
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
@@ -1,8 +1,7 @@
1
1
  <template>
2
2
  <div class="relative flex items-center gap-2">
3
- <div class="overflow-hidden rounded-lg">
3
+ <div v-if="image" class="overflow-hidden rounded-lg">
4
4
  <UploraImage
5
- v-if="image"
6
5
  v-bind="image"
7
6
  :sizes="[{ width: 32, height: 32, descriptor: '1x' }]"
8
7
  :ui="{ picture: 'aspect-square' }"
@@ -1,13 +1,13 @@
1
1
  <template>
2
2
  <NodeViewWrapper>
3
- <InputUploraImage v-model="attrs" />
3
+ <FormUploraImage v-model="attrs" :nested="false" />
4
4
  </NodeViewWrapper>
5
5
  </template>
6
6
 
7
7
  <script setup>
8
8
  import { NodeViewWrapper } from "@tiptap/vue-3";
9
9
  import { computed } from "vue";
10
- import InputUploraImage from "../../components/InputUploraImage.vue";
10
+ import FormUploraImage from "../../components/FormUploraImage.vue";
11
11
  const props = defineProps({
12
12
  decorations: { type: Array, required: true },
13
13
  selected: { type: Boolean, required: true },
@@ -1,7 +1,7 @@
1
1
  import { useRuntimeConfig } from "#imports";
2
2
  import { getValidatedRouterParams } from "h3";
3
3
  import { z } from "zod";
4
- import { defineHttpHandler } from "../../utils/httpHandler.js";
4
+ import { defineHttpHandler } from "../../utils/http.js";
5
5
  export const filesDeleteRouteParamsSchema = z.object({
6
6
  id: z.string().min(24).max(24)
7
7
  });
@@ -1,10 +1,8 @@
1
1
  import { Buffer } from "node:buffer";
2
- import { HTTP_CODE_BAD_REQUEST } from "#cms/http-codes";
3
2
  import { useRuntimeConfig } from "#imports";
4
3
  import { isImageMimeType } from "@uplora/formats";
5
4
  import { z } from "zod";
6
- import { InternalHttpError } from "../../errors/InternalHttpError.js";
7
- import { defineHttpHandler } from "../../utils/httpHandler.js";
5
+ import { createHttpError, defineHttpHandler } from "../../utils/http.js";
8
6
  import { readValidatedMultipartFormData } from "../../utils/validation.js";
9
7
  const filesCreatePayloadSchema = z.object({
10
8
  file: z.object({
@@ -18,7 +16,7 @@ export default defineHttpHandler(async (event) => {
18
16
  const { file } = await readValidatedMultipartFormData(event, filesCreatePayloadSchema.parse);
19
17
  const { uplora } = useRuntimeConfig();
20
18
  if (!file) {
21
- throw new InternalHttpError(HTTP_CODE_BAD_REQUEST);
19
+ throw createHttpError("badRequest");
22
20
  }
23
21
  const formData = new FormData();
24
22
  formData.append("file", new Blob([file.data], { type: file.type }), file.filename);
@@ -0,0 +1,8 @@
1
+ import type { HttpStatusKey } from '#cms/http-statuses';
2
+ import type { H3Error } from 'h3';
3
+ export type HttpErrorOptions = Partial<Pick<H3Error, 'cause' | 'fatal' | 'data'>>;
4
+ export declare class HttpError extends Error {
5
+ readonly httpStatusKey: HttpStatusKey;
6
+ readonly options?: HttpErrorOptions | undefined;
7
+ constructor(httpStatusKey: HttpStatusKey, options?: HttpErrorOptions | undefined);
8
+ }
@@ -0,0 +1,7 @@
1
+ export class HttpError extends Error {
2
+ constructor(httpStatusKey, options) {
3
+ super("Http Error");
4
+ this.httpStatusKey = httpStatusKey;
5
+ this.options = options;
6
+ }
7
+ }
@@ -1,2 +1,2 @@
1
- export * from './InternalHttpError';
1
+ export * from './HttpError';
2
2
  export * from './TimeoutError';
@@ -1,2 +1,2 @@
1
- export * from "./InternalHttpError.js";
1
+ export * from "./HttpError.js";
2
2
  export * from "./TimeoutError.js";
@@ -0,0 +1,43 @@
1
+ import type { HttpStatusKey } from '#cms/http-statuses';
2
+ import type { EventHandler, EventHandlerRequest, EventHandlerResponse, H3Event } from 'h3';
3
+ import type { CachedEventHandlerOptions } from 'nitropack/types';
4
+ import type { HttpErrorOptions } from '../errors';
5
+ import { H3Error } from 'h3';
6
+ import { HttpError } from '../errors';
7
+ type HttpStatusesCodesMap = Record<string, HttpStatusKey>;
8
+ interface DefineHttpHandlerOptions<Response extends EventHandlerResponse> {
9
+ httpCodesMap?: HttpStatusesCodesMap;
10
+ cache?: CachedEventHandlerOptions<Response>;
11
+ access?: 'admin' | 'employee' | 'user';
12
+ }
13
+ /**
14
+ * Разрешает и форматирует ошибку для HTTP ответов сервера.
15
+ * Логирует ошибку и возвращает отформатированную H3Error с кодом статуса и сообщением.
16
+ *
17
+ * @param event - Объект события.
18
+ * @param error - Ошибка для разрешения.
19
+ * @param httpCodesMap - Опциональное пользовательское сопоставление типов ошибок с ключами статусов.
20
+ * @returns Отформатированная H3Error для ответа.
21
+ */
22
+ export declare function errorServerResolver(event: H3Event, error: unknown, httpCodesMap?: HttpStatusesCodesMap): Promise<H3Error<unknown>>;
23
+ /**
24
+ * Создает новый экземпляр HttpError с заданным ключом статуса и опциями.
25
+ *
26
+ * @param errorStatusKey - Ключ, представляющий HTTP статус.
27
+ * @param options - Дополнительные опции ошибки (cause, fatal).
28
+ * @returns Созданный экземпляр HttpError.
29
+ */
30
+ export declare function createHttpError(errorStatusKey: HttpStatusKey, options?: HttpErrorOptions): HttpError;
31
+ /**
32
+ * Определяет HTTP обработчик, который оборачивает предоставленный обработчик и обрабатывает ошибки.
33
+ * Перехватывает и форматирует ошибки для HTTP ответов, включая ошибки валидации и базы данных.
34
+ *
35
+ * @typeParam Request - Тип объекта запроса.
36
+ * @typeParam Response - Тип объекта ответа.
37
+ * @param handler - Основная функция обработчика.
38
+ * @param options - Опциональное пользовательское сопоставление типов ошибок с ключами статусов.
39
+ * @param options.httpCodesMap - Опциональное пользовательское сопоставление типов ошибок с ключами статусов.
40
+ * @returns Обернутый обработчик событий с обработкой ошибок.
41
+ */
42
+ export declare function defineHttpHandler<Request extends EventHandlerRequest, Response extends EventHandlerResponse>(handler: EventHandler<Request, Response | Promise<Response>>, options?: DefineHttpHandlerOptions<Response>): EventHandler<Request, Promise<Response>>;
43
+ export {};
@@ -0,0 +1,86 @@
1
+ import { httpStatuses } from "#cms/http-statuses";
2
+ import defu from "defu";
3
+ import { DrizzleQueryError } from "drizzle-orm/errors";
4
+ import { createError, eventHandler, H3Error } from "h3";
5
+ import { cachedEventHandler } from "nitropack/runtime";
6
+ import { camelCase } from "scule";
7
+ import { z } from "zod";
8
+ import { logger } from "../../utils/logger.js";
9
+ import { HttpError } from "../errors/index.js";
10
+ const defaultHttpCodes = {
11
+ default: "internalServerError",
12
+ zod: "badRequest",
13
+ db: "internalServerError"
14
+ };
15
+ const excludedLoggedStatuses = ["unauthorized"];
16
+ function extractHttpStatusKey(error, httpCodesMap = {}) {
17
+ const codesMap = defu(httpCodesMap, defaultHttpCodes);
18
+ if (error instanceof HttpError) {
19
+ return error.httpStatusKey;
20
+ } else if (error instanceof z.ZodError) {
21
+ return codesMap.zod;
22
+ } else if (error instanceof DrizzleQueryError) {
23
+ const maybeStatus = `db_${error.cause?.code}`;
24
+ return codesMap[maybeStatus] ?? codesMap.db;
25
+ } else if (error instanceof H3Error && error.cause instanceof HttpError) {
26
+ return error.cause.httpStatusKey;
27
+ } else if (error instanceof Error) {
28
+ const maybeStatus = camelCase(error.message);
29
+ return codesMap[maybeStatus] ?? codesMap.default;
30
+ }
31
+ return codesMap.default;
32
+ }
33
+ function enrichHttpError(error) {
34
+ if (error instanceof z.ZodError) {
35
+ return { data: error.issues };
36
+ }
37
+ if (error instanceof HttpError) {
38
+ return { data: error.options?.data };
39
+ }
40
+ return {};
41
+ }
42
+ export async function errorServerResolver(event, error, httpCodesMap = {}) {
43
+ const httpStatusKey = extractHttpStatusKey(error, httpCodesMap);
44
+ const httpStatusCode = httpStatuses[httpStatusKey].code;
45
+ const httpStatusMessage = httpStatuses[httpStatusKey].message;
46
+ if (!excludedLoggedStatuses.includes(httpStatusKey)) {
47
+ logger.error.raw({
48
+ key: httpStatusKey,
49
+ code: httpStatusCode,
50
+ path: event.path,
51
+ method: event.method,
52
+ ...error instanceof HttpError ? { data: JSON.stringify(error.options?.data) } : { error: JSON.stringify(error) }
53
+ });
54
+ }
55
+ return createError(defu(
56
+ {
57
+ statusCode: httpStatusCode,
58
+ message: httpStatusMessage
59
+ },
60
+ enrichHttpError(error)
61
+ ));
62
+ }
63
+ export function createHttpError(errorStatusKey, options) {
64
+ return new HttpError(errorStatusKey, options);
65
+ }
66
+ export function defineHttpHandler(handler, options) {
67
+ async function handlerWrapper(event) {
68
+ try {
69
+ return await handler(event);
70
+ } catch (e) {
71
+ let error = e;
72
+ if (error.cause?.data instanceof Error) {
73
+ error = error.cause?.data;
74
+ }
75
+ throw await errorServerResolver(event, error, options?.httpCodesMap);
76
+ }
77
+ }
78
+ if (options?.cache) {
79
+ return cachedEventHandler(handlerWrapper, {
80
+ group: "http",
81
+ swr: false,
82
+ ...options.cache
83
+ });
84
+ }
85
+ return eventHandler(handlerWrapper);
86
+ }
@@ -1,9 +1,8 @@
1
- import { HTTP_CODE_BAD_REQUEST } from "#cms/http-codes";
2
1
  import { readMultipartFormData } from "h3";
3
- import { InternalHttpError } from "../errors/InternalHttpError.js";
2
+ import { createHttpError } from "./http.js";
4
3
  export function getValidatedSort(query, availableColumns) {
5
4
  if (!query.sortColumn || !availableColumns.includes(query.sortColumn)) {
6
- throw new InternalHttpError(HTTP_CODE_BAD_REQUEST);
5
+ throw createHttpError("badRequest");
7
6
  }
8
7
  const sortType = query.sortType === "asc" ? "asc" : "desc";
9
8
  const sortColumn = query.sortColumn;
@@ -15,7 +14,7 @@ export function getValidatedSort(query, availableColumns) {
15
14
  export function getValidatedPagination(query) {
16
15
  const perPage = Number(query.perPage);
17
16
  if (!Number.isInteger(perPage) || perPage < 1 || perPage > 100) {
18
- throw new InternalHttpError(HTTP_CODE_BAD_REQUEST);
17
+ throw createHttpError("badRequest");
19
18
  }
20
19
  const page = Number(query.page) || 1;
21
20
  const pageOffset = (page - 1) * perPage;
@@ -28,7 +27,7 @@ export function getValidatedPagination(query) {
28
27
  export async function readValidatedMultipartFormData(event, validate) {
29
28
  const formData = await readMultipartFormData(event);
30
29
  if (!formData) {
31
- throw new InternalHttpError(HTTP_CODE_BAD_REQUEST);
30
+ throw createHttpError("badRequest");
32
31
  }
33
32
  try {
34
33
  const transformedFormData = {};
@@ -42,13 +41,13 @@ export async function readValidatedMultipartFormData(event, validate) {
42
41
  }
43
42
  const res = await validate(transformedFormData);
44
43
  if (res === false) {
45
- throw new InternalHttpError(HTTP_CODE_BAD_REQUEST);
44
+ throw createHttpError("badRequest");
46
45
  }
47
46
  if (res === true) {
48
47
  return formData;
49
48
  }
50
49
  return res ?? formData;
51
50
  } catch (error) {
52
- throw new InternalHttpError(HTTP_CODE_BAD_REQUEST, { cause: error });
51
+ throw createHttpError("badRequest", { cause: error });
53
52
  }
54
53
  }
@@ -7,9 +7,9 @@ export * from '../components/EditorLinkPopover.vue';
7
7
  export * from '../components/FormPanel.vue';
8
8
  export * from '../components/FormPanelAsideSection.vue';
9
9
  export * from '../components/FormPanelSection.vue';
10
- export * from '../components/InputSeo.vue';
11
- export * from '../components/InputSlug.vue';
12
- export * from '../components/InputUploraImage.vue';
10
+ export * from '../components/FormSeo.vue';
11
+ export * from '../components/FormSlug.vue';
12
+ export * from '../components/FormUploraImage.vue';
13
13
  export * from '../components/Layout.vue';
14
14
  export * from '../components/ModalConfirm.vue';
15
15
  export * from '../components/prose/UploraImage.vue';
@@ -7,9 +7,9 @@ export * from "../components/EditorLinkPopover.vue";
7
7
  export * from "../components/FormPanel.vue";
8
8
  export * from "../components/FormPanelAsideSection.vue";
9
9
  export * from "../components/FormPanelSection.vue";
10
- export * from "../components/InputSeo.vue";
11
- export * from "../components/InputSlug.vue";
12
- export * from "../components/InputUploraImage.vue";
10
+ export * from "../components/FormSeo.vue";
11
+ export * from "../components/FormSlug.vue";
12
+ export * from "../components/FormUploraImage.vue";
13
13
  export * from "../components/Layout.vue";
14
14
  export * from "../components/ModalConfirm.vue";
15
15
  export * from "../components/prose/UploraImage.vue";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@hywax/cms",
3
3
  "type": "module",
4
- "version": "2.1.0",
4
+ "version": "3.0.0",
5
5
  "description": "Hywax CMS. ⚠️ This package is intended for internal use only.",
6
6
  "imports": {
7
7
  "#build/cms/*": "./.nuxt/cms/*.ts",
@@ -48,7 +48,8 @@
48
48
  ],
49
49
  "peerDependencies": {
50
50
  "@unovis/ts": "^1.6.2",
51
- "@unovis/vue": "^1.6.2"
51
+ "@unovis/vue": "^1.6.2",
52
+ "drizzle-orm": "^0.45.1"
52
53
  },
53
54
  "peerDependenciesMeta": {
54
55
  "@unovis/ts": {
@@ -88,7 +89,7 @@
88
89
  "@nuxt/devtools": "^3.1.1",
89
90
  "@nuxt/module-builder": "^1.0.2",
90
91
  "@nuxt/schema": "^4.2.2",
91
- "@nuxt/test-utils": "^3.22.0",
92
+ "@nuxt/test-utils": "^3.23.0",
92
93
  "@types/sortablejs": "^1.15.9",
93
94
  "@vue/test-utils": "^2.4.6",
94
95
  "changelogen-monorepo": "^0.5.0",
@@ -99,7 +100,7 @@
99
100
  "nuxt": "^4.2.2",
100
101
  "typescript": "^5.9.3",
101
102
  "vitest": "^3.2.4",
102
- "vue-tsc": "^3.2.1"
103
+ "vue-tsc": "^3.2.2"
103
104
  },
104
105
  "resolutions": {
105
106
  "@hywax/cms": "workspace:*"
@@ -1,8 +0,0 @@
1
- export const HTTP_CODE_BAD_REQUEST = '400: Неверный запрос'
2
- export const HTTP_CODE_UNAUTHORIZED = '401: Не авторизован'
3
- export const HTTP_CODE_FORBIDDEN = '403: Доступ запрещен'
4
- export const HTTP_CODE_NOT_FOUND = '404: Не найдено'
5
- export const HTTP_CODE_REQUEST_TIMEOUT = '408: Время ожидания запроса истекло'
6
- export const HTTP_CODE_INTERNAL_SERVER_ERROR = '500: Внутренняя ошибка сервера'
7
- export const HTTP_CODE_BAD_GATEWAY = '502: Ошибка шлюза'
8
- export const HTTP_CODE_SERVICE_UNAVAILABLE = '503: Сервис недоступен'
@@ -1,40 +0,0 @@
1
- import type { AppConfig } from '@nuxt/schema';
2
- import type { ComponentConfig } from '../types';
3
- import theme from '#build/cms/input-uplora-image';
4
- type InputUploraImage = ComponentConfig<typeof theme, AppConfig, 'inputUploraImage'>;
5
- export interface InputUploraImageProps {
6
- showExtensions?: boolean;
7
- id?: string;
8
- name?: string;
9
- disabled?: boolean;
10
- as?: any;
11
- class?: any;
12
- ui?: InputUploraImage['slots'];
13
- }
14
- export interface InputUploraImageEmits {
15
- upload: [InputUploraImageModelValue];
16
- delete: [];
17
- }
18
- export interface InputUploraImageModelValue {
19
- image?: string;
20
- alt?: string;
21
- color?: string;
22
- lqip?: string;
23
- }
24
- declare const _default: typeof __VLS_export;
25
- export default _default;
26
- declare const __VLS_export: import("vue").DefineComponent<InputUploraImageProps & {
27
- modelValue?: InputUploraImageModelValue;
28
- }, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
29
- delete: () => any;
30
- "update:modelValue": (value: InputUploraImageModelValue) => any;
31
- upload: (args_0: InputUploraImageModelValue) => any;
32
- }, string, import("vue").PublicProps, Readonly<InputUploraImageProps & {
33
- modelValue?: InputUploraImageModelValue;
34
- }> & Readonly<{
35
- onDelete?: (() => any) | undefined;
36
- "onUpdate:modelValue"?: ((value: InputUploraImageModelValue) => any) | undefined;
37
- onUpload?: ((args_0: InputUploraImageModelValue) => any) | undefined;
38
- }>, {
39
- showExtensions: boolean;
40
- }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;