@voyantjs/products 0.3.1 → 0.4.1

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 (52) hide show
  1. package/dist/index.d.ts +6 -1
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +5 -1
  4. package/dist/routes-public.d.ts +167 -12
  5. package/dist/routes-public.d.ts.map +1 -1
  6. package/dist/routes-public.js +13 -1
  7. package/dist/routes.d.ts +669 -0
  8. package/dist/routes.d.ts.map +1 -1
  9. package/dist/routes.js +117 -1
  10. package/dist/schema-itinerary.d.ts +51 -0
  11. package/dist/schema-itinerary.d.ts.map +1 -1
  12. package/dist/schema-itinerary.js +3 -0
  13. package/dist/schema-relations.d.ts +14 -0
  14. package/dist/schema-relations.d.ts.map +1 -1
  15. package/dist/schema-relations.js +28 -1
  16. package/dist/schema-taxonomy.d.ts +435 -0
  17. package/dist/schema-taxonomy.d.ts.map +1 -1
  18. package/dist/schema-taxonomy.js +47 -0
  19. package/dist/service-catalog.d.ts +237 -0
  20. package/dist/service-catalog.d.ts.map +1 -0
  21. package/dist/service-catalog.js +478 -0
  22. package/dist/service-public.d.ts +136 -12
  23. package/dist/service-public.d.ts.map +1 -1
  24. package/dist/service-public.js +146 -260
  25. package/dist/service.d.ts +292 -1
  26. package/dist/service.d.ts.map +1 -1
  27. package/dist/service.js +388 -2
  28. package/dist/tasks/brochure-printers.d.ts +29 -0
  29. package/dist/tasks/brochure-printers.d.ts.map +1 -0
  30. package/dist/tasks/brochure-printers.js +94 -0
  31. package/dist/tasks/brochure-templates.d.ts +36 -0
  32. package/dist/tasks/brochure-templates.d.ts.map +1 -0
  33. package/dist/tasks/brochure-templates.js +98 -0
  34. package/dist/tasks/brochures.d.ts +42 -0
  35. package/dist/tasks/brochures.d.ts.map +1 -0
  36. package/dist/tasks/brochures.js +69 -0
  37. package/dist/tasks/index.d.ts +3 -0
  38. package/dist/tasks/index.d.ts.map +1 -1
  39. package/dist/tasks/index.js +3 -0
  40. package/dist/validation-catalog.d.ts +388 -0
  41. package/dist/validation-catalog.d.ts.map +1 -0
  42. package/dist/validation-catalog.js +54 -0
  43. package/dist/validation-content.d.ts +109 -0
  44. package/dist/validation-content.d.ts.map +1 -1
  45. package/dist/validation-content.js +63 -1
  46. package/dist/validation-public.d.ts +208 -19
  47. package/dist/validation-public.d.ts.map +1 -1
  48. package/dist/validation-public.js +39 -2
  49. package/dist/validation-shared.d.ts +6 -0
  50. package/dist/validation-shared.d.ts.map +1 -1
  51. package/dist/validation-shared.js +1 -0
  52. package/package.json +6 -4
