@voyantjs/extras 0.20.0 → 0.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,254 @@
1
+ /**
2
+ * Extras sourced-content cache. Sibling to the products / cruises /
3
+ * hospitality / charters variants — same shape, different vertical.
4
+ *
5
+ * One row per sourced extra × locale × market. Stores the content the
6
+ * upstream adapter served via `getContent`, plus the SWR metadata the
7
+ * read service needs.
8
+ *
9
+ * Extras are booking add-ons (optional line items layered on a parent
10
+ * product). Per `catalog-policy.ts`, extras are a partial-adoption
11
+ * vertical: they don't appear in the search index, but sourced extras
12
+ * (e.g. a TUI excursion add-on) still need rich content for the
13
+ * booking-flow's add-on selection UI. The sourced-content cache covers
14
+ * exactly that surface.
15
+ *
16
+ * See `docs/architecture/catalog-sourced-content.md` §3.2.
17
+ */
18
+ export type ExtrasSourcedContentFetchStatus = "ok" | "stale" | "error" | "unsupported";
19
+ export declare const EXTRAS_CONTENT_MARKET_ANY = "*";
20
+ export declare const extrasSourcedContentTable: import("drizzle-orm/pg-core").PgTableWithColumns<{
21
+ name: "extras_sourced_content";
22
+ schema: undefined;
23
+ columns: {
24
+ entity_id: import("drizzle-orm/pg-core").PgColumn<{
25
+ name: "entity_id";
26
+ tableName: "extras_sourced_content";
27
+ dataType: "string";
28
+ columnType: "PgText";
29
+ data: string;
30
+ driverParam: string;
31
+ notNull: true;
32
+ hasDefault: false;
33
+ isPrimaryKey: false;
34
+ isAutoincrement: false;
35
+ hasRuntimeDefault: false;
36
+ enumValues: [string, ...string[]];
37
+ baseColumn: never;
38
+ identity: undefined;
39
+ generated: undefined;
40
+ }, {}, {}>;
41
+ locale: import("drizzle-orm/pg-core").PgColumn<{
42
+ name: "locale";
43
+ tableName: "extras_sourced_content";
44
+ dataType: "string";
45
+ columnType: "PgText";
46
+ data: string;
47
+ driverParam: string;
48
+ notNull: true;
49
+ hasDefault: false;
50
+ isPrimaryKey: false;
51
+ isAutoincrement: false;
52
+ hasRuntimeDefault: false;
53
+ enumValues: [string, ...string[]];
54
+ baseColumn: never;
55
+ identity: undefined;
56
+ generated: undefined;
57
+ }, {}, {}>;
58
+ market: import("drizzle-orm/pg-core").PgColumn<{
59
+ name: "market";
60
+ tableName: "extras_sourced_content";
61
+ dataType: "string";
62
+ columnType: "PgText";
63
+ data: string;
64
+ driverParam: string;
65
+ notNull: true;
66
+ hasDefault: true;
67
+ isPrimaryKey: false;
68
+ isAutoincrement: false;
69
+ hasRuntimeDefault: false;
70
+ enumValues: [string, ...string[]];
71
+ baseColumn: never;
72
+ identity: undefined;
73
+ generated: undefined;
74
+ }, {}, {}>;
75
+ payload: import("drizzle-orm/pg-core").PgColumn<{
76
+ name: "payload";
77
+ tableName: "extras_sourced_content";
78
+ dataType: "json";
79
+ columnType: "PgJsonb";
80
+ data: Record<string, unknown>;
81
+ driverParam: unknown;
82
+ notNull: true;
83
+ hasDefault: false;
84
+ isPrimaryKey: false;
85
+ isAutoincrement: false;
86
+ hasRuntimeDefault: false;
87
+ enumValues: undefined;
88
+ baseColumn: never;
89
+ identity: undefined;
90
+ generated: undefined;
91
+ }, {}, {
92
+ $type: Record<string, unknown>;
93
+ }>;
94
+ content_schema_version: import("drizzle-orm/pg-core").PgColumn<{
95
+ name: "content_schema_version";
96
+ tableName: "extras_sourced_content";
97
+ dataType: "string";
98
+ columnType: "PgText";
99
+ data: string;
100
+ driverParam: string;
101
+ notNull: true;
102
+ hasDefault: false;
103
+ isPrimaryKey: false;
104
+ isAutoincrement: false;
105
+ hasRuntimeDefault: false;
106
+ enumValues: [string, ...string[]];
107
+ baseColumn: never;
108
+ identity: undefined;
109
+ generated: undefined;
110
+ }, {}, {}>;
111
+ returned_locale: import("drizzle-orm/pg-core").PgColumn<{
112
+ name: "returned_locale";
113
+ tableName: "extras_sourced_content";
114
+ dataType: "string";
115
+ columnType: "PgText";
116
+ data: string;
117
+ driverParam: string;
118
+ notNull: true;
119
+ hasDefault: false;
120
+ isPrimaryKey: false;
121
+ isAutoincrement: false;
122
+ hasRuntimeDefault: false;
123
+ enumValues: [string, ...string[]];
124
+ baseColumn: never;
125
+ identity: undefined;
126
+ generated: undefined;
127
+ }, {}, {}>;
128
+ machine_translated: import("drizzle-orm/pg-core").PgColumn<{
129
+ name: "machine_translated";
130
+ tableName: "extras_sourced_content";
131
+ dataType: "boolean";
132
+ columnType: "PgBoolean";
133
+ data: boolean;
134
+ driverParam: boolean;
135
+ notNull: true;
136
+ hasDefault: true;
137
+ isPrimaryKey: false;
138
+ isAutoincrement: false;
139
+ hasRuntimeDefault: false;
140
+ enumValues: undefined;
141
+ baseColumn: never;
142
+ identity: undefined;
143
+ generated: undefined;
144
+ }, {}, {}>;
145
+ source_updated_at: import("drizzle-orm/pg-core").PgColumn<{
146
+ name: "source_updated_at";
147
+ tableName: "extras_sourced_content";
148
+ dataType: "date";
149
+ columnType: "PgTimestamp";
150
+ data: Date;
151
+ driverParam: string;
152
+ notNull: false;
153
+ hasDefault: false;
154
+ isPrimaryKey: false;
155
+ isAutoincrement: false;
156
+ hasRuntimeDefault: false;
157
+ enumValues: undefined;
158
+ baseColumn: never;
159
+ identity: undefined;
160
+ generated: undefined;
161
+ }, {}, {}>;
162
+ fetched_at: import("drizzle-orm/pg-core").PgColumn<{
163
+ name: "fetched_at";
164
+ tableName: "extras_sourced_content";
165
+ dataType: "date";
166
+ columnType: "PgTimestamp";
167
+ data: Date;
168
+ driverParam: string;
169
+ notNull: true;
170
+ hasDefault: true;
171
+ isPrimaryKey: false;
172
+ isAutoincrement: false;
173
+ hasRuntimeDefault: false;
174
+ enumValues: undefined;
175
+ baseColumn: never;
176
+ identity: undefined;
177
+ generated: undefined;
178
+ }, {}, {}>;
179
+ fresh_until: import("drizzle-orm/pg-core").PgColumn<{
180
+ name: "fresh_until";
181
+ tableName: "extras_sourced_content";
182
+ dataType: "date";
183
+ columnType: "PgTimestamp";
184
+ data: Date;
185
+ driverParam: string;
186
+ notNull: false;
187
+ hasDefault: false;
188
+ isPrimaryKey: false;
189
+ isAutoincrement: false;
190
+ hasRuntimeDefault: false;
191
+ enumValues: undefined;
192
+ baseColumn: never;
193
+ identity: undefined;
194
+ generated: undefined;
195
+ }, {}, {}>;
196
+ etag: import("drizzle-orm/pg-core").PgColumn<{
197
+ name: "etag";
198
+ tableName: "extras_sourced_content";
199
+ dataType: "string";
200
+ columnType: "PgText";
201
+ data: string;
202
+ driverParam: string;
203
+ notNull: false;
204
+ hasDefault: false;
205
+ isPrimaryKey: false;
206
+ isAutoincrement: false;
207
+ hasRuntimeDefault: false;
208
+ enumValues: [string, ...string[]];
209
+ baseColumn: never;
210
+ identity: undefined;
211
+ generated: undefined;
212
+ }, {}, {}>;
213
+ fetch_status: import("drizzle-orm/pg-core").PgColumn<{
214
+ name: "fetch_status";
215
+ tableName: "extras_sourced_content";
216
+ dataType: "string";
217
+ columnType: "PgText";
218
+ data: ExtrasSourcedContentFetchStatus;
219
+ driverParam: string;
220
+ notNull: true;
221
+ hasDefault: true;
222
+ isPrimaryKey: false;
223
+ isAutoincrement: false;
224
+ hasRuntimeDefault: false;
225
+ enumValues: [string, ...string[]];
226
+ baseColumn: never;
227
+ identity: undefined;
228
+ generated: undefined;
229
+ }, {}, {
230
+ $type: ExtrasSourcedContentFetchStatus;
231
+ }>;
232
+ fetch_error: import("drizzle-orm/pg-core").PgColumn<{
233
+ name: "fetch_error";
234
+ tableName: "extras_sourced_content";
235
+ dataType: "string";
236
+ columnType: "PgText";
237
+ data: string;
238
+ driverParam: string;
239
+ notNull: false;
240
+ hasDefault: false;
241
+ isPrimaryKey: false;
242
+ isAutoincrement: false;
243
+ hasRuntimeDefault: false;
244
+ enumValues: [string, ...string[]];
245
+ baseColumn: never;
246
+ identity: undefined;
247
+ generated: undefined;
248
+ }, {}, {}>;
249
+ };
250
+ dialect: "pg";
251
+ }>;
252
+ export type InsertExtrasSourcedContent = typeof extrasSourcedContentTable.$inferInsert;
253
+ export type SelectExtrasSourcedContent = typeof extrasSourcedContentTable.$inferSelect;
254
+ //# sourceMappingURL=schema-sourced-content.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-sourced-content.d.ts","sourceRoot":"","sources":["../src/schema-sourced-content.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,MAAM,MAAM,+BAA+B,GAAG,IAAI,GAAG,OAAO,GAAG,OAAO,GAAG,aAAa,CAAA;AAEtF,eAAO,MAAM,yBAAyB,MAAM,CAAA;AAE5C,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiCrC,CAAA;AAED,MAAM,MAAM,0BAA0B,GAAG,OAAO,yBAAyB,CAAC,YAAY,CAAA;AACtF,MAAM,MAAM,0BAA0B,GAAG,OAAO,yBAAyB,CAAC,YAAY,CAAA"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Extras sourced-content cache. Sibling to the products / cruises /
3
+ * hospitality / charters variants — same shape, different vertical.
4
+ *
5
+ * One row per sourced extra × locale × market. Stores the content the
6
+ * upstream adapter served via `getContent`, plus the SWR metadata the
7
+ * read service needs.
8
+ *
9
+ * Extras are booking add-ons (optional line items layered on a parent
10
+ * product). Per `catalog-policy.ts`, extras are a partial-adoption
11
+ * vertical: they don't appear in the search index, but sourced extras
12
+ * (e.g. a TUI excursion add-on) still need rich content for the
13
+ * booking-flow's add-on selection UI. The sourced-content cache covers
14
+ * exactly that surface.
15
+ *
16
+ * See `docs/architecture/catalog-sourced-content.md` §3.2.
17
+ */
18
+ import { boolean, index, jsonb, pgTable, primaryKey, text, timestamp } from "drizzle-orm/pg-core";
19
+ export const EXTRAS_CONTENT_MARKET_ANY = "*";
20
+ export const extrasSourcedContentTable = pgTable("extras_sourced_content", {
21
+ /** TypeID matching the extras module — `pxtr_*` (product_extras). */
22
+ entity_id: text("entity_id").notNull(),
23
+ /** BCP 47 language tag. */
24
+ locale: text("locale").notNull(),
25
+ /** Market id, or `'*'` for all-markets. */
26
+ market: text("market").notNull().default(EXTRAS_CONTENT_MARKET_ANY),
27
+ payload: jsonb("payload").$type().notNull(),
28
+ content_schema_version: text("content_schema_version").notNull(),
29
+ returned_locale: text("returned_locale").notNull(),
30
+ machine_translated: boolean("machine_translated").notNull().default(false),
31
+ source_updated_at: timestamp("source_updated_at", { withTimezone: true }),
32
+ fetched_at: timestamp("fetched_at", { withTimezone: true }).notNull().defaultNow(),
33
+ fresh_until: timestamp("fresh_until", { withTimezone: true }),
34
+ etag: text("etag"),
35
+ fetch_status: text("fetch_status")
36
+ .$type()
37
+ .notNull()
38
+ .default("ok"),
39
+ fetch_error: text("fetch_error"),
40
+ }, (table) => [
41
+ primaryKey({ columns: [table.entity_id, table.locale, table.market] }),
42
+ index("extras_sourced_content_locale_fresh_idx").on(table.locale, table.fresh_until),
43
+ index("extras_sourced_content_returned_locale_idx").on(table.entity_id, table.returned_locale),
44
+ index("extras_sourced_content_schema_version_idx").on(table.content_schema_version),
45
+ ]);
package/dist/schema.d.ts CHANGED
@@ -39,6 +39,23 @@ export declare const productExtras: import("drizzle-orm/pg-core").PgTableWithCol
39
39
  identity: undefined;
