@deallony/shared 1.2.50 → 1.2.52

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 (40) hide show
  1. package/dist/cjs/constants/ad/AdMedia.d.ts +8 -0
  2. package/dist/cjs/constants/ad/AdMedia.js +16 -0
  3. package/dist/cjs/constants/ad/index.d.ts +1 -0
  4. package/dist/cjs/constants/ad/index.js +1 -0
  5. package/dist/cjs/dto/addresses/addresses.dto.d.ts +7 -0
  6. package/dist/cjs/dto/addresses/addresses.dto.js +2 -0
  7. package/dist/cjs/dto/index.d.ts +1 -0
  8. package/dist/cjs/dto/index.js +2 -1
  9. package/dist/cjs/schema/ad/save-ad.schema.d.ts +5 -0
  10. package/dist/cjs/schema/ad/save-ad.schema.js +39 -2
  11. package/dist/cjs/schema/addresses/addresses.schema.d.ts +19 -0
  12. package/dist/cjs/schema/addresses/addresses.schema.js +18 -0
  13. package/dist/cjs/schema/index.d.ts +1 -0
  14. package/dist/cjs/schema/index.js +2 -1
  15. package/dist/cjs/types/ad/Ad.d.ts +1 -0
  16. package/dist/cjs/types/ad/Ad.js +1 -0
  17. package/dist/cjs/types/addresses/Address.d.ts +14 -0
  18. package/dist/cjs/types/addresses/Address.js +2 -0
  19. package/dist/cjs/types/communication/Chat.d.ts +8 -1
  20. package/dist/cjs/types/communication/Chat.js +1 -0
  21. package/dist/cjs/types/index.d.ts +1 -0
  22. package/dist/cjs/types/index.js +3 -2
  23. package/dist/cjs/utils/adMedia.d.ts +5 -0
  24. package/dist/cjs/utils/adMedia.js +27 -0
  25. package/dist/cjs/utils/index.d.ts +1 -0
  26. package/dist/cjs/utils/index.js +1 -0
  27. package/dist/esm/constants/ad/AdMedia.js +13 -0
  28. package/dist/esm/constants/ad/index.js +1 -0
  29. package/dist/esm/dto/addresses/addresses.dto.js +1 -0
  30. package/dist/esm/dto/index.js +1 -0
  31. package/dist/esm/schema/ad/save-ad.schema.js +38 -1
  32. package/dist/esm/schema/addresses/addresses.schema.js +15 -0
  33. package/dist/esm/schema/index.js +1 -0
  34. package/dist/esm/types/ad/Ad.js +1 -0
  35. package/dist/esm/types/addresses/Address.js +1 -0
  36. package/dist/esm/types/communication/Chat.js +1 -0
  37. package/dist/esm/types/index.js +1 -0
  38. package/dist/esm/utils/adMedia.js +22 -0
  39. package/dist/esm/utils/index.js +1 -0
  40. package/package.json +1 -1
@@ -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,16 @@
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
+ exports.MAX_AD_VIDEO_BYTES = 50 * 1024 * 1024;
9
+ // Stable codes carried in `params.code` of adMediaSchema issues, so clients can
10
+ // show localized messages without re-implementing the rules.
11
+ var AdMediaIssueCode;
12
+ (function (AdMediaIssueCode) {
13
+ AdMediaIssueCode["TOO_MANY_IMAGES"] = "too_many_images";
14
+ AdMediaIssueCode["TOO_MANY_VIDEOS"] = "too_many_videos";
15
+ AdMediaIssueCode["VIDEO_TOO_LARGE"] = "video_too_large";
16
+ })(AdMediaIssueCode || (exports.AdMediaIssueCode = AdMediaIssueCode = {}));
@@ -1 +1,2 @@
1
1
  export * from "./Ad";
2
+ export * from "./AdMedia";
@@ -15,3 +15,4 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./Ad"), exports);
18
+ __exportStar(require("./AdMedia"), exports);
@@ -0,0 +1,7 @@
1
+ import type { z } from "zod";
2
+ import type { createAddressSchema, updateAddressSchema } from "../../schema/addresses/addresses.schema";
3
+ import type { IAddress } from "../../types/addresses/Address";
4
+ export type CreateAddressDto = z.infer<typeof createAddressSchema>;
5
+ export type UpdateAddressDto = z.infer<typeof updateAddressSchema>;
6
+ export type AddressResponse = IAddress;
7
+ export type AddressListResponse = IAddress[];
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -3,3 +3,4 @@ export * as AD from './ad/Ad.dto';
3
3
  export * as EVENTS from './events';