@@ -0,0 +1,98 @@
1
+ import { renderStructuredTemplate, } from "@voyantjs/utils/template-renderer";
2
+ import { asc, eq } from "drizzle-orm";
3
+ import { productDayServices, productDays, products } from "../schema.js";
4
+ async function resolveTemplateValue(value, context) {
5
+ if (typeof value === "function") {
6
+ return await value(context);
7
+ }
8
+ return value;
9
+ }
10
+ function normalizeFilename(value, productName) {
11
+ const fallback = `${productName.replace(/[^a-zA-Z0-9]/g, "_")}.pdf`;
12
+ const trimmed = value?.trim();
13
+ return trimmed || fallback;
14
+ }
15
+ export async function loadProductBrochureTemplateContext(db, productId) {
16
+ const [product] = await db.select().from(products).where(eq(products.id, productId)).limit(1);
17
+ if (!product) {
18
+ throw new Error(`Product not found: ${productId}`);
19
+ }
20
+ const days = await db
21
+ .select()
22
+ .from(productDays)
23
+ .where(eq(productDays.productId, productId))
24
+ .orderBy(asc(productDays.dayNumber));
25
+ const daysWithServices = await Promise.all(days.map(async (day) => {
26
+ const services = await db
27
+ .select()
28
+ .from(productDayServices)
29
+ .where(eq(productDayServices.dayId, day.id))
30
+ .orderBy(asc(productDayServices.sortOrder));
31
+ return {
32
+ ...day,
33
+ services,
34
+ };
35
+ }));
36
+ return {
37
+ product,
38
+ days: daysWithServices,
39
+ generatedAt: new Date(),
40
+ };
41
+ }
42
+ export function createDefaultProductBrochureTemplate() {
43
+ return {
44
+ bodyFormat: "markdown",
45
+ title: ({ product }) => product.name,
46
+ filename: ({ product }) => `${product.name.replace(/[^a-zA-Z0-9]/g, "_")}.pdf`,
47
+ metadataLines: ({ product, generatedAt }) => [
48
+ `Product ID: ${product.id}`,
49
+ `Generated: ${generatedAt.toISOString()}`,
50
+ ],
51
+ body: [
52
+ "# {{ product.name }}",
53
+ "",
54
+ "{% if product.startDate or product.endDate %}",
55
+ "Dates: {{ product.startDate | default: 'TBD' }} - {{ product.endDate | default: 'TBD' }}",
56
+ "{% endif %}",
57
+ "{% if product.pax %}",
58
+ "Travelers: {{ product.pax }}",
59
+ "{% endif %}",
60
+ "{% if product.sellAmountCents %}",
61
+ "Total: {{ product.sellAmountCents | divided_by: 100.0 }} {{ product.sellCurrency }}",
62
+ "{% endif %}",
63
+ "",
64
+ "{% if product.description %}{{ product.description }}{% endif %}",
65
+ "",
66
+ "{% for day in days %}",
67
+ "## Day {{ day.dayNumber }}{% if day.title %}: {{ day.title }}{% endif %}",
68
+ "{% if day.location %}Location: {{ day.location }}{% endif %}",
69
+ "{% if day.description %}{{ day.description }}{% endif %}",
70
+ "",
71
+ "{% for service in day.services %}",
72
+ "- {{ service.name }} ({{ service.serviceType }}){% if service.quantity > 1 %} x{{ service.quantity }}{% endif %}",
73
+ "{% if service.notes %} {{ service.notes }}{% endif %}",
74
+ "{% endfor %}",
75
+ "",
76
+ "{% endfor %}",
77
+ ].join("\n"),
78
+ };
79
+ }
80
+ export async function renderProductBrochureTemplate(template, context) {
81
+ const rawBody = (await resolveTemplateValue(template.body, context)) ?? "";
82
+ const variables = (await resolveTemplateValue(template.variables, context)) ?? {
83
+ product: context.product,
84
+ days: context.days,
85
+ generatedAt: context.generatedAt.toISOString(),
86
+ };
87
+ const title = (await resolveTemplateValue(template.title, context))?.trim() || context.product.name;
88
+ const filename = normalizeFilename(await resolveTemplateValue(template.filename, context), context.product.name);
89
+ const metadataLines = (await resolveTemplateValue(template.metadataLines, context)) ?? [];
90
+ return {
91
+ body: renderStructuredTemplate(rawBody, template.bodyFormat, variables),
92
+ bodyFormat: template.bodyFormat,
93
+ title,
94
+ filename,
95
+ variables,
96
+ metadataLines,
97
+ };
98
+ }
@@ -0,0 +1,42 @@
1
+ import type { StorageProvider } from "@voyantjs/voyant-storage";
2
+ import type { PostgresJsDatabase } from "drizzle-orm/postgres-js";
3
+ import { type ProductBrochurePrinter } from "./brochure-printers.js";
4
+ import { type ProductBrochureTemplateDefinition } from "./brochure-templates.js";
5
+ export interface GenerateAndStoreProductBrochureOptions {
6
+ storage: StorageProvider;
7
+ template?: ProductBrochureTemplateDefinition;
8
+ printer?: ProductBrochurePrinter;
9
+ keyPrefix?: string;
10
+ filename?: string | ((generated: {
11
+ productId: string;
12
+ filename: string;
13
+ }) => string);
14
+ signedUrlExpiresIn?: number;
15
+ }
16
+ export declare function generateAndStoreProductBrochure(db: PostgresJsDatabase, productId: string, options: GenerateAndStoreProductBrochureOptions): Promise<{
17
+ brochure: {
18
+ productId: string;
19
+ name: string;
20
+ createdAt: Date;
21
+ updatedAt: Date;
22
+ id: string;
23
+ sortOrder: number;
24
+ dayId: string | null;
25
+ mediaType: "image" | "video" | "document";
26
+ url: string;
27
+ storageKey: string | null;
28
+ mimeType: string | null;
29
+ fileSize: number | null;
30
+ altText: string | null;
31
+ isCover: boolean;
32
+ isBrochure: boolean;
33
+ isBrochureCurrent: boolean;
34
+ brochureVersion: number | null;
35
+ };
36
+ filename: string;
37
+ metadata: Record<string, unknown> | null;
38
+ sizeBytes: number;
39
+ storageKey: string;
40
+ url: string;
41
+ }>;
42
+ //# sourceMappingURL=brochures.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"brochures.d.ts","sourceRoot":"","sources":["../../src/tasks/brochures.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AAC/D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAGjE,OAAO,EAEL,KAAK,sBAAsB,EAC5B,MAAM,wBAAwB,CAAA;AAC/B,OAAO,EAGL,KAAK,iCAAiC,EAEvC,MAAM,yBAAyB,CAAA;AAGhC,MAAM,WAAW,sCAAsC;IACrD,OAAO,EAAE,eAAe,CAAA;IACxB,QAAQ,CAAC,EAAE,iCAAiC,CAAA;IAC5C,OAAO,CAAC,EAAE,sBAAsB,CAAA;IAChC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,SAAS,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,KAAK,MAAM,CAAC,CAAA;IACpF,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAC5B;AAED,wBAAsB,+BAA+B,CACnD,EAAE,EAAE,kBAAkB,EACtB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,sCAAsC;;;;;;;;;;;;;;;;;;;;;;;;;GA2EhD"}
@@ -0,0 +1,69 @@
1
+ import { productsService } from "../service.js";
2
+ import { createBasicPdfProductBrochurePrinter, } from "./brochure-printers.js";
3
+ import { createDefaultProductBrochureTemplate, loadProductBrochureTemplateContext, renderProductBrochureTemplate, } from "./brochure-templates.js";
4
+ import { generateProductPdf } from "./generate-pdf.js";
5
+ export async function generateAndStoreProductBrochure(db, productId, options) {
6
+ let filename;
7
+ let pdfBytes;
8
+ let sizeBytes;
9
+ let mimeType = "application/pdf";
10
+ let metadata = null;
11
+ if (options.template || options.printer) {
12
+ const templateContext = await loadProductBrochureTemplateContext(db, productId);
13
+ const rendered = await renderProductBrochureTemplate(options.template ?? createDefaultProductBrochureTemplate(), templateContext);
14
+ const printer = options.printer ?? createBasicPdfProductBrochurePrinter();
15
+ const printed = await printer({
16
+ template: rendered,
17
+ context: templateContext,
18
+ });
19
+ filename =
20
+ typeof options.filename === "function"
21
+ ? options.filename({ productId, filename: rendered.filename })
22
+ : options.filename?.trim() || rendered.filename;
23
+ pdfBytes = printed.body;
24
+ sizeBytes = printed.fileSize ?? printed.body.byteLength;
25
+ mimeType = printed.mimeType ?? mimeType;
26
+ metadata = printed.metadata ?? null;
27
+ }
28
+ else {
29
+ const generated = await generateProductPdf(db, productId);
30
+ filename =
31
+ typeof options.filename === "function"
32
+ ? options.filename({ productId, filename: generated.filename })
33
+ : options.filename?.trim() || generated.filename;
34
+ pdfBytes = generated.pdfBytes;
35
+ sizeBytes = generated.sizeBytes;
36
+ }
37
+ const keyPrefix = options.keyPrefix?.trim() || `brochures/products/${productId}`;
38
+ const uploaded = await options.storage.upload(pdfBytes, {
39
+ key: `${keyPrefix.replace(/\/$/, "")}/${filename}`,
40
+ contentType: mimeType,
41
+ });
42
+ const url = uploaded.url ||
43
+ (options.signedUrlExpiresIn
44
+ ? await options.storage.signedUrl(uploaded.key, options.signedUrlExpiresIn)
45
+ : null);
46
+ if (!url) {
47
+ throw new Error("Brochure upload did not return a public or signed URL.");
48
+ }
49
+ const brochure = await productsService.upsertBrochure(db, productId, {
50
+ name: filename,
51
+ url,
52
+ storageKey: uploaded.key,
53
+ mimeType,
54
+ fileSize: sizeBytes,
55
+ altText: null,
56
+ sortOrder: 0,
57
+ });
58
+ if (!brochure) {
59
+ throw new Error(`Unable to persist brochure for product ${productId}.`);
60
+ }
61
+ return {
62
+ brochure,
63
+ filename,
64
+ metadata,
65
+ sizeBytes,
66
+ storageKey: uploaded.key,
67
+ url,
68
+ };
69
+ }
@@ -1,2 +1,5 @@
1
+ export { type CloudflareBrowserBrochurePrinterOptions, createBasicPdfProductBrochurePrinter, createCloudflareBrowserProductBrochurePrinter, createCloudflareBrowserProductBrochurePrinterFromEnv, type PrintedProductBrochureArtifact, type ProductBrochurePrinter, type ProductBrochurePrinterContext, } from "./brochure-printers.js";
2
+ export { createDefaultProductBrochureTemplate, loadProductBrochureTemplateContext, type ProductBrochureDayContext, type ProductBrochureTemplateContext, type ProductBrochureTemplateDefinition, type RenderedProductBrochureTemplate, renderProductBrochureTemplate, } from "./brochure-templates.js";
3
+ export { type GenerateAndStoreProductBrochureOptions, generateAndStoreProductBrochure, } from "./brochures.js";
1
4
  export { type GenerateProductPdfResult, generateProductPdf } from "./generate-pdf.js";