40
40
  generated: undefined;
41
41
  }, {}, {}>;
42
+ supplierId: import("drizzle-orm/pg-core").PgColumn<{
43
+ name: "supplier_id";
44
+ tableName: "product_extras";
45
+ dataType: "string";
46
+ columnType: "PgText";
47
+ data: string;
48
+ driverParam: string;
49
+ notNull: false;
50
+ hasDefault: false;
51
+ isPrimaryKey: false;
52
+ isAutoincrement: false;
53
+ hasRuntimeDefault: false;
54
+ enumValues: [string, ...string[]];
55
+ baseColumn: never;
56
+ identity: undefined;
57
+ generated: undefined;
58
+ }, {}, {}>;
42
59
  code: import("drizzle-orm/pg-core").PgColumn<{
43
60
  name: "code";
44
61
  tableName: "product_extras";
@@ -95,7 +112,7 @@ export declare const productExtras: import("drizzle-orm/pg-core").PgTableWithCol
95
112
  tableName: "product_extras";
96
113
  dataType: "string";
97
114
  columnType: "PgEnumColumn";
98
- data: "optional" | "required" | "default_selected" | "unavailable";
115
+ data: "unavailable" | "optional" | "default_selected" | "required";
99
116
  driverParam: string;
100
117
  notNull: true;
101
118
  hasDefault: true;
@@ -342,7 +359,7 @@ export declare const optionExtraConfigs: import("drizzle-orm/pg-core").PgTableWi
342
359
  tableName: "option_extra_configs";
343
360
  dataType: "string";
344
361
  columnType: "PgEnumColumn";
345
- data: "optional" | "required" | "default_selected" | "unavailable";
362
+ data: "unavailable" | "optional" | "default_selected" | "required";
346
363
  driverParam: string;
347
364
  notNull: false;
348
365
  hasDefault: false;
@@ -674,7 +691,7 @@ export declare const bookingExtras: import("drizzle-orm/pg-core").PgTableWithCol
674
691
  tableName: "booking_extras";
675
692
  dataType: "string";
676
693
  columnType: "PgEnumColumn";
677
- data: "draft" | "selected" | "confirmed" | "cancelled" | "fulfilled";
694
+ data: "confirmed" | "cancelled" | "draft" | "selected" | "fulfilled";
678
695
  driverParam: string;
679
696
  notNull: true;
680
697
  hasDefault: true;
@@ -930,4 +947,5 @@ export declare const bookingExtrasRelations: import("drizzle-orm").Relations<"bo
930
947
  productExtra: import("drizzle-orm").One<"product_extras", false>;
931
948
  optionExtraConfig: import("drizzle-orm").One<"option_extra_configs", false>;
932
949
  }>;
