@voyant-travel/inventory 0.3.6 → 0.3.8

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.
@@ -1,10 +1,14 @@
1
1
  import type { KVStore } from "@voyant-travel/utils/cache";
2
2
  export declare function productDocKey(productId: string, variant: string): string;
3
- export declare function productSlugMapKey(slug: string): string;
3
+ export declare function productSlugMapKey(slug: string, variant: string): string;
4
4
  /** Stable variant id from the detail query (currently just the locale). */
5
5
  export declare function productDocVariant(query: {
6
6
  languageTag?: string | null;
7
7
  }): string;
8
+ export interface ProductSlugResolution {
9
+ productId: string;
10
+ languageTag: string | null;
11
+ }
8
12
  /**
9
13
  * Read-through document fetch. `null` compute results (missing/inactive
10
14
  * product) are never cached — a 404 must not mask a product that
@@ -15,7 +19,7 @@ export declare function readThroughProductDoc<T>(kv: KVStore | undefined, key: s
15
19
  fromReadModel: boolean;
16
20
  }>;
17
21
  /** Resolve a slug to a product id through the KV mapping. */
18
- export declare function readThroughSlugMapping(kv: KVStore | undefined, slug: string, resolve: () => Promise<string | null>): Promise<string | null>;
22
+ export declare function readThroughSlugMapping(kv: KVStore | undefined, slug: string, variant: string, resolve: () => Promise<ProductSlugResolution | null>): Promise<ProductSlugResolution | null>;
19
23
  /**
20
24
  * Drop every cached document variant for a product. Uses KV `list` by
21
25
  * prefix (optional on the KVStore contract — silently a no-op without
@@ -1 +1 @@
1
- {"version":3,"file":"read-model.d.ts","sourceRoot":"","sources":["../src/read-model.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAA;AA2BzD,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAExE;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED,2EAA2E;AAC3E,wBAAgB,iBAAiB,CAAC,KAAK,EAAE;IAAE,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAAG,MAAM,CAEhF;AAED;;;;GAIG;AACH,wBAAsB,qBAAqB,CAAC,CAAC,EAC3C,EAAE,EAAE,OAAO,GAAG,SAAS,EACvB,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,GAC/B,OAAO,CAAC;IAAE,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC;IAAC,aAAa,EAAE,OAAO,CAAA;CAAE,CAAC,CAkBrD;AAED,6DAA6D;AAC7D,wBAAsB,sBAAsB,CAC1C,EAAE,EAAE,OAAO,GAAG,SAAS,EACvB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,GACpC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAkBxB;AAED;;;;GAIG;AACH,wBAAsB,0BAA0B,CAAC,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAQ9F"}
1
+ {"version":3,"file":"read-model.d.ts","sourceRoot":"","sources":["../src/read-model.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAA;AA2BzD,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAExE;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAEvE;AAED,2EAA2E;AAC3E,wBAAgB,iBAAiB,CAAC,KAAK,EAAE;IAAE,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAAG,MAAM,CAEhF;AAED,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;CAC3B;AAED;;;;GAIG;AACH,wBAAsB,qBAAqB,CAAC,CAAC,EAC3C,EAAE,EAAE,OAAO,GAAG,SAAS,EACvB,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,GAC/B,OAAO,CAAC;IAAE,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC;IAAC,aAAa,EAAE,OAAO,CAAA;CAAE,CAAC,CAkBrD;AAED,6DAA6D;AAC7D,wBAAsB,sBAAsB,CAC1C,EAAE,EAAE,OAAO,GAAG,SAAS,EACvB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC,GACnD,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC,CAmBvC;AAED;;;;GAIG;AACH,wBAAsB,0BAA0B,CAAC,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAQ9F"}
@@ -10,8 +10,8 @@
10
10
  * `productsReadModelInvalidation` in routes.ts), and a generous TTL
11
11
  * bounds staleness for anything invalidation misses.
12
12
  *
13
- * Slug lookups resolve through a short-lived slug→id mapping so the
14
- * id-keyed document is shared between `/:id` and `/slug/:slug`. The
13
+ * Slug lookups resolve through a short-lived slug→product+locale mapping
14
+ * so the id-keyed document is shared between `/:id` and `/slug/:slug`. The
15
15
  * mapping is deliberately NOT invalidated on mutation: it's cheap to
16
16
  * refill, and its short TTL bounds the only affected case (a renamed
17
17
  * slug serving the old document) to a few minutes.
@@ -24,8 +24,8 @@ const SLUG_MAP_TTL_SECONDS = 5 * 60;
24
24
  export function productDocKey(productId, variant) {
25
25
  return `${RM_PREFIX}:${productId}:${variant}`;
26
26
  }
27
- export function productSlugMapKey(slug) {
28
- return `rm:v1:product-slug:${slug}`;
27
+ export function productSlugMapKey(slug, variant) {
28
+ return `rm:v1:product-slug:${variant}:${slug}`;
29
29
  }
30
30
  /** Stable variant id from the detail query (currently just the locale). */