2
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tasks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,wBAAwB,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tasks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,uCAAuC,EAC5C,oCAAoC,EACpC,6CAA6C,EAC7C,oDAAoD,EACpD,KAAK,8BAA8B,EACnC,KAAK,sBAAsB,EAC3B,KAAK,6BAA6B,GACnC,MAAM,wBAAwB,CAAA;AAC/B,OAAO,EACL,oCAAoC,EACpC,kCAAkC,EAClC,KAAK,yBAAyB,EAC9B,KAAK,8BAA8B,EACnC,KAAK,iCAAiC,EACtC,KAAK,+BAA+B,EACpC,6BAA6B,GAC9B,MAAM,yBAAyB,CAAA;AAChC,OAAO,EACL,KAAK,sCAAsC,EAC3C,+BAA+B,GAChC,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAE,KAAK,wBAAwB,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA"}
@@ -1 +1,4 @@
1
+ export { createBasicPdfProductBrochurePrinter, createCloudflareBrowserProductBrochurePrinter, createCloudflareBrowserProductBrochurePrinterFromEnv, } from "./brochure-printers.js";
2
+ export { createDefaultProductBrochureTemplate, loadProductBrochureTemplateContext, renderProductBrochureTemplate, } from "./brochure-templates.js";
3
+ export { generateAndStoreProductBrochure, } from "./brochures.js";
1
4
  export { generateProductPdf } from "./generate-pdf.js";