950
+ export { EXTRAS_CONTENT_MARKET_ANY, type ExtrasSourcedContentFetchStatus, extrasSourcedContentTable, type InsertExtrasSourcedContent, type SelectExtrasSourcedContent, } from "./schema-sourced-content.js";
933
951
  //# sourceMappingURL=schema.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAcA,eAAO,MAAM,sBAAsB,mGAKjC,CAAA;AAEF,eAAO,MAAM,oBAAoB,yHAO/B,CAAA;AAEF,eAAO,MAAM,sBAAsB,oGAMjC,CAAA;AAEF,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA0BzB,CAAA;AAED,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAyC9B,CAAA;AAED,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAyCzB,CAAA;AAED,MAAM,MAAM,YAAY,GAAG,OAAO,aAAa,CAAC,YAAY,CAAA;AAC5D,MAAM,MAAM,eAAe,GAAG,OAAO,aAAa,CAAC,YAAY,CAAA;AAC/D,MAAM,MAAM,iBAAiB,GAAG,OAAO,kBAAkB,CAAC,YAAY,CAAA;AACtE,MAAM,MAAM,oBAAoB,GAAG,OAAO,kBAAkB,CAAC,YAAY,CAAA;AACzE,MAAM,MAAM,YAAY,GAAG,OAAO,aAAa,CAAC,YAAY,CAAA;AAC5D,MAAM,MAAM,eAAe,GAAG,OAAO,aAAa,CAAC,YAAY,CAAA;AAE/D,eAAO,MAAM,sBAAsB;;;EAGhC,CAAA;AAEH,eAAO,MAAM,2BAA2B;;;EAMrC,CAAA;AAEH,eAAO,MAAM,sBAAsB;;;EAShC,CAAA"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAcA,eAAO,MAAM,sBAAsB,mGAKjC,CAAA;AAEF,eAAO,MAAM,oBAAoB,yHAO/B,CAAA;AAEF,eAAO,MAAM,sBAAsB,oGAMjC,CAAA;AAEF,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgCzB,CAAA;AAED,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAyC9B,CAAA;AAED,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAyCzB,CAAA;AAED,MAAM,MAAM,YAAY,GAAG,OAAO,aAAa,CAAC,YAAY,CAAA;AAC5D,MAAM,MAAM,eAAe,GAAG,OAAO,aAAa,CAAC,YAAY,CAAA;AAC/D,MAAM,MAAM,iBAAiB,GAAG,OAAO,kBAAkB,CAAC,YAAY,CAAA;AACtE,MAAM,MAAM,oBAAoB,GAAG,OAAO,kBAAkB,CAAC,YAAY,CAAA;AACzE,MAAM,MAAM,YAAY,GAAG,OAAO,aAAa,CAAC,YAAY,CAAA;AAC5D,MAAM,MAAM,eAAe,GAAG,OAAO,aAAa,CAAC,YAAY,CAAA;AAE/D,eAAO,MAAM,sBAAsB;;;EAGhC,CAAA;AAEH,eAAO,MAAM,2BAA2B;;;EAMrC,CAAA;AAEH,eAAO,MAAM,sBAAsB;;;EAShC,CAAA;AAKH,OAAO,EACL,yBAAyB,EACzB,KAAK,+BAA+B,EACpC,yBAAyB,EACzB,KAAK,0BAA0B,EAC/B,KAAK,0BAA0B,GAChC,MAAM,6BAA6B,CAAA"}
