@deallony/shared 1.2.51 → 1.2.53
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/dist/cjs/constants/ad/AdMedia.d.ts +8 -0
- package/dist/cjs/constants/ad/AdMedia.js +17 -0
- package/dist/cjs/constants/ad/index.d.ts +1 -0
- package/dist/cjs/constants/ad/index.js +1 -0
- package/dist/cjs/schema/ad/save-ad.schema.d.ts +1 -0
- package/dist/cjs/schema/ad/save-ad.schema.js +38 -2
- package/dist/cjs/utils/adMedia.d.ts +5 -0
- package/dist/cjs/utils/adMedia.js +27 -0
- package/dist/cjs/utils/index.d.ts +1 -0
- package/dist/cjs/utils/index.js +1 -0
- package/dist/esm/constants/ad/AdMedia.js +14 -0
- package/dist/esm/constants/ad/index.js +1 -0
- package/dist/esm/schema/ad/save-ad.schema.js +37 -1
- package/dist/esm/utils/adMedia.js +22 -0
- package/dist/esm/utils/index.js +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare const MAX_AD_IMAGES = 30;
|
|
2
|
+
export declare const MAX_AD_VIDEOS = 1;
|
|
3
|
+
export declare const MAX_AD_VIDEO_BYTES: number;
|
|
4
|
+
export declare enum AdMediaIssueCode {
|
|
5
|
+
TOO_MANY_IMAGES = "too_many_images",
|
|
6
|
+
TOO_MANY_VIDEOS = "too_many_videos",
|
|
7
|
+
VIDEO_TOO_LARGE = "video_too_large"
|
|
8
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AdMediaIssueCode = exports.MAX_AD_VIDEO_BYTES = exports.MAX_AD_VIDEOS = exports.MAX_AD_IMAGES = void 0;
|
|
4
|
+
// Media is optional on every ad. These are the only limits, shared by every
|
|
5
|
+
// client and the API so they can never drift apart.
|
|
6
|
+
exports.MAX_AD_IMAGES = 30;
|
|
7
|
+
exports.MAX_AD_VIDEOS = 1;
|
|
8
|
+
// Raw upload size; the assets service compresses videos after upload.
|
|
9
|
+
exports.MAX_AD_VIDEO_BYTES = 200 * 1024 * 1024;
|
|
10
|
+
// Stable codes carried in `params.code` of adMediaSchema issues, so clients can
|
|
11
|
+
// show localized messages without re-implementing the rules.
|
|
12
|
+
var AdMediaIssueCode;
|
|
13
|
+
(function (AdMediaIssueCode) {
|
|
14
|
+
AdMediaIssueCode["TOO_MANY_IMAGES"] = "too_many_images";
|
|
15
|
+
AdMediaIssueCode["TOO_MANY_VIDEOS"] = "too_many_videos";
|
|
16
|
+
AdMediaIssueCode["VIDEO_TOO_LARGE"] = "video_too_large";
|
|
17
|
+
})(AdMediaIssueCode || (exports.AdMediaIssueCode = AdMediaIssueCode = {}));
|
|
@@ -5,6 +5,7 @@ export declare const subjectTypeSchema: z.ZodEnum<{
|
|
|
5
5
|
motors: "motors";
|
|
6
6
|
used_products: "used_products";
|
|
7
7
|
}>;
|
|
8
|
+
export declare const adMediaSchema: z.ZodNullable<z.ZodOptional<z.ZodArray<z.ZodAny>>>;
|
|
8
9
|
export declare const createAdSchema: z.ZodObject<{
|
|
9
10
|
motor: z.ZodNullable<z.ZodOptional<z.ZodObject<{
|
|
10
11
|
ad_id: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.saveAdSchema = exports.updateAdSchema = exports.createAdSchema = exports.subjectTypeSchema = void 0;
|
|
3
|
+
exports.saveAdSchema = exports.updateAdSchema = exports.createAdSchema = exports.adMediaSchema = exports.subjectTypeSchema = void 0;
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
|
+
const AdMedia_1 = require("../../constants/ad/AdMedia");
|
|
6
|
+
const adMedia_1 = require("../../utils/adMedia");
|
|
5
7
|
exports.subjectTypeSchema = zod_1.z.enum([
|
|
6
8
|
"properties",
|
|
7
9
|
"services",
|
|
@@ -130,6 +132,40 @@ const createServiceSchema = baseServiceSchema;
|
|
|
130
132
|
const updateServiceSchema = baseServiceSchema.extend({
|
|
131
133
|
id: zod_1.z.coerce.number().int().positive().optional(),
|
|
132
134
|
});
|
|
135
|
+
// Media is optional: an ad may have no media, only one video, or only images.
|
|
136
|
+
exports.adMediaSchema = zod_1.z
|
|
137
|
+
.array(zod_1.z.any())
|
|
138
|
+
.superRefine((media, ctx) => {
|
|
139
|
+
const { images, videos } = (0, adMedia_1.countAdMedia)(media);
|
|
140
|
+
if (images > AdMedia_1.MAX_AD_IMAGES) {
|
|
141
|
+
ctx.addIssue({
|
|
142
|
+
code: "custom",
|
|
143
|
+
message: `An ad can contain up to ${AdMedia_1.MAX_AD_IMAGES} images`,
|
|
144
|
+
params: { code: AdMedia_1.AdMediaIssueCode.TOO_MANY_IMAGES, max: AdMedia_1.MAX_AD_IMAGES },
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
if (videos > AdMedia_1.MAX_AD_VIDEOS) {
|
|
148
|
+
ctx.addIssue({
|
|
149
|
+
code: "custom",
|
|
150
|
+
message: `An ad can contain up to ${AdMedia_1.MAX_AD_VIDEOS} video`,
|
|
151
|
+
params: { code: AdMedia_1.AdMediaIssueCode.TOO_MANY_VIDEOS, max: AdMedia_1.MAX_AD_VIDEOS },
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
media.forEach((item, index) => {
|
|
155
|
+
if ((0, adMedia_1.isAdVideoMedia)(item) &&
|
|
156
|
+
typeof (item === null || item === void 0 ? void 0 : item.size) === "number" &&
|
|
157
|
+
item.size > AdMedia_1.MAX_AD_VIDEO_BYTES) {
|
|
158
|
+
ctx.addIssue({
|
|
159
|
+
code: "custom",
|
|
160
|
+
path: [index],
|
|
161
|
+
message: `An ad video cannot exceed ${AdMedia_1.MAX_AD_VIDEO_BYTES / (1024 * 1024)} MB`,
|
|
162
|
+
params: { code: AdMedia_1.AdMediaIssueCode.VIDEO_TOO_LARGE, max: AdMedia_1.MAX_AD_VIDEO_BYTES },
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
})
|
|
167
|
+
.optional()
|
|
168
|
+
.nullable();
|
|
133
169
|
const baseAdCommon = zod_1.z.object({
|
|
134
170
|
title: zod_1.z.string().trim().optional(),
|
|
135
171
|
status_id: zod_1.z.coerce.number().int().positive().optional(),
|
|
@@ -146,7 +182,7 @@ const baseAdCommon = zod_1.z.object({
|
|
|
146
182
|
return undefined;
|
|
147
183
|
return value;
|
|
148
184
|
}, zod_1.z.coerce.number().optional().nullable()),
|
|
149
|
-
media:
|
|
185
|
+
media: exports.adMediaSchema,
|
|
150
186
|
subject_type: exports.subjectTypeSchema.optional(),
|
|
151
187
|
base_price: zod_1.z.coerce.number().optional().nullable(),
|
|
152
188
|
contact_methods: zod_1.z
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.countAdMedia = exports.isAdVideoMedia = void 0;
|
|
4
|
+
const VIDEO_EXTENSION = /\.(mp4|mov|webm|m4v|ogv)(?:[?#]|$)/i;
|
|
5
|
+
// Older records can omit mimetype: fall back to the URL extension, and count
|
|
6
|
+
// anything unknown as an image rather than accepting unlimited untyped media.
|
|
7
|
+
const isAdVideoMedia = (media) => {
|
|
8
|
+
if (!media || typeof media !== "object")
|
|
9
|
+
return false;
|
|
10
|
+
const item = media;
|
|
11
|
+
const mimetype = typeof item.mimetype === "string" ? item.mimetype.toLowerCase() : "";
|
|
12
|
+
if (mimetype.startsWith("video/"))
|
|
13
|
+
return true;
|
|
14
|
+
if (mimetype.startsWith("image/"))
|
|
15
|
+
return false;
|
|
16
|
+
const source = typeof item.url === "string" && item.url
|
|
17
|
+
? item.url
|
|
18
|
+
: typeof item.path === "string" ? item.path : "";
|
|
19
|
+
return VIDEO_EXTENSION.test(source);
|
|
20
|
+
};
|
|
21
|
+
exports.isAdVideoMedia = isAdVideoMedia;
|
|
22
|
+
const countAdMedia = (media) => {
|
|
23
|
+
const items = Array.isArray(media) ? media : [];
|
|
24
|
+
const videos = items.filter(exports.isAdVideoMedia).length;
|
|
25
|
+
return { images: items.length - videos, videos };
|
|
26
|
+
};
|
|
27
|
+
exports.countAdMedia = countAdMedia;
|
package/dist/cjs/utils/index.js
CHANGED
|
@@ -16,3 +16,4 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
__exportStar(require("./converter"), exports);
|
|
18
18
|
__exportStar(require("./routes"), exports);
|
|
19
|
+
__exportStar(require("./adMedia"), exports);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Media is optional on every ad. These are the only limits, shared by every
|
|
2
|
+
// client and the API so they can never drift apart.
|
|
3
|
+
export const MAX_AD_IMAGES = 30;
|
|
4
|
+
export const MAX_AD_VIDEOS = 1;
|
|
5
|
+
// Raw upload size; the assets service compresses videos after upload.
|
|
6
|
+
export const MAX_AD_VIDEO_BYTES = 200 * 1024 * 1024;
|
|
7
|
+
// Stable codes carried in `params.code` of adMediaSchema issues, so clients can
|
|
8
|
+
// show localized messages without re-implementing the rules.
|
|
9
|
+
export var AdMediaIssueCode;
|
|
10
|
+
(function (AdMediaIssueCode) {
|
|
11
|
+
AdMediaIssueCode["TOO_MANY_IMAGES"] = "too_many_images";
|
|
12
|
+
AdMediaIssueCode["TOO_MANY_VIDEOS"] = "too_many_videos";
|
|
13
|
+
AdMediaIssueCode["VIDEO_TOO_LARGE"] = "video_too_large";
|
|
14
|
+
})(AdMediaIssueCode || (AdMediaIssueCode = {}));
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { AdMediaIssueCode, MAX_AD_IMAGES, MAX_AD_VIDEO_BYTES, MAX_AD_VIDEOS, } from "../../constants/ad/AdMedia.js";
|
|
3
|
+
import { countAdMedia, isAdVideoMedia } from "../../utils/adMedia.js";
|
|
2
4
|
export const subjectTypeSchema = z.enum([
|
|
3
5
|
"properties",
|
|
4
6
|
"services",
|
|
@@ -127,6 +129,40 @@ const createServiceSchema = baseServiceSchema;
|
|
|
127
129
|
const updateServiceSchema = baseServiceSchema.extend({
|
|
128
130
|
id: z.coerce.number().int().positive().optional(),
|
|
129
131
|
});
|
|
132
|
+
// Media is optional: an ad may have no media, only one video, or only images.
|
|
133
|
+
export const adMediaSchema = z
|
|
134
|
+
.array(z.any())
|
|
135
|
+
.superRefine((media, ctx) => {
|
|
136
|
+
const { images, videos } = countAdMedia(media);
|
|
137
|
+
if (images > MAX_AD_IMAGES) {
|
|
138
|
+
ctx.addIssue({
|
|
139
|
+
code: "custom",
|
|
140
|
+
message: `An ad can contain up to ${MAX_AD_IMAGES} images`,
|
|
141
|
+
params: { code: AdMediaIssueCode.TOO_MANY_IMAGES, max: MAX_AD_IMAGES },
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
if (videos > MAX_AD_VIDEOS) {
|
|
145
|
+
ctx.addIssue({
|
|
146
|
+
code: "custom",
|
|
147
|
+
message: `An ad can contain up to ${MAX_AD_VIDEOS} video`,
|
|
148
|
+
params: { code: AdMediaIssueCode.TOO_MANY_VIDEOS, max: MAX_AD_VIDEOS },
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
media.forEach((item, index) => {
|
|
152
|
+
if (isAdVideoMedia(item) &&
|
|
153
|
+
typeof (item === null || item === void 0 ? void 0 : item.size) === "number" &&
|
|
154
|
+
item.size > MAX_AD_VIDEO_BYTES) {
|
|
155
|
+
ctx.addIssue({
|
|
156
|
+
code: "custom",
|
|
157
|
+
path: [index],
|
|
158
|
+
message: `An ad video cannot exceed ${MAX_AD_VIDEO_BYTES / (1024 * 1024)} MB`,
|
|
159
|
+
params: { code: AdMediaIssueCode.VIDEO_TOO_LARGE, max: MAX_AD_VIDEO_BYTES },
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
})
|
|
164
|
+
.optional()
|
|
165
|
+
.nullable();
|
|
130
166
|
const baseAdCommon = z.object({
|
|
131
167
|
title: z.string().trim().optional(),
|
|
132
168
|
status_id: z.coerce.number().int().positive().optional(),
|
|
@@ -143,7 +179,7 @@ const baseAdCommon = z.object({
|
|
|
143
179
|
return undefined;
|
|
144
180
|
return value;
|
|
145
181
|
}, z.coerce.number().optional().nullable()),
|
|
146
|
-
media:
|
|
182
|
+
media: adMediaSchema,
|
|
147
183
|
subject_type: subjectTypeSchema.optional(),
|
|
148
184
|
base_price: z.coerce.number().optional().nullable(),
|
|
149
185
|
contact_methods: z
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
const VIDEO_EXTENSION = /\.(mp4|mov|webm|m4v|ogv)(?:[?#]|$)/i;
|
|
2
|
+
// Older records can omit mimetype: fall back to the URL extension, and count
|
|
3
|
+
// anything unknown as an image rather than accepting unlimited untyped media.
|
|
4
|
+
export const isAdVideoMedia = (media) => {
|
|
5
|
+
if (!media || typeof media !== "object")
|
|
6
|
+
return false;
|
|
7
|
+
const item = media;
|
|
8
|
+
const mimetype = typeof item.mimetype === "string" ? item.mimetype.toLowerCase() : "";
|
|
9
|
+
if (mimetype.startsWith("video/"))
|
|
10
|
+
return true;
|
|
11
|
+
if (mimetype.startsWith("image/"))
|
|
12
|
+
return false;
|
|
13
|
+
const source = typeof item.url === "string" && item.url
|
|
14
|
+
? item.url
|
|
15
|
+
: typeof item.path === "string" ? item.path : "";
|
|
16
|
+
return VIDEO_EXTENSION.test(source);
|
|
17
|
+
};
|
|
18
|
+
export const countAdMedia = (media) => {
|
|
19
|
+
const items = Array.isArray(media) ? media : [];
|
|
20
|
+
const videos = items.filter(isAdVideoMedia).length;
|
|
21
|
+
return { images: items.length - videos, videos };
|
|
22
|
+
};
|
package/dist/esm/utils/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deallony/shared",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.53",
|
|
4
4
|
"private": false,
|
|
5
5
|
"main": "dist/cjs/index.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"deploy": "node ./scripts/publish.js npm patch",
|
|
22
22
|
"=========": "============= UPDATE APPS LIBRARY =============",
|
|
23
23
|
"all:update": "npm run mobile:update && npm run backend:update && npm run dashboard:update && npm run whatsapp:update",
|
|
24
|
-
"mobile:update": "cd ../app && npm install
|
|
24
|
+
"mobile:update": "cd ../app && npm install upgrade:deallony:shared",
|
|
25
25
|
"backend:update": "cd ../backend-service-marketplace && pnpm install gitlab:qatayef-tech-aloo/deallony-development/shared-deallony",
|
|
26
26
|
"dashboard:update": "cd ../frontend-react-aloo && pnpm install gitlab:qatayef-tech-aloo/deallony-development/shared-deallony",
|
|
27
27
|
"whatsapp:update": "cd ../backend-nest-whatsapp-service-aloo && pnpm install gitlab:qatayef-tech-aloo/deallony-development/shared-deallony",
|