31
31
  export function productDocVariant(query) {
@@ -59,10 +59,11 @@ export async function readThroughProductDoc(kv, key, compute) {
59
59
  return { data, fromReadModel: false };
60
60
  }
61
61
  /** Resolve a slug to a product id through the KV mapping. */
62
- export async function readThroughSlugMapping(kv, slug, resolve) {
62
+ export async function readThroughSlugMapping(kv, slug, variant, resolve) {
63
+ const key = productSlugMapKey(slug, variant);
63
64
  if (kv) {
64
65
  try {
65
- const hit = await kv.get(productSlugMapKey(slug), { type: "text" });
66
+ const hit = await kv.get(key, { type: "json" });
66
67
  if (hit)
67
68
  return hit;
68
69
  }
@@ -70,16 +71,16 @@ export async function readThroughSlugMapping(kv, slug, resolve) {
70
71
  // fall through
71
72
  }
72
73
  }
73
- const id = await resolve();
74
- if (id && kv) {
74
+ const resolution = await resolve();
75
+ if (resolution && kv) {
75
76
  try {
76
- await kv.put(productSlugMapKey(slug), id, { expirationTtl: SLUG_MAP_TTL_SECONDS });
77
+ await kv.put(key, JSON.stringify(resolution), { expirationTtl: SLUG_MAP_TTL_SECONDS });
77
78
  }
78
79
  catch {
79
80
  // best-effort
80
81
  }
81
82
  }
82
- return id;
83
+ return resolution;
83
84
  }
84
85
  /**
85
86
  * Drop every cached document variant for a product. Uses KV `list` by
@@ -1 +1 @@
1
- {"version":3,"file":"routes-public.d.ts","sourceRoot":"","sources":["../src/routes-public.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAA;AACzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAqBjE,KAAK,GAAG,GAAG;IACT,QAAQ,EAAE;QACR,mEAAmE;QACnE,KAAK,CAAC,EAAE,OAAO,CAAA;KAChB,CAAA;IACD,SAAS,EAAE;QACT,EAAE,EAAE,kBAAkB,CAAA;QACtB,MAAM,CAAC,EAAE,MAAM,CAAA;KAChB,CAAA;CACF,CAAA;AA2DD,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBAkF5B,CAAA;AAEJ,MAAM,MAAM,mBAAmB,GAAG,OAAO,mBAAmB,CAAA"}
1
+ {"version":3,"file":"routes-public.d.ts","sourceRoot":"","sources":["../src/routes-public.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAA;AACzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAqBjE,KAAK,GAAG,GAAG;IACT,QAAQ,EAAE;QACR,mEAAmE;QACnE,KAAK,CAAC,EAAE,OAAO,CAAA;KAChB,CAAA;IACD,SAAS,EAAE;QACT,EAAE,EAAE,kBAAkB,CAAA;QACtB,MAAM,CAAC,EAAE,MAAM,CAAA;KAChB,CAAA;CACF,CAAA;AA2DD,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBAgG5B,CAAA;AAEJ,MAAM,MAAM,mBAAmB,GAAG,OAAO,mBAAmB,CAAA"}
@@ -66,14 +66,26 @@ export const publicProductRoutes = new Hono()
66
66
  const slug = c.req.param("slug");
67
67
  // Resolve slug → id through the short-lived KV mapping so both detail
68
68
  // routes share one id-keyed document per variant.
69
- const productId = await readThroughSlugMapping(kv, slug, async () => {
69
+ const requestedVariant = productDocVariant(query);
70
+ const resolution = await readThroughSlugMapping(kv, slug, requestedVariant, async () => {
70
71
  const row = await publicProductsService.getCatalogProductBySlug(c.get("db"), slug, query);
71
- return row ? (row.id ?? null) : null;
72
+ const productId = row ? (row.id ?? null) : null;
73
+ if (!productId)
74
+ return null;
75
+ return {
76
+ productId,
77
+ languageTag: row.contentLanguageTag ??
78
+ query.languageTag ??
79
+ null,
80
+ };
72
81
  });
73
- if (!productId) {
82
+ if (!resolution) {
74
83
  return c.json({ error: "Catalog product not found" }, 404);
75
84
  }
76
- const { data } = await readThroughProductDoc(kv, productDocKey(productId, productDocVariant(query)), () => publicProductsService.getCatalogProductById(c.get("db"), productId, query));
85
+ const detailQuery = resolution.languageTag
86
+ ? { ...query, languageTag: resolution.languageTag }
87
+ : query;
88
+ const { data } = await readThroughProductDoc(kv, productDocKey(resolution.productId, productDocVariant(detailQuery)), () => publicProductsService.getCatalogProductById(c.get("db"), resolution.productId, detailQuery));
77
89
  if (!data) {
78
90
  return c.json({ error: "Catalog product not found" }, 404);
79
91
  }
@@ -7,6 +7,7 @@ type HydrateCatalogProductOptions = {
7
7
  languageTag?: string | null;
8
8
  fallbackLanguageTags?: string[];
9
9
  };
10
+ export declare const DEFAULT_CATALOG_SEARCH_FALLBACK_LANGUAGE_TAGS: readonly ["en", "ro"];
10
11
  export declare const catalogProductsService: {
11
12
  hydrateProducts(db: PostgresJsDatabase, productRows: CatalogProductRow[], options?: HydrateCatalogProductOptions): Promise<({
12
13
  description: string | null;
@@ -1 +1 @@
1
- {"version":3,"file":"service-catalog.d.ts","sourceRoot":"","sources":["../src/service-catalog.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAEjE,OAAO,EAWL,QAAQ,EAMT,MAAM,aAAa,CAAA;AACpB,OAAO,KAAK,EACV,qBAAqB,EACrB,8BAA8B,EAE/B,MAAM,yBAAyB,CAAA;AAEhC,KAAK,iBAAiB,GAAG,OAAO,QAAQ,CAAC,YAAY,CAAA;AAErD,KAAK,4BAA4B,GAAG;IAClC,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAA;CAChC,CAAA;AA2aD,eAAO,MAAM,sBAAsB;wBAE3B,kBAAkB,eACT,iBAAiB,EAAE,YACvB,4BAA4B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4BAkIjC,kBAAkB,SACf,8BAA8B,GACpC,OAAO,CAAC;QACT,IAAI,EAAE,qBAAqB,EAAE,CAAA;QAC7B,KAAK,EAAE,MAAM,CAAA;QACb,KAAK,EAAE,MAAM,CAAA;QACb,MAAM,EAAE,MAAM,CAAA;KACf,CAAC;qCAkFI,kBAAkB,aACX,MAAM,UACV,OAAO,CAAC,IAAI,CAAC,8BAA8B,EAAE,YAAY,GAAG,OAAO,GAAG,QAAQ,CAAC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAa1F,CAAA"}
1
+ {"version":3,"file":"service-catalog.d.ts","sourceRoot":"","sources":["../src/service-catalog.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAEjE,OAAO,EAWL,QAAQ,EAMT,MAAM,aAAa,CAAA;AACpB,OAAO,KAAK,EACV,qBAAqB,EACrB,8BAA8B,EAE/B,MAAM,yBAAyB,CAAA;AAEhC,KAAK,iBAAiB,GAAG,OAAO,QAAQ,CAAC,YAAY,CAAA;AAErD,KAAK,4BAA4B,GAAG;IAClC,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAA;CAChC,CAAA;AAED,eAAO,MAAM,6CAA6C,uBAAwB,CAAA;AA2alF,eAAO,MAAM,sBAAsB;wBAE3B,kBAAkB,eACT,iBAAiB,EAAE,YACvB,4BAA4B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4BAkIjC,kBAAkB,SACf,8BAA8B,GACpC,OAAO,CAAC;QACT,IAAI,EAAE,qBAAqB,EAAE,CAAA;QAC7B,KAAK,EAAE,MAAM,CAAA;QACb,KAAK,EAAE,MAAM,CAAA;QACb,MAAM,EAAE,MAAM,CAAA;KACf,CAAC;qCAoFI,kBAAkB,aACX,MAAM,UACV,OAAO,CAAC,IAAI,CAAC,8BAA8B,EAAE,YAAY,GAAG,OAAO,GAAG,QAAQ,CAAC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAa1F,CAAA"}
@@ -1,6 +1,7 @@
1
1
  // agent-quality: file-size exception -- owner: inventory; existing service module stays co-located until a dedicated split preserves behavior and tests.
2
2
  import { and, asc, desc, eq, inArray, sql } from "drizzle-orm";
3
3
  import { destinations, destinationTranslations, productCapabilities, productCategories, productCategoryProducts, productDestinations, productFaqs, productFeatures, productLocations, productMedia, products, productTagProducts, productTags, productTranslations, productTypes, productVisibilitySettings, } from "./schema.js";
4
+ export const DEFAULT_CATALOG_SEARCH_FALLBACK_LANGUAGE_TAGS = ["en", "ro"];
4
5
  function normalizeDate(value) {
5
6
  if (!value) {
6
7
  return null;
@@ -456,7 +457,8 @@ export const catalogProductsService = {
456
457
  const localizedProducts = (await this.hydrateProducts(db, rows, {
457
458
  includeContent: true,
458
459
  languageTag: query.languageTag,
459
- fallbackLanguageTags: query.fallbackLanguageTags ?? (query.languageTag ? ["en", "ro"] : []),
460
+ fallbackLanguageTags: query.fallbackLanguageTags ??
461
+ (query.languageTag ? [...DEFAULT_CATALOG_SEARCH_FALLBACK_LANGUAGE_TAGS] : []),
460
462
  }));
461
463
  const rowById = new Map(rows.map((row) => [row.id, row]));
462
464
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"service-public.d.ts","sourceRoot":"","sources":["../src/service-public.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAgBjE,OAAO,KAAK,EACV,8BAA8B,EAC9B,iCAAiC,EACjC,6BAA6B,EAC7B,qCAAqC,EACrC,yBAAyB,EAC1B,MAAM,wBAAwB,CAAA;AAgI/B,eAAO,MAAM,qBAAqB;4BAE1B,kBAAkB,SACf,6BAA6B,GAAG;QAAE,cAAc,CAAC,EAAE,OAAO,CAAA;KAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8BA6H/D,kBAAkB,MAClB,MAAM,UACH;QAAE,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gCA2BlC,kBAAkB,QAChB,MAAM,UACL,qCAAqC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kCAqCxC,kBAAkB,aACX,MAAM,UACV;QAAE,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE;;;;;;;;;;;;;8BAMR,kBAAkB,SAAS,8BAA8B;;;;;;;;;;;;;wBAkD/D,kBAAkB,SAAS,yBAAyB;;;;;;;;;gCA+B5C,kBAAkB,SAAS,iCAAiC;;;;;;;;;;;;;;;;;;;CAqG/F,CAAA"}
1
+ {"version":3,"file":"service-public.d.ts","sourceRoot":"","sources":["../src/service-public.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAmBjE,OAAO,KAAK,EACV,8BAA8B,EAC9B,iCAAiC,EACjC,6BAA6B,EAC7B,qCAAqC,EACrC,yBAAyB,EAC1B,MAAM,wBAAwB,CAAA;AA0I/B,eAAO,MAAM,qBAAqB;4BAE1B,kBAAkB,SACf,6BAA6B,GAAG;QAAE,cAAc,CAAC,EAAE,OAAO,CAAA;KAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8BA6H/D,kBAAkB,MAClB,MAAM,UACH;QAAE,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gCA2BlC,kBAAkB,QAChB,MAAM,UACL,qCAAqC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kCAoDxC,kBAAkB,aACX,MAAM,UACV;QAAE,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE;;;;;;;;;;;;;8BAMR,kBAAkB,SAAS,8BAA8B;;;;;;;;;;;;;wBAkD/D,kBAAkB,SAAS,yBAAyB;;;;;;;;;gCA+B5C,kBAAkB,SAAS,iCAAiC;;;;;;;;;;;;;;;;;;;CAqG/F,CAAA"}
@@ -1,7 +1,7 @@
1
1
  // agent-quality: file-size exception -- owner: inventory; existing service module stays co-located until a dedicated split preserves behavior and tests.
2
2
  import { and, asc, desc, eq, ilike, inArray, notInArray, or, sql } from "drizzle-orm";
3
3
  import { destinations, destinationTranslations, productCategories, productCategoryProducts, productDestinations, productLocations, products, productTagProducts, productTags, productTranslations, productVisibilitySettings, } from "./schema.js";
4
- import { catalogProductsService } from "./service-catalog.js";
4
+ import { catalogProductsService, DEFAULT_CATALOG_SEARCH_FALLBACK_LANGUAGE_TAGS, } from "./service-catalog.js";
5
5
  function impossibleCondition() {
6
6
  return sql `1 = 0`;
7
7
  }
@@ -9,6 +9,11 @@ function normalizeLanguageTag(value) {
9
9
  const normalized = value?.trim().toLowerCase();
10
10
  return normalized || null;
11
11
  }
12
+ function normalizeLanguageTagList(values) {
13
+ return Array.from(new Set(values
14
+ .map((value) => normalizeLanguageTag(value))
15
+ .filter((value) => Boolean(value))));
16
+ }
12
17
  async function listProductIdsForCategory(db, categoryId) {
13
18
  const rows = await db
14
19
  .select({ productId: productCategoryProducts.productId })
@@ -198,6 +203,12 @@ export const publicProductsService = {
198
203
  async getCatalogProductBySlug(db, slug, query = {}) {
199
204
  const normalizedSlug = slug.trim().toLowerCase();
200
205
  const normalizedLanguageTag = normalizeLanguageTag(query.languageTag);
206
+ const candidateLanguageTags = normalizedLanguageTag
207
+ ? normalizeLanguageTagList([
208
+ normalizedLanguageTag,
209
+ ...DEFAULT_CATALOG_SEARCH_FALLBACK_LANGUAGE_TAGS,
210
+ ])
211
+ : [];
201
212
  const conditions = [
202
213
  // agent-quality: raw-sql reviewed -- owner: inventory; dynamic SQL interpolation uses Drizzle parameter binding or vetted SQL identifiers.
203
214
  sql `lower(${productTranslations.slug}) = ${normalizedSlug}`,
@@ -206,9 +217,9 @@ export const publicProductsService = {
206
217
  eq(products.visibility, "public"),
207
218
  ];
208
219
  if (normalizedLanguageTag) {
209
- conditions.push(eq(productTranslations.languageTag, normalizedLanguageTag));
220
+ conditions.push(inArray(productTranslations.languageTag, candidateLanguageTags));
210
221
  }
211
- const [row] = await db
222
+ const rows = await db
212
223
  .select({
213
224
  productId: products.id,
214
225
  languageTag: productTranslations.languageTag,
@@ -217,12 +228,17 @@ export const publicProductsService = {
217
228
  .innerJoin(products, eq(products.id, productTranslations.productId))
218
229
  .where(and(...conditions))
219
230
  .orderBy(desc(productTranslations.updatedAt))
220
- .limit(1);
231
+ .limit(candidateLanguageTags.length || 1);
232
+ const row = candidateLanguageTags.length > 0
233
+ ? (candidateLanguageTags
234
+ .map((languageTag) => rows.find((item) => normalizeLanguageTag(item.languageTag) === languageTag))
235
+ .find(Boolean) ?? null)
236
+ : (rows[0] ?? null);
221
237
  if (!row) {
222
238
  return null;
223
239
  }
224
240
  return this.getCatalogProductById(db, row.productId, {
225
- languageTag: normalizedLanguageTag ?? row.languageTag,
241
+ languageTag: row.languageTag,
226
242
  });
227
243
  },
228
244
  async getCatalogProductBrochure(db, productId, query = {}) {
@@ -0,0 +1,774 @@
1
+ CREATE EXTENSION IF NOT EXISTS "pg_trgm";
2
+ --> statement-breakpoint
3
+ DO $$ BEGIN
4
+ CREATE TYPE "public"."extra_collection_mode" AS ENUM('booking_total', 'cash_on_trip', 'external', 'included', 'none');
5
+ EXCEPTION WHEN duplicate_object THEN null;
6
+ END $$;--> statement-breakpoint
7
+ DO $$ BEGIN
8
+ CREATE TYPE "public"."extra_pricing_mode" AS ENUM('included', 'per_person', 'per_booking', 'quantity_based', 'on_request', 'free');
9
+ EXCEPTION WHEN duplicate_object THEN null;
10
+ END $$;--> statement-breakpoint
11
+ DO $$ BEGIN
12
+ CREATE TYPE "public"."extra_selection_type" AS ENUM('optional', 'required', 'default_selected', 'unavailable');
13
+ EXCEPTION WHEN duplicate_object THEN null;
14
+ END $$;--> statement-breakpoint
15
+ DO $$ BEGIN
16
+ CREATE TYPE "public"."option_unit_type" AS ENUM('person', 'group', 'room', 'vehicle', 'service', 'other');
17
+ EXCEPTION WHEN duplicate_object THEN null;
18
+ END $$;--> statement-breakpoint
19
+ DO $$ BEGIN
20
+ CREATE TYPE "public"."product_activation_mode" AS ENUM('manual', 'scheduled', 'channel_controlled');
21
+ EXCEPTION WHEN duplicate_object THEN null;
22
+ END $$;--> statement-breakpoint
23
+ DO $$ BEGIN
24
+ CREATE TYPE "public"."product_booking_mode" AS ENUM('date', 'date_time', 'open', 'stay', 'transfer', 'itinerary', 'other');
25
+ EXCEPTION WHEN duplicate_object THEN null;
26
+ END $$;--> statement-breakpoint
27
+ DO $$ BEGIN
28
+ CREATE TYPE "public"."product_capability" AS ENUM('instant_confirmation', 'on_request', 'pickup_available', 'dropoff_available', 'guided', 'private', 'shared', 'digital_ticket', 'voucher_required', 'external_inventory', 'multi_day', 'accommodation', 'transport');
29
+ EXCEPTION WHEN duplicate_object THEN null;
30
+ END $$;--> statement-breakpoint
31
+ DO $$ BEGIN
32
+ CREATE TYPE "public"."product_capacity_mode" AS ENUM('free_sale', 'limited', 'on_request');
33
+ EXCEPTION WHEN duplicate_object THEN null;
34
+ END $$;--> statement-breakpoint
35
+ DO $$ BEGIN
36
+ CREATE TYPE "public"."product_delivery_format" AS ENUM('voucher', 'ticket', 'pdf', 'qr_code', 'barcode', 'email', 'mobile', 'none');
37
+ EXCEPTION WHEN duplicate_object THEN null;
38
+ END $$;--> statement-breakpoint
39
+ DO $$ BEGIN
40
+ CREATE TYPE "public"."product_feature_type" AS ENUM('inclusion', 'exclusion', 'highlight', 'important_information', 'other');
41
+ EXCEPTION WHEN duplicate_object THEN null;
42
+ END $$;--> statement-breakpoint
43
+ DO $$ BEGIN
44
+ CREATE TYPE "public"."product_location_type" AS ENUM('start', 'end', 'meeting_point', 'pickup', 'dropoff', 'point_of_interest', 'other');
45
+ EXCEPTION WHEN duplicate_object THEN null;
46
+ END $$;--> statement-breakpoint
47
+ DO $$ BEGIN
48
+ CREATE TYPE "public"."product_media_type" AS ENUM('image', 'video', 'document');
49
+ EXCEPTION WHEN duplicate_object THEN null;
50
+ END $$;--> statement-breakpoint
51
+ DO $$ BEGIN
52
+ CREATE TYPE "public"."product_option_status" AS ENUM('draft', 'active', 'archived');
53
+ EXCEPTION WHEN duplicate_object THEN null;
54
+ END $$;--> statement-breakpoint
55
+ DO $$ BEGIN
56
+ CREATE TYPE "public"."product_status" AS ENUM('draft', 'active', 'archived');
57
+ EXCEPTION WHEN duplicate_object THEN null;
58
+ END $$;--> statement-breakpoint
59
+ DO $$ BEGIN
60
+ CREATE TYPE "public"."product_ticket_fulfillment" AS ENUM('none', 'per_booking', 'per_participant', 'per_item');
61
+ EXCEPTION WHEN duplicate_object THEN null;
62
+ END $$;--> statement-breakpoint
63
+ DO $$ BEGIN
64
+ CREATE TYPE "public"."product_visibility" AS ENUM('public', 'private', 'hidden');
65
+ EXCEPTION WHEN duplicate_object THEN null;
66
+ END $$;--> statement-breakpoint
67
+ DO $$ BEGIN
68
+ CREATE TYPE "public"."service_type" AS ENUM('accommodation', 'transfer', 'experience', 'guide', 'meal', 'other');
69
+ EXCEPTION WHEN duplicate_object THEN null;
70
+ END $$;--> statement-breakpoint
71
+ CREATE TABLE "booking_item_product_details" (
72
+ "booking_item_id" text PRIMARY KEY NOT NULL,
73
+ "product_id" text,
74
+ "option_id" text,
75
+ "unit_id" text,
76
+ "supplier_service_id" text,
77
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
78
+ "updated_at" timestamp with time zone DEFAULT now() NOT NULL
79
+ );
80
+ --> statement-breakpoint
81
+ CREATE TABLE "booking_product_details" (
82
+ "booking_id" text PRIMARY KEY NOT NULL,
83
+ "product_id" text,
84
+ "option_id" text,
85
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
86
+ "updated_at" timestamp with time zone DEFAULT now() NOT NULL
87
+ );
88
+ --> statement-breakpoint
89
+ CREATE TABLE "products_sourced_content" (
90
+ "entity_id" text NOT NULL,
91
+ "locale" text NOT NULL,
92
+ "market" text DEFAULT '*' NOT NULL,
93
+ "payload" jsonb NOT NULL,
94
+ "content_schema_version" text NOT NULL,
95
+ "returned_locale" text NOT NULL,
96
+ "machine_translated" boolean DEFAULT false NOT NULL,
97
+ "source_updated_at" timestamp with time zone,
98
+ "fetched_at" timestamp with time zone DEFAULT now() NOT NULL,
99
+ "fresh_until" timestamp with time zone,
100
+ "etag" text,
101
+ "fetch_status" text DEFAULT 'ok' NOT NULL,
102
+ "fetch_error" text,
103
+ CONSTRAINT "products_sourced_content_entity_id_locale_market_pk" PRIMARY KEY("entity_id","locale","market")
104
+ );
105
+ --> statement-breakpoint
106
+ CREATE TABLE "extras_sourced_content" (
107
+ "entity_id" text NOT NULL,
108
+ "locale" text NOT NULL,
109
+ "market" text DEFAULT '*' NOT NULL,
110
+ "payload" jsonb NOT NULL,
111
+ "content_schema_version" text NOT NULL,
112
+ "returned_locale" text NOT NULL,
113
+ "machine_translated" boolean DEFAULT false NOT NULL,
114
+ "source_updated_at" timestamp with time zone,
115
+ "fetched_at" timestamp with time zone DEFAULT now() NOT NULL,
116
+ "fresh_until" timestamp with time zone,
117
+ "etag" text,
118
+ "fetch_status" text DEFAULT 'ok' NOT NULL,
119
+ "fetch_error" text,
120
+ CONSTRAINT "extras_sourced_content_entity_id_locale_market_pk" PRIMARY KEY("entity_id","locale","market")
121
+ );
122
+ --> statement-breakpoint
123
+ CREATE TABLE "option_extra_configs" (
124
+ "id" text PRIMARY KEY NOT NULL,
125
+ "option_id" text NOT NULL,
126
+ "product_extra_id" text NOT NULL,
127
+ "selection_type" "extra_selection_type",
128
+ "pricing_mode" "extra_pricing_mode",
129
+ "priced_per_person" boolean,
130
+ "min_quantity" integer,
131
+ "max_quantity" integer,
132
+ "default_quantity" integer,
133
+ "is_default" boolean DEFAULT false NOT NULL,
134
+ "active" boolean DEFAULT true NOT NULL,
135
+ "sort_order" integer DEFAULT 0 NOT NULL,
136
+ "notes" text,
137
+ "metadata" jsonb,
138
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
139
+ "updated_at" timestamp with time zone DEFAULT now() NOT NULL
140
+ );
141
+ --> statement-breakpoint
142
+ CREATE TABLE "product_extras" (
143
+ "id" text PRIMARY KEY NOT NULL,
144
+ "product_id" text NOT NULL,
145
+ "supplier_id" text,
146
+ "code" text,
147
+ "name" text NOT NULL,
148
+ "description" text,
149
+ "selection_type" "extra_selection_type" DEFAULT 'optional' NOT NULL,
150
+ "pricing_mode" "extra_pricing_mode" DEFAULT 'per_booking' NOT NULL,
151
+ "priced_per_person" boolean DEFAULT false NOT NULL,
152
+ "collection_mode" "extra_collection_mode" DEFAULT 'booking_total' NOT NULL,
153
+ "show_on_slot_manifest" boolean DEFAULT true NOT NULL,
154
+ "min_quantity" integer,
155
+ "max_quantity" integer,
156
+ "default_quantity" integer,
157
+ "active" boolean DEFAULT true NOT NULL,
158
+ "sort_order" integer DEFAULT 0 NOT NULL,
159
+ "metadata" jsonb,
160
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
161
+ "updated_at" timestamp with time zone DEFAULT now() NOT NULL
162
+ );
163
+ --> statement-breakpoint
164
+ CREATE TABLE "option_units" (
165
+ "id" text PRIMARY KEY NOT NULL,
166
+ "option_id" text NOT NULL,
167
+ "name" text NOT NULL,
168
+ "code" text,
169
+ "description" text,
170
+ "unit_type" "option_unit_type" DEFAULT 'person' NOT NULL,
171
+ "min_quantity" integer,
172
+ "max_quantity" integer,
173
+ "min_age" integer,
174
+ "max_age" integer,
175
+ "occupancy_min" integer,
176
+ "occupancy_max" integer,
177
+ "is_required" boolean DEFAULT false NOT NULL,
178
+ "is_hidden" boolean DEFAULT false NOT NULL,
179
+ "sort_order" integer DEFAULT 0 NOT NULL,
180
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
181
+ "updated_at" timestamp with time zone DEFAULT now() NOT NULL
182
+ );
183
+ --> statement-breakpoint
184
+ CREATE TABLE "product_options" (
185
+ "id" text PRIMARY KEY NOT NULL,
186
+ "product_id" text NOT NULL,
187
+ "name" text NOT NULL,
188
+ "code" text,
189
+ "description" text,
190
+ "status" "product_option_status" DEFAULT 'draft' NOT NULL,
191
+ "is_default" boolean DEFAULT false NOT NULL,
192
+ "sort_order" integer DEFAULT 0 NOT NULL,
193
+ "available_from" date,
194
+ "available_to" date,
195
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
196
+ "updated_at" timestamp with time zone DEFAULT now() NOT NULL
197
+ );
198
+ --> statement-breakpoint
199
+ CREATE TABLE "product_pax_pricing_tiers" (
200
+ "id" text PRIMARY KEY NOT NULL,
201
+ "product_id" text NOT NULL,
202
+ "option_unit_id" text,
203
+ "tier_pax" integer NOT NULL,
204
+ "price_per_pax_cents" integer NOT NULL,
205
+ "promo_price_per_pax_cents" integer,
206
+ "effective_from" date,
207
+ "effective_to" date,
208
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
209
+ "updated_at" timestamp with time zone DEFAULT now() NOT NULL
210
+ );
211
+ --> statement-breakpoint
212
+ CREATE TABLE "products" (
213
+ "id" text PRIMARY KEY NOT NULL,
214
+ "name" text NOT NULL,
215
+ "status" "product_status" DEFAULT 'draft' NOT NULL,
216
+ "description" text,
217
+ "inclusions_html" text,
218
+ "exclusions_html" text,
219
+ "terms_html" text,
220
+ "terms_show_on_contract" boolean DEFAULT false NOT NULL,
221
+ "booking_mode" "product_booking_mode" DEFAULT 'date' NOT NULL,
222
+ "capacity_mode" "product_capacity_mode" DEFAULT 'limited' NOT NULL,
223
+ "timezone" text,
224
+ "default_language_tag" text,
225
+ "visibility" "product_visibility" DEFAULT 'private' NOT NULL,
226
+ "activated" boolean DEFAULT false NOT NULL,
227
+ "reservation_timeout_minutes" integer,
228
+ "sell_currency" text NOT NULL,
229
+ "sell_amount_cents" integer,
230
+ "cost_amount_cents" integer,
231
+ "margin_percent" integer,
232
+ "facility_id" text,
233
+ "supplier_id" text,
234
+ "start_date" date,
235
+ "end_date" date,
236
+ "pax" integer,
237
+ "product_type_id" text,
238
+ "contract_template_id" text,
239
+ "tax_class_id" text,
240
+ "customer_payment_policy" jsonb,
241
+ "tags" jsonb DEFAULT '[]'::jsonb,
242
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
243
+ "updated_at" timestamp with time zone DEFAULT now() NOT NULL
244
+ );
245
+ --> statement-breakpoint
246
+ CREATE TABLE "product_day_services" (
247
+ "id" text PRIMARY KEY NOT NULL,
248
+ "day_id" text NOT NULL,
249
+ "supplier_service_id" text,
250
+ "service_type" "service_type" NOT NULL,
251
+ "name" text NOT NULL,
252
+ "description" text,
253
+ "country_code" text,
254
+ "cost_currency" text NOT NULL,
255
+ "cost_amount_cents" integer NOT NULL,
256
+ "quantity" integer DEFAULT 1 NOT NULL,
257
+ "sort_order" integer,
258
+ "notes" text,
259
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL
260
+ );
261
+ --> statement-breakpoint
262
+ CREATE TABLE "product_day_translations" (
263
+ "id" text PRIMARY KEY NOT NULL,
264
+ "day_id" text NOT NULL,
265
+ "language_tag" text NOT NULL,
266
+ "title" text,
267
+ "description" text,
268
+ "location" text,
269
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
270
+ "updated_at" timestamp with time zone DEFAULT now() NOT NULL
271
+ );
272
+ --> statement-breakpoint
273
+ CREATE TABLE "product_days" (
274
+ "id" text PRIMARY KEY NOT NULL,
275
+ "itinerary_id" text NOT NULL,
276
+ "day_number" integer NOT NULL,
277
+ "title" text,
278
+ "description" text,
279
+ "location" text,
280
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
281
+ "updated_at" timestamp with time zone DEFAULT now() NOT NULL
282
+ );
283
+ --> statement-breakpoint
284
+ CREATE TABLE "product_itineraries" (
285
+ "id" text PRIMARY KEY NOT NULL,
286
+ "product_id" text NOT NULL,
287
+ "name" text NOT NULL,
288
+ "is_default" boolean DEFAULT false NOT NULL,
289
+ "sort_order" integer DEFAULT 0 NOT NULL,
290
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
291
+ "updated_at" timestamp with time zone DEFAULT now() NOT NULL
292
+ );
293
+ --> statement-breakpoint
294
+ CREATE TABLE "product_media" (
295
+ "id" text PRIMARY KEY NOT NULL,
296
+ "product_id" text NOT NULL,
297
+ "day_id" text,
298
+ "media_type" "product_media_type" NOT NULL,
299
+ "name" text NOT NULL,
300
+ "url" text NOT NULL,
301
+ "storage_key" text,
302
+ "mime_type" text,
303
+ "file_size" integer,
304
+ "alt_text" text,
305
+ "sort_order" integer DEFAULT 0 NOT NULL,
306
+ "is_cover" boolean DEFAULT false NOT NULL,
307
+ "is_brochure" boolean DEFAULT false NOT NULL,
308
+ "is_brochure_current" boolean DEFAULT false NOT NULL,
309
+ "brochure_version" integer,
310
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
311
+ "updated_at" timestamp with time zone DEFAULT now() NOT NULL
312
+ );
313
+ --> statement-breakpoint
314
+ CREATE TABLE "product_notes" (
315
+ "id" text PRIMARY KEY NOT NULL,
316
+ "product_id" text NOT NULL,
317
+ "author_id" text NOT NULL,
318
+ "content" text NOT NULL,
319
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL
320
+ );
321
+ --> statement-breakpoint
322
+ CREATE TABLE "product_versions" (
323
+ "id" text PRIMARY KEY NOT NULL,
324
+ "product_id" text NOT NULL,
325
+ "version_number" integer NOT NULL,
326
+ "snapshot" jsonb NOT NULL,
327
+ "author_id" text NOT NULL,
328
+ "notes" text,
329
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL
330
+ );
331
+ --> statement-breakpoint
332
+ CREATE TABLE "option_unit_translations" (
333
+ "id" text PRIMARY KEY NOT NULL,
334
+ "unit_id" text NOT NULL,
335
+ "language_tag" text NOT NULL,
336
+ "name" text NOT NULL,
337
+ "short_description" text,
338
+ "description" text,
339
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
340
+ "updated_at" timestamp with time zone DEFAULT now() NOT NULL
341
+ );
342
+ --> statement-breakpoint
343
+ CREATE TABLE "product_activation_settings" (
344
+ "id" text PRIMARY KEY NOT NULL,
345
+ "product_id" text NOT NULL,
346
+ "activation_mode" "product_activation_mode" DEFAULT 'manual' NOT NULL,
347
+ "activate_at" timestamp with time zone,
348
+ "deactivate_at" timestamp with time zone,
349
+ "sell_at" timestamp with time zone,
350
+ "stop_sell_at" timestamp with time zone,
351
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
352
+ "updated_at" timestamp with time zone DEFAULT now() NOT NULL
353
+ );
354
+ --> statement-breakpoint
355
+ CREATE TABLE "product_capabilities" (
356
+ "id" text PRIMARY KEY NOT NULL,
357
+ "product_id" text NOT NULL,
358
+ "capability" "product_capability" NOT NULL,
359
+ "enabled" boolean DEFAULT true NOT NULL,
360
+ "notes" text,
361
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
362
+ "updated_at" timestamp with time zone DEFAULT now() NOT NULL
363
+ );
364
+ --> statement-breakpoint
365
+ CREATE TABLE "product_delivery_formats" (
366
+ "id" text PRIMARY KEY NOT NULL,
367
+ "product_id" text NOT NULL,
368
+ "format" "product_delivery_format" NOT NULL,
369
+ "is_default" boolean DEFAULT false NOT NULL,
370
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
371
+ "updated_at" timestamp with time zone DEFAULT now() NOT NULL
372
+ );
373
+ --> statement-breakpoint
374
+ CREATE TABLE "product_faqs" (
375
+ "id" text PRIMARY KEY NOT NULL,
376
+ "product_id" text NOT NULL,
377
+ "question" text NOT NULL,
378
+ "answer" text NOT NULL,
379
+ "sort_order" integer DEFAULT 0 NOT NULL,
380
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
381
+ "updated_at" timestamp with time zone DEFAULT now() NOT NULL
382
+ );
383
+ --> statement-breakpoint
384
+ CREATE TABLE "product_features" (
385
+ "id" text PRIMARY KEY NOT NULL,
386
+ "product_id" text NOT NULL,
387
+ "feature_type" "product_feature_type" DEFAULT 'highlight' NOT NULL,
388
+ "title" text NOT NULL,
389
+ "description" text,
390
+ "sort_order" integer DEFAULT 0 NOT NULL,
391
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
392
+ "updated_at" timestamp with time zone DEFAULT now() NOT NULL
393
+ );
394
+ --> statement-breakpoint
395
+ CREATE TABLE "product_locations" (
396
+ "id" text PRIMARY KEY NOT NULL,
397
+ "product_id" text NOT NULL,
398
+ "location_type" "product_location_type" DEFAULT 'point_of_interest' NOT NULL,
399
+ "title" text NOT NULL,
400
+ "address" text,
401
+ "city" text,
402
+ "country_code" text,
403
+ "latitude" double precision,
404
+ "longitude" double precision,
405
+ "google_place_id" text,
406
+ "apple_place_id" text,
407
+ "tripadvisor_location_id" text,
408
+ "sort_order" integer DEFAULT 0 NOT NULL,
409
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
410
+ "updated_at" timestamp with time zone DEFAULT now() NOT NULL
411
+ );
412
+ --> statement-breakpoint
413
+ CREATE TABLE "product_option_translations" (
414
+ "id" text PRIMARY KEY NOT NULL,
415
+ "option_id" text NOT NULL,
416
+ "language_tag" text NOT NULL,
417
+ "name" text NOT NULL,
418
+ "short_description" text,
419
+ "description" text,
420
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
421
+ "updated_at" timestamp with time zone DEFAULT now() NOT NULL
422
+ );
423
+ --> statement-breakpoint
424
+ CREATE TABLE "product_ticket_settings" (
425
+ "id" text PRIMARY KEY NOT NULL,
426
+ "product_id" text NOT NULL,
427
+ "fulfillment_mode" "product_ticket_fulfillment" DEFAULT 'none' NOT NULL,
428
+ "default_delivery_format" "product_delivery_format" DEFAULT 'none' NOT NULL,
429
+ "ticket_per_unit" boolean DEFAULT false NOT NULL,
430
+ "barcode_format" text,
431
+ "voucher_message" text,
432
+ "ticket_message" text,
433
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
434
+ "updated_at" timestamp with time zone DEFAULT now() NOT NULL
435
+ );
436
+ --> statement-breakpoint
437
+ CREATE TABLE "product_translations" (
438
+ "id" text PRIMARY KEY NOT NULL,
439
+ "product_id" text NOT NULL,
440
+ "language_tag" text NOT NULL,
441
+ "slug" text,
442
+ "name" text NOT NULL,
443
+ "short_description" text,
444
+ "description" text,
445
+ "inclusions_html" text,
446
+ "exclusions_html" text,
447
+ "terms_html" text,
448
+ "seo_title" text,
449
+ "seo_description" text,
450
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
451
+ "updated_at" timestamp with time zone DEFAULT now() NOT NULL
452
+ );
453
+ --> statement-breakpoint
454
+ CREATE TABLE "product_visibility_settings" (
455
+ "id" text PRIMARY KEY NOT NULL,
456
+ "product_id" text NOT NULL,
457
+ "is_searchable" boolean DEFAULT false NOT NULL,
458
+ "is_bookable" boolean DEFAULT false NOT NULL,
459
+ "is_featured" boolean DEFAULT false NOT NULL,
460
+ "requires_authentication" boolean DEFAULT false NOT NULL,
461
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
462
+ "updated_at" timestamp with time zone DEFAULT now() NOT NULL
463
+ );
464
+ --> statement-breakpoint
465
+ CREATE TABLE "destination_translations" (
466
+ "id" text PRIMARY KEY NOT NULL,
467
+ "destination_id" text NOT NULL,
468
+ "language_tag" text NOT NULL,
469
+ "name" text NOT NULL,
470
+ "description" text,
471
+ "seo_title" text,
472
+ "seo_description" text,
473
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
474
+ "updated_at" timestamp with time zone DEFAULT now() NOT NULL
475
+ );
476
+ --> statement-breakpoint
477
+ CREATE TABLE "destinations" (
478
+ "id" text PRIMARY KEY NOT NULL,
479
+ "parent_id" text,
480
+ "slug" text NOT NULL,
481
+ "code" text,
482
+ "canonical_place_id" text,
483
+ "destination_type" text DEFAULT 'destination' NOT NULL,
484
+ "latitude" double precision,
485
+ "longitude" double precision,
486
+ "sort_order" integer DEFAULT 0 NOT NULL,
487
+ "active" boolean DEFAULT true NOT NULL,
488
+ "metadata" jsonb,
489
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
490
+ "updated_at" timestamp with time zone DEFAULT now() NOT NULL
491
+ );
492
+ --> statement-breakpoint
493
+ CREATE TABLE "product_categories" (
494
+ "id" text PRIMARY KEY NOT NULL,
495
+ "parent_id" text,
496
+ "name" text NOT NULL,
497
+ "slug" text NOT NULL,
498
+ "description" text,
499
+ "sort_order" integer DEFAULT 0 NOT NULL,
500
+ "active" boolean DEFAULT true NOT NULL,
501
+ "customer_payment_policy" jsonb,
502
+ "metadata" jsonb,
503
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
504
+ "updated_at" timestamp with time zone DEFAULT now() NOT NULL
505
+ );
506
+ --> statement-breakpoint
507
+ CREATE TABLE "product_category_products" (
508
+ "product_id" text NOT NULL,
509
+ "category_id" text NOT NULL,
510
+ "sort_order" integer DEFAULT 0 NOT NULL,
511
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
512
+ "updated_at" timestamp with time zone DEFAULT now() NOT NULL,
513
+ CONSTRAINT "product_category_products_product_id_category_id_pk" PRIMARY KEY("product_id","category_id")
514
+ );
515
+ --> statement-breakpoint
516
+ CREATE TABLE "product_category_translations" (
517
+ "id" text PRIMARY KEY NOT NULL,
518
+ "category_id" text NOT NULL,
519
+ "language_tag" text NOT NULL,
520
+ "name" text NOT NULL,
521
+ "description" text,
522
+ "seo_title" text,
523
+ "seo_description" text,
524
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
525
+ "updated_at" timestamp with time zone DEFAULT now() NOT NULL
526
+ );
527
+ --> statement-breakpoint
528
+ CREATE TABLE "product_destinations" (
529
+ "product_id" text NOT NULL,
530
+ "destination_id" text NOT NULL,
531
+ "sort_order" integer DEFAULT 0 NOT NULL,
532
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
533
+ "updated_at" timestamp with time zone DEFAULT now() NOT NULL,
534
+ CONSTRAINT "product_destinations_product_id_destination_id_pk" PRIMARY KEY("product_id","destination_id")
535
+ );
536
+ --> statement-breakpoint
537
+ CREATE TABLE "product_tag_products" (
538
+ "product_id" text NOT NULL,
539
+ "tag_id" text NOT NULL,
540
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
541
+ CONSTRAINT "product_tag_products_product_id_tag_id_pk" PRIMARY KEY("product_id","tag_id")
542
+ );
543
+ --> statement-breakpoint
544
+ CREATE TABLE "product_tag_translations" (
545
+ "id" text PRIMARY KEY NOT NULL,
546
+ "tag_id" text NOT NULL,
547
+ "language_tag" text NOT NULL,
548
+ "name" text NOT NULL,
549
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
550
+ "updated_at" timestamp with time zone DEFAULT now() NOT NULL
551
+ );
552
+ --> statement-breakpoint
553
+ CREATE TABLE "product_tags" (
554
+ "id" text PRIMARY KEY NOT NULL,
555
+ "name" text NOT NULL,
556
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
557
+ "updated_at" timestamp with time zone DEFAULT now() NOT NULL
558
+ );
559
+ --> statement-breakpoint
560
+ CREATE TABLE "product_types" (
561
+ "id" text PRIMARY KEY NOT NULL,
562
+ "name" text NOT NULL,
563
+ "code" text NOT NULL,
564
+ "description" text,
565
+ "sort_order" integer DEFAULT 0 NOT NULL,
566
+ "active" boolean DEFAULT true NOT NULL,
567
+ "metadata" jsonb,
568
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
569
+ "updated_at" timestamp with time zone DEFAULT now() NOT NULL
570
+ );
571
+ --> statement-breakpoint
572
+ ALTER TABLE "option_extra_configs" ADD CONSTRAINT "option_extra_configs_product_extra_id_product_extras_id_fk" FOREIGN KEY ("product_extra_id") REFERENCES "public"."product_extras"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
573
+ ALTER TABLE "option_units" ADD CONSTRAINT "option_units_option_id_product_options_id_fk" FOREIGN KEY ("option_id") REFERENCES "public"."product_options"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
574
+ ALTER TABLE "product_options" ADD CONSTRAINT "product_options_product_id_products_id_fk" FOREIGN KEY ("product_id") REFERENCES "public"."products"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
575
+ ALTER TABLE "product_pax_pricing_tiers" ADD CONSTRAINT "product_pax_pricing_tiers_product_id_products_id_fk" FOREIGN KEY ("product_id") REFERENCES "public"."products"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
576
+ ALTER TABLE "product_pax_pricing_tiers" ADD CONSTRAINT "product_pax_pricing_tiers_option_unit_id_option_units_id_fk" FOREIGN KEY ("option_unit_id") REFERENCES "public"."option_units"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
577
+ ALTER TABLE "product_day_services" ADD CONSTRAINT "product_day_services_day_id_product_days_id_fk" FOREIGN KEY ("day_id") REFERENCES "public"."product_days"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
578
+ ALTER TABLE "product_day_translations" ADD CONSTRAINT "product_day_translations_day_id_product_days_id_fk" FOREIGN KEY ("day_id") REFERENCES "public"."product_days"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
579
+ ALTER TABLE "product_days" ADD CONSTRAINT "product_days_itinerary_id_product_itineraries_id_fk" FOREIGN KEY ("itinerary_id") REFERENCES "public"."product_itineraries"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
580
+ ALTER TABLE "product_itineraries" ADD CONSTRAINT "product_itineraries_product_id_products_id_fk" FOREIGN KEY ("product_id") REFERENCES "public"."products"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
581
+ ALTER TABLE "product_media" ADD CONSTRAINT "product_media_product_id_products_id_fk" FOREIGN KEY ("product_id") REFERENCES "public"."products"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
582
+ ALTER TABLE "product_media" ADD CONSTRAINT "product_media_day_id_product_days_id_fk" FOREIGN KEY ("day_id") REFERENCES "public"."product_days"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
583
+ ALTER TABLE "product_notes" ADD CONSTRAINT "product_notes_product_id_products_id_fk" FOREIGN KEY ("product_id") REFERENCES "public"."products"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
584
+ ALTER TABLE "product_versions" ADD CONSTRAINT "product_versions_product_id_products_id_fk" FOREIGN KEY ("product_id") REFERENCES "public"."products"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
585
+ ALTER TABLE "option_unit_translations" ADD CONSTRAINT "option_unit_translations_unit_id_option_units_id_fk" FOREIGN KEY ("unit_id") REFERENCES "public"."option_units"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
586
+ ALTER TABLE "product_activation_settings" ADD CONSTRAINT "product_activation_settings_product_id_products_id_fk" FOREIGN KEY ("product_id") REFERENCES "public"."products"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
587
+ ALTER TABLE "product_capabilities" ADD CONSTRAINT "product_capabilities_product_id_products_id_fk" FOREIGN KEY ("product_id") REFERENCES "public"."products"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
588
+ ALTER TABLE "product_delivery_formats" ADD CONSTRAINT "product_delivery_formats_product_id_products_id_fk" FOREIGN KEY ("product_id") REFERENCES "public"."products"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
589
+ ALTER TABLE "product_faqs" ADD CONSTRAINT "product_faqs_product_id_products_id_fk" FOREIGN KEY ("product_id") REFERENCES "public"."products"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
590
+ ALTER TABLE "product_features" ADD CONSTRAINT "product_features_product_id_products_id_fk" FOREIGN KEY ("product_id") REFERENCES "public"."products"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
591
+ ALTER TABLE "product_locations" ADD CONSTRAINT "product_locations_product_id_products_id_fk" FOREIGN KEY ("product_id") REFERENCES "public"."products"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
592
+ ALTER TABLE "product_option_translations" ADD CONSTRAINT "product_option_translations_option_id_product_options_id_fk" FOREIGN KEY ("option_id") REFERENCES "public"."product_options"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
593
+ ALTER TABLE "product_ticket_settings" ADD CONSTRAINT "product_ticket_settings_product_id_products_id_fk" FOREIGN KEY ("product_id") REFERENCES "public"."products"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
594
+ ALTER TABLE "product_translations" ADD CONSTRAINT "product_translations_product_id_products_id_fk" FOREIGN KEY ("product_id") REFERENCES "public"."products"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
595
+ ALTER TABLE "product_visibility_settings" ADD CONSTRAINT "product_visibility_settings_product_id_products_id_fk" FOREIGN KEY ("product_id") REFERENCES "public"."products"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
596
+ ALTER TABLE "destination_translations" ADD CONSTRAINT "destination_translations_destination_id_destinations_id_fk" FOREIGN KEY ("destination_id") REFERENCES "public"."destinations"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
597
+ ALTER TABLE "product_category_products" ADD CONSTRAINT "product_category_products_product_id_products_id_fk" FOREIGN KEY ("product_id") REFERENCES "public"."products"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
598
+ ALTER TABLE "product_category_products" ADD CONSTRAINT "product_category_products_category_id_product_categories_id_fk" FOREIGN KEY ("category_id") REFERENCES "public"."product_categories"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
599
+ ALTER TABLE "product_category_translations" ADD CONSTRAINT "product_category_translations_category_id_product_categories_id_fk" FOREIGN KEY ("category_id") REFERENCES "public"."product_categories"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
600
+ ALTER TABLE "product_destinations" ADD CONSTRAINT "product_destinations_product_id_products_id_fk" FOREIGN KEY ("product_id") REFERENCES "public"."products"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
601
+ ALTER TABLE "product_destinations" ADD CONSTRAINT "product_destinations_destination_id_destinations_id_fk" FOREIGN KEY ("destination_id") REFERENCES "public"."destinations"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
602
+ ALTER TABLE "product_tag_products" ADD CONSTRAINT "product_tag_products_product_id_products_id_fk" FOREIGN KEY ("product_id") REFERENCES "public"."products"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
603
+ ALTER TABLE "product_tag_products" ADD CONSTRAINT "product_tag_products_tag_id_product_tags_id_fk" FOREIGN KEY ("tag_id") REFERENCES "public"."product_tags"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
604
+ ALTER TABLE "product_tag_translations" ADD CONSTRAINT "product_tag_translations_tag_id_product_tags_id_fk" FOREIGN KEY ("tag_id") REFERENCES "public"."product_tags"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
605
+ CREATE INDEX "idx_bipd_product" ON "booking_item_product_details" USING btree ("product_id");--> statement-breakpoint
606
+ CREATE INDEX "idx_bipd_option" ON "booking_item_product_details" USING btree ("option_id");--> statement-breakpoint
607
+ CREATE INDEX "idx_bipd_unit" ON "booking_item_product_details" USING btree ("unit_id");--> statement-breakpoint
608
+ CREATE INDEX "idx_bipd_supplier_service" ON "booking_item_product_details" USING btree ("supplier_service_id");--> statement-breakpoint
609
+ CREATE INDEX "idx_bpd_product" ON "booking_product_details" USING btree ("product_id");--> statement-breakpoint
610
+ CREATE INDEX "idx_bpd_option" ON "booking_product_details" USING btree ("option_id");--> statement-breakpoint
611
+ CREATE INDEX "products_sourced_content_locale_fresh_idx" ON "products_sourced_content" USING btree ("locale","fresh_until");--> statement-breakpoint
612
+ CREATE INDEX "products_sourced_content_returned_locale_idx" ON "products_sourced_content" USING btree ("entity_id","returned_locale");--> statement-breakpoint
613
+ CREATE INDEX "products_sourced_content_schema_version_idx" ON "products_sourced_content" USING btree ("content_schema_version");--> statement-breakpoint
614
+ CREATE INDEX "extras_sourced_content_locale_fresh_idx" ON "extras_sourced_content" USING btree ("locale","fresh_until");--> statement-breakpoint
615
+ CREATE INDEX "extras_sourced_content_returned_locale_idx" ON "extras_sourced_content" USING btree ("entity_id","returned_locale");--> statement-breakpoint
616
+ CREATE INDEX "extras_sourced_content_schema_version_idx" ON "extras_sourced_content" USING btree ("content_schema_version");--> statement-breakpoint
617
+ CREATE INDEX "idx_option_extra_configs_sort_default" ON "option_extra_configs" USING btree ("sort_order","is_default");--> statement-breakpoint
618
+ CREATE INDEX "idx_option_extra_configs_option_sort_default" ON "option_extra_configs" USING btree ("option_id","sort_order","is_default");--> statement-breakpoint
619
+ CREATE INDEX "idx_option_extra_configs_extra_sort_default" ON "option_extra_configs" USING btree ("product_extra_id","sort_order","is_default");--> statement-breakpoint
620
+ CREATE INDEX "idx_option_extra_configs_active_sort_default" ON "option_extra_configs" USING btree ("active","sort_order","is_default");--> statement-breakpoint
621
+ CREATE UNIQUE INDEX "uidx_option_extra_configs_option_extra" ON "option_extra_configs" USING btree ("option_id","product_extra_id");--> statement-breakpoint
622
+ CREATE INDEX "idx_product_extras_sort_name" ON "product_extras" USING btree ("sort_order","name");--> statement-breakpoint
623
+ CREATE INDEX "idx_product_extras_product_sort_name" ON "product_extras" USING btree ("product_id","sort_order","name");--> statement-breakpoint
624
+ CREATE INDEX "idx_product_extras_supplier_sort_name" ON "product_extras" USING btree ("supplier_id","sort_order","name");--> statement-breakpoint
625
+ CREATE INDEX "idx_product_extras_active_sort_name" ON "product_extras" USING btree ("active","sort_order","name");--> statement-breakpoint
626
+ CREATE UNIQUE INDEX "uidx_product_extras_product_code" ON "product_extras" USING btree ("product_id","code");--> statement-breakpoint
627
+ CREATE INDEX "idx_option_units_option" ON "option_units" USING btree ("option_id");--> statement-breakpoint
628
+ CREATE INDEX "idx_option_units_option_sort" ON "option_units" USING btree ("option_id","sort_order","created_at");--> statement-breakpoint
629
+ CREATE INDEX "idx_option_units_type" ON "option_units" USING btree ("unit_type");--> statement-breakpoint
630
+ CREATE UNIQUE INDEX "uidx_option_units_option_code" ON "option_units" USING btree ("option_id","code");--> statement-breakpoint
631
+ CREATE INDEX "idx_product_options_product" ON "product_options" USING btree ("product_id");--> statement-breakpoint
632
+ CREATE INDEX "idx_product_options_product_sort" ON "product_options" USING btree ("product_id","sort_order","created_at");--> statement-breakpoint
633
+ CREATE INDEX "idx_product_options_status" ON "product_options" USING btree ("status");--> statement-breakpoint
634
+ CREATE INDEX "idx_product_options_default" ON "product_options" USING btree ("is_default");--> statement-breakpoint
635
+ CREATE UNIQUE INDEX "uidx_product_options_product_code" ON "product_options" USING btree ("product_id","code");--> statement-breakpoint
636
+ CREATE INDEX "idx_pax_tiers_product" ON "product_pax_pricing_tiers" USING btree ("product_id");--> statement-breakpoint
637
+ CREATE INDEX "idx_pax_tiers_unit" ON "product_pax_pricing_tiers" USING btree ("option_unit_id");--> statement-breakpoint
638
+ CREATE UNIQUE INDEX "uidx_pax_tiers_unit_pax" ON "product_pax_pricing_tiers" USING btree ("option_unit_id","tier_pax");--> statement-breakpoint
639
+ CREATE INDEX "idx_products_status" ON "products" USING btree ("status");--> statement-breakpoint
640
+ CREATE INDEX "idx_products_facility" ON "products" USING btree ("facility_id");--> statement-breakpoint
641
+ CREATE INDEX "idx_products_supplier" ON "products" USING btree ("supplier_id");--> statement-breakpoint
642
+ CREATE INDEX "idx_products_product_type" ON "products" USING btree ("product_type_id");--> statement-breakpoint
643
+ CREATE INDEX "idx_products_contract_template" ON "products" USING btree ("contract_template_id");--> statement-breakpoint
644
+ CREATE INDEX "idx_products_status_created" ON "products" USING btree ("status","created_at");--> statement-breakpoint
645
+ CREATE INDEX "idx_products_booking_mode_created" ON "products" USING btree ("booking_mode","created_at");--> statement-breakpoint
646
+ CREATE INDEX "idx_products_capacity_mode_created" ON "products" USING btree ("capacity_mode","created_at");--> statement-breakpoint
647
+ CREATE INDEX "idx_products_visibility_created" ON "products" USING btree ("visibility","created_at");--> statement-breakpoint
648
+ CREATE INDEX "idx_products_activated_created" ON "products" USING btree ("activated","created_at");--> statement-breakpoint
649
+ CREATE INDEX "idx_products_facility_created" ON "products" USING btree ("facility_id","created_at");--> statement-breakpoint
650
+ CREATE INDEX "idx_products_supplier_created" ON "products" USING btree ("supplier_id","created_at");--> statement-breakpoint
651
+ CREATE INDEX "idx_products_product_type_created" ON "products" USING btree ("product_type_id","created_at");--> statement-breakpoint
652
+ CREATE INDEX "idx_products_public_created" ON "products" USING btree ("status","activated","visibility","created_at");--> statement-breakpoint
653
+ CREATE INDEX "idx_products_name_trgm" ON "products" USING gin ("name" gin_trgm_ops);--> statement-breakpoint
654
+ CREATE INDEX "idx_products_description_trgm" ON "products" USING gin ("description" gin_trgm_ops);--> statement-breakpoint
655
+ CREATE INDEX "idx_product_day_services_day" ON "product_day_services" USING btree ("day_id");--> statement-breakpoint
656
+ CREATE INDEX "idx_product_day_services_day_sort" ON "product_day_services" USING btree ("day_id","sort_order");--> statement-breakpoint
657
+ CREATE INDEX "idx_product_day_services_supplier_service" ON "product_day_services" USING btree ("supplier_service_id");--> statement-breakpoint
658
+ CREATE INDEX "idx_product_day_translations_day" ON "product_day_translations" USING btree ("day_id");--> statement-breakpoint
659
+ CREATE INDEX "idx_product_day_translations_language" ON "product_day_translations" USING btree ("language_tag");--> statement-breakpoint
660
+ CREATE UNIQUE INDEX "uidx_product_day_translations_day_language" ON "product_day_translations" USING btree ("day_id","language_tag");--> statement-breakpoint
661
+ CREATE INDEX "idx_product_days_itinerary" ON "product_days" USING btree ("itinerary_id");--> statement-breakpoint
662
+ CREATE INDEX "idx_product_days_itinerary_day_number" ON "product_days" USING btree ("itinerary_id","day_number");--> statement-breakpoint
663
+ CREATE INDEX "idx_product_itineraries_product" ON "product_itineraries" USING btree ("product_id");--> statement-breakpoint
664
+ CREATE INDEX "idx_product_itineraries_product_sort" ON "product_itineraries" USING btree ("product_id","sort_order","created_at");--> statement-breakpoint
665
+ CREATE INDEX "idx_product_itineraries_product_default" ON "product_itineraries" USING btree ("product_id","is_default");--> statement-breakpoint
666
+ CREATE UNIQUE INDEX "uidx_product_itineraries_default" ON "product_itineraries" USING btree ("product_id") WHERE "product_itineraries"."is_default" = true;--> statement-breakpoint
667
+ CREATE INDEX "idx_product_media_product" ON "product_media" USING btree ("product_id");--> statement-breakpoint
668
+ CREATE INDEX "idx_product_media_day" ON "product_media" USING btree ("day_id");--> statement-breakpoint
669
+ CREATE INDEX "idx_product_media_product_day" ON "product_media" USING btree ("product_id","day_id");--> statement-breakpoint
670
+ CREATE INDEX "idx_product_media_product_cover_sort" ON "product_media" USING btree ("product_id","is_cover","sort_order","created_at");--> statement-breakpoint
671
+ CREATE INDEX "idx_product_media_product_day_cover_sort" ON "product_media" USING btree ("product_id","day_id","is_cover","sort_order","created_at");--> statement-breakpoint
672
+ CREATE INDEX "idx_product_media_product_brochure_current_version" ON "product_media" USING btree ("product_id","is_brochure","day_id","is_brochure_current","brochure_version","updated_at","created_at");--> statement-breakpoint
673
+ CREATE INDEX "idx_product_notes_product" ON "product_notes" USING btree ("product_id");--> statement-breakpoint
674
+ CREATE INDEX "idx_product_notes_product_created" ON "product_notes" USING btree ("product_id","created_at");--> statement-breakpoint
675
+ CREATE INDEX "idx_product_versions_product" ON "product_versions" USING btree ("product_id");--> statement-breakpoint
676
+ CREATE INDEX "idx_product_versions_product_version" ON "product_versions" USING btree ("product_id","version_number");--> statement-breakpoint
677
+ CREATE INDEX "idx_option_unit_translations_unit" ON "option_unit_translations" USING btree ("unit_id");--> statement-breakpoint
678
+ CREATE INDEX "idx_option_unit_translations_language" ON "option_unit_translations" USING btree ("language_tag");--> statement-breakpoint
679
+ CREATE INDEX "idx_option_unit_translations_unit_language_created" ON "option_unit_translations" USING btree ("unit_id","language_tag","created_at");--> statement-breakpoint
680
+ CREATE INDEX "idx_option_unit_translations_language_created" ON "option_unit_translations" USING btree ("language_tag","created_at");--> statement-breakpoint
681
+ CREATE UNIQUE INDEX "uidx_option_unit_translations_unit_language" ON "option_unit_translations" USING btree ("unit_id","language_tag");--> statement-breakpoint
682
+ CREATE UNIQUE INDEX "uidx_product_activation_settings_product" ON "product_activation_settings" USING btree ("product_id");--> statement-breakpoint
683
+ CREATE INDEX "idx_product_activation_settings_created" ON "product_activation_settings" USING btree ("created_at");--> statement-breakpoint
684
+ CREATE INDEX "idx_product_activation_settings_mode" ON "product_activation_settings" USING btree ("activation_mode");--> statement-breakpoint
685
+ CREATE INDEX "idx_product_activation_settings_mode_created" ON "product_activation_settings" USING btree ("activation_mode","created_at");--> statement-breakpoint
686
+ CREATE INDEX "idx_product_capabilities_product" ON "product_capabilities" USING btree ("product_id");--> statement-breakpoint
687
+ CREATE INDEX "idx_product_capabilities_capability" ON "product_capabilities" USING btree ("capability");--> statement-breakpoint
688
+ CREATE INDEX "idx_product_capabilities_capability_created" ON "product_capabilities" USING btree ("capability","created_at");--> statement-breakpoint
689
+ CREATE INDEX "idx_product_capabilities_enabled_capability_created" ON "product_capabilities" USING btree ("enabled","capability","created_at");--> statement-breakpoint
690
+ CREATE UNIQUE INDEX "uidx_product_capabilities_product_capability" ON "product_capabilities" USING btree ("product_id","capability");--> statement-breakpoint
691
+ CREATE INDEX "idx_product_delivery_formats_product" ON "product_delivery_formats" USING btree ("product_id");--> statement-breakpoint
692
+ CREATE INDEX "idx_product_delivery_formats_default_created" ON "product_delivery_formats" USING btree ("is_default","created_at");--> statement-breakpoint
693
+ CREATE INDEX "idx_product_delivery_formats_product_default_created" ON "product_delivery_formats" USING btree ("product_id","is_default","created_at");--> statement-breakpoint
694
+ CREATE INDEX "idx_product_delivery_formats_format_default_created" ON "product_delivery_formats" USING btree ("format","is_default","created_at");--> statement-breakpoint
695
+ CREATE UNIQUE INDEX "uidx_product_delivery_formats_product_format" ON "product_delivery_formats" USING btree ("product_id","format");--> statement-breakpoint
696
+ CREATE INDEX "idx_product_faqs_product" ON "product_faqs" USING btree ("product_id");--> statement-breakpoint
697
+ CREATE INDEX "idx_product_faqs_sort" ON "product_faqs" USING btree ("sort_order","created_at");--> statement-breakpoint
698
+ CREATE INDEX "idx_product_faqs_product_sort" ON "product_faqs" USING btree ("product_id","sort_order","created_at");--> statement-breakpoint
699
+ CREATE INDEX "idx_product_features_product" ON "product_features" USING btree ("product_id");--> statement-breakpoint
700
+ CREATE INDEX "idx_product_features_sort" ON "product_features" USING btree ("sort_order","created_at");--> statement-breakpoint
701
+ CREATE INDEX "idx_product_features_product_sort" ON "product_features" USING btree ("product_id","sort_order","created_at");--> statement-breakpoint
702
+ CREATE INDEX "idx_product_features_type" ON "product_features" USING btree ("feature_type");--> statement-breakpoint
703
+ CREATE INDEX "idx_product_features_type_sort" ON "product_features" USING btree ("feature_type","sort_order","created_at");--> statement-breakpoint
704
+ CREATE INDEX "idx_product_features_product_type_sort" ON "product_features" USING btree ("product_id","feature_type","sort_order","created_at");--> statement-breakpoint
705
+ CREATE INDEX "idx_product_locations_product" ON "product_locations" USING btree ("product_id");--> statement-breakpoint
706
+ CREATE INDEX "idx_product_locations_sort" ON "product_locations" USING btree ("sort_order","created_at");--> statement-breakpoint
707
+ CREATE INDEX "idx_product_locations_product_sort" ON "product_locations" USING btree ("product_id","sort_order","created_at");--> statement-breakpoint
708
+ CREATE INDEX "idx_product_locations_type" ON "product_locations" USING btree ("location_type");--> statement-breakpoint
709
+ CREATE INDEX "idx_product_locations_type_product" ON "product_locations" USING btree ("location_type","product_id");--> statement-breakpoint
710
+ CREATE INDEX "idx_product_locations_type_sort" ON "product_locations" USING btree ("location_type","sort_order","created_at");--> statement-breakpoint
711
+ CREATE INDEX "idx_product_locations_product_type_sort" ON "product_locations" USING btree ("product_id","location_type","sort_order","created_at");--> statement-breakpoint
712
+ CREATE INDEX "idx_product_locations_country_product" ON "product_locations" USING btree ("country_code","product_id");--> statement-breakpoint
713
+ CREATE INDEX "idx_product_locations_title_trgm" ON "product_locations" USING gin ("title" gin_trgm_ops);--> statement-breakpoint
714
+ CREATE INDEX "idx_product_locations_city_trgm" ON "product_locations" USING gin ("city" gin_trgm_ops);--> statement-breakpoint
715
+ CREATE INDEX "idx_product_option_translations_option" ON "product_option_translations" USING btree ("option_id");--> statement-breakpoint
716
+ CREATE INDEX "idx_product_option_translations_language" ON "product_option_translations" USING btree ("language_tag");--> statement-breakpoint
717
+ CREATE INDEX "idx_product_option_translations_option_language_created" ON "product_option_translations" USING btree ("option_id","language_tag","created_at");--> statement-breakpoint
718
+ CREATE INDEX "idx_product_option_translations_language_created" ON "product_option_translations" USING btree ("language_tag","created_at");--> statement-breakpoint
719
+ CREATE UNIQUE INDEX "uidx_product_option_translations_option_language" ON "product_option_translations" USING btree ("option_id","language_tag");--> statement-breakpoint
720
+ CREATE UNIQUE INDEX "uidx_product_ticket_settings_product" ON "product_ticket_settings" USING btree ("product_id");--> statement-breakpoint
721
+ CREATE INDEX "idx_product_ticket_settings_created" ON "product_ticket_settings" USING btree ("created_at");--> statement-breakpoint
722
+ CREATE INDEX "idx_product_ticket_settings_fulfillment_created" ON "product_ticket_settings" USING btree ("fulfillment_mode","created_at");--> statement-breakpoint
723
+ CREATE INDEX "idx_product_translations_product" ON "product_translations" USING btree ("product_id");--> statement-breakpoint
724
+ CREATE INDEX "idx_product_translations_language" ON "product_translations" USING btree ("language_tag");--> statement-breakpoint
725
+ CREATE INDEX "idx_product_translations_product_language_created" ON "product_translations" USING btree ("product_id","language_tag","created_at");--> statement-breakpoint
726
+ CREATE INDEX "idx_product_translations_language_created" ON "product_translations" USING btree ("language_tag","created_at");--> statement-breakpoint
727
+ CREATE UNIQUE INDEX "uidx_product_translations_product_language" ON "product_translations" USING btree ("product_id","language_tag");--> statement-breakpoint
728
+ CREATE UNIQUE INDEX "uidx_product_visibility_settings_product" ON "product_visibility_settings" USING btree ("product_id");--> statement-breakpoint
729
+ CREATE INDEX "idx_product_visibility_settings_created" ON "product_visibility_settings" USING btree ("created_at");--> statement-breakpoint
730
+ CREATE INDEX "idx_product_visibility_settings_searchable_created" ON "product_visibility_settings" USING btree ("is_searchable","created_at");--> statement-breakpoint
731
+ CREATE INDEX "idx_product_visibility_settings_bookable_created" ON "product_visibility_settings" USING btree ("is_bookable","created_at");--> statement-breakpoint
732
+ CREATE INDEX "idx_product_visibility_settings_featured_product" ON "product_visibility_settings" USING btree ("is_featured","product_id");--> statement-breakpoint
733
+ CREATE UNIQUE INDEX "uidx_destination_translations_locale" ON "destination_translations" USING btree ("destination_id","language_tag");--> statement-breakpoint
734
+ CREATE INDEX "idx_destination_translations_language" ON "destination_translations" USING btree ("language_tag");--> statement-breakpoint
735
+ CREATE INDEX "idx_destination_translations_destination_language_created" ON "destination_translations" USING btree ("destination_id","language_tag","created_at");--> statement-breakpoint
736
+ CREATE INDEX "idx_destination_translations_language_created" ON "destination_translations" USING btree ("language_tag","created_at");--> statement-breakpoint
737
+ CREATE INDEX "idx_destination_translations_name_trgm" ON "destination_translations" USING gin ("name" gin_trgm_ops);--> statement-breakpoint
738
+ CREATE INDEX "idx_destination_translations_description_trgm" ON "destination_translations" USING gin ("description" gin_trgm_ops);--> statement-breakpoint
739
+ CREATE UNIQUE INDEX "uidx_destinations_slug" ON "destinations" USING btree ("slug");--> statement-breakpoint
740
+ CREATE UNIQUE INDEX "uidx_destinations_code" ON "destinations" USING btree ("code");--> statement-breakpoint
741
+ CREATE INDEX "idx_destinations_parent" ON "destinations" USING btree ("parent_id");--> statement-breakpoint
742
+ CREATE INDEX "idx_destinations_active" ON "destinations" USING btree ("active");--> statement-breakpoint
743
+ CREATE INDEX "idx_destinations_canonical_place" ON "destinations" USING btree ("canonical_place_id");--> statement-breakpoint
744
+ CREATE INDEX "idx_destinations_sort_slug" ON "destinations" USING btree ("sort_order","slug");--> statement-breakpoint
745
+ CREATE INDEX "idx_destinations_active_sort_slug" ON "destinations" USING btree ("active","sort_order","slug");--> statement-breakpoint
746
+ CREATE INDEX "idx_destinations_type_sort_slug" ON "destinations" USING btree ("destination_type","sort_order","slug");--> statement-breakpoint
747
+ CREATE INDEX "idx_destinations_parent_sort_slug" ON "destinations" USING btree ("parent_id","sort_order","slug");--> statement-breakpoint
748
+ CREATE UNIQUE INDEX "uidx_product_categories_slug" ON "product_categories" USING btree ("slug");--> statement-breakpoint
749
+ CREATE INDEX "idx_product_categories_parent" ON "product_categories" USING btree ("parent_id");--> statement-breakpoint
750
+ CREATE INDEX "idx_product_categories_active" ON "product_categories" USING btree ("active");--> statement-breakpoint
751
+ CREATE INDEX "idx_product_categories_sort_name" ON "product_categories" USING btree ("sort_order","name");--> statement-breakpoint
752
+ CREATE INDEX "idx_product_categories_active_sort_name" ON "product_categories" USING btree ("active","sort_order","name");--> statement-breakpoint
753
+ CREATE INDEX "idx_product_categories_parent_sort_name" ON "product_categories" USING btree ("parent_id","sort_order","name");--> statement-breakpoint
754
+ CREATE INDEX "idx_product_categories_name_trgm" ON "product_categories" USING gin ("name" gin_trgm_ops);--> statement-breakpoint
755
+ CREATE INDEX "idx_product_categories_slug_trgm" ON "product_categories" USING gin ("slug" gin_trgm_ops);--> statement-breakpoint
756
+ CREATE INDEX "idx_pcp_product_sort" ON "product_category_products" USING btree ("product_id","sort_order");--> statement-breakpoint
757
+ CREATE INDEX "idx_pcp_category" ON "product_category_products" USING btree ("category_id");--> statement-breakpoint
758
+ CREATE UNIQUE INDEX "uidx_product_category_translations_locale" ON "product_category_translations" USING btree ("category_id","language_tag");--> statement-breakpoint
759
+ CREATE INDEX "idx_product_category_translations_language" ON "product_category_translations" USING btree ("language_tag");--> statement-breakpoint
760
+ CREATE INDEX "idx_product_category_translations_category_language_created" ON "product_category_translations" USING btree ("category_id","language_tag","created_at");--> statement-breakpoint
761
+ CREATE INDEX "idx_product_category_translations_language_created" ON "product_category_translations" USING btree ("language_tag","created_at");--> statement-breakpoint
762
+ CREATE INDEX "idx_product_destinations_product_sort" ON "product_destinations" USING btree ("product_id","sort_order");--> statement-breakpoint
763
+ CREATE INDEX "idx_product_destinations_destination_sort" ON "product_destinations" USING btree ("destination_id","sort_order");--> statement-breakpoint
764
+ CREATE INDEX "idx_ptp_tag" ON "product_tag_products" USING btree ("tag_id");--> statement-breakpoint
765
+ CREATE UNIQUE INDEX "uidx_product_tag_translations_locale" ON "product_tag_translations" USING btree ("tag_id","language_tag");--> statement-breakpoint
766
+ CREATE INDEX "idx_product_tag_translations_language" ON "product_tag_translations" USING btree ("language_tag");--> statement-breakpoint
767
+ CREATE INDEX "idx_product_tag_translations_tag_language_created" ON "product_tag_translations" USING btree ("tag_id","language_tag","created_at");--> statement-breakpoint
768
+ CREATE INDEX "idx_product_tag_translations_language_created" ON "product_tag_translations" USING btree ("language_tag","created_at");--> statement-breakpoint
769
+ CREATE UNIQUE INDEX "uidx_product_tags_name" ON "product_tags" USING btree ("name");--> statement-breakpoint
770
+ CREATE INDEX "idx_product_tags_name_trgm" ON "product_tags" USING gin ("name" gin_trgm_ops);--> statement-breakpoint
771
+ CREATE UNIQUE INDEX "uidx_product_types_code" ON "product_types" USING btree ("code");--> statement-breakpoint
772
+ CREATE INDEX "idx_product_types_active" ON "product_types" USING btree ("active");--> statement-breakpoint
773
+ CREATE INDEX "idx_product_types_sort_name" ON "product_types" USING btree ("sort_order","name");--> statement-breakpoint
774
+ CREATE INDEX "idx_product_types_active_sort_name" ON "product_types" USING btree ("active","sort_order","name");
@@ -0,0 +1,13 @@
1
+ {
2
+ "version": "7",
3
+ "dialect": "postgresql",
4
+ "entries": [
5
+ {
6
+ "idx": 0,
7
+ "version": "7",
8
+ "when": 1781947487847,
9
+ "tag": "0000_inventory_baseline",
10
+ "breakpoints": true
11
+ }
12
+ ]
13
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voyant-travel/inventory",
3
- "version": "0.3.6",
3
+ "version": "0.3.8",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "exports": {
@@ -162,26 +162,29 @@
162
162
  "pdf-lib": "^1.17.1",
163
163
  "sanitize-html": "^2.17.4",
164
164
  "zod": "^4.3.6",
165
- "@voyant-travel/action-ledger": "^0.105.2",
166
- "@voyant-travel/catalog": "^0.124.0",
167
- "@voyant-travel/core": "^0.110.0",
168
- "@voyant-travel/db": "^0.108.3",
165
+ "@voyant-travel/action-ledger": "^0.105.3",
166
+ "@voyant-travel/catalog": "^0.124.1",
169
167
  "@voyant-travel/extras-contracts": "^0.104.2",
168
+ "@voyant-travel/core": "^0.110.0",
169
+ "@voyant-travel/db": "^0.108.4",
170
170
  "@voyant-travel/hono": "^0.112.2",
171
- "@voyant-travel/commerce": "^0.8.0",
172
- "@voyant-travel/products-contracts": "^0.105.7",
171
+ "@voyant-travel/commerce": "^0.8.1",
173
172
  "@voyant-travel/storage": "^0.105.0",
174
173
  "@voyant-travel/utils": "^0.105.2",
175
- "@voyant-travel/operations": "^0.1.6"
174
+ "@voyant-travel/products-contracts": "^0.105.7",
175
+ "@voyant-travel/operations": "^0.1.7"
176
176
  },
177
177
  "devDependencies": {
178
178
  "@types/sanitize-html": "^2.16.1",
179
+ "drizzle-kit": "^0.31.10",
179
180
  "typescript": "^6.0.2",
180
181
  "vitest": "^4.1.2",
181
182
  "@voyant-travel/voyant-typescript-config": "^0.1.0"
182
183
  },
183
184
  "files": [
184
- "dist"
185
+ "dist",
186
+ "migrations/*.sql",
187
+ "migrations/meta/_journal.json"
185
188
  ],
186
189
  "publishConfig": {
187
190
  "access": "public"
@@ -202,7 +205,8 @@
202
205
  "lint": "biome check src/",
203
206
  "test": "vitest run",
204
207
  "build": "tsc -p tsconfig.json",
205
- "clean": "rm -rf dist tsconfig.tsbuildinfo"
208
+ "clean": "rm -rf dist tsconfig.tsbuildinfo",
209
+ "db:generate": "drizzle-kit generate --config=drizzle.migrations.config.ts --name=inventory_baseline && node ../../scripts/d2/guard-create-type.mjs ./migrations && node ../../scripts/d2/ensure-extensions.mjs ./migrations"
206
210
  },
207
211
  "main": "./dist/index.js",
208
212
  "types": "./dist/index.d.ts"