package/dist/schema.js CHANGED
@@ -25,6 +25,7 @@ export const bookingExtraStatusEnum = pgEnum("booking_extra_status", [
25
25
  export const productExtras = pgTable("product_extras", {
26
26
  id: typeId("product_extras"),
27
27
  productId: text("product_id").notNull(),
28
+ supplierId: text("supplier_id"),
28
29
  code: text("code"),
29
30
  name: text("name").notNull(),
30
31
  description: text("description"),
@@ -42,6 +43,7 @@ export const productExtras = pgTable("product_extras", {
42
43
  }, (table) => [
43
44
  index("idx_product_extras_sort_name").on(table.sortOrder, table.name),
44
45
  index("idx_product_extras_product_sort_name").on(table.productId, table.sortOrder, table.name),
46
+ index("idx_product_extras_supplier_sort_name").on(table.supplierId, table.sortOrder, table.name),
45
47
  index("idx_product_extras_active_sort_name").on(table.active, table.sortOrder, table.name),
46
48
  uniqueIndex("uidx_product_extras_product_code").on(table.productId, table.code),
47
49
  ]);
@@ -124,3 +126,7 @@ export const bookingExtrasRelations = relations(bookingExtras, ({ one }) => ({
124
126
  references: [optionExtraConfigs.id],
125
127
  }),
126
128
  }));
129
+ // ─── Sourced-content cache ──────────────────────────────────────────
130
+ // Re-exported here so templates pick it up via the package's `./schema`
131
+ // entry without needing a separate config entry.
132
+ export { EXTRAS_CONTENT_MARKET_ANY, extrasSourcedContentTable, } from "./schema-sourced-content.js";
@@ -1 +1 @@
1
- {"version":3,"file":"service-catalog-plane.d.ts","sourceRoot":"","sources":["../src/service-catalog-plane.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAGL,KAAK,oBAAoB,EAEzB,KAAK,eAAe,EACpB,KAAK,eAAe,EAEpB,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,aAAa,EAEnB,MAAM,mBAAmB,CAAA;AAC1B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAIhD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAU3C;;;;;GAKG;AACH,wBAAgB,2BAA2B,CACzC,GAAG,EAAE,OAAO,aAAa,CAAC,YAAY,EACtC,OAAO,EAAE;IAAE,gBAAgB,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAC7E,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,CA4B9B;AAED,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,OAAO,aAAa,CAAC,YAAY,EACvC,OAAO,EAAE;IAAE,gBAAgB,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAC7E,UAAU,CAMZ;AAED,MAAM,WAAW,0BAA0B;IACzC,gBAAgB,EAAE,MAAM,CAAA;IACxB,KAAK,EAAE,aAAa,CAAA;IACpB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;;;GAKG;AACH,wBAAsB,oBAAoB,CACxC,EAAE,EAAE,YAAY,EAChB,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,0BAA0B,GAClC,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAW9B;AAED,wBAAsB,kBAAkB,CACtC,EAAE,EAAE,YAAY,EAChB,IAAI,EAAE,aAAa,CAAC,OAAO,aAAa,CAAC,YAAY,CAAC,EACtD,OAAO,EAAE,0BAA0B,GAClC,OAAO,CAAC,YAAY,EAAE,CAAC,CAazB;AAED;;;;;GAKG;AACH,wBAAsB,uBAAuB,CAC3C,EAAE,EAAE,YAAY,EAChB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,0BAA0B,GAAG;IAAE,YAAY,CAAC,EAAE,YAAY,CAAA;CAAE,GACpE,OAAO,CAAC,IAAI,CAAC,oBAAoB,EAAE,WAAW,CAAC,GAAG,IAAI,CAAC,CAUzD;AAMD;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE;IAClD,gBAAgB,EAAE,MAAM,CAAA;IACxB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,GAAG,eAAe,CAAC,OAAO,aAAa,CAAC,YAAY,CAAC,CAarD;AAED,wBAAgB,0BAA0B,CACxC,EAAE,EAAE,YAAY,EAChB,OAAO,EAAE;IAAE,gBAAgB,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAC7E,eAAe,CAYjB;AAED,YAAY,EACV,oBAAoB,EACpB,eAAe,EACf,eAAe,EACf,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,aAAa,GACd,CAAA"}
1
+ {"version":3,"file":"service-catalog-plane.d.ts","sourceRoot":"","sources":["../src/service-catalog-plane.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAGL,KAAK,oBAAoB,EAEzB,KAAK,eAAe,EACpB,KAAK,eAAe,EAEpB,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,aAAa,EAEnB,MAAM,mBAAmB,CAAA;AAC1B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAIhD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAU3C;;;;;GAKG;AACH,wBAAgB,2BAA2B,CACzC,GAAG,EAAE,OAAO,aAAa,CAAC,YAAY,EACtC,OAAO,EAAE;IAAE,gBAAgB,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAC7E,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,CA6B9B;AAED,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,OAAO,aAAa,CAAC,YAAY,EACvC,OAAO,EAAE;IAAE,gBAAgB,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAC7E,UAAU,CAMZ;AAED,MAAM,WAAW,0BAA0B;IACzC,gBAAgB,EAAE,MAAM,CAAA;IACxB,KAAK,EAAE,aAAa,CAAA;IACpB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;;;GAKG;AACH,wBAAsB,oBAAoB,CACxC,EAAE,EAAE,YAAY,EAChB,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,0BAA0B,GAClC,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAW9B;AAED,wBAAsB,kBAAkB,CACtC,EAAE,EAAE,YAAY,EAChB,IAAI,EAAE,aAAa,CAAC,OAAO,aAAa,CAAC,YAAY,CAAC,EACtD,OAAO,EAAE,0BAA0B,GAClC,OAAO,CAAC,YAAY,EAAE,CAAC,CAazB;AAED;;;;;GAKG;AACH,wBAAsB,uBAAuB,CAC3C,EAAE,EAAE,YAAY,EAChB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,0BAA0B,GAAG;IAAE,YAAY,CAAC,EAAE,YAAY,CAAA;CAAE,GACpE,OAAO,CAAC,IAAI,CAAC,oBAAoB,EAAE,WAAW,CAAC,GAAG,IAAI,CAAC,CAUzD;AAMD;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE;IAClD,gBAAgB,EAAE,MAAM,CAAA;IACxB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,GAAG,eAAe,CAAC,OAAO,aAAa,CAAC,YAAY,CAAC,CAarD;AAED,wBAAgB,0BAA0B,CACxC,EAAE,EAAE,YAAY,EAChB,OAAO,EAAE;IAAE,gBAAgB,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAC7E,eAAe,CAYjB;AAED,YAAY,EACV,oBAAoB,EACpB,eAAe,EACf,eAAe,EACf,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,aAAa,GACd,CAAA"}
@@ -43,6 +43,7 @@ export function productExtraRowToProjection(row, context) {
43
43
  ["id", row.id],
44
44
  ["code", row.code],
45
45
  ["productId", row.productId],
46
+ ["supplierId", row.supplierId],
46
47
  ["createdAt", row.createdAt],
47
48
  ["updatedAt", row.updatedAt],
48
49
  // Snapshot-relevant managed fields
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Extras content synthesizer — fallback for thin adapters that declare
3
+ * `supportsContentFetch: false`.
4
+ *
5
+ * Produces the most complete `ExtraContent` blob we can legitimately
6
+ * synthesize from the durable sourced-entry projection + locale-aware
7
+ * overlays + plane-level provenance. Sub-options render as a typed
8
+ * empty state unless the projection genuinely carries them.
9
+ *
10
+ * Per §3.6: never invents plausible-but-unverified fields, never
11
+ * machine-translates, never mines snapshots, never caches its own
12
+ * output.
13
+ */
14
+ import { type ProvenanceReadResult } from "@voyantjs/catalog";
15
+ import type { AnyDrizzleDb } from "@voyantjs/db";
16
+ import { type ExtraContent } from "./content-shape.js";
17
+ export interface SynthesizeExtraContentOptions {
18
+ provenance: Extract<ProvenanceReadResult, {
19
+ kind: "sourced";
20
+ }>;
21
+ overlays?: ReadonlyArray<{
22
+ field_path: string;
23
+ value: unknown;
24
+ }>;
25
+ }
26
+ export interface SynthesizedExtraContent {
27
+ content: ExtraContent;
28
+ content_schema_version: string;
29
+ served_locale: string;
30
+ source_kind: string;
31
+ source_provider?: string;
32
+ }
33
+ export declare function synthesizeExtraContent(scope: {
34
+ locale: string;
35
+ }, options: SynthesizeExtraContentOptions): SynthesizedExtraContent;
36
+ export declare function synthesizeExtraContentFromDb(db: AnyDrizzleDb, scope: {
37
+ locale: string;
38
+ }, provenance: Extract<ProvenanceReadResult, {
39
+ kind: "sourced";
40
+ }>): Promise<SynthesizedExtraContent>;
41
+ //# sourceMappingURL=service-content-synthesizer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-content-synthesizer.d.ts","sourceRoot":"","sources":["../src/service-content-synthesizer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAGL,KAAK,oBAAoB,EAC1B,MAAM,mBAAmB,CAAA;AAC1B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAEhD,OAAO,EAEL,KAAK,YAAY,EAElB,MAAM,oBAAoB,CAAA;AAE3B,MAAM,WAAW,6BAA6B;IAC5C,UAAU,EAAE,OAAO,CAAC,oBAAoB,EAAE;QAAE,IAAI,EAAE,SAAS,CAAA;KAAE,CAAC,CAAA;IAC9D,QAAQ,CAAC,EAAE,aAAa,CAAC;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC,CAAA;CACjE;AAED,MAAM,WAAW,uBAAuB;IACtC,OAAO,EAAE,YAAY,CAAA;IACrB,sBAAsB,EAAE,MAAM,CAAA;IAC9B,aAAa,EAAE,MAAM,CAAA;IACrB,WAAW,EAAE,MAAM,CAAA;IACnB,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB;AAED,wBAAgB,sBAAsB,CACpC,KAAK,EAAE;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,EACzB,OAAO,EAAE,6BAA6B,GACrC,uBAAuB,CAiCzB;AAED,wBAAsB,4BAA4B,CAChD,EAAE,EAAE,YAAY,EAChB,KAAK,EAAE;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,EACzB,UAAU,EAAE,OAAO,CAAC,oBAAoB,EAAE;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,CAAC,GAC7D,OAAO,CAAC,uBAAuB,CAAC,CAOlC"}
@@ -0,0 +1,138 @@
1
+ /**
2
+ * Extras content synthesizer — fallback for thin adapters that declare
3
+ * `supportsContentFetch: false`.
4
+ *
5
+ * Produces the most complete `ExtraContent` blob we can legitimately
6
+ * synthesize from the durable sourced-entry projection + locale-aware
7
+ * overlays + plane-level provenance. Sub-options render as a typed
8
+ * empty state unless the projection genuinely carries them.
9
+ *
10
+ * Per §3.6: never invents plausible-but-unverified fields, never
11
+ * machine-translates, never mines snapshots, never caches its own
12
+ * output.
13
+ */
14
+ import { fetchOverlaysForEntity, mergeOverlaysIntoContent, } from "@voyantjs/catalog";
15
+ import { EXTRAS_CONTENT_SCHEMA_VERSION, extraContentSchema, } from "./content-shape.js";
16
+ export function synthesizeExtraContent(scope, options) {
17
+ const projection = options.provenance.projection;
18
+ const extra = pickExtraSummary(projection, options.provenance);
19
+ const media = pickMedia(projection);
20
+ const policies = pickPolicies(projection);
21
+ const baseContent = {
22
+ extra,
23
+ options: [],
24
+ media,
25
+ policies,
26
+ };
27
+ let merged = baseContent;
28
+ if (options.overlays && options.overlays.length > 0) {
29
+ const result = mergeOverlaysIntoContent(baseContent, options.overlays, {
30
+ validate(p) {
31
+ const r = extraContentSchema.safeParse(p);
32
+ return r.success
33
+ ? { valid: true }
34
+ : { valid: false, reason: r.error.issues[0]?.message ?? "invalid" };
35
+ },
36
+ });
37
+ merged = extraContentSchema.parse(result);
38
+ }
39
+ return {
40
+ content: merged,
41
+ content_schema_version: EXTRAS_CONTENT_SCHEMA_VERSION,
42
+ served_locale: scope.locale,
43
+ source_kind: options.provenance.provenance.source_kind,
44
+ source_provider: options.provenance.provenance.source_provider,
45
+ };
46
+ }
47
+ export async function synthesizeExtraContentFromDb(db, scope, provenance) {
48
+ const entityId = entityIdFromProvenance(provenance);
49
+ const overlays = await fetchOverlaysForEntity(db, "extras", entityId);
50
+ return synthesizeExtraContent(scope, {
51
+ provenance,
52
+ overlays: overlays.map((o) => ({ field_path: o.field_path, value: o.value })),
53
+ });
54
+ }
55
+ function entityIdFromProvenance(provenance) {
56
+ const fromProjection = provenance.projection.id;
57
+ if (typeof fromProjection === "string" && fromProjection.length > 0) {
58
+ return fromProjection;
59
+ }
60
+ return provenance.entry_id;
61
+ }
62
+ function pickExtraSummary(projection, provenance) {
63
+ return {
64
+ id: stringOr(projection.id, "") || provenance.entry_id,
65
+ name: stringOr(projection.name, "") || stringOr(projection.title, "") || "Unnamed extra",
66
+ status: stringOr(projection.status, undefined),
67
+ description: stringOr(projection.description, null),
68
+ selection_type: stringOr(projection.selection_type, "optional"),
69
+ pricing_mode: stringOr(projection.pricing_mode, "per_booking"),
70
+ priced_per_person: typeof projection.priced_per_person === "boolean" ? projection.priced_per_person : undefined,
71
+ category: stringOr(projection.category, null),
72
+ hero_image_url: stringOr(projection.hero_image_url, null),
73
+ highlights: stringArrayOr(projection.highlights, []),
74
+ supplier: stringOr(projection.supplier, null) ??
75
+ stringOr(projection.supplier_name, null) ??
76
+ provenance.provenance.source_provider ??
77
+ null,
78
+ duration_minutes: numberOr(projection.duration_minutes, null),
79
+ requirements_summary: stringOr(projection.requirements_summary, null),
80
+ };
81
+ }
82
+ function pickMedia(projection) {
83
+ const heroUrl = stringOr(projection.hero_image_url, null);
84
+ const out = [];
85
+ if (heroUrl) {
86
+ out.push({ url: heroUrl, type: "image", caption: null, alt: null });
87
+ }
88
+ const additional = projection.media;
89
+ if (Array.isArray(additional)) {
90
+ for (const item of additional) {
91
+ if (item && typeof item === "object") {
92
+ const obj = item;
93
+ const url = stringOr(obj.url, null);
94
+ if (!url)
95
+ continue;
96
+ out.push({
97
+ url,
98
+ type: pickMediaType(obj.type),
99
+ caption: stringOr(obj.caption, null),
100
+ alt: stringOr(obj.alt, null),
101
+ });
102
+ }
103
+ }
104
+ }
105
+ return out;
106
+ }
107
+ function pickMediaType(value) {
108
+ if (value === "video")
109
+ return "video";
110
+ if (value === "document")
111
+ return "document";
112
+ return "image";
113
+ }
114
+ function pickPolicies(projection) {
115
+ const out = [];
116
+ const cancel = stringOr(projection.cancellation_policy, null);
117
+ if (cancel)
118
+ out.push({ kind: "cancellation", body: cancel });
119
+ const payment = stringOr(projection.payment_terms, null);
120
+ if (payment)
121
+ out.push({ kind: "payment", body: payment });
122
+ const requirements = stringOr(projection.requirements, null);
123
+ if (requirements)
124
+ out.push({ kind: "requirements", body: requirements });
125
+ return out;
126
+ }
127
+ function stringOr(value, fallback) {
128
+ return typeof value === "string" && value.length > 0 ? value : fallback;
129
+ }
130
+ function numberOr(value, fallback) {
131
+ return typeof value === "number" && Number.isFinite(value) ? value : fallback;
132
+ }
133
+ function stringArrayOr(value, fallback) {
134
+ if (!Array.isArray(value))
135
+ return fallback;
136
+ const out = value.filter((v) => typeof v === "string");
137
+ return out.length > 0 ? out : fallback;
138
+ }
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Extras content service — `getExtraContent` with locale-resolved
3
+ * cache reads, SWR refresh, and synthesizer fallback.
4
+ *
5
+ * Mirrors `service-content.ts` in the products / cruises / hospitality
6
+ * / charters packages but extras-shaped. The extras content aggregate
7
+ * (§3.2 / §3.6) is `{ extra, options[], media[], policies[] }` — one
8
+ * payload returned by a single getContent. Pricing stays out (volatile-
9
+ * live, flows through `liveResolve`).
10
+ *
11
+ * Extras don't appear in the search index (per the vertical's catalog-
12
+ * policy.ts), but sourced extras still need rich content for the
13
+ * booking-flow's add-on selection UI. The cache layer covers exactly
14
+ * that surface.
15
+ */
16
+ import { type ContentLocaleResolution, type InvalidateOnDrift, type SourceAdapter, type SourceAdapterContext } from "@voyantjs/catalog";
17
+ import type { SourceAdapterRegistry } from "@voyantjs/catalog/booking-engine";
18
+ import type { AnyDrizzleDb } from "@voyantjs/db";
19
+ import { type ExtraContent } from "./content-shape.js";
20
+ export interface ExtraContentScope {
21
+ preferredLocales: ReadonlyArray<string>;
22
+ market?: string;
23
+ currency?: string;
24
+ acceptMachineTranslated?: boolean;
25
+ }
26
+ export interface GetExtraContentOptions {
27
+ registry: SourceAdapterRegistry;
28
+ buildAdapterContext?: (adapter: SourceAdapter) => SourceAdapterContext;
29
+ onOverlayError?: (event: {
30
+ field_path: string;
31
+ reason: string;
32
+ }) => void;
33
+ }
34
+ export interface ResolvedExtraContent {
35
+ content: ExtraContent;
36
+ resolution: ContentLocaleResolution<{
37
+ locale: string;
38
+ payload: ExtraContent;
39
+ }>;
40
+ source: "sourced-cache" | "sourced-fresh" | "synthesized";
41
+ served_stale: boolean;
42
+ synthesized: boolean;
43
+ machine_translated: boolean;
44
+ }
45
+ export declare function getExtraContent(db: AnyDrizzleDb, entityId: string, scope: ExtraContentScope, options: GetExtraContentOptions): Promise<ResolvedExtraContent | null>;
46
+ /** Drift event consumer for the extras content cache. Per §3.4.1. */
47
+ export declare const invalidateExtraContentOnDrift: InvalidateOnDrift;
48
+ //# sourceMappingURL=service-content.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-content.d.ts","sourceRoot":"","sources":["../src/service-content.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EACL,KAAK,uBAAuB,EAK5B,KAAK,iBAAiB,EAKtB,KAAK,aAAa,EAClB,KAAK,oBAAoB,EAE1B,MAAM,mBAAmB,CAAA;AAC1B,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAA;AAC7E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAGhD,OAAO,EAEL,KAAK,YAAY,EAIlB,MAAM,oBAAoB,CAAA;AAc3B,MAAM,WAAW,iBAAiB;IAChC,gBAAgB,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;IACvC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,uBAAuB,CAAC,EAAE,OAAO,CAAA;CAClC;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,qBAAqB,CAAA;IAC/B,mBAAmB,CAAC,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,oBAAoB,CAAA;IACtE,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAA;CACzE;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,YAAY,CAAA;IACrB,UAAU,EAAE,uBAAuB,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,YAAY,CAAA;KAAE,CAAC,CAAA;IAC9E,MAAM,EAAE,eAAe,GAAG,eAAe,GAAG,aAAa,CAAA;IACzD,YAAY,EAAE,OAAO,CAAA;IACrB,WAAW,EAAE,OAAO,CAAA;IACpB,kBAAkB,EAAE,OAAO,CAAA;CAC5B;AAED,wBAAsB,eAAe,CACnC,EAAE,EAAE,YAAY,EAChB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,iBAAiB,EACxB,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CA0FtC;AA2ND,qEAAqE;AACrE,eAAO,MAAM,6BAA6B,EAAE,iBAG3C,CAAA"}