4
4
  export * as Ai from './ai/Ai.dto';
5
5
  export * as PAYMENTS from './payments';
6
+ export * as ADDRESSES from './addresses/addresses.dto';
@@ -33,10 +33,11 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.PAYMENTS = exports.Ai = exports.EVENTS = exports.AD = exports.AdDto = void 0;
36
+ exports.ADDRESSES = exports.PAYMENTS = exports.Ai = exports.EVENTS = exports.AD = exports.AdDto = void 0;
37
37
  var Ad_dto_1 = require("./ad/Ad.dto");
38
38
  Object.defineProperty(exports, "AdDto", { enumerable: true, get: function () { return Ad_dto_1.AdDto; } });
39
39
  exports.AD = __importStar(require("./ad/Ad.dto"));
40
40
  exports.EVENTS = __importStar(require("./events"));
41
41
  exports.Ai = __importStar(require("./ai/Ai.dto"));
42
42
  exports.PAYMENTS = __importStar(require("./payments"));
43
+ exports.ADDRESSES = __importStar(require("./addresses/addresses.dto"));
@@ -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>>;
@@ -75,6 +76,7 @@ export declare const createAdSchema: z.ZodObject<{
75
76
  negotiable: z.ZodNullable<z.ZodOptional<z.ZodCoercedBoolean<unknown>>>;
76
77
  latitude: z.ZodNullable<z.ZodOptional<z.ZodCoercedNumber<unknown>>>;
77
78
  longitude: z.ZodNullable<z.ZodOptional<z.ZodCoercedNumber<unknown>>>;
79
+ saved_address_id: z.ZodNullable<z.ZodOptional<z.ZodCoercedNumber<unknown>>>;
78
80
  baseAdminBoundaryId: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodNullable<z.ZodOptional<z.ZodCoercedNumber<unknown>>>>;
79
81
  media: z.ZodNullable<z.ZodOptional<z.ZodArray<z.ZodAny>>>;
80
82
  subject_type: z.ZodOptional<z.ZodEnum<{
@@ -172,6 +174,7 @@ export declare const updateAdSchema: z.ZodObject<{
172
174
  negotiable: z.ZodNullable<z.ZodOptional<z.ZodCoercedBoolean<unknown>>>;
173
175
  latitude: z.ZodNullable<z.ZodOptional<z.ZodCoercedNumber<unknown>>>;
174
176
  longitude: z.ZodNullable<z.ZodOptional<z.ZodCoercedNumber<unknown>>>;
177
+ saved_address_id: z.ZodNullable<z.ZodOptional<z.ZodCoercedNumber<unknown>>>;
175
178
  baseAdminBoundaryId: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodNullable<z.ZodOptional<z.ZodCoercedNumber<unknown>>>>;
176
179
  media: z.ZodNullable<z.ZodOptional<z.ZodArray<z.ZodAny>>>;
177
180
  subject_type: z.ZodOptional<z.ZodEnum<{
@@ -264,6 +267,7 @@ export declare const saveAdSchema: z.ZodUnion<readonly [z.ZodObject<{
264
267
  negotiable: z.ZodNullable<z.ZodOptional<z.ZodCoercedBoolean<unknown>>>;
265
268
  latitude: z.ZodNullable<z.ZodOptional<z.ZodCoercedNumber<unknown>>>;
266
269
  longitude: z.ZodNullable<z.ZodOptional<z.ZodCoercedNumber<unknown>>>;
270
+ saved_address_id: z.ZodNullable<z.ZodOptional<z.ZodCoercedNumber<unknown>>>;
267
271
  baseAdminBoundaryId: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodNullable<z.ZodOptional<z.ZodCoercedNumber<unknown>>>>;
268
272
  media: z.ZodNullable<z.ZodOptional<z.ZodArray<z.ZodAny>>>;
269
273
  subject_type: z.ZodOptional<z.ZodEnum<{
@@ -360,6 +364,7 @@ export declare const saveAdSchema: z.ZodUnion<readonly [z.ZodObject<{
360
364
  negotiable: z.ZodNullable<z.ZodOptional<z.ZodCoercedBoolean<unknown>>>;
361
365
  latitude: z.ZodNullable<z.ZodOptional<z.ZodCoercedNumber<unknown>>>;
362
366
  longitude: z.ZodNullable<z.ZodOptional<z.ZodCoercedNumber<unknown>>>;
367
+ saved_address_id: z.ZodNullable<z.ZodOptional<z.ZodCoercedNumber<unknown>>>;
363
368
  baseAdminBoundaryId: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodNullable<z.ZodOptional<z.ZodCoercedNumber<unknown>>>>;
364
369
  media: z.ZodNullable<z.ZodOptional<z.ZodArray<z.ZodAny>>>;
365
370
  subject_type: z.ZodOptional<z.ZodEnum<{
@@ -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(),
@@ -140,12 +176,13 @@ const baseAdCommon = zod_1.z.object({
140
176
  negotiable: zod_1.z.coerce.boolean().optional().nullable(),
141
177
  latitude: zod_1.z.coerce.number().optional().nullable(),
142
178
  longitude: zod_1.z.coerce.number().optional().nullable(),
179
+ saved_address_id: zod_1.z.coerce.number().int().positive().optional().nullable(),
143
180
  baseAdminBoundaryId: zod_1.z.preprocess((value) => {
144
181
  if (value === 0 || value === "0")
145
182
  return undefined;
146
183
  return value;
147
184
  }, zod_1.z.coerce.number().optional().nullable()),
148
- media: zod_1.z.array(zod_1.z.any()).optional().nullable(),
185
+ media: exports.adMediaSchema,
149
186
  subject_type: exports.subjectTypeSchema.optional(),
150
187
  base_price: zod_1.z.coerce.number().optional().nullable(),
151
188
  contact_methods: zod_1.z
@@ -0,0 +1,19 @@
1
+ import { z } from "zod";
2
+ export declare const createAddressSchema: z.ZodObject<{
3
+ label: z.ZodString;
4
+ location_description: z.ZodOptional<z.ZodNullable<z.ZodString>>;
5
+ formatted_address: z.ZodOptional<z.ZodNullable<z.ZodString>>;
6
+ latitude: z.ZodCoercedNumber<unknown>;
7
+ longitude: z.ZodCoercedNumber<unknown>;
8
+ admin_boundary_id: z.ZodCoercedNumber<unknown>;
9
+ is_default: z.ZodOptional<z.ZodBoolean>;
10
+ }, z.core.$strip>;
11
+ export declare const updateAddressSchema: z.ZodObject<{
12
+ label: z.ZodOptional<z.ZodString>;
13
+ location_description: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
14
+ formatted_address: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
15
+ latitude: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
16
+ longitude: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
17
+ admin_boundary_id: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
18
+ is_default: z.ZodOptional<z.ZodOptional<z.ZodBoolean>>;
19
+ }, z.core.$strip>;
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.updateAddressSchema = exports.createAddressSchema = void 0;
4
+ const zod_1 = require("zod");
5
+ exports.createAddressSchema = zod_1.z.object({
6
+ label: zod_1.z.string().trim().min(1).max(100),
7
+ location_description: zod_1.z.string().trim().max(500).nullable().optional(),
8
+ formatted_address: zod_1.z.string().trim().max(1000).nullable().optional(),
9
+ latitude: zod_1.z.coerce.number().finite().min(-90).max(90),
10
+ longitude: zod_1.z.coerce.number().finite().min(-180).max(180),
11
+ admin_boundary_id: zod_1.z.coerce.number().int().positive(),
12
+ is_default: zod_1.z.boolean().optional(),
13
+ });
14
+ exports.updateAddressSchema = exports.createAddressSchema
15
+ .partial()
16
+ .refine((value) => Object.keys(value).length > 0, {
17
+ message: "At least one field is required",
18
+ });
@@ -4,3 +4,4 @@ export * as COMMON from './common';
4
4
  export * as EVENTS from './events';
5
5
  export * as PAYMENTS from './payments';
6
6
  export * as COMMUNICATION from './communication';
7
+ export * as ADDRESSES from './addresses/addresses.schema';
@@ -33,10 +33,11 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.COMMUNICATION = exports.PAYMENTS = exports.EVENTS = exports.COMMON = exports.AI = exports.AD = void 0;
36
+ exports.ADDRESSES = exports.COMMUNICATION = exports.PAYMENTS = exports.EVENTS = exports.COMMON = exports.AI = exports.AD = void 0;
37
37
  exports.AD = __importStar(require("./ad"));
38
38
  exports.AI = __importStar(require("./ai"));
39
39
  exports.COMMON = __importStar(require("./common"));
40
40
  exports.EVENTS = __importStar(require("./events"));
41
41
  exports.PAYMENTS = __importStar(require("./payments"));
42
42
  exports.COMMUNICATION = __importStar(require("./communication"));
43
+ exports.ADDRESSES = __importStar(require("./addresses/addresses.schema"));
@@ -24,6 +24,7 @@ export type IAd = {
24
24
  latitude?: number | null;
25
25
  longitude?: number | null;
26
26
  baseAdminBoundaryId?: number | null;
27
+ saved_address_id?: number | null;
27
28
  adLocations?: IAdLocations;
28
29
  subject_id?: number | null;
29
30
  contact_methods: {
@@ -11,6 +11,7 @@ exports.emptyAd = {
11
11
  latitude: null,
12
12
  longitude: null,
13
13
  baseAdminBoundaryId: null,
14
+ saved_address_id: null,
14
15
  contact_methods: null,
15
16
  selected_phone: null,
16
17
  media: [],
@@ -0,0 +1,14 @@
1
+ /** Reusable, private address owned by a user. */
2
+ export interface IAddress {
3
+ id: number;
4
+ user_id: number;
5
+ label: string;
6
+ location_description: string | null;
7
+ formatted_address: string | null;
8
+ latitude: number;
9
+ longitude: number;
10
+ admin_boundary_id: number;
11
+ is_default: boolean;
12
+ created_at: string;
13
+ updated_at: string;
14
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -40,9 +40,16 @@ export type IChatMessage = {
40
40
  };
41
41
  export declare enum MessageTypeEnum {
42
42
  TEXT = 1,
43
- PRICE_OFFER = 2
43
+ PRICE_OFFER = 2,
44
+ CONTACT_INVITATION = 3
44
45
  }
45
46
  export { MessageTypeEnum as MessageTypeType };
47
+ export type ContactInvitationPayload = {
48
+ version: 1;
49
+ phone_e164: string;
50
+ can_call: boolean;
51
+ can_whatsapp: boolean;
52
+ };
46
53
  export type SendMessageDto = {
47
54
  chat_room_id: number;
48
55
  requester_id: number;
@@ -5,4 +5,5 @@ var MessageTypeEnum;
5
5
  (function (MessageTypeEnum) {
6
6
  MessageTypeEnum[MessageTypeEnum["TEXT"] = 1] = "TEXT";
7
7
  MessageTypeEnum[MessageTypeEnum["PRICE_OFFER"] = 2] = "PRICE_OFFER";
8
+ MessageTypeEnum[MessageTypeEnum["CONTACT_INVITATION"] = 3] = "CONTACT_INVITATION";
8
9
  })(MessageTypeEnum || (exports.MessageTypeType = exports.MessageTypeEnum = MessageTypeEnum = {}));
@@ -6,6 +6,7 @@ export * as Config from "./common/Config";
6
6
  export * as FilterParams from "./common/FilterParams";
7
7
  export * as Ad from "./ad/Ad";
8
8
  export * as AdLocation from "./ad/AdLocation";
9
+ export * as Addresses from "./addresses/Address";
9
10
  export * as AdPromotion from "./ad/AdPromotion";
10
11
  export * as Motor from "./motor/Motor";
11
12
  export * as MotorTrim from "./motor/MotorTrim";
@@ -36,8 +36,8 @@ var __importStar = (this && this.__importStar) || (function () {
36
36
  };
37
37
  })();
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.Company = exports.PotentialUser = exports.Loyalty = exports.Favorite = exports.Wallet = exports.Permission = exports.Role = exports.User = exports.EventVenue = exports.EventWedding = exports.EventTimeline = exports.EventRsvp = exports.Event = exports.District = exports.City = exports.AdminBoundary = exports.WorkType = exports.UsedProductCondition = exports.UsedProductAge = exports.Unit = exports.Transmission = exports.RegionalSpec = exports.PublisherType = exports.PropertyStatus = exports.PriceType = exports.OfferType = exports.LicenseType = exports.FuelType = exports.Feature = exports.Facility = exports.Currency = exports.Color = exports.CategoryWorkType = exports.Category = exports.CarBody = exports.UsedProduct = exports.Service = exports.PropertySubType = exports.Property = exports.MotorTrim = exports.Motor = exports.AdPromotion = exports.AdLocation = exports.Ad = exports.FilterParams = exports.Config = exports.AccessType = exports.Status = exports.Response = exports.LocalizedName = void 0;
40
- exports.Payment = exports.Analysis = exports.Google = exports.Kyc = exports.SocialMediaProfile = exports.SocialMediaPlatform = exports.Image = exports.Media = exports.File = exports.NotificationToken = exports.MessageTemplate = exports.Device = exports.Chat = exports.AppStartScreen = exports.MetaData = void 0;
39
+ exports.PotentialUser = exports.Loyalty = exports.Favorite = exports.Wallet = exports.Permission = exports.Role = exports.User = exports.EventVenue = exports.EventWedding = exports.EventTimeline = exports.EventRsvp = exports.Event = exports.District = exports.City = exports.AdminBoundary = exports.WorkType = exports.UsedProductCondition = exports.UsedProductAge = exports.Unit = exports.Transmission = exports.RegionalSpec = exports.PublisherType = exports.PropertyStatus = exports.PriceType = exports.OfferType = exports.LicenseType = exports.FuelType = exports.Feature = exports.Facility = exports.Currency = exports.Color = exports.CategoryWorkType = exports.Category = exports.CarBody = exports.UsedProduct = exports.Service = exports.PropertySubType = exports.Property = exports.MotorTrim = exports.Motor = exports.AdPromotion = exports.Addresses = exports.AdLocation = exports.Ad = exports.FilterParams = exports.Config = exports.AccessType = exports.Status = exports.Response = exports.LocalizedName = void 0;
40
+ exports.Payment = exports.Analysis = exports.Google = exports.Kyc = exports.SocialMediaProfile = exports.SocialMediaPlatform = exports.Image = exports.Media = exports.File = exports.NotificationToken = exports.MessageTemplate = exports.Device = exports.Chat = exports.AppStartScreen = exports.MetaData = exports.Company = void 0;
41
41
  // common
42
42
  exports.LocalizedName = __importStar(require("./common/LocalizedName"));
43
43
  exports.Response = __importStar(require("./common/Response"));
@@ -48,6 +48,7 @@ exports.FilterParams = __importStar(require("./common/FilterParams"));
48
48
  // listings
49
49
  exports.Ad = __importStar(require("./ad/Ad"));
50
50
  exports.AdLocation = __importStar(require("./ad/AdLocation"));
51
+ exports.Addresses = __importStar(require("./addresses/Address"));
51
52
  exports.AdPromotion = __importStar(require("./ad/AdPromotion"));
52
53
  exports.Motor = __importStar(require("./motor/Motor"));
53
54
  exports.MotorTrim = __importStar(require("./motor/MotorTrim"));
@@ -0,0 +1,5 @@
1
+ export declare const isAdVideoMedia: (media: unknown) => boolean;
2
+ export declare const countAdMedia: (media: unknown) => {
3
+ images: number;
4
+ videos: number;
5
+ };
@@ -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;
@@ -1,2 +1,3 @@
1
1
  export * from './converter';
2
2
  export * from './routes';
3
+ export * from './adMedia';
@@ -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,13 @@
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
+ export const MAX_AD_VIDEO_BYTES = 50 * 1024 * 1024;
6
+ // Stable codes carried in `params.code` of adMediaSchema issues, so clients can
7
+ // show localized messages without re-implementing the rules.
8
+ export var AdMediaIssueCode;
9
+ (function (AdMediaIssueCode) {
10
+ AdMediaIssueCode["TOO_MANY_IMAGES"] = "too_many_images";
11
+ AdMediaIssueCode["TOO_MANY_VIDEOS"] = "too_many_videos";
12
+ AdMediaIssueCode["VIDEO_TOO_LARGE"] = "video_too_large";
13
+ })(AdMediaIssueCode || (AdMediaIssueCode = {}));
@@ -1 +1,2 @@
1
1
  export * from "./Ad.js";
2
+ export * from "./AdMedia.js";
@@ -0,0 +1 @@
1
+ export {};
@@ -3,3 +3,4 @@ export * as AD from './ad/Ad.dto.js';
3
3
  export * as EVENTS from './events/index.js';
4
4
  export * as Ai from './ai/Ai.dto.js';
5
5
  export * as PAYMENTS from './payments/index.js';
6
+ export * as ADDRESSES from './addresses/addresses.dto.js';
@@ -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(),
@@ -137,12 +173,13 @@ const baseAdCommon = z.object({
137
173
  negotiable: z.coerce.boolean().optional().nullable(),
138
174
  latitude: z.coerce.number().optional().nullable(),
139
175
  longitude: z.coerce.number().optional().nullable(),
176
+ saved_address_id: z.coerce.number().int().positive().optional().nullable(),
140
177
  baseAdminBoundaryId: z.preprocess((value) => {
141
178
  if (value === 0 || value === "0")
142
179
  return undefined;
143
180
  return value;
144
181
  }, z.coerce.number().optional().nullable()),
145
- media: z.array(z.any()).optional().nullable(),
182
+ media: adMediaSchema,
146
183
  subject_type: subjectTypeSchema.optional(),
147
184
  base_price: z.coerce.number().optional().nullable(),
148
185
  contact_methods: z
@@ -0,0 +1,15 @@
1
+ import { z } from "zod";
2
+ export const createAddressSchema = z.object({
3
+ label: z.string().trim().min(1).max(100),
4
+ location_description: z.string().trim().max(500).nullable().optional(),
5
+ formatted_address: z.string().trim().max(1000).nullable().optional(),
6
+ latitude: z.coerce.number().finite().min(-90).max(90),
7
+ longitude: z.coerce.number().finite().min(-180).max(180),
8
+ admin_boundary_id: z.coerce.number().int().positive(),
9
+ is_default: z.boolean().optional(),
10
+ });
11
+ export const updateAddressSchema = createAddressSchema
12
+ .partial()
13
+ .refine((value) => Object.keys(value).length > 0, {
14
+ message: "At least one field is required",
15
+ });
@@ -4,3 +4,4 @@ export * as COMMON from './common/index.js';
4
4
  export * as EVENTS from './events/index.js';
5
5
  export * as PAYMENTS from './payments/index.js';
6
6
  export * as COMMUNICATION from './communication/index.js';
7
+ export * as ADDRESSES from './addresses/addresses.schema.js';
@@ -8,6 +8,7 @@ export const emptyAd = {
8
8
  latitude: null,
9
9
  longitude: null,
10
10
  baseAdminBoundaryId: null,
11
+ saved_address_id: null,
11
12
  contact_methods: null,
12
13
  selected_phone: null,
13
14
  media: [],
@@ -0,0 +1 @@
1
+ export {};
@@ -2,5 +2,6 @@ export var MessageTypeEnum;
2
2
  (function (MessageTypeEnum) {
3
3
  MessageTypeEnum[MessageTypeEnum["TEXT"] = 1] = "TEXT";
4
4
  MessageTypeEnum[MessageTypeEnum["PRICE_OFFER"] = 2] = "PRICE_OFFER";
5
+ MessageTypeEnum[MessageTypeEnum["CONTACT_INVITATION"] = 3] = "CONTACT_INVITATION";
5
6
  })(MessageTypeEnum || (MessageTypeEnum = {}));
6
7
  export { MessageTypeEnum as MessageTypeType };
@@ -11,6 +11,7 @@ export * as FilterParams from "./common/FilterParams.js";
11
11
  // listings
12
12
  export * as Ad from "./ad/Ad.js";
13
13
  export * as AdLocation from "./ad/AdLocation.js";
14
+ export * as Addresses from "./addresses/Address.js";
14
15
  export * as AdPromotion from "./ad/AdPromotion.js";
15
16
  export * as Motor from "./motor/Motor.js";
16
17
  export * as MotorTrim from "./motor/MotorTrim.js";
@@ -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
+ };
@@ -1,2 +1,3 @@
1
1
  export * from './converter.js';
2
2
  export * from './routes.js';
3
+ export * from './adMedia.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deallony/shared",
3
- "version": "1.2.50",
3
+ "version": "1.2.52",
4
4
  "private": false,
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",