@@ -0,0 +1,388 @@
1
+ import { z } from "zod";
2
+ export declare const localizedCatalogProductSummarySchema: z.ZodObject<{
3
+ id: z.ZodString;
4
+ name: z.ZodString;
5
+ description: z.ZodNullable<z.ZodString>;
6
+ contentLanguageTag: z.ZodNullable<z.ZodString>;
7
+ slug: z.ZodNullable<z.ZodString>;
8
+ shortDescription: z.ZodNullable<z.ZodString>;
9
+ seoTitle: z.ZodNullable<z.ZodString>;
10
+ seoDescription: z.ZodNullable<z.ZodString>;
11
+ bookingMode: z.ZodEnum<{
12
+ date: "date";
13
+ other: "other";
14
+ date_time: "date_time";
15
+ open: "open";
16
+ stay: "stay";
17
+ transfer: "transfer";
18
+ itinerary: "itinerary";
19
+ }>;
20
+ capacityMode: z.ZodEnum<{
21
+ free_sale: "free_sale";
22
+ limited: "limited";
23
+ on_request: "on_request";
24
+ }>;
25
+ visibility: z.ZodEnum<{
26
+ public: "public";
27
+ private: "private";
28
+ hidden: "hidden";
29
+ }>;
30
+ sellCurrency: z.ZodString;
31
+ sellAmountCents: z.ZodNullable<z.ZodNumber>;
32
+ startDate: z.ZodNullable<z.ZodString>;
33
+ endDate: z.ZodNullable<z.ZodString>;
34
+ pax: z.ZodNullable<z.ZodNumber>;
35
+ productType: z.ZodNullable<z.ZodObject<{
36
+ id: z.ZodString;
37
+ code: z.ZodString;
38
+ name: z.ZodString;
39
+ description: z.ZodNullable<z.ZodString>;
40
+ }, z.core.$strip>>;
41
+ categories: z.ZodArray<z.ZodObject<{
42
+ id: z.ZodString;
43
+ parentId: z.ZodNullable<z.ZodString>;
44
+ name: z.ZodString;
45
+ slug: z.ZodString;
46
+ description: z.ZodNullable<z.ZodString>;
47
+ sortOrder: z.ZodNumber;
48
+ }, z.core.$strip>>;
49
+ tags: z.ZodArray<z.ZodObject<{
50
+ id: z.ZodString;
51
+ name: z.ZodString;
52
+ }, z.core.$strip>>;
53
+ capabilities: z.ZodArray<z.ZodEnum<{
54
+ on_request: "on_request";
55
+ private: "private";
56
+ instant_confirmation: "instant_confirmation";
57
+ pickup_available: "pickup_available";
58
+ dropoff_available: "dropoff_available";
59
+ guided: "guided";
60
+ shared: "shared";
61
+ digital_ticket: "digital_ticket";
62
+ voucher_required: "voucher_required";
63
+ external_inventory: "external_inventory";
64
+ multi_day: "multi_day";
65
+ accommodation: "accommodation";
66
+ transport: "transport";
67
+ }>>;
68
+ destinations: z.ZodArray<z.ZodObject<{
69
+ id: z.ZodString;
70
+ parentId: z.ZodNullable<z.ZodString>;
71
+ slug: z.ZodString;
72
+ name: z.ZodString;
73
+ description: z.ZodNullable<z.ZodString>;
74
+ seoTitle: z.ZodNullable<z.ZodString>;
75
+ seoDescription: z.ZodNullable<z.ZodString>;
76
+ destinationType: z.ZodEnum<{
77
+ city: "city";
78
+ destination: "destination";
79
+ region: "region";
80
+ country: "country";
81
+ }>;
82
+ sortOrder: z.ZodNumber;
83
+ }, z.core.$strip>>;
84
+ locations: z.ZodArray<z.ZodObject<{
85
+ id: z.ZodString;
86
+ locationType: z.ZodEnum<{
87
+ other: "other";
88
+ start: "start";
89
+ end: "end";
90
+ meeting_point: "meeting_point";
91
+ pickup: "pickup";
92
+ dropoff: "dropoff";
93
+ point_of_interest: "point_of_interest";
94
+ }>;
95
+ title: z.ZodString;
96
+ address: z.ZodNullable<z.ZodString>;
97
+ city: z.ZodNullable<z.ZodString>;
98
+ countryCode: z.ZodNullable<z.ZodString>;
99
+ latitude: z.ZodNullable<z.ZodNumber>;
100
+ longitude: z.ZodNullable<z.ZodNumber>;
101
+ sortOrder: z.ZodNumber;
102
+ }, z.core.$strip>>;
103
+ coverMedia: z.ZodNullable<z.ZodObject<{
104
+ id: z.ZodString;
105
+ mediaType: z.ZodEnum<{
106
+ image: "image";
107
+ video: "video";
108
+ document: "document";
109
+ }>;
110
+ name: z.ZodString;
111
+ url: z.ZodString;
112
+ mimeType: z.ZodNullable<z.ZodString>;
113
+ altText: z.ZodNullable<z.ZodString>;
114
+ sortOrder: z.ZodNumber;
115
+ isCover: z.ZodBoolean;
116
+ isBrochure: z.ZodBoolean;
117
+ isBrochureCurrent: z.ZodBoolean;
118
+ brochureVersion: z.ZodNullable<z.ZodNumber>;
119
+ }, z.core.$strip>>;
120
+ isFeatured: z.ZodBoolean;
121
+ }, z.core.$strip>;
122
+ export declare const localizedCatalogProductDetailSchema: z.ZodObject<{
123
+ id: z.ZodString;
124
+ name: z.ZodString;
125
+ description: z.ZodNullable<z.ZodString>;
126
+ contentLanguageTag: z.ZodNullable<z.ZodString>;
127
+ slug: z.ZodNullable<z.ZodString>;
128
+ shortDescription: z.ZodNullable<z.ZodString>;
129
+ seoTitle: z.ZodNullable<z.ZodString>;
130
+ seoDescription: z.ZodNullable<z.ZodString>;
131
+ bookingMode: z.ZodEnum<{
132
+ date: "date";
133
+ other: "other";
134
+ date_time: "date_time";
135
+ open: "open";
136
+ stay: "stay";
137
+ transfer: "transfer";
138
+ itinerary: "itinerary";
139
+ }>;
140
+ capacityMode: z.ZodEnum<{
141
+ free_sale: "free_sale";
142
+ limited: "limited";
143
+ on_request: "on_request";
144
+ }>;
145
+ visibility: z.ZodEnum<{
146
+ public: "public";
147
+ private: "private";
148
+ hidden: "hidden";
149
+ }>;
150
+ sellCurrency: z.ZodString;
151
+ sellAmountCents: z.ZodNullable<z.ZodNumber>;
152
+ startDate: z.ZodNullable<z.ZodString>;
153
+ endDate: z.ZodNullable<z.ZodString>;
154
+ pax: z.ZodNullable<z.ZodNumber>;
155
+ productType: z.ZodNullable<z.ZodObject<{
156
+ id: z.ZodString;
157
+ code: z.ZodString;
158
+ name: z.ZodString;
159
+ description: z.ZodNullable<z.ZodString>;
160
+ }, z.core.$strip>>;
161
+ categories: z.ZodArray<z.ZodObject<{
162
+ id: z.ZodString;
163
+ parentId: z.ZodNullable<z.ZodString>;
164
+ name: z.ZodString;
165
+ slug: z.ZodString;
166
+ description: z.ZodNullable<z.ZodString>;
167
+ sortOrder: z.ZodNumber;
168
+ }, z.core.$strip>>;
169
+ tags: z.ZodArray<z.ZodObject<{
170
+ id: z.ZodString;
171
+ name: z.ZodString;
172
+ }, z.core.$strip>>;
173
+ capabilities: z.ZodArray<z.ZodEnum<{
174
+ on_request: "on_request";
175
+ private: "private";
176
+ instant_confirmation: "instant_confirmation";
177
+ pickup_available: "pickup_available";
178
+ dropoff_available: "dropoff_available";
179
+ guided: "guided";
180
+ shared: "shared";
181
+ digital_ticket: "digital_ticket";
182
+ voucher_required: "voucher_required";
183
+ external_inventory: "external_inventory";
184
+ multi_day: "multi_day";
185
+ accommodation: "accommodation";
186
+ transport: "transport";
187
+ }>>;
188
+ destinations: z.ZodArray<z.ZodObject<{
189
+ id: z.ZodString;
190
+ parentId: z.ZodNullable<z.ZodString>;
191
+ slug: z.ZodString;
192
+ name: z.ZodString;
193
+ description: z.ZodNullable<z.ZodString>;
194
+ seoTitle: z.ZodNullable<z.ZodString>;
195
+ seoDescription: z.ZodNullable<z.ZodString>;
196
+ destinationType: z.ZodEnum<{
197
+ city: "city";
198
+ destination: "destination";
199
+ region: "region";
200
+ country: "country";
201
+ }>;
202
+ sortOrder: z.ZodNumber;
203
+ }, z.core.$strip>>;
204
+ locations: z.ZodArray<z.ZodObject<{
205
+ id: z.ZodString;
206
+ locationType: z.ZodEnum<{
207
+ other: "other";
208
+ start: "start";
209
+ end: "end";
210
+ meeting_point: "meeting_point";
211
+ pickup: "pickup";
212
+ dropoff: "dropoff";
213
+ point_of_interest: "point_of_interest";
214
+ }>;
215
+ title: z.ZodString;
216
+ address: z.ZodNullable<z.ZodString>;
217
+ city: z.ZodNullable<z.ZodString>;
218
+ countryCode: z.ZodNullable<z.ZodString>;
219
+ latitude: z.ZodNullable<z.ZodNumber>;
220
+ longitude: z.ZodNullable<z.ZodNumber>;
221
+ sortOrder: z.ZodNumber;
222
+ }, z.core.$strip>>;
223
+ coverMedia: z.ZodNullable<z.ZodObject<{
224
+ id: z.ZodString;
225
+ mediaType: z.ZodEnum<{
226
+ image: "image";
227
+ video: "video";
228
+ document: "document";
229
+ }>;
230
+ name: z.ZodString;
231
+ url: z.ZodString;
232
+ mimeType: z.ZodNullable<z.ZodString>;
233
+ altText: z.ZodNullable<z.ZodString>;
234
+ sortOrder: z.ZodNumber;
235
+ isCover: z.ZodBoolean;
236
+ isBrochure: z.ZodBoolean;
237
+ isBrochureCurrent: z.ZodBoolean;
238
+ brochureVersion: z.ZodNullable<z.ZodNumber>;
239
+ }, z.core.$strip>>;
240
+ isFeatured: z.ZodBoolean;
241
+ brochure: z.ZodNullable<z.ZodObject<{
242
+ id: z.ZodString;
243
+ mediaType: z.ZodEnum<{
244
+ image: "image";
245
+ video: "video";
246
+ document: "document";
247
+ }>;
248
+ name: z.ZodString;
249
+ url: z.ZodString;
250
+ mimeType: z.ZodNullable<z.ZodString>;
251
+ altText: z.ZodNullable<z.ZodString>;
252
+ sortOrder: z.ZodNumber;
253
+ isCover: z.ZodBoolean;
254
+ isBrochure: z.ZodBoolean;
255
+ isBrochureCurrent: z.ZodBoolean;
256
+ brochureVersion: z.ZodNullable<z.ZodNumber>;
257
+ }, z.core.$strip>>;
258
+ media: z.ZodArray<z.ZodObject<{
259
+ id: z.ZodString;
260
+ mediaType: z.ZodEnum<{
261
+ image: "image";
262
+ video: "video";
263
+ document: "document";
264
+ }>;
265
+ name: z.ZodString;
266
+ url: z.ZodString;
267
+ mimeType: z.ZodNullable<z.ZodString>;
268
+ altText: z.ZodNullable<z.ZodString>;
269
+ sortOrder: z.ZodNumber;
270
+ isCover: z.ZodBoolean;
271
+ isBrochure: z.ZodBoolean;
272
+ isBrochureCurrent: z.ZodBoolean;
273
+ brochureVersion: z.ZodNullable<z.ZodNumber>;
274
+ }, z.core.$strip>>;
275
+ features: z.ZodArray<z.ZodObject<{
276
+ id: z.ZodString;
277
+ featureType: z.ZodEnum<{
278
+ other: "other";
279
+ inclusion: "inclusion";
280
+ exclusion: "exclusion";
281
+ highlight: "highlight";
282
+ important_information: "important_information";
283
+ }>;
284
+ title: z.ZodString;
285
+ description: z.ZodNullable<z.ZodString>;
286
+ sortOrder: z.ZodNumber;
287
+ }, z.core.$strip>>;
288
+ faqs: z.ZodArray<z.ZodObject<{
289
+ id: z.ZodString;
290
+ question: z.ZodString;
291
+ answer: z.ZodString;
292
+ sortOrder: z.ZodNumber;
293
+ }, z.core.$strip>>;
294
+ }, z.core.$strip>;
295
+ export declare const catalogSearchDocumentSchema: z.ZodObject<{
296
+ id: z.ZodString;
297
+ productId: z.ZodString;
298
+ languageTag: z.ZodNullable<z.ZodString>;
299
+ name: z.ZodString;
300
+ slug: z.ZodNullable<z.ZodString>;
301
+ shortDescription: z.ZodNullable<z.ZodString>;
302
+ description: z.ZodNullable<z.ZodString>;
303
+ seoTitle: z.ZodNullable<z.ZodString>;
304
+ seoDescription: z.ZodNullable<z.ZodString>;
305
+ sellCurrency: z.ZodString;
306
+ sellAmountCents: z.ZodNullable<z.ZodNumber>;
307
+ startDate: z.ZodNullable<z.ZodString>;
308
+ endDate: z.ZodNullable<z.ZodString>;
309
+ pax: z.ZodNullable<z.ZodNumber>;
310
+ productTypeCode: z.ZodNullable<z.ZodString>;
311
+ productTypeName: z.ZodNullable<z.ZodString>;
312
+ categoryIds: z.ZodArray<z.ZodString>;
313
+ categoryNames: z.ZodArray<z.ZodString>;
314
+ categorySlugs: z.ZodArray<z.ZodString>;
315
+ tagIds: z.ZodArray<z.ZodString>;
316
+ tagNames: z.ZodArray<z.ZodString>;
317
+ capabilities: z.ZodArray<z.ZodString>;
318
+ destinationIds: z.ZodArray<z.ZodString>;
319
+ destinationNames: z.ZodArray<z.ZodString>;
320
+ destinationSlugs: z.ZodArray<z.ZodString>;
321
+ locationTitles: z.ZodArray<z.ZodString>;
322
+ locationCities: z.ZodArray<z.ZodString>;
323
+ locationCountryCodes: z.ZodArray<z.ZodString>;
324
+ coverMediaUrl: z.ZodNullable<z.ZodString>;
325
+ isFeatured: z.ZodBoolean;
326
+ createdAt: z.ZodNullable<z.ZodString>;
327
+ updatedAt: z.ZodNullable<z.ZodString>;
328
+ }, z.core.$strip>;
329
+ export declare const catalogSearchDocumentListQuerySchema: z.ZodObject<{
330
+ productIds: z.ZodOptional<z.ZodArray<z.ZodString>>;
331
+ languageTag: z.ZodOptional<z.ZodString>;
332
+ fallbackLanguageTags: z.ZodOptional<z.ZodArray<z.ZodString>>;
333
+ visibility: z.ZodDefault<z.ZodEnum<{
334
+ all: "all";
335
+ public: "public";
336
+ }>>;
337
+ status: z.ZodDefault<z.ZodEnum<{
338
+ all: "all";
339
+ active: "active";
340
+ }>>;
341
+ limit: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
342
+ offset: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
343
+ }, z.core.$strip>;
344
+ export declare const catalogSearchDocumentListResponseSchema: z.ZodObject<{
345
+ data: z.ZodArray<z.ZodObject<{
346
+ id: z.ZodString;
347
+ productId: z.ZodString;
348
+ languageTag: z.ZodNullable<z.ZodString>;
349
+ name: z.ZodString;
350
+ slug: z.ZodNullable<z.ZodString>;
351
+ shortDescription: z.ZodNullable<z.ZodString>;
352
+ description: z.ZodNullable<z.ZodString>;
353
+ seoTitle: z.ZodNullable<z.ZodString>;
354
+ seoDescription: z.ZodNullable<z.ZodString>;
355
+ sellCurrency: z.ZodString;
356
+ sellAmountCents: z.ZodNullable<z.ZodNumber>;
357
+ startDate: z.ZodNullable<z.ZodString>;
358
+ endDate: z.ZodNullable<z.ZodString>;
359
+ pax: z.ZodNullable<z.ZodNumber>;
360
+ productTypeCode: z.ZodNullable<z.ZodString>;
361
+ productTypeName: z.ZodNullable<z.ZodString>;
362
+ categoryIds: z.ZodArray<z.ZodString>;
363
+ categoryNames: z.ZodArray<z.ZodString>;
364
+ categorySlugs: z.ZodArray<z.ZodString>;
365
+ tagIds: z.ZodArray<z.ZodString>;
366
+ tagNames: z.ZodArray<z.ZodString>;
367
+ capabilities: z.ZodArray<z.ZodString>;
368
+ destinationIds: z.ZodArray<z.ZodString>;
369
+ destinationNames: z.ZodArray<z.ZodString>;
370
+ destinationSlugs: z.ZodArray<z.ZodString>;
371
+ locationTitles: z.ZodArray<z.ZodString>;
372
+ locationCities: z.ZodArray<z.ZodString>;
373
+ locationCountryCodes: z.ZodArray<z.ZodString>;
374
+ coverMediaUrl: z.ZodNullable<z.ZodString>;
375
+ isFeatured: z.ZodBoolean;
376
+ createdAt: z.ZodNullable<z.ZodString>;
377
+ updatedAt: z.ZodNullable<z.ZodString>;
378
+ }, z.core.$strip>>;
379
+ total: z.ZodNumber;
380
+ limit: z.ZodNumber;
381
+ offset: z.ZodNumber;
382
+ }, z.core.$strip>;
383
+ export type LocalizedCatalogProductSummary = z.infer<typeof localizedCatalogProductSummarySchema>;
384
+ export type LocalizedCatalogProductDetail = z.infer<typeof localizedCatalogProductDetailSchema>;
385
+ export type CatalogSearchDocument = z.infer<typeof catalogSearchDocumentSchema>;
386
+ export type CatalogSearchDocumentListQuery = z.infer<typeof catalogSearchDocumentListQuerySchema>;
387
+ export type CatalogSearchDocumentListResponse = z.infer<typeof catalogSearchDocumentListResponseSchema>;
388
+ //# sourceMappingURL=validation-catalog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation-catalog.d.ts","sourceRoot":"","sources":["../src/validation-catalog.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAQvB,eAAO,MAAM,oCAAoC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAAoC,CAAA;AACrF,eAAO,MAAM,mCAAmC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAAmC,CAAA;AAEnF,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAiCtC,CAAA;AAEF,eAAO,MAAM,oCAAoC;;;;;;;;;;;;;;iBAQ/C,CAAA;AAEF,eAAO,MAAM,uCAAuC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAKlD,CAAA;AAEF,MAAM,MAAM,8BAA8B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oCAAoC,CAAC,CAAA;AACjG,MAAM,MAAM,6BAA6B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mCAAmC,CAAC,CAAA;AAC/F,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAA;AAC/E,MAAM,MAAM,8BAA8B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oCAAoC,CAAC,CAAA;AACjG,MAAM,MAAM,iCAAiC,GAAG,CAAC,CAAC,KAAK,CACrD,OAAO,uCAAuC,CAC/C,CAAA"}
@@ -0,0 +1,54 @@
1
+ import { z } from "zod";
2
+ import { publicCatalogProductDetailSchema, publicCatalogProductSummarySchema, } from "./validation-public.js";
3
+ import { languageTagSchema } from "./validation-shared.js";
4
+ export const localizedCatalogProductSummarySchema = publicCatalogProductSummarySchema;
5
+ export const localizedCatalogProductDetailSchema = publicCatalogProductDetailSchema;
6
+ export const catalogSearchDocumentSchema = z.object({
7
+ id: z.string(),
8
+ productId: z.string(),
9
+ languageTag: z.string().nullable(),
10
+ name: z.string(),
11
+ slug: z.string().nullable(),
12
+ shortDescription: z.string().nullable(),
13
+ description: z.string().nullable(),
14
+ seoTitle: z.string().nullable(),
15
+ seoDescription: z.string().nullable(),
16
+ sellCurrency: z.string(),
17
+ sellAmountCents: z.number().int().nullable(),
18
+ startDate: z.string().nullable(),
19
+ endDate: z.string().nullable(),
20
+ pax: z.number().int().nullable(),
21
+ productTypeCode: z.string().nullable(),
22
+ productTypeName: z.string().nullable(),
23
+ categoryIds: z.array(z.string()),
24
+ categoryNames: z.array(z.string()),
25
+ categorySlugs: z.array(z.string()),
26
+ tagIds: z.array(z.string()),
27
+ tagNames: z.array(z.string()),
28
+ capabilities: z.array(z.string()),
29
+ destinationIds: z.array(z.string()),
30
+ destinationNames: z.array(z.string()),
31
+ destinationSlugs: z.array(z.string()),
32
+ locationTitles: z.array(z.string()),
33
+ locationCities: z.array(z.string()),
34
+ locationCountryCodes: z.array(z.string()),
35
+ coverMediaUrl: z.string().nullable(),
36
+ isFeatured: z.boolean(),
37
+ createdAt: z.string().nullable(),
38
+ updatedAt: z.string().nullable(),
39
+ });
40
+ export const catalogSearchDocumentListQuerySchema = z.object({
41
+ productIds: z.array(z.string()).optional(),
42
+ languageTag: languageTagSchema.optional(),
43
+ fallbackLanguageTags: z.array(languageTagSchema).optional(),
44
+ visibility: z.enum(["public", "all"]).default("public"),
45
+ status: z.enum(["active", "all"]).default("active"),
46
+ limit: z.coerce.number().int().min(1).max(200).default(100),
47
+ offset: z.coerce.number().int().min(0).default(0),
48
+ });
49
+ export const catalogSearchDocumentListResponseSchema = z.object({
50
+ data: z.array(catalogSearchDocumentSchema),
51
+ total: z.number().int(),
52
+ limit: z.number().int(),
53
+ offset: z.number().int(),
54
+ });