@endora-commerce/contracts 0.100.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.
- package/LICENSE +21 -0
- package/README.md +34 -0
- package/dist/actor.d.ts +79 -0
- package/dist/actor.d.ts.map +1 -0
- package/dist/actor.js +41 -0
- package/dist/actor.js.map +1 -0
- package/dist/addresses.d.ts +134 -0
- package/dist/addresses.d.ts.map +1 -0
- package/dist/addresses.js +16 -0
- package/dist/addresses.js.map +1 -0
- package/dist/admin-actions.d.ts +367 -0
- package/dist/admin-actions.d.ts.map +1 -0
- package/dist/admin-actions.js +287 -0
- package/dist/admin-actions.js.map +1 -0
- package/dist/admin-contributions.d.ts +518 -0
- package/dist/admin-contributions.d.ts.map +1 -0
- package/dist/admin-contributions.js +495 -0
- package/dist/admin-contributions.js.map +1 -0
- package/dist/admin-i18n.d.ts +135 -0
- package/dist/admin-i18n.d.ts.map +1 -0
- package/dist/admin-i18n.js +72 -0
- package/dist/admin-i18n.js.map +1 -0
- package/dist/admin-notifications.d.ts +55 -0
- package/dist/admin-notifications.d.ts.map +1 -0
- package/dist/admin-notifications.js +16 -0
- package/dist/admin-notifications.js.map +1 -0
- package/dist/admin-roles.d.ts +125 -0
- package/dist/admin-roles.d.ts.map +1 -0
- package/dist/admin-roles.js +2 -0
- package/dist/admin-roles.js.map +1 -0
- package/dist/admin-users.d.ts +178 -0
- package/dist/admin-users.d.ts.map +1 -0
- package/dist/admin-users.js +14 -0
- package/dist/admin-users.js.map +1 -0
- package/dist/admin.d.ts +243 -0
- package/dist/admin.d.ts.map +1 -0
- package/dist/admin.js +246 -0
- package/dist/admin.js.map +1 -0
- package/dist/analytics.d.ts +123 -0
- package/dist/analytics.d.ts.map +1 -0
- package/dist/analytics.js +68 -0
- package/dist/analytics.js.map +1 -0
- package/dist/api-keys.d.ts +97 -0
- package/dist/api-keys.d.ts.map +1 -0
- package/dist/api-keys.js +64 -0
- package/dist/api-keys.js.map +1 -0
- package/dist/assets-library.d.ts +684 -0
- package/dist/assets-library.d.ts.map +1 -0
- package/dist/assets-library.js +181 -0
- package/dist/assets-library.js.map +1 -0
- package/dist/audit-logs.d.ts +141 -0
- package/dist/audit-logs.d.ts.map +1 -0
- package/dist/audit-logs.js +31 -0
- package/dist/audit-logs.js.map +1 -0
- package/dist/auth.d.ts +174 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +27 -0
- package/dist/auth.js.map +1 -0
- package/dist/blog.d.ts +669 -0
- package/dist/blog.d.ts.map +1 -0
- package/dist/blog.js +360 -0
- package/dist/blog.js.map +1 -0
- package/dist/capabilities.d.ts +40 -0
- package/dist/capabilities.d.ts.map +1 -0
- package/dist/capabilities.js +38 -0
- package/dist/capabilities.js.map +1 -0
- package/dist/carts.d.ts +1367 -0
- package/dist/carts.d.ts.map +1 -0
- package/dist/carts.js +405 -0
- package/dist/carts.js.map +1 -0
- package/dist/catalog.d.ts +2855 -0
- package/dist/catalog.d.ts.map +1 -0
- package/dist/catalog.js +1543 -0
- package/dist/catalog.js.map +1 -0
- package/dist/cms.d.ts +872 -0
- package/dist/cms.d.ts.map +1 -0
- package/dist/cms.js +468 -0
- package/dist/cms.js.map +1 -0
- package/dist/common.d.ts +82 -0
- package/dist/common.d.ts.map +1 -0
- package/dist/common.js +72 -0
- package/dist/common.js.map +1 -0
- package/dist/comparisons.d.ts +487 -0
- package/dist/comparisons.d.ts.map +1 -0
- package/dist/comparisons.js +221 -0
- package/dist/comparisons.js.map +1 -0
- package/dist/credentials.d.ts +292 -0
- package/dist/credentials.d.ts.map +1 -0
- package/dist/credentials.js +142 -0
- package/dist/credentials.js.map +1 -0
- package/dist/credit-limits.d.ts +111 -0
- package/dist/credit-limits.d.ts.map +1 -0
- package/dist/credit-limits.js +35 -0
- package/dist/credit-limits.js.map +1 -0
- package/dist/currencies.d.ts +127 -0
- package/dist/currencies.d.ts.map +1 -0
- package/dist/currencies.js +20 -0
- package/dist/currencies.js.map +1 -0
- package/dist/custom-fields.d.ts +345 -0
- package/dist/custom-fields.d.ts.map +1 -0
- package/dist/custom-fields.js +185 -0
- package/dist/custom-fields.js.map +1 -0
- package/dist/customer-accounts.d.ts +690 -0
- package/dist/customer-accounts.d.ts.map +1 -0
- package/dist/customer-accounts.js +41 -0
- package/dist/customer-accounts.js.map +1 -0
- package/dist/customers.d.ts +305 -0
- package/dist/customers.d.ts.map +1 -0
- package/dist/customers.js +158 -0
- package/dist/customers.js.map +1 -0
- package/dist/dictionary.d.ts +580 -0
- package/dist/dictionary.d.ts.map +1 -0
- package/dist/dictionary.js +297 -0
- package/dist/dictionary.js.map +1 -0
- package/dist/email-address.d.ts +62 -0
- package/dist/email-address.d.ts.map +1 -0
- package/dist/email-address.js +64 -0
- package/dist/email-address.js.map +1 -0
- package/dist/email.d.ts +175 -0
- package/dist/email.d.ts.map +1 -0
- package/dist/email.js +45 -0
- package/dist/email.js.map +1 -0
- package/dist/envelopes.d.ts +15 -0
- package/dist/envelopes.d.ts.map +1 -0
- package/dist/envelopes.js +16 -0
- package/dist/envelopes.js.map +1 -0
- package/dist/environment-inputs.d.ts +306 -0
- package/dist/environment-inputs.d.ts.map +1 -0
- package/dist/environment-inputs.js +277 -0
- package/dist/environment-inputs.js.map +1 -0
- package/dist/erp-connector.d.ts +52 -0
- package/dist/erp-connector.d.ts.map +1 -0
- package/dist/erp-connector.js +34 -0
- package/dist/erp-connector.js.map +1 -0
- package/dist/errors.d.ts +455 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +532 -0
- package/dist/errors.js.map +1 -0
- package/dist/google-analytics.d.ts +181 -0
- package/dist/google-analytics.d.ts.map +1 -0
- package/dist/google-analytics.js +176 -0
- package/dist/google-analytics.js.map +1 -0
- package/dist/google-tag-manager.d.ts +111 -0
- package/dist/google-tag-manager.d.ts.map +1 -0
- package/dist/google-tag-manager.js +129 -0
- package/dist/google-tag-manager.js.map +1 -0
- package/dist/i18n.d.ts +69 -0
- package/dist/i18n.d.ts.map +1 -0
- package/dist/i18n.js +59 -0
- package/dist/i18n.js.map +1 -0
- package/dist/import-export.d.ts +63 -0
- package/dist/import-export.d.ts.map +1 -0
- package/dist/import-export.js +37 -0
- package/dist/import-export.js.map +1 -0
- package/dist/index.d.ts +82 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +126 -0
- package/dist/index.js.map +1 -0
- package/dist/inventory.d.ts +673 -0
- package/dist/inventory.d.ts.map +1 -0
- package/dist/inventory.js +412 -0
- package/dist/inventory.js.map +1 -0
- package/dist/invoice-ledger.d.ts +366 -0
- package/dist/invoice-ledger.d.ts.map +1 -0
- package/dist/invoice-ledger.js +114 -0
- package/dist/invoice-ledger.js.map +1 -0
- package/dist/invoices.d.ts +845 -0
- package/dist/invoices.d.ts.map +1 -0
- package/dist/invoices.js +314 -0
- package/dist/invoices.js.map +1 -0
- package/dist/kernel.d.ts +49 -0
- package/dist/kernel.d.ts.map +1 -0
- package/dist/kernel.js +19 -0
- package/dist/kernel.js.map +1 -0
- package/dist/languages.d.ts +122 -0
- package/dist/languages.d.ts.map +1 -0
- package/dist/languages.js +24 -0
- package/dist/languages.js.map +1 -0
- package/dist/linkedin-ads.d.ts +167 -0
- package/dist/linkedin-ads.d.ts.map +1 -0
- package/dist/linkedin-ads.js +156 -0
- package/dist/linkedin-ads.js.map +1 -0
- package/dist/megamenu.d.ts +556 -0
- package/dist/megamenu.d.ts.map +1 -0
- package/dist/megamenu.js +186 -0
- package/dist/megamenu.js.map +1 -0
- package/dist/meta-ads.d.ts +126 -0
- package/dist/meta-ads.d.ts.map +1 -0
- package/dist/meta-ads.js +112 -0
- package/dist/meta-ads.js.map +1 -0
- package/dist/mfa.d.ts +274 -0
- package/dist/mfa.d.ts.map +1 -0
- package/dist/mfa.js +187 -0
- package/dist/mfa.js.map +1 -0
- package/dist/modules.d.ts +1706 -0
- package/dist/modules.d.ts.map +1 -0
- package/dist/modules.js +1390 -0
- package/dist/modules.js.map +1 -0
- package/dist/newsletter.d.ts +611 -0
- package/dist/newsletter.d.ts.map +1 -0
- package/dist/newsletter.js +345 -0
- package/dist/newsletter.js.map +1 -0
- package/dist/orders.d.ts +1175 -0
- package/dist/orders.d.ts.map +1 -0
- package/dist/orders.js +630 -0
- package/dist/orders.js.map +1 -0
- package/dist/organizations.d.ts +938 -0
- package/dist/organizations.d.ts.map +1 -0
- package/dist/organizations.js +418 -0
- package/dist/organizations.js.map +1 -0
- package/dist/pagination.d.ts +21 -0
- package/dist/pagination.d.ts.map +1 -0
- package/dist/pagination.js +22 -0
- package/dist/pagination.js.map +1 -0
- package/dist/payment-methods.d.ts +472 -0
- package/dist/payment-methods.d.ts.map +1 -0
- package/dist/payment-methods.js +175 -0
- package/dist/payment-methods.js.map +1 -0
- package/dist/payment-return-url.d.ts +53 -0
- package/dist/payment-return-url.d.ts.map +1 -0
- package/dist/payment-return-url.js +35 -0
- package/dist/payment-return-url.js.map +1 -0
- package/dist/payments.d.ts +386 -0
- package/dist/payments.d.ts.map +1 -0
- package/dist/payments.js +84 -0
- package/dist/payments.js.map +1 -0
- package/dist/pim-connector.d.ts +60 -0
- package/dist/pim-connector.d.ts.map +1 -0
- package/dist/pim-connector.js +43 -0
- package/dist/pim-connector.js.map +1 -0
- package/dist/pim-field-path.d.ts +6 -0
- package/dist/pim-field-path.d.ts.map +1 -0
- package/dist/pim-field-path.js +101 -0
- package/dist/pim-field-path.js.map +1 -0
- package/dist/platform-language.d.ts +20 -0
- package/dist/platform-language.d.ts.map +1 -0
- package/dist/platform-language.js +22 -0
- package/dist/platform-language.js.map +1 -0
- package/dist/price-lists.d.ts +685 -0
- package/dist/price-lists.d.ts.map +1 -0
- package/dist/price-lists.js +330 -0
- package/dist/price-lists.js.map +1 -0
- package/dist/product-feeds.d.ts +2837 -0
- package/dist/product-feeds.d.ts.map +1 -0
- package/dist/product-feeds.js +1504 -0
- package/dist/product-feeds.js.map +1 -0
- package/dist/product-scope-overrides.d.ts +134 -0
- package/dist/product-scope-overrides.d.ts.map +1 -0
- package/dist/product-scope-overrides.js +82 -0
- package/dist/product-scope-overrides.js.map +1 -0
- package/dist/product-value-resolver.d.ts +88 -0
- package/dist/product-value-resolver.d.ts.map +1 -0
- package/dist/product-value-resolver.js +128 -0
- package/dist/product-value-resolver.js.map +1 -0
- package/dist/promotions.d.ts +678 -0
- package/dist/promotions.d.ts.map +1 -0
- package/dist/promotions.js +479 -0
- package/dist/promotions.js.map +1 -0
- package/dist/prompt-actions.d.ts +582 -0
- package/dist/prompt-actions.d.ts.map +1 -0
- package/dist/prompt-actions.js +221 -0
- package/dist/prompt-actions.js.map +1 -0
- package/dist/pwa.d.ts +293 -0
- package/dist/pwa.d.ts.map +1 -0
- package/dist/pwa.js +204 -0
- package/dist/pwa.js.map +1 -0
- package/dist/quick-order.d.ts +340 -0
- package/dist/quick-order.d.ts.map +1 -0
- package/dist/quick-order.js +177 -0
- package/dist/quick-order.js.map +1 -0
- package/dist/quote-requests.d.ts +538 -0
- package/dist/quote-requests.d.ts.map +1 -0
- package/dist/quote-requests.js +308 -0
- package/dist/quote-requests.js.map +1 -0
- package/dist/returns.d.ts +774 -0
- package/dist/returns.d.ts.map +1 -0
- package/dist/returns.js +389 -0
- package/dist/returns.js.map +1 -0
- package/dist/sales-channels.d.ts +392 -0
- package/dist/sales-channels.d.ts.map +1 -0
- package/dist/sales-channels.js +285 -0
- package/dist/sales-channels.js.map +1 -0
- package/dist/scope-notice.d.ts +60 -0
- package/dist/scope-notice.d.ts.map +1 -0
- package/dist/scope-notice.js +56 -0
- package/dist/scope-notice.js.map +1 -0
- package/dist/search.d.ts +321 -0
- package/dist/search.d.ts.map +1 -0
- package/dist/search.js +160 -0
- package/dist/search.js.map +1 -0
- package/dist/seo.d.ts +113 -0
- package/dist/seo.d.ts.map +1 -0
- package/dist/seo.js +63 -0
- package/dist/seo.js.map +1 -0
- package/dist/settings.d.ts +453 -0
- package/dist/settings.d.ts.map +1 -0
- package/dist/settings.js +337 -0
- package/dist/settings.js.map +1 -0
- package/dist/shipments.d.ts +140 -0
- package/dist/shipments.d.ts.map +1 -0
- package/dist/shipments.js +14 -0
- package/dist/shipments.js.map +1 -0
- package/dist/shipping-methods.d.ts +350 -0
- package/dist/shipping-methods.d.ts.map +1 -0
- package/dist/shipping-methods.js +99 -0
- package/dist/shipping-methods.js.map +1 -0
- package/dist/shopping-lists.d.ts +122 -0
- package/dist/shopping-lists.d.ts.map +1 -0
- package/dist/shopping-lists.js +92 -0
- package/dist/shopping-lists.js.map +1 -0
- package/dist/taxes.d.ts +106 -0
- package/dist/taxes.d.ts.map +1 -0
- package/dist/taxes.js +80 -0
- package/dist/taxes.js.map +1 -0
- package/dist/text-normalization.d.ts +199 -0
- package/dist/text-normalization.d.ts.map +1 -0
- package/dist/text-normalization.js +205 -0
- package/dist/text-normalization.js.map +1 -0
- package/dist/transactional-emails.d.ts +459 -0
- package/dist/transactional-emails.d.ts.map +1 -0
- package/dist/transactional-emails.js +212 -0
- package/dist/transactional-emails.js.map +1 -0
- package/dist/webhooks.d.ts +69 -0
- package/dist/webhooks.d.ts.map +1 -0
- package/dist/webhooks.js +53 -0
- package/dist/webhooks.js.map +1 -0
- package/package.json +46 -0
|
@@ -0,0 +1,2855 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { type ProductVisibility } from './common.js';
|
|
3
|
+
import type { FulfilmentStrategy } from './inventory.js';
|
|
4
|
+
import type { BulkImportReport } from './import-export.js';
|
|
5
|
+
import type { AttributeScope } from './product-value-resolver.js';
|
|
6
|
+
/**
|
|
7
|
+
* Catalog module contracts — Source of truth per Principle V.
|
|
8
|
+
* See specs/001-b2b-platform-foundation/contracts/catalog.contract.md.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Product types. Foundation 001 used `simple | variant | grouped |
|
|
12
|
+
* virtual`; feature 002 (data-model.md §1.1) renames `variant` →
|
|
13
|
+
* `configurable` and adds `bundle`. The application enum is the only
|
|
14
|
+
* source of truth — the DB column is `varchar(16)` with no CHECK
|
|
15
|
+
* constraint (research.md R-1).
|
|
16
|
+
*/
|
|
17
|
+
export declare const productTypeSchema: z.ZodEnum<{
|
|
18
|
+
simple: "simple";
|
|
19
|
+
configurable: "configurable";
|
|
20
|
+
grouped: "grouped";
|
|
21
|
+
bundle: "bundle";
|
|
22
|
+
virtual: "virtual";
|
|
23
|
+
}>;
|
|
24
|
+
export type ProductType = z.infer<typeof productTypeSchema>;
|
|
25
|
+
export declare const productStatusSchema: z.ZodEnum<{
|
|
26
|
+
active: "active";
|
|
27
|
+
inactive: "inactive";
|
|
28
|
+
draft: "draft";
|
|
29
|
+
}>;
|
|
30
|
+
export type ProductStatus = z.infer<typeof productStatusSchema>;
|
|
31
|
+
/** Maps legacy `archived` writes to `inactive` (feature 032). */
|
|
32
|
+
export declare function coerceProductStatusWrite(value: unknown): 'draft' | 'active' | 'inactive' | unknown;
|
|
33
|
+
export declare const productStatusWriteSchema: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodEnum<{
|
|
34
|
+
active: "active";
|
|
35
|
+
inactive: "inactive";
|
|
36
|
+
draft: "draft";
|
|
37
|
+
}>>;
|
|
38
|
+
export declare const stockModeSchema: z.ZodEnum<{
|
|
39
|
+
categorical: "categorical";
|
|
40
|
+
numeric: "numeric";
|
|
41
|
+
}>;
|
|
42
|
+
export type StockMode = z.infer<typeof stockModeSchema>;
|
|
43
|
+
export declare const stockIndicatorSchema: z.ZodEnum<{
|
|
44
|
+
available: "available";
|
|
45
|
+
out_of_stock: "out_of_stock";
|
|
46
|
+
to_order: "to_order";
|
|
47
|
+
}>;
|
|
48
|
+
export type StockIndicator = z.infer<typeof stockIndicatorSchema>;
|
|
49
|
+
/**
|
|
50
|
+
* DB-level attribute value types. Foundation 001 introduced the original
|
|
51
|
+
* 5-element enum (`string | number | boolean | enum | date`). Feature 002
|
|
52
|
+
* adds `multiselect` and `price` per data-model.md §1.2.
|
|
53
|
+
*
|
|
54
|
+
* The API-facing presentation form (`apiAttributeTypeSchema` below)
|
|
55
|
+
* surfaces additional affordances (`input`, `select`, `slider`) that
|
|
56
|
+
* map to this DB enum + the sibling `displayAsSlider` flag — see
|
|
57
|
+
* research.md R-4 / R-7.
|
|
58
|
+
*/
|
|
59
|
+
export declare const attributeValueTypeSchema: z.ZodEnum<{
|
|
60
|
+
string: "string";
|
|
61
|
+
number: "number";
|
|
62
|
+
boolean: "boolean";
|
|
63
|
+
date: "date";
|
|
64
|
+
enum: "enum";
|
|
65
|
+
select: "select";
|
|
66
|
+
price: "price";
|
|
67
|
+
multiselect: "multiselect";
|
|
68
|
+
}>;
|
|
69
|
+
export type AttributeValueType = z.infer<typeof attributeValueTypeSchema>;
|
|
70
|
+
/**
|
|
71
|
+
* API-facing attribute type form for feature 002 contracts. Maps onto
|
|
72
|
+
* `attributeValueTypeSchema` + `displayAsSlider` in the service layer.
|
|
73
|
+
*/
|
|
74
|
+
export declare const apiAttributeTypeSchema: z.ZodEnum<{
|
|
75
|
+
number: "number";
|
|
76
|
+
input: "input";
|
|
77
|
+
select: "select";
|
|
78
|
+
price: "price";
|
|
79
|
+
multiselect: "multiselect";
|
|
80
|
+
slider: "slider";
|
|
81
|
+
}>;
|
|
82
|
+
export type ApiAttributeType = z.infer<typeof apiAttributeTypeSchema>;
|
|
83
|
+
/**
|
|
84
|
+
* The API-form type of a stored attribute, derived from the pair the catalogue
|
|
85
|
+
* persists (`valueType`, `displayAsSlider`). This is the single definition:
|
|
86
|
+
* the catalogue reports every attribute's `type` through it, and a connector
|
|
87
|
+
* that binds a source attribute to an existing one compares against it — two
|
|
88
|
+
* derivations of one rule drift, and a drift creates attributes the catalogue
|
|
89
|
+
* then reports as another kind.
|
|
90
|
+
*
|
|
91
|
+
* A slider flag only means something on a numeric type (`number`, `price`);
|
|
92
|
+
* elsewhere it is ignored. `string`, `boolean` and `date` have no richer API
|
|
93
|
+
* form and surface as `input`; `enum` and `select` share one affordance.
|
|
94
|
+
*/
|
|
95
|
+
export declare function apiAttributeTypeOf(valueType: AttributeValueType, displayAsSlider: boolean): ApiAttributeType;
|
|
96
|
+
export declare const assetKindSchema: z.ZodEnum<{
|
|
97
|
+
image: "image";
|
|
98
|
+
video: "video";
|
|
99
|
+
pdf: "pdf";
|
|
100
|
+
certificate: "certificate";
|
|
101
|
+
other: "other";
|
|
102
|
+
}>;
|
|
103
|
+
export type AssetKind = z.infer<typeof assetKindSchema>;
|
|
104
|
+
export declare const attributeOptionSchema: z.ZodObject<{
|
|
105
|
+
id: z.ZodString;
|
|
106
|
+
attributeId: z.ZodString;
|
|
107
|
+
value: z.ZodString;
|
|
108
|
+
label: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
109
|
+
labelDefault: z.ZodString;
|
|
110
|
+
isDefault: z.ZodBoolean;
|
|
111
|
+
sortOrder: z.ZodNumber;
|
|
112
|
+
createdAt: z.ZodString;
|
|
113
|
+
updatedAt: z.ZodString;
|
|
114
|
+
}, z.core.$strip>;
|
|
115
|
+
export type AttributeOption = z.infer<typeof attributeOptionSchema>;
|
|
116
|
+
export declare const createAttributeOptionRequestSchema: z.ZodObject<{
|
|
117
|
+
value: z.ZodString;
|
|
118
|
+
label: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
119
|
+
labelDefault: z.ZodString;
|
|
120
|
+
isDefault: z.ZodOptional<z.ZodBoolean>;
|
|
121
|
+
sortOrder: z.ZodOptional<z.ZodNumber>;
|
|
122
|
+
}, z.core.$strip>;
|
|
123
|
+
export type CreateAttributeOptionRequest = z.infer<typeof createAttributeOptionRequestSchema>;
|
|
124
|
+
export declare const replaceAttributeOptionsRequestSchema: z.ZodObject<{
|
|
125
|
+
options: z.ZodArray<z.ZodObject<{
|
|
126
|
+
value: z.ZodString;
|
|
127
|
+
label: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
128
|
+
labelDefault: z.ZodString;
|
|
129
|
+
isDefault: z.ZodOptional<z.ZodBoolean>;
|
|
130
|
+
sortOrder: z.ZodOptional<z.ZodNumber>;
|
|
131
|
+
}, z.core.$strip>>;
|
|
132
|
+
}, z.core.$strip>;
|
|
133
|
+
export type ReplaceAttributeOptionsRequest = z.infer<typeof replaceAttributeOptionsRequestSchema>;
|
|
134
|
+
export declare const patchAttributeOptionRequestSchema: z.ZodObject<{
|
|
135
|
+
label: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
136
|
+
labelDefault: z.ZodOptional<z.ZodString>;
|
|
137
|
+
isDefault: z.ZodOptional<z.ZodBoolean>;
|
|
138
|
+
sortOrder: z.ZodOptional<z.ZodNumber>;
|
|
139
|
+
}, z.core.$strict>;
|
|
140
|
+
export type PatchAttributeOptionRequest = z.infer<typeof patchAttributeOptionRequestSchema>;
|
|
141
|
+
export declare const productAssetSchema: z.ZodObject<{
|
|
142
|
+
id: z.ZodString;
|
|
143
|
+
kind: z.ZodEnum<{
|
|
144
|
+
image: "image";
|
|
145
|
+
video: "video";
|
|
146
|
+
pdf: "pdf";
|
|
147
|
+
certificate: "certificate";
|
|
148
|
+
other: "other";
|
|
149
|
+
}>;
|
|
150
|
+
url: z.ZodString;
|
|
151
|
+
altText: z.ZodNullable<z.ZodString>;
|
|
152
|
+
}, z.core.$strip>;
|
|
153
|
+
export type ProductAsset = z.infer<typeof productAssetSchema>;
|
|
154
|
+
/**
|
|
155
|
+
* Availability indication mirrored from the inventory display bands the
|
|
156
|
+
* storefront shows (`available` = stock not managed for the product).
|
|
157
|
+
*/
|
|
158
|
+
export declare const productAvailabilityBandSchema: z.ZodEnum<{
|
|
159
|
+
available: "available";
|
|
160
|
+
out_of_stock: "out_of_stock";
|
|
161
|
+
high: "high";
|
|
162
|
+
medium: "medium";
|
|
163
|
+
low: "low";
|
|
164
|
+
}>;
|
|
165
|
+
export type ProductAvailabilityBand = z.infer<typeof productAvailabilityBandSchema>;
|
|
166
|
+
export declare const productAvailabilitySchema: z.ZodObject<{
|
|
167
|
+
band: z.ZodEnum<{
|
|
168
|
+
available: "available";
|
|
169
|
+
out_of_stock: "out_of_stock";
|
|
170
|
+
high: "high";
|
|
171
|
+
medium: "medium";
|
|
172
|
+
low: "low";
|
|
173
|
+
}>;
|
|
174
|
+
inStock: z.ZodBoolean;
|
|
175
|
+
}, z.core.$strip>;
|
|
176
|
+
export type ProductAvailability = z.infer<typeof productAvailabilitySchema>;
|
|
177
|
+
/**
|
|
178
|
+
* One rung of the bound Organization's resolved quantity-bracket price
|
|
179
|
+
* ladder (external product detail only).
|
|
180
|
+
*/
|
|
181
|
+
export declare const productPriceTierSchema: z.ZodObject<{
|
|
182
|
+
minQuantity: z.ZodNumber;
|
|
183
|
+
amount: z.ZodNumber;
|
|
184
|
+
currency: z.ZodString;
|
|
185
|
+
isSale: z.ZodBoolean;
|
|
186
|
+
}, z.core.$strip>;
|
|
187
|
+
export type ProductPriceTier = z.infer<typeof productPriceTierSchema>;
|
|
188
|
+
export declare const productSummarySchema: z.ZodObject<{
|
|
189
|
+
id: z.ZodString;
|
|
190
|
+
sku: z.ZodString;
|
|
191
|
+
type: z.ZodEnum<{
|
|
192
|
+
simple: "simple";
|
|
193
|
+
configurable: "configurable";
|
|
194
|
+
grouped: "grouped";
|
|
195
|
+
bundle: "bundle";
|
|
196
|
+
virtual: "virtual";
|
|
197
|
+
}>;
|
|
198
|
+
name: z.ZodString;
|
|
199
|
+
slug: z.ZodString;
|
|
200
|
+
categorySlugs: z.ZodArray<z.ZodString>;
|
|
201
|
+
primaryAssetUrl: z.ZodNullable<z.ZodString>;
|
|
202
|
+
price: z.ZodNullable<z.ZodObject<{
|
|
203
|
+
amount: z.ZodNumber;
|
|
204
|
+
currency: z.ZodString;
|
|
205
|
+
}, z.core.$strip>>;
|
|
206
|
+
stockIndicator: z.ZodNullable<z.ZodEnum<{
|
|
207
|
+
available: "available";
|
|
208
|
+
out_of_stock: "out_of_stock";
|
|
209
|
+
to_order: "to_order";
|
|
210
|
+
}>>;
|
|
211
|
+
stockLevel: z.ZodNullable<z.ZodNumber>;
|
|
212
|
+
priceUnavailable: z.ZodOptional<z.ZodBoolean>;
|
|
213
|
+
availability: z.ZodOptional<z.ZodObject<{
|
|
214
|
+
band: z.ZodEnum<{
|
|
215
|
+
available: "available";
|
|
216
|
+
out_of_stock: "out_of_stock";
|
|
217
|
+
high: "high";
|
|
218
|
+
medium: "medium";
|
|
219
|
+
low: "low";
|
|
220
|
+
}>;
|
|
221
|
+
inStock: z.ZodBoolean;
|
|
222
|
+
}, z.core.$strip>>;
|
|
223
|
+
}, z.core.$strip>;
|
|
224
|
+
export type ProductSummary = z.infer<typeof productSummarySchema>;
|
|
225
|
+
export declare const productVariantSchema: z.ZodObject<{
|
|
226
|
+
id: z.ZodString;
|
|
227
|
+
sku: z.ZodString;
|
|
228
|
+
variantAttributeValues: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
229
|
+
priceOverride: z.ZodNullable<z.ZodNumber>;
|
|
230
|
+
stockLevel: z.ZodNullable<z.ZodNumber>;
|
|
231
|
+
}, z.core.$strip>;
|
|
232
|
+
export type ProductVariant = z.infer<typeof productVariantSchema>;
|
|
233
|
+
export declare const seoMetaSchema: z.ZodObject<{
|
|
234
|
+
metaTitle: z.ZodString;
|
|
235
|
+
metaDescription: z.ZodString;
|
|
236
|
+
openGraph: z.ZodObject<{
|
|
237
|
+
title: z.ZodString;
|
|
238
|
+
description: z.ZodString;
|
|
239
|
+
imageUrl: z.ZodNullable<z.ZodString>;
|
|
240
|
+
}, z.core.$strip>;
|
|
241
|
+
}, z.core.$strip>;
|
|
242
|
+
export type SeoMeta = z.infer<typeof seoMetaSchema>;
|
|
243
|
+
export declare const productDetailSchema: z.ZodObject<{
|
|
244
|
+
id: z.ZodString;
|
|
245
|
+
sku: z.ZodString;
|
|
246
|
+
type: z.ZodEnum<{
|
|
247
|
+
simple: "simple";
|
|
248
|
+
configurable: "configurable";
|
|
249
|
+
grouped: "grouped";
|
|
250
|
+
bundle: "bundle";
|
|
251
|
+
virtual: "virtual";
|
|
252
|
+
}>;
|
|
253
|
+
name: z.ZodString;
|
|
254
|
+
slug: z.ZodString;
|
|
255
|
+
categorySlugs: z.ZodArray<z.ZodString>;
|
|
256
|
+
primaryAssetUrl: z.ZodNullable<z.ZodString>;
|
|
257
|
+
price: z.ZodNullable<z.ZodObject<{
|
|
258
|
+
amount: z.ZodNumber;
|
|
259
|
+
currency: z.ZodString;
|
|
260
|
+
}, z.core.$strip>>;
|
|
261
|
+
stockIndicator: z.ZodNullable<z.ZodEnum<{
|
|
262
|
+
available: "available";
|
|
263
|
+
out_of_stock: "out_of_stock";
|
|
264
|
+
to_order: "to_order";
|
|
265
|
+
}>>;
|
|
266
|
+
stockLevel: z.ZodNullable<z.ZodNumber>;
|
|
267
|
+
priceUnavailable: z.ZodOptional<z.ZodBoolean>;
|
|
268
|
+
availability: z.ZodOptional<z.ZodObject<{
|
|
269
|
+
band: z.ZodEnum<{
|
|
270
|
+
available: "available";
|
|
271
|
+
out_of_stock: "out_of_stock";
|
|
272
|
+
high: "high";
|
|
273
|
+
medium: "medium";
|
|
274
|
+
low: "low";
|
|
275
|
+
}>;
|
|
276
|
+
inStock: z.ZodBoolean;
|
|
277
|
+
}, z.core.$strip>>;
|
|
278
|
+
description: z.ZodString;
|
|
279
|
+
attributeValues: z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>;
|
|
280
|
+
assets: z.ZodArray<z.ZodObject<{
|
|
281
|
+
id: z.ZodString;
|
|
282
|
+
kind: z.ZodEnum<{
|
|
283
|
+
image: "image";
|
|
284
|
+
video: "video";
|
|
285
|
+
pdf: "pdf";
|
|
286
|
+
certificate: "certificate";
|
|
287
|
+
other: "other";
|
|
288
|
+
}>;
|
|
289
|
+
url: z.ZodString;
|
|
290
|
+
altText: z.ZodNullable<z.ZodString>;
|
|
291
|
+
}, z.core.$strip>>;
|
|
292
|
+
variants: z.ZodArray<z.ZodObject<{
|
|
293
|
+
id: z.ZodString;
|
|
294
|
+
sku: z.ZodString;
|
|
295
|
+
variantAttributeValues: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
296
|
+
priceOverride: z.ZodNullable<z.ZodNumber>;
|
|
297
|
+
stockLevel: z.ZodNullable<z.ZodNumber>;
|
|
298
|
+
}, z.core.$strip>>;
|
|
299
|
+
categories: z.ZodArray<z.ZodObject<{
|
|
300
|
+
id: z.ZodString;
|
|
301
|
+
name: z.ZodString;
|
|
302
|
+
slug: z.ZodString;
|
|
303
|
+
}, z.core.$strip>>;
|
|
304
|
+
seo: z.ZodObject<{
|
|
305
|
+
metaTitle: z.ZodString;
|
|
306
|
+
metaDescription: z.ZodString;
|
|
307
|
+
openGraph: z.ZodObject<{
|
|
308
|
+
title: z.ZodString;
|
|
309
|
+
description: z.ZodString;
|
|
310
|
+
imageUrl: z.ZodNullable<z.ZodString>;
|
|
311
|
+
}, z.core.$strip>;
|
|
312
|
+
}, z.core.$strip>;
|
|
313
|
+
structuredDataJsonLd: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
314
|
+
attributeSet: z.ZodOptional<z.ZodObject<{
|
|
315
|
+
id: z.ZodString;
|
|
316
|
+
code: z.ZodString;
|
|
317
|
+
name: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
318
|
+
}, z.core.$strip>>;
|
|
319
|
+
gallery: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
320
|
+
id: z.ZodString;
|
|
321
|
+
position: z.ZodNumber;
|
|
322
|
+
labels: z.ZodArray<z.ZodEnum<{
|
|
323
|
+
base_image: "base_image";
|
|
324
|
+
small_image: "small_image";
|
|
325
|
+
thumbnail: "thumbnail";
|
|
326
|
+
}>>;
|
|
327
|
+
asset: z.ZodObject<{
|
|
328
|
+
id: z.ZodString;
|
|
329
|
+
kind: z.ZodString;
|
|
330
|
+
url: z.ZodString;
|
|
331
|
+
}, z.core.$strip>;
|
|
332
|
+
}, z.core.$strip>>>;
|
|
333
|
+
groupedItems: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
334
|
+
id: z.ZodString;
|
|
335
|
+
position: z.ZodNumber;
|
|
336
|
+
quantity: z.ZodNumber;
|
|
337
|
+
product: z.ZodObject<{
|
|
338
|
+
id: z.ZodString;
|
|
339
|
+
sku: z.ZodString;
|
|
340
|
+
slug: z.ZodString;
|
|
341
|
+
name: z.ZodString;
|
|
342
|
+
primaryAssetUrl: z.ZodNullable<z.ZodString>;
|
|
343
|
+
price: z.ZodNullable<z.ZodObject<{
|
|
344
|
+
amount: z.ZodNumber;
|
|
345
|
+
currency: z.ZodString;
|
|
346
|
+
}, z.core.$strip>>;
|
|
347
|
+
}, z.core.$strip>;
|
|
348
|
+
}, z.core.$strip>>>;
|
|
349
|
+
bundleSlots: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
350
|
+
id: z.ZodString;
|
|
351
|
+
name: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
352
|
+
minQuantity: z.ZodNumber;
|
|
353
|
+
maxQuantity: z.ZodNumber;
|
|
354
|
+
position: z.ZodNumber;
|
|
355
|
+
options: z.ZodArray<z.ZodObject<{
|
|
356
|
+
id: z.ZodString;
|
|
357
|
+
defaultQuantity: z.ZodNumber;
|
|
358
|
+
position: z.ZodNumber;
|
|
359
|
+
product: z.ZodObject<{
|
|
360
|
+
id: z.ZodString;
|
|
361
|
+
sku: z.ZodString;
|
|
362
|
+
slug: z.ZodString;
|
|
363
|
+
name: z.ZodString;
|
|
364
|
+
primaryAssetUrl: z.ZodNullable<z.ZodString>;
|
|
365
|
+
price: z.ZodNullable<z.ZodObject<{
|
|
366
|
+
amount: z.ZodNumber;
|
|
367
|
+
currency: z.ZodString;
|
|
368
|
+
}, z.core.$strip>>;
|
|
369
|
+
}, z.core.$strip>;
|
|
370
|
+
}, z.core.$strip>>;
|
|
371
|
+
}, z.core.$strip>>>;
|
|
372
|
+
virtual: z.ZodOptional<z.ZodObject<{
|
|
373
|
+
downloadAssetId: z.ZodNullable<z.ZodString>;
|
|
374
|
+
downloadUrl: z.ZodNullable<z.ZodString>;
|
|
375
|
+
}, z.core.$strip>>;
|
|
376
|
+
links: z.ZodOptional<z.ZodObject<{
|
|
377
|
+
related: z.ZodArray<z.ZodObject<{
|
|
378
|
+
id: z.ZodString;
|
|
379
|
+
kind: z.ZodEnum<{
|
|
380
|
+
related: "related";
|
|
381
|
+
up_sell: "up_sell";
|
|
382
|
+
cross_sell: "cross_sell";
|
|
383
|
+
}>;
|
|
384
|
+
position: z.ZodNumber;
|
|
385
|
+
product: z.ZodObject<{
|
|
386
|
+
id: z.ZodString;
|
|
387
|
+
sku: z.ZodString;
|
|
388
|
+
slug: z.ZodString;
|
|
389
|
+
name: z.ZodString;
|
|
390
|
+
primaryAssetUrl: z.ZodNullable<z.ZodString>;
|
|
391
|
+
price: z.ZodNullable<z.ZodObject<{
|
|
392
|
+
amount: z.ZodNumber;
|
|
393
|
+
currency: z.ZodString;
|
|
394
|
+
}, z.core.$strip>>;
|
|
395
|
+
}, z.core.$strip>;
|
|
396
|
+
}, z.core.$strip>>;
|
|
397
|
+
upSell: z.ZodArray<z.ZodObject<{
|
|
398
|
+
id: z.ZodString;
|
|
399
|
+
kind: z.ZodEnum<{
|
|
400
|
+
related: "related";
|
|
401
|
+
up_sell: "up_sell";
|
|
402
|
+
cross_sell: "cross_sell";
|
|
403
|
+
}>;
|
|
404
|
+
position: z.ZodNumber;
|
|
405
|
+
product: z.ZodObject<{
|
|
406
|
+
id: z.ZodString;
|
|
407
|
+
sku: z.ZodString;
|
|
408
|
+
slug: z.ZodString;
|
|
409
|
+
name: z.ZodString;
|
|
410
|
+
primaryAssetUrl: z.ZodNullable<z.ZodString>;
|
|
411
|
+
price: z.ZodNullable<z.ZodObject<{
|
|
412
|
+
amount: z.ZodNumber;
|
|
413
|
+
currency: z.ZodString;
|
|
414
|
+
}, z.core.$strip>>;
|
|
415
|
+
}, z.core.$strip>;
|
|
416
|
+
}, z.core.$strip>>;
|
|
417
|
+
crossSell: z.ZodArray<z.ZodObject<{
|
|
418
|
+
id: z.ZodString;
|
|
419
|
+
kind: z.ZodEnum<{
|
|
420
|
+
related: "related";
|
|
421
|
+
up_sell: "up_sell";
|
|
422
|
+
cross_sell: "cross_sell";
|
|
423
|
+
}>;
|
|
424
|
+
position: z.ZodNumber;
|
|
425
|
+
product: z.ZodObject<{
|
|
426
|
+
id: z.ZodString;
|
|
427
|
+
sku: z.ZodString;
|
|
428
|
+
slug: z.ZodString;
|
|
429
|
+
name: z.ZodString;
|
|
430
|
+
primaryAssetUrl: z.ZodNullable<z.ZodString>;
|
|
431
|
+
price: z.ZodNullable<z.ZodObject<{
|
|
432
|
+
amount: z.ZodNumber;
|
|
433
|
+
currency: z.ZodString;
|
|
434
|
+
}, z.core.$strip>>;
|
|
435
|
+
}, z.core.$strip>;
|
|
436
|
+
}, z.core.$strip>>;
|
|
437
|
+
}, z.core.$strip>>;
|
|
438
|
+
attachments: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
439
|
+
id: z.ZodString;
|
|
440
|
+
position: z.ZodNumber;
|
|
441
|
+
name: z.ZodString;
|
|
442
|
+
description: z.ZodNullable<z.ZodString>;
|
|
443
|
+
type: z.ZodObject<{
|
|
444
|
+
id: z.ZodString;
|
|
445
|
+
code: z.ZodString;
|
|
446
|
+
name: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
447
|
+
}, z.core.$strip>;
|
|
448
|
+
asset: z.ZodObject<{
|
|
449
|
+
id: z.ZodString;
|
|
450
|
+
kind: z.ZodString;
|
|
451
|
+
url: z.ZodString;
|
|
452
|
+
filename: z.ZodString;
|
|
453
|
+
sizeBytes: z.ZodNumber;
|
|
454
|
+
mimeType: z.ZodString;
|
|
455
|
+
}, z.core.$strip>;
|
|
456
|
+
}, z.core.$strip>>>;
|
|
457
|
+
visibleAttributes: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
458
|
+
key: z.ZodString;
|
|
459
|
+
label: z.ZodString;
|
|
460
|
+
valueType: z.ZodEnum<{
|
|
461
|
+
string: "string";
|
|
462
|
+
number: "number";
|
|
463
|
+
boolean: "boolean";
|
|
464
|
+
date: "date";
|
|
465
|
+
enum: "enum";
|
|
466
|
+
select: "select";
|
|
467
|
+
price: "price";
|
|
468
|
+
multiselect: "multiselect";
|
|
469
|
+
}>;
|
|
470
|
+
valueRendered: z.ZodString;
|
|
471
|
+
}, z.core.$strip>>>;
|
|
472
|
+
packagingUnits: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
473
|
+
id: z.ZodString;
|
|
474
|
+
name: z.ZodString;
|
|
475
|
+
baseQuantity: z.ZodNumber;
|
|
476
|
+
position: z.ZodNumber;
|
|
477
|
+
isDefault: z.ZodBoolean;
|
|
478
|
+
}, z.core.$strip>>>;
|
|
479
|
+
priceTiers: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
480
|
+
minQuantity: z.ZodNumber;
|
|
481
|
+
amount: z.ZodNumber;
|
|
482
|
+
currency: z.ZodString;
|
|
483
|
+
isSale: z.ZodBoolean;
|
|
484
|
+
}, z.core.$strip>>>;
|
|
485
|
+
}, z.core.$strip>;
|
|
486
|
+
export type ProductDetail = z.infer<typeof productDetailSchema>;
|
|
487
|
+
export declare const catalogBulkPriceRequestSchema: z.ZodObject<{
|
|
488
|
+
lines: z.ZodArray<z.ZodObject<{
|
|
489
|
+
sku: z.ZodString;
|
|
490
|
+
quantity: z.ZodNumber;
|
|
491
|
+
}, z.core.$strip>>;
|
|
492
|
+
}, z.core.$strip>;
|
|
493
|
+
export type CatalogBulkPriceRequest = z.infer<typeof catalogBulkPriceRequestSchema>;
|
|
494
|
+
export declare const catalogBulkPriceMissReasonSchema: z.ZodEnum<{
|
|
495
|
+
sku_not_in_assortment: "sku_not_in_assortment";
|
|
496
|
+
price_unavailable: "price_unavailable";
|
|
497
|
+
}>;
|
|
498
|
+
export type CatalogBulkPriceMissReason = z.infer<typeof catalogBulkPriceMissReasonSchema>;
|
|
499
|
+
/**
|
|
500
|
+
* Per-line result, order-preserving. Misses are data, not errors — the
|
|
501
|
+
* partner needs a total answer for a basket. `amount` is the exact decimal
|
|
502
|
+
* string the pricing resolver charges the bound org on the bound channel at
|
|
503
|
+
* that quantity (SC-001 parity with cart pricing).
|
|
504
|
+
*/
|
|
505
|
+
export declare const catalogBulkPriceLineSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
506
|
+
sku: z.ZodString;
|
|
507
|
+
quantity: z.ZodNumber;
|
|
508
|
+
price: z.ZodObject<{
|
|
509
|
+
amount: z.ZodString;
|
|
510
|
+
currency: z.ZodString;
|
|
511
|
+
isSale: z.ZodBoolean;
|
|
512
|
+
bracketStartQuantity: z.ZodNumber;
|
|
513
|
+
priceListId: z.ZodString;
|
|
514
|
+
}, z.core.$strip>;
|
|
515
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
516
|
+
sku: z.ZodString;
|
|
517
|
+
quantity: z.ZodNumber;
|
|
518
|
+
price: z.ZodNull;
|
|
519
|
+
reason: z.ZodEnum<{
|
|
520
|
+
sku_not_in_assortment: "sku_not_in_assortment";
|
|
521
|
+
price_unavailable: "price_unavailable";
|
|
522
|
+
}>;
|
|
523
|
+
}, z.core.$strip>]>;
|
|
524
|
+
export type CatalogBulkPriceLine = z.infer<typeof catalogBulkPriceLineSchema>;
|
|
525
|
+
export declare const catalogBulkPriceResponseSchema: z.ZodObject<{
|
|
526
|
+
data: z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
|
|
527
|
+
sku: z.ZodString;
|
|
528
|
+
quantity: z.ZodNumber;
|
|
529
|
+
price: z.ZodObject<{
|
|
530
|
+
amount: z.ZodString;
|
|
531
|
+
currency: z.ZodString;
|
|
532
|
+
isSale: z.ZodBoolean;
|
|
533
|
+
bracketStartQuantity: z.ZodNumber;
|
|
534
|
+
priceListId: z.ZodString;
|
|
535
|
+
}, z.core.$strip>;
|
|
536
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
537
|
+
sku: z.ZodString;
|
|
538
|
+
quantity: z.ZodNumber;
|
|
539
|
+
price: z.ZodNull;
|
|
540
|
+
reason: z.ZodEnum<{
|
|
541
|
+
sku_not_in_assortment: "sku_not_in_assortment";
|
|
542
|
+
price_unavailable: "price_unavailable";
|
|
543
|
+
}>;
|
|
544
|
+
}, z.core.$strip>]>>;
|
|
545
|
+
}, z.core.$strip>;
|
|
546
|
+
export type CatalogBulkPriceResponse = z.infer<typeof catalogBulkPriceResponseSchema>;
|
|
547
|
+
export interface CategoryNode {
|
|
548
|
+
id: string;
|
|
549
|
+
name: string;
|
|
550
|
+
slug: string;
|
|
551
|
+
sortOrder: number;
|
|
552
|
+
productCount: number;
|
|
553
|
+
children: CategoryNode[];
|
|
554
|
+
}
|
|
555
|
+
export declare const categoryNodeSchema: z.ZodType<CategoryNode>;
|
|
556
|
+
export declare const filterOptionSchema: z.ZodObject<{
|
|
557
|
+
value: z.ZodString;
|
|
558
|
+
label: z.ZodString;
|
|
559
|
+
count: z.ZodNumber;
|
|
560
|
+
}, z.core.$strip>;
|
|
561
|
+
export type FilterOption = z.infer<typeof filterOptionSchema>;
|
|
562
|
+
export declare const filterRangeSchema: z.ZodObject<{
|
|
563
|
+
min: z.ZodNumber;
|
|
564
|
+
max: z.ZodNumber;
|
|
565
|
+
}, z.core.$strip>;
|
|
566
|
+
export type FilterRange = z.infer<typeof filterRangeSchema>;
|
|
567
|
+
export declare const filterDefinitionSchema: z.ZodObject<{
|
|
568
|
+
attributeKey: z.ZodString;
|
|
569
|
+
label: z.ZodString;
|
|
570
|
+
valueType: z.ZodEnum<{
|
|
571
|
+
string: "string";
|
|
572
|
+
number: "number";
|
|
573
|
+
boolean: "boolean";
|
|
574
|
+
date: "date";
|
|
575
|
+
enum: "enum";
|
|
576
|
+
select: "select";
|
|
577
|
+
price: "price";
|
|
578
|
+
multiselect: "multiselect";
|
|
579
|
+
}>;
|
|
580
|
+
options: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
581
|
+
value: z.ZodString;
|
|
582
|
+
label: z.ZodString;
|
|
583
|
+
count: z.ZodNumber;
|
|
584
|
+
}, z.core.$strip>>>;
|
|
585
|
+
range: z.ZodOptional<z.ZodObject<{
|
|
586
|
+
min: z.ZodNumber;
|
|
587
|
+
max: z.ZodNumber;
|
|
588
|
+
}, z.core.$strip>>;
|
|
589
|
+
filterPosition: z.ZodDefault<z.ZodNumber>;
|
|
590
|
+
}, z.core.$strip>;
|
|
591
|
+
export type FilterDefinition = z.infer<typeof filterDefinitionSchema>;
|
|
592
|
+
export declare const createProductRequestSchema: z.ZodObject<{
|
|
593
|
+
sku: z.ZodString;
|
|
594
|
+
type: z.ZodEnum<{
|
|
595
|
+
simple: "simple";
|
|
596
|
+
configurable: "configurable";
|
|
597
|
+
grouped: "grouped";
|
|
598
|
+
bundle: "bundle";
|
|
599
|
+
virtual: "virtual";
|
|
600
|
+
}>;
|
|
601
|
+
name: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
602
|
+
description: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
603
|
+
categoryIds: z.ZodArray<z.ZodString>;
|
|
604
|
+
attributeValues: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
605
|
+
stockMode: z.ZodOptional<z.ZodEnum<{
|
|
606
|
+
categorical: "categorical";
|
|
607
|
+
numeric: "numeric";
|
|
608
|
+
}>>;
|
|
609
|
+
visibility: z.ZodEnum<{
|
|
610
|
+
public: "public";
|
|
611
|
+
logged_in_only: "logged_in_only";
|
|
612
|
+
organization_restricted: "organization_restricted";
|
|
613
|
+
}>;
|
|
614
|
+
status: z.ZodOptional<z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodEnum<{
|
|
615
|
+
active: "active";
|
|
616
|
+
inactive: "inactive";
|
|
617
|
+
draft: "draft";
|
|
618
|
+
}>>>;
|
|
619
|
+
allowedOrganizationIds: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
620
|
+
assetIds: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
621
|
+
initialStock: z.ZodOptional<z.ZodNumber>;
|
|
622
|
+
attributeSetId: z.ZodOptional<z.ZodString>;
|
|
623
|
+
downloadAssetId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
624
|
+
downloadUrl: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
625
|
+
manageStock: z.ZodOptional<z.ZodBoolean>;
|
|
626
|
+
backorderEnabled: z.ZodOptional<z.ZodBoolean>;
|
|
627
|
+
lowStockThreshold: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
628
|
+
lowStockThresholdMode: z.ZodOptional<z.ZodEnum<{
|
|
629
|
+
cumulative: "cumulative";
|
|
630
|
+
per_warehouse: "per_warehouse";
|
|
631
|
+
}>>;
|
|
632
|
+
fulfilmentStrategy: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
|
|
633
|
+
any: "any";
|
|
634
|
+
default_first: "default_first";
|
|
635
|
+
lowest_stock_first: "lowest_stock_first";
|
|
636
|
+
highest_stock_first: "highest_stock_first";
|
|
637
|
+
defined_order: "defined_order";
|
|
638
|
+
}>>>;
|
|
639
|
+
fulfilmentStrategyWarehouseOrder: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString>>>;
|
|
640
|
+
}, z.core.$strip>;
|
|
641
|
+
export type CreateProductRequest = z.infer<typeof createProductRequestSchema>;
|
|
642
|
+
export declare const updateProductRequestSchema: z.ZodObject<{
|
|
643
|
+
description: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
644
|
+
name: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
645
|
+
status: z.ZodOptional<z.ZodOptional<z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodEnum<{
|
|
646
|
+
active: "active";
|
|
647
|
+
inactive: "inactive";
|
|
648
|
+
draft: "draft";
|
|
649
|
+
}>>>>;
|
|
650
|
+
visibility: z.ZodOptional<z.ZodEnum<{
|
|
651
|
+
public: "public";
|
|
652
|
+
logged_in_only: "logged_in_only";
|
|
653
|
+
organization_restricted: "organization_restricted";
|
|
654
|
+
}>>;
|
|
655
|
+
assetIds: z.ZodOptional<z.ZodOptional<z.ZodArray<z.ZodString>>>;
|
|
656
|
+
categoryIds: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
657
|
+
sku: z.ZodOptional<z.ZodString>;
|
|
658
|
+
manageStock: z.ZodOptional<z.ZodOptional<z.ZodBoolean>>;
|
|
659
|
+
backorderEnabled: z.ZodOptional<z.ZodOptional<z.ZodBoolean>>;
|
|
660
|
+
lowStockThreshold: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodNumber>>>;
|
|
661
|
+
lowStockThresholdMode: z.ZodOptional<z.ZodOptional<z.ZodEnum<{
|
|
662
|
+
cumulative: "cumulative";
|
|
663
|
+
per_warehouse: "per_warehouse";
|
|
664
|
+
}>>>;
|
|
665
|
+
attributeValues: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
666
|
+
downloadAssetId: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
|
|
667
|
+
downloadUrl: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
|
|
668
|
+
stockMode: z.ZodOptional<z.ZodOptional<z.ZodEnum<{
|
|
669
|
+
categorical: "categorical";
|
|
670
|
+
numeric: "numeric";
|
|
671
|
+
}>>>;
|
|
672
|
+
allowedOrganizationIds: z.ZodOptional<z.ZodOptional<z.ZodArray<z.ZodString>>>;
|
|
673
|
+
initialStock: z.ZodOptional<z.ZodOptional<z.ZodNumber>>;
|
|
674
|
+
attributeSetId: z.ZodOptional<z.ZodOptional<z.ZodString>>;
|
|
675
|
+
fulfilmentStrategy: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodEnum<{
|
|
676
|
+
any: "any";
|
|
677
|
+
default_first: "default_first";
|
|
678
|
+
lowest_stock_first: "lowest_stock_first";
|
|
679
|
+
highest_stock_first: "highest_stock_first";
|
|
680
|
+
defined_order: "defined_order";
|
|
681
|
+
}>>>>;
|
|
682
|
+
fulfilmentStrategyWarehouseOrder: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString>>>>;
|
|
683
|
+
}, z.core.$strip>;
|
|
684
|
+
export type UpdateProductRequest = z.infer<typeof updateProductRequestSchema>;
|
|
685
|
+
export declare const batchByIdProductsRequestSchema: z.ZodObject<{
|
|
686
|
+
ids: z.ZodArray<z.ZodString>;
|
|
687
|
+
page: z.ZodOptional<z.ZodNumber>;
|
|
688
|
+
pageSize: z.ZodOptional<z.ZodNumber>;
|
|
689
|
+
}, z.core.$strip>;
|
|
690
|
+
export type BatchByIdProductsRequest = z.infer<typeof batchByIdProductsRequestSchema>;
|
|
691
|
+
export declare const MAX_RESOLVE_SELECTION_SIZE = 10000;
|
|
692
|
+
export declare const resolveProductIdsRequestSchema: z.ZodObject<{
|
|
693
|
+
status: z.ZodOptional<z.ZodEnum<{
|
|
694
|
+
active: "active";
|
|
695
|
+
inactive: "inactive";
|
|
696
|
+
draft: "draft";
|
|
697
|
+
}>>;
|
|
698
|
+
type: z.ZodOptional<z.ZodEnum<{
|
|
699
|
+
simple: "simple";
|
|
700
|
+
configurable: "configurable";
|
|
701
|
+
grouped: "grouped";
|
|
702
|
+
bundle: "bundle";
|
|
703
|
+
virtual: "virtual";
|
|
704
|
+
}>>;
|
|
705
|
+
q: z.ZodOptional<z.ZodString>;
|
|
706
|
+
includeArchived: z.ZodOptional<z.ZodBoolean>;
|
|
707
|
+
}, z.core.$strip>;
|
|
708
|
+
export type ResolveProductIdsRequest = z.infer<typeof resolveProductIdsRequestSchema>;
|
|
709
|
+
export declare const resolveProductIdsResponseSchema: z.ZodObject<{
|
|
710
|
+
data: z.ZodObject<{
|
|
711
|
+
productIds: z.ZodArray<z.ZodString>;
|
|
712
|
+
total: z.ZodNumber;
|
|
713
|
+
}, z.core.$strip>;
|
|
714
|
+
}, z.core.$strip>;
|
|
715
|
+
export type ResolveProductIdsResponse = z.infer<typeof resolveProductIdsResponseSchema>;
|
|
716
|
+
export declare const bulkUpdateProductsRequestSchema: z.ZodObject<{
|
|
717
|
+
productIds: z.ZodArray<z.ZodString>;
|
|
718
|
+
fields: z.ZodObject<{
|
|
719
|
+
status: z.ZodOptional<z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodEnum<{
|
|
720
|
+
active: "active";
|
|
721
|
+
inactive: "inactive";
|
|
722
|
+
draft: "draft";
|
|
723
|
+
}>>>;
|
|
724
|
+
visibility: z.ZodOptional<z.ZodEnum<{
|
|
725
|
+
public: "public";
|
|
726
|
+
logged_in_only: "logged_in_only";
|
|
727
|
+
organization_restricted: "organization_restricted";
|
|
728
|
+
}>>;
|
|
729
|
+
salesChannels: z.ZodOptional<z.ZodObject<{
|
|
730
|
+
mode: z.ZodEnum<{
|
|
731
|
+
replace: "replace";
|
|
732
|
+
add: "add";
|
|
733
|
+
}>;
|
|
734
|
+
channelIds: z.ZodArray<z.ZodString>;
|
|
735
|
+
}, z.core.$strip>>;
|
|
736
|
+
categories: z.ZodOptional<z.ZodObject<{
|
|
737
|
+
mode: z.ZodEnum<{
|
|
738
|
+
replace: "replace";
|
|
739
|
+
add: "add";
|
|
740
|
+
remove: "remove";
|
|
741
|
+
}>;
|
|
742
|
+
categoryIds: z.ZodArray<z.ZodString>;
|
|
743
|
+
}, z.core.$strip>>;
|
|
744
|
+
attributeSetId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
745
|
+
attributeValues: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
746
|
+
}, z.core.$strip>;
|
|
747
|
+
}, z.core.$strip>;
|
|
748
|
+
export type BulkUpdateProductsRequest = z.infer<typeof bulkUpdateProductsRequestSchema>;
|
|
749
|
+
export declare const bulkUpdateProductResultSchema: z.ZodObject<{
|
|
750
|
+
productId: z.ZodString;
|
|
751
|
+
status: z.ZodEnum<{
|
|
752
|
+
failed: "failed";
|
|
753
|
+
skipped: "skipped";
|
|
754
|
+
succeeded: "succeeded";
|
|
755
|
+
}>;
|
|
756
|
+
reason: z.ZodOptional<z.ZodEnum<{
|
|
757
|
+
product_not_found: "product_not_found";
|
|
758
|
+
attribute_not_in_set: "attribute_not_in_set";
|
|
759
|
+
validation_failed: "validation_failed";
|
|
760
|
+
permission_denied: "permission_denied";
|
|
761
|
+
concurrent_modification: "concurrent_modification";
|
|
762
|
+
}>>;
|
|
763
|
+
details: z.ZodOptional<z.ZodObject<{
|
|
764
|
+
code: z.ZodOptional<z.ZodString>;
|
|
765
|
+
message: z.ZodOptional<z.ZodString>;
|
|
766
|
+
attribute: z.ZodOptional<z.ZodString>;
|
|
767
|
+
}, z.core.$strip>>;
|
|
768
|
+
changedFields: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
769
|
+
}, z.core.$strip>;
|
|
770
|
+
export type BulkUpdateProductResult = z.infer<typeof bulkUpdateProductResultSchema>;
|
|
771
|
+
export declare const bulkUpdateProductsResponseSchema: z.ZodObject<{
|
|
772
|
+
data: z.ZodObject<{
|
|
773
|
+
bulkOperationId: z.ZodString;
|
|
774
|
+
summary: z.ZodObject<{
|
|
775
|
+
succeeded: z.ZodNumber;
|
|
776
|
+
skipped: z.ZodNumber;
|
|
777
|
+
failed: z.ZodNumber;
|
|
778
|
+
total: z.ZodNumber;
|
|
779
|
+
}, z.core.$strip>;
|
|
780
|
+
results: z.ZodArray<z.ZodObject<{
|
|
781
|
+
productId: z.ZodString;
|
|
782
|
+
status: z.ZodEnum<{
|
|
783
|
+
failed: "failed";
|
|
784
|
+
skipped: "skipped";
|
|
785
|
+
succeeded: "succeeded";
|
|
786
|
+
}>;
|
|
787
|
+
reason: z.ZodOptional<z.ZodEnum<{
|
|
788
|
+
product_not_found: "product_not_found";
|
|
789
|
+
attribute_not_in_set: "attribute_not_in_set";
|
|
790
|
+
validation_failed: "validation_failed";
|
|
791
|
+
permission_denied: "permission_denied";
|
|
792
|
+
concurrent_modification: "concurrent_modification";
|
|
793
|
+
}>>;
|
|
794
|
+
details: z.ZodOptional<z.ZodObject<{
|
|
795
|
+
code: z.ZodOptional<z.ZodString>;
|
|
796
|
+
message: z.ZodOptional<z.ZodString>;
|
|
797
|
+
attribute: z.ZodOptional<z.ZodString>;
|
|
798
|
+
}, z.core.$strip>>;
|
|
799
|
+
changedFields: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
800
|
+
}, z.core.$strip>>;
|
|
801
|
+
}, z.core.$strip>;
|
|
802
|
+
}, z.core.$strip>;
|
|
803
|
+
export type BulkUpdateProductsResponse = z.infer<typeof bulkUpdateProductsResponseSchema>;
|
|
804
|
+
export declare const bulkUpdateQueuedResponseSchema: z.ZodObject<{
|
|
805
|
+
data: z.ZodObject<{
|
|
806
|
+
queued: z.ZodLiteral<true>;
|
|
807
|
+
bulkOperationId: z.ZodString;
|
|
808
|
+
total: z.ZodNumber;
|
|
809
|
+
}, z.core.$strip>;
|
|
810
|
+
}, z.core.$strip>;
|
|
811
|
+
export type BulkUpdateQueuedResponse = z.infer<typeof bulkUpdateQueuedResponseSchema>;
|
|
812
|
+
export declare const bulkOperationStatusSchema: z.ZodEnum<{
|
|
813
|
+
pending: "pending";
|
|
814
|
+
completed: "completed";
|
|
815
|
+
failed: "failed";
|
|
816
|
+
running: "running";
|
|
817
|
+
}>;
|
|
818
|
+
export type BulkOperationStatus = z.infer<typeof bulkOperationStatusSchema>;
|
|
819
|
+
/**
|
|
820
|
+
* One timestamped lifecycle event in a bulk operation's log trail, surfaced
|
|
821
|
+
* in the bulk-operations detail view next to the per-element results.
|
|
822
|
+
*/
|
|
823
|
+
export declare const bulkOperationLogEntrySchema: z.ZodObject<{
|
|
824
|
+
ts: z.ZodString;
|
|
825
|
+
level: z.ZodEnum<{
|
|
826
|
+
error: "error";
|
|
827
|
+
info: "info";
|
|
828
|
+
warn: "warn";
|
|
829
|
+
}>;
|
|
830
|
+
message: z.ZodString;
|
|
831
|
+
}, z.core.$strip>;
|
|
832
|
+
export type BulkOperationLogEntry = z.infer<typeof bulkOperationLogEntrySchema>;
|
|
833
|
+
/**
|
|
834
|
+
* Known bulk-operation kinds. `type` on the record is an open string (the
|
|
835
|
+
* queue is generic), but these are the kinds the platform ships:
|
|
836
|
+
* - `product_bulk_update` — the queued large product bulk-edit (feature 022).
|
|
837
|
+
* - `search_reindex` — a full Meilisearch reindex (the `search:reindex`
|
|
838
|
+
* CLI equivalent), enqueued when an attribute's `searchable` flag changes.
|
|
839
|
+
*/
|
|
840
|
+
export declare const BULK_OPERATION_TYPES: {
|
|
841
|
+
readonly PRODUCT_BULK_UPDATE: "product_bulk_update";
|
|
842
|
+
readonly SEARCH_REINDEX: "search_reindex";
|
|
843
|
+
};
|
|
844
|
+
export type BulkOperationType = (typeof BULK_OPERATION_TYPES)[keyof typeof BULK_OPERATION_TYPES];
|
|
845
|
+
export declare const bulkOperationSchema: z.ZodObject<{
|
|
846
|
+
id: z.ZodString;
|
|
847
|
+
type: z.ZodString;
|
|
848
|
+
status: z.ZodEnum<{
|
|
849
|
+
pending: "pending";
|
|
850
|
+
completed: "completed";
|
|
851
|
+
failed: "failed";
|
|
852
|
+
running: "running";
|
|
853
|
+
}>;
|
|
854
|
+
requestedByAdminUserId: z.ZodString;
|
|
855
|
+
total: z.ZodNumber;
|
|
856
|
+
processed: z.ZodNumber;
|
|
857
|
+
succeeded: z.ZodNumber;
|
|
858
|
+
skipped: z.ZodNumber;
|
|
859
|
+
failed: z.ZodNumber;
|
|
860
|
+
touchedFields: z.ZodArray<z.ZodString>;
|
|
861
|
+
results: z.ZodNullable<z.ZodArray<z.ZodObject<{
|
|
862
|
+
productId: z.ZodString;
|
|
863
|
+
status: z.ZodEnum<{
|
|
864
|
+
failed: "failed";
|
|
865
|
+
skipped: "skipped";
|
|
866
|
+
succeeded: "succeeded";
|
|
867
|
+
}>;
|
|
868
|
+
reason: z.ZodOptional<z.ZodEnum<{
|
|
869
|
+
product_not_found: "product_not_found";
|
|
870
|
+
attribute_not_in_set: "attribute_not_in_set";
|
|
871
|
+
validation_failed: "validation_failed";
|
|
872
|
+
permission_denied: "permission_denied";
|
|
873
|
+
concurrent_modification: "concurrent_modification";
|
|
874
|
+
}>>;
|
|
875
|
+
details: z.ZodOptional<z.ZodObject<{
|
|
876
|
+
code: z.ZodOptional<z.ZodString>;
|
|
877
|
+
message: z.ZodOptional<z.ZodString>;
|
|
878
|
+
attribute: z.ZodOptional<z.ZodString>;
|
|
879
|
+
}, z.core.$strip>>;
|
|
880
|
+
changedFields: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
881
|
+
}, z.core.$strip>>>;
|
|
882
|
+
logs: z.ZodNullable<z.ZodArray<z.ZodObject<{
|
|
883
|
+
ts: z.ZodString;
|
|
884
|
+
level: z.ZodEnum<{
|
|
885
|
+
error: "error";
|
|
886
|
+
info: "info";
|
|
887
|
+
warn: "warn";
|
|
888
|
+
}>;
|
|
889
|
+
message: z.ZodString;
|
|
890
|
+
}, z.core.$strip>>>;
|
|
891
|
+
error: z.ZodNullable<z.ZodString>;
|
|
892
|
+
createdAt: z.ZodString;
|
|
893
|
+
startedAt: z.ZodNullable<z.ZodString>;
|
|
894
|
+
finishedAt: z.ZodNullable<z.ZodString>;
|
|
895
|
+
reversible: z.ZodBoolean;
|
|
896
|
+
undoStatus: z.ZodEnum<{
|
|
897
|
+
none: "none";
|
|
898
|
+
reverted: "reverted";
|
|
899
|
+
partially_reverted: "partially_reverted";
|
|
900
|
+
}>;
|
|
901
|
+
undoneAt: z.ZodNullable<z.ZodString>;
|
|
902
|
+
}, z.core.$strip>;
|
|
903
|
+
export type BulkOperation = z.infer<typeof bulkOperationSchema>;
|
|
904
|
+
/** Response of POST /admin/catalog/bulk-operations/:id/undo. */
|
|
905
|
+
export declare const bulkOperationUndoResponseSchema: z.ZodObject<{
|
|
906
|
+
data: z.ZodObject<{
|
|
907
|
+
undoStatus: z.ZodEnum<{
|
|
908
|
+
none: "none";
|
|
909
|
+
reverted: "reverted";
|
|
910
|
+
partially_reverted: "partially_reverted";
|
|
911
|
+
}>;
|
|
912
|
+
reverted: z.ZodNumber;
|
|
913
|
+
conflicts: z.ZodArray<z.ZodObject<{
|
|
914
|
+
recordId: z.ZodString;
|
|
915
|
+
reason: z.ZodString;
|
|
916
|
+
}, z.core.$strip>>;
|
|
917
|
+
}, z.core.$strip>;
|
|
918
|
+
}, z.core.$strip>;
|
|
919
|
+
export type BulkOperationUndoResponse = z.infer<typeof bulkOperationUndoResponseSchema>;
|
|
920
|
+
export declare const bulkOperationsListResponseSchema: z.ZodObject<{
|
|
921
|
+
data: z.ZodArray<z.ZodObject<{
|
|
922
|
+
id: z.ZodString;
|
|
923
|
+
type: z.ZodString;
|
|
924
|
+
status: z.ZodEnum<{
|
|
925
|
+
pending: "pending";
|
|
926
|
+
completed: "completed";
|
|
927
|
+
failed: "failed";
|
|
928
|
+
running: "running";
|
|
929
|
+
}>;
|
|
930
|
+
requestedByAdminUserId: z.ZodString;
|
|
931
|
+
total: z.ZodNumber;
|
|
932
|
+
processed: z.ZodNumber;
|
|
933
|
+
succeeded: z.ZodNumber;
|
|
934
|
+
skipped: z.ZodNumber;
|
|
935
|
+
failed: z.ZodNumber;
|
|
936
|
+
touchedFields: z.ZodArray<z.ZodString>;
|
|
937
|
+
results: z.ZodNullable<z.ZodArray<z.ZodObject<{
|
|
938
|
+
productId: z.ZodString;
|
|
939
|
+
status: z.ZodEnum<{
|
|
940
|
+
failed: "failed";
|
|
941
|
+
skipped: "skipped";
|
|
942
|
+
succeeded: "succeeded";
|
|
943
|
+
}>;
|
|
944
|
+
reason: z.ZodOptional<z.ZodEnum<{
|
|
945
|
+
product_not_found: "product_not_found";
|
|
946
|
+
attribute_not_in_set: "attribute_not_in_set";
|
|
947
|
+
validation_failed: "validation_failed";
|
|
948
|
+
permission_denied: "permission_denied";
|
|
949
|
+
concurrent_modification: "concurrent_modification";
|
|
950
|
+
}>>;
|
|
951
|
+
details: z.ZodOptional<z.ZodObject<{
|
|
952
|
+
code: z.ZodOptional<z.ZodString>;
|
|
953
|
+
message: z.ZodOptional<z.ZodString>;
|
|
954
|
+
attribute: z.ZodOptional<z.ZodString>;
|
|
955
|
+
}, z.core.$strip>>;
|
|
956
|
+
changedFields: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
957
|
+
}, z.core.$strip>>>;
|
|
958
|
+
logs: z.ZodNullable<z.ZodArray<z.ZodObject<{
|
|
959
|
+
ts: z.ZodString;
|
|
960
|
+
level: z.ZodEnum<{
|
|
961
|
+
error: "error";
|
|
962
|
+
info: "info";
|
|
963
|
+
warn: "warn";
|
|
964
|
+
}>;
|
|
965
|
+
message: z.ZodString;
|
|
966
|
+
}, z.core.$strip>>>;
|
|
967
|
+
error: z.ZodNullable<z.ZodString>;
|
|
968
|
+
createdAt: z.ZodString;
|
|
969
|
+
startedAt: z.ZodNullable<z.ZodString>;
|
|
970
|
+
finishedAt: z.ZodNullable<z.ZodString>;
|
|
971
|
+
reversible: z.ZodBoolean;
|
|
972
|
+
undoStatus: z.ZodEnum<{
|
|
973
|
+
none: "none";
|
|
974
|
+
reverted: "reverted";
|
|
975
|
+
partially_reverted: "partially_reverted";
|
|
976
|
+
}>;
|
|
977
|
+
undoneAt: z.ZodNullable<z.ZodString>;
|
|
978
|
+
}, z.core.$strip>>;
|
|
979
|
+
pagination: z.ZodObject<{
|
|
980
|
+
total: z.ZodNumber;
|
|
981
|
+
limit: z.ZodNumber;
|
|
982
|
+
offset: z.ZodNumber;
|
|
983
|
+
}, z.core.$strip>;
|
|
984
|
+
}, z.core.$strip>;
|
|
985
|
+
export type BulkOperationsListResponse = z.infer<typeof bulkOperationsListResponseSchema>;
|
|
986
|
+
export declare const bulkOperationResponseSchema: z.ZodObject<{
|
|
987
|
+
data: z.ZodObject<{
|
|
988
|
+
id: z.ZodString;
|
|
989
|
+
type: z.ZodString;
|
|
990
|
+
status: z.ZodEnum<{
|
|
991
|
+
pending: "pending";
|
|
992
|
+
completed: "completed";
|
|
993
|
+
failed: "failed";
|
|
994
|
+
running: "running";
|
|
995
|
+
}>;
|
|
996
|
+
requestedByAdminUserId: z.ZodString;
|
|
997
|
+
total: z.ZodNumber;
|
|
998
|
+
processed: z.ZodNumber;
|
|
999
|
+
succeeded: z.ZodNumber;
|
|
1000
|
+
skipped: z.ZodNumber;
|
|
1001
|
+
failed: z.ZodNumber;
|
|
1002
|
+
touchedFields: z.ZodArray<z.ZodString>;
|
|
1003
|
+
results: z.ZodNullable<z.ZodArray<z.ZodObject<{
|
|
1004
|
+
productId: z.ZodString;
|
|
1005
|
+
status: z.ZodEnum<{
|
|
1006
|
+
failed: "failed";
|
|
1007
|
+
skipped: "skipped";
|
|
1008
|
+
succeeded: "succeeded";
|
|
1009
|
+
}>;
|
|
1010
|
+
reason: z.ZodOptional<z.ZodEnum<{
|
|
1011
|
+
product_not_found: "product_not_found";
|
|
1012
|
+
attribute_not_in_set: "attribute_not_in_set";
|
|
1013
|
+
validation_failed: "validation_failed";
|
|
1014
|
+
permission_denied: "permission_denied";
|
|
1015
|
+
concurrent_modification: "concurrent_modification";
|
|
1016
|
+
}>>;
|
|
1017
|
+
details: z.ZodOptional<z.ZodObject<{
|
|
1018
|
+
code: z.ZodOptional<z.ZodString>;
|
|
1019
|
+
message: z.ZodOptional<z.ZodString>;
|
|
1020
|
+
attribute: z.ZodOptional<z.ZodString>;
|
|
1021
|
+
}, z.core.$strip>>;
|
|
1022
|
+
changedFields: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
1023
|
+
}, z.core.$strip>>>;
|
|
1024
|
+
logs: z.ZodNullable<z.ZodArray<z.ZodObject<{
|
|
1025
|
+
ts: z.ZodString;
|
|
1026
|
+
level: z.ZodEnum<{
|
|
1027
|
+
error: "error";
|
|
1028
|
+
info: "info";
|
|
1029
|
+
warn: "warn";
|
|
1030
|
+
}>;
|
|
1031
|
+
message: z.ZodString;
|
|
1032
|
+
}, z.core.$strip>>>;
|
|
1033
|
+
error: z.ZodNullable<z.ZodString>;
|
|
1034
|
+
createdAt: z.ZodString;
|
|
1035
|
+
startedAt: z.ZodNullable<z.ZodString>;
|
|
1036
|
+
finishedAt: z.ZodNullable<z.ZodString>;
|
|
1037
|
+
reversible: z.ZodBoolean;
|
|
1038
|
+
undoStatus: z.ZodEnum<{
|
|
1039
|
+
none: "none";
|
|
1040
|
+
reverted: "reverted";
|
|
1041
|
+
partially_reverted: "partially_reverted";
|
|
1042
|
+
}>;
|
|
1043
|
+
undoneAt: z.ZodNullable<z.ZodString>;
|
|
1044
|
+
}, z.core.$strip>;
|
|
1045
|
+
}, z.core.$strip>;
|
|
1046
|
+
export type BulkOperationResponse = z.infer<typeof bulkOperationResponseSchema>;
|
|
1047
|
+
export declare const createVariantRequestSchema: z.ZodObject<{
|
|
1048
|
+
sku: z.ZodString;
|
|
1049
|
+
variantAttributeValues: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
1050
|
+
priceOverride: z.ZodOptional<z.ZodNumber>;
|
|
1051
|
+
stockLevel: z.ZodOptional<z.ZodNumber>;
|
|
1052
|
+
}, z.core.$strip>;
|
|
1053
|
+
export type CreateVariantRequest = z.infer<typeof createVariantRequestSchema>;
|
|
1054
|
+
export declare const updateVariantRequestSchema: z.ZodObject<{
|
|
1055
|
+
stockLevel: z.ZodOptional<z.ZodOptional<z.ZodNumber>>;
|
|
1056
|
+
variantAttributeValues: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
1057
|
+
priceOverride: z.ZodOptional<z.ZodOptional<z.ZodNumber>>;
|
|
1058
|
+
}, z.core.$strip>;
|
|
1059
|
+
export type UpdateVariantRequest = z.infer<typeof updateVariantRequestSchema>;
|
|
1060
|
+
/**
|
|
1061
|
+
* Slider-numeric-kind discriminant (feature 002 T013/T021/T022). The API
|
|
1062
|
+
* `type=slider` form needs an extra hint so the service knows whether the
|
|
1063
|
+
* underlying DB `valueType` is `number` or `price`.
|
|
1064
|
+
*/
|
|
1065
|
+
export declare const numericKindSchema: z.ZodEnum<{
|
|
1066
|
+
number: "number";
|
|
1067
|
+
price: "price";
|
|
1068
|
+
}>;
|
|
1069
|
+
export type NumericKind = z.infer<typeof numericKindSchema>;
|
|
1070
|
+
export declare const createAttributeRequestSchema: z.ZodObject<{
|
|
1071
|
+
key: z.ZodString;
|
|
1072
|
+
label: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
1073
|
+
type: z.ZodOptional<z.ZodEnum<{
|
|
1074
|
+
number: "number";
|
|
1075
|
+
input: "input";
|
|
1076
|
+
select: "select";
|
|
1077
|
+
price: "price";
|
|
1078
|
+
multiselect: "multiselect";
|
|
1079
|
+
slider: "slider";
|
|
1080
|
+
}>>;
|
|
1081
|
+
numericKind: z.ZodOptional<z.ZodEnum<{
|
|
1082
|
+
number: "number";
|
|
1083
|
+
price: "price";
|
|
1084
|
+
}>>;
|
|
1085
|
+
valueType: z.ZodOptional<z.ZodEnum<{
|
|
1086
|
+
string: "string";
|
|
1087
|
+
number: "number";
|
|
1088
|
+
boolean: "boolean";
|
|
1089
|
+
date: "date";
|
|
1090
|
+
enum: "enum";
|
|
1091
|
+
select: "select";
|
|
1092
|
+
price: "price";
|
|
1093
|
+
multiselect: "multiselect";
|
|
1094
|
+
}>>;
|
|
1095
|
+
enumValues: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
1096
|
+
isSearchable: z.ZodBoolean;
|
|
1097
|
+
isFilterable: z.ZodBoolean;
|
|
1098
|
+
isVariantAxis: z.ZodBoolean;
|
|
1099
|
+
displayAsSlider: z.ZodOptional<z.ZodBoolean>;
|
|
1100
|
+
isComparable: z.ZodOptional<z.ZodBoolean>;
|
|
1101
|
+
labelDefault: z.ZodOptional<z.ZodString>;
|
|
1102
|
+
isRequired: z.ZodOptional<z.ZodBoolean>;
|
|
1103
|
+
isPromoRule: z.ZodOptional<z.ZodBoolean>;
|
|
1104
|
+
filterPosition: z.ZodOptional<z.ZodNumber>;
|
|
1105
|
+
isVisibleOnProductPage: z.ZodOptional<z.ZodBoolean>;
|
|
1106
|
+
channelScoped: z.ZodOptional<z.ZodBoolean>;
|
|
1107
|
+
languageScoped: z.ZodOptional<z.ZodBoolean>;
|
|
1108
|
+
massEditable: z.ZodOptional<z.ZodBoolean>;
|
|
1109
|
+
quickSearchable: z.ZodOptional<z.ZodBoolean>;
|
|
1110
|
+
options: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
1111
|
+
value: z.ZodString;
|
|
1112
|
+
label: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
1113
|
+
labelDefault: z.ZodString;
|
|
1114
|
+
isDefault: z.ZodOptional<z.ZodBoolean>;
|
|
1115
|
+
sortOrder: z.ZodOptional<z.ZodNumber>;
|
|
1116
|
+
}, z.core.$strip>>>;
|
|
1117
|
+
}, z.core.$strip>;
|
|
1118
|
+
export type CreateAttributeRequest = z.infer<typeof createAttributeRequestSchema>;
|
|
1119
|
+
export declare const updateAttributeRequestSchema: z.ZodObject<{
|
|
1120
|
+
label: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
1121
|
+
type: z.ZodOptional<z.ZodEnum<{
|
|
1122
|
+
number: "number";
|
|
1123
|
+
input: "input";
|
|
1124
|
+
select: "select";
|
|
1125
|
+
price: "price";
|
|
1126
|
+
multiselect: "multiselect";
|
|
1127
|
+
slider: "slider";
|
|
1128
|
+
}>>;
|
|
1129
|
+
numericKind: z.ZodOptional<z.ZodEnum<{
|
|
1130
|
+
number: "number";
|
|
1131
|
+
price: "price";
|
|
1132
|
+
}>>;
|
|
1133
|
+
enumValues: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
1134
|
+
isSearchable: z.ZodOptional<z.ZodBoolean>;
|
|
1135
|
+
isFilterable: z.ZodOptional<z.ZodBoolean>;
|
|
1136
|
+
isVariantAxis: z.ZodOptional<z.ZodBoolean>;
|
|
1137
|
+
displayAsSlider: z.ZodOptional<z.ZodBoolean>;
|
|
1138
|
+
isComparable: z.ZodOptional<z.ZodBoolean>;
|
|
1139
|
+
labelDefault: z.ZodOptional<z.ZodString>;
|
|
1140
|
+
isRequired: z.ZodOptional<z.ZodBoolean>;
|
|
1141
|
+
isPromoRule: z.ZodOptional<z.ZodBoolean>;
|
|
1142
|
+
filterPosition: z.ZodOptional<z.ZodNumber>;
|
|
1143
|
+
isVisibleOnProductPage: z.ZodOptional<z.ZodBoolean>;
|
|
1144
|
+
channelScoped: z.ZodOptional<z.ZodBoolean>;
|
|
1145
|
+
languageScoped: z.ZodOptional<z.ZodBoolean>;
|
|
1146
|
+
massEditable: z.ZodOptional<z.ZodBoolean>;
|
|
1147
|
+
quickSearchable: z.ZodOptional<z.ZodBoolean>;
|
|
1148
|
+
}, z.core.$strict>;
|
|
1149
|
+
export type UpdateAttributeRequest = z.infer<typeof updateAttributeRequestSchema>;
|
|
1150
|
+
/**
|
|
1151
|
+
* Feature 061 — admin attribute payload returned by
|
|
1152
|
+
* `GET/POST/PATCH /api/v1/admin/catalog/attributes*`. Formalizes the shape
|
|
1153
|
+
* `serializeAdminAttribute` has emitted since features 002/012/022/023/039 and
|
|
1154
|
+
* adds the single additive field `customFieldDefinitionId` — the backing
|
|
1155
|
+
* product-host Custom Field definition (contracts/attribute-admin-api.md).
|
|
1156
|
+
* All request schemas above are byte-compatible and unchanged (FR-007, SC-003).
|
|
1157
|
+
*/
|
|
1158
|
+
export declare const adminAttributeResponseSchema: z.ZodObject<{
|
|
1159
|
+
id: z.ZodString;
|
|
1160
|
+
key: z.ZodString;
|
|
1161
|
+
label: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
1162
|
+
labelDefault: z.ZodString;
|
|
1163
|
+
type: z.ZodEnum<{
|
|
1164
|
+
number: "number";
|
|
1165
|
+
input: "input";
|
|
1166
|
+
select: "select";
|
|
1167
|
+
price: "price";
|
|
1168
|
+
multiselect: "multiselect";
|
|
1169
|
+
slider: "slider";
|
|
1170
|
+
}>;
|
|
1171
|
+
numericKind: z.ZodOptional<z.ZodEnum<{
|
|
1172
|
+
number: "number";
|
|
1173
|
+
price: "price";
|
|
1174
|
+
}>>;
|
|
1175
|
+
valueType: z.ZodEnum<{
|
|
1176
|
+
string: "string";
|
|
1177
|
+
number: "number";
|
|
1178
|
+
boolean: "boolean";
|
|
1179
|
+
date: "date";
|
|
1180
|
+
enum: "enum";
|
|
1181
|
+
select: "select";
|
|
1182
|
+
price: "price";
|
|
1183
|
+
multiselect: "multiselect";
|
|
1184
|
+
}>;
|
|
1185
|
+
enumValues: z.ZodNullable<z.ZodArray<z.ZodString>>;
|
|
1186
|
+
isSearchable: z.ZodBoolean;
|
|
1187
|
+
isFilterable: z.ZodBoolean;
|
|
1188
|
+
isVariantAxis: z.ZodBoolean;
|
|
1189
|
+
displayAsSlider: z.ZodBoolean;
|
|
1190
|
+
isComparable: z.ZodBoolean;
|
|
1191
|
+
isRequired: z.ZodBoolean;
|
|
1192
|
+
isPromoRule: z.ZodBoolean;
|
|
1193
|
+
filterPosition: z.ZodNumber;
|
|
1194
|
+
isVisibleOnProductPage: z.ZodBoolean;
|
|
1195
|
+
massEditable: z.ZodBoolean;
|
|
1196
|
+
quickSearchable: z.ZodBoolean;
|
|
1197
|
+
customFieldDefinitionId: z.ZodString;
|
|
1198
|
+
createdAt: z.ZodString;
|
|
1199
|
+
updatedAt: z.ZodString;
|
|
1200
|
+
}, z.core.$strip>;
|
|
1201
|
+
export type AdminAttributeResponse = z.infer<typeof adminAttributeResponseSchema>;
|
|
1202
|
+
export declare const createCategoryRequestSchema: z.ZodObject<{
|
|
1203
|
+
parentCategoryId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
1204
|
+
name: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
1205
|
+
slug: z.ZodString;
|
|
1206
|
+
sortOrder: z.ZodOptional<z.ZodNumber>;
|
|
1207
|
+
isActive: z.ZodOptional<z.ZodBoolean>;
|
|
1208
|
+
}, z.core.$strip>;
|
|
1209
|
+
export type CreateCategoryRequest = z.infer<typeof createCategoryRequestSchema>;
|
|
1210
|
+
export declare const updateCategoryRequestSchema: z.ZodObject<{
|
|
1211
|
+
parentCategoryId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
1212
|
+
name: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
1213
|
+
slug: z.ZodOptional<z.ZodString>;
|
|
1214
|
+
sortOrder: z.ZodOptional<z.ZodNumber>;
|
|
1215
|
+
isActive: z.ZodOptional<z.ZodBoolean>;
|
|
1216
|
+
mainImageAssetId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
1217
|
+
customFieldValues: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
1218
|
+
}, z.core.$strict>;
|
|
1219
|
+
export type UpdateCategoryRequest = z.infer<typeof updateCategoryRequestSchema>;
|
|
1220
|
+
/**
|
|
1221
|
+
* The orderings the storefront listing accepts.
|
|
1222
|
+
*
|
|
1223
|
+
* Feature 086 adds `price` / `-price`, following the convention the two `name`
|
|
1224
|
+
* members set: the bare member ascends, the `-` prefix descends. "Price" is the
|
|
1225
|
+
* **viewer's own** resolved unit price at quantity 1 — the figure the card
|
|
1226
|
+
* renders — never a stored base price, a channel price or anything a search
|
|
1227
|
+
* index carries.
|
|
1228
|
+
*/
|
|
1229
|
+
export declare const productListSortSchema: z.ZodEnum<{
|
|
1230
|
+
name: "name";
|
|
1231
|
+
price: "price";
|
|
1232
|
+
relevance: "relevance";
|
|
1233
|
+
"-createdAt": "-createdAt";
|
|
1234
|
+
"-name": "-name";
|
|
1235
|
+
"-price": "-price";
|
|
1236
|
+
}>;
|
|
1237
|
+
export type ProductListSort = z.infer<typeof productListSortSchema>;
|
|
1238
|
+
/** The two orderings feature 086 added, as a narrowing a consumer can reuse. */
|
|
1239
|
+
export declare function isPriceSort(sort: ProductListSort | undefined): sort is 'price' | '-price';
|
|
1240
|
+
export declare const productListQuerySchema: z.ZodObject<{
|
|
1241
|
+
q: z.ZodOptional<z.ZodString>;
|
|
1242
|
+
limit: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
1243
|
+
cursor: z.ZodOptional<z.ZodString>;
|
|
1244
|
+
sort: z.ZodOptional<z.ZodEnum<{
|
|
1245
|
+
name: "name";
|
|
1246
|
+
price: "price";
|
|
1247
|
+
relevance: "relevance";
|
|
1248
|
+
"-createdAt": "-createdAt";
|
|
1249
|
+
"-name": "-name";
|
|
1250
|
+
"-price": "-price";
|
|
1251
|
+
}>>;
|
|
1252
|
+
changedSince: z.ZodOptional<z.ZodString>;
|
|
1253
|
+
minPrice: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
|
|
1254
|
+
maxPrice: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
|
|
1255
|
+
}, z.core.$strip>;
|
|
1256
|
+
export type ProductListQuery = z.infer<typeof productListQuerySchema>;
|
|
1257
|
+
/**
|
|
1258
|
+
* What the listing surface may offer this viewer on this page — feature 086 /
|
|
1259
|
+
* FR-023.
|
|
1260
|
+
*
|
|
1261
|
+
* It rides on the listing response because the storefront has to decide whether
|
|
1262
|
+
* to *render* the price controls, and the answer depends on the viewer and the
|
|
1263
|
+
* channel: a non-public channel publishes no prices, and
|
|
1264
|
+
* `pricing.unauthenticated_display_mode = none` hides them until login. A
|
|
1265
|
+
* storefront that guessed would guess wrong on exactly the deployments that
|
|
1266
|
+
* care, and a control that offers an ordering the API refuses is a worse defect
|
|
1267
|
+
* than no control.
|
|
1268
|
+
*
|
|
1269
|
+
* It is **not** on the filter-definitions endpoint, which is anonymous and
|
|
1270
|
+
* shared (FR-010): a per-viewer answer may not travel on a response whose cache
|
|
1271
|
+
* key omits the viewer.
|
|
1272
|
+
*/
|
|
1273
|
+
export declare const productListCapabilitiesSchema: z.ZodObject<{
|
|
1274
|
+
priceOrdering: z.ZodBoolean;
|
|
1275
|
+
}, z.core.$strip>;
|
|
1276
|
+
export type ProductListCapabilities = z.infer<typeof productListCapabilitiesSchema>;
|
|
1277
|
+
export declare const notifyWhenAvailableRequestSchema: z.ZodObject<{
|
|
1278
|
+
variantId: z.ZodOptional<z.ZodString>;
|
|
1279
|
+
}, z.core.$strip>;
|
|
1280
|
+
export type NotifyWhenAvailableRequest = z.infer<typeof notifyWhenAvailableRequestSchema>;
|
|
1281
|
+
export declare const notifyWhenAvailableResponseSchema: z.ZodObject<{
|
|
1282
|
+
subscriptionId: z.ZodString;
|
|
1283
|
+
requestedAt: z.ZodString;
|
|
1284
|
+
}, z.core.$strip>;
|
|
1285
|
+
export type NotifyWhenAvailableResponse = z.infer<typeof notifyWhenAvailableResponseSchema>;
|
|
1286
|
+
export declare const attributeSetSchema: z.ZodObject<{
|
|
1287
|
+
id: z.ZodString;
|
|
1288
|
+
code: z.ZodString;
|
|
1289
|
+
name: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
1290
|
+
description: z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
1291
|
+
isSystem: z.ZodBoolean;
|
|
1292
|
+
attributeCount: z.ZodNumber;
|
|
1293
|
+
productCount: z.ZodNumber;
|
|
1294
|
+
createdAt: z.ZodString;
|
|
1295
|
+
updatedAt: z.ZodString;
|
|
1296
|
+
}, z.core.$strip>;
|
|
1297
|
+
export type AttributeSet = z.infer<typeof attributeSetSchema>;
|
|
1298
|
+
export declare const attributeSetAssignedAttributeSchema: z.ZodObject<{
|
|
1299
|
+
id: z.ZodString;
|
|
1300
|
+
key: z.ZodString;
|
|
1301
|
+
label: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
1302
|
+
valueType: z.ZodEnum<{
|
|
1303
|
+
string: "string";
|
|
1304
|
+
number: "number";
|
|
1305
|
+
boolean: "boolean";
|
|
1306
|
+
date: "date";
|
|
1307
|
+
enum: "enum";
|
|
1308
|
+
select: "select";
|
|
1309
|
+
price: "price";
|
|
1310
|
+
multiselect: "multiselect";
|
|
1311
|
+
}>;
|
|
1312
|
+
position: z.ZodNumber;
|
|
1313
|
+
languageScoped: z.ZodBoolean;
|
|
1314
|
+
}, z.core.$strip>;
|
|
1315
|
+
export type AttributeSetAssignedAttribute = z.infer<typeof attributeSetAssignedAttributeSchema>;
|
|
1316
|
+
export declare const attributeSetDetailSchema: z.ZodObject<{
|
|
1317
|
+
id: z.ZodString;
|
|
1318
|
+
code: z.ZodString;
|
|
1319
|
+
name: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
1320
|
+
description: z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
1321
|
+
isSystem: z.ZodBoolean;
|
|
1322
|
+
attributeCount: z.ZodNumber;
|
|
1323
|
+
productCount: z.ZodNumber;
|
|
1324
|
+
createdAt: z.ZodString;
|
|
1325
|
+
updatedAt: z.ZodString;
|
|
1326
|
+
attributes: z.ZodArray<z.ZodObject<{
|
|
1327
|
+
id: z.ZodString;
|
|
1328
|
+
key: z.ZodString;
|
|
1329
|
+
label: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
1330
|
+
valueType: z.ZodEnum<{
|
|
1331
|
+
string: "string";
|
|
1332
|
+
number: "number";
|
|
1333
|
+
boolean: "boolean";
|
|
1334
|
+
date: "date";
|
|
1335
|
+
enum: "enum";
|
|
1336
|
+
select: "select";
|
|
1337
|
+
price: "price";
|
|
1338
|
+
multiselect: "multiselect";
|
|
1339
|
+
}>;
|
|
1340
|
+
position: z.ZodNumber;
|
|
1341
|
+
languageScoped: z.ZodBoolean;
|
|
1342
|
+
}, z.core.$strip>>;
|
|
1343
|
+
}, z.core.$strip>;
|
|
1344
|
+
export type AttributeSetDetail = z.infer<typeof attributeSetDetailSchema>;
|
|
1345
|
+
export declare const createAttributeSetRequestSchema: z.ZodObject<{
|
|
1346
|
+
code: z.ZodString;
|
|
1347
|
+
name: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
1348
|
+
description: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
1349
|
+
attributeIds: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
1350
|
+
}, z.core.$strict>;
|
|
1351
|
+
export type CreateAttributeSetRequest = z.infer<typeof createAttributeSetRequestSchema>;
|
|
1352
|
+
export declare const updateAttributeSetRequestSchema: z.ZodObject<{
|
|
1353
|
+
code: z.ZodOptional<z.ZodString>;
|
|
1354
|
+
name: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
1355
|
+
description: z.ZodOptional<z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodString>>>;
|
|
1356
|
+
}, z.core.$strict>;
|
|
1357
|
+
export type UpdateAttributeSetRequest = z.infer<typeof updateAttributeSetRequestSchema>;
|
|
1358
|
+
export declare const assignAttributesRequestSchema: z.ZodObject<{
|
|
1359
|
+
assignments: z.ZodArray<z.ZodObject<{
|
|
1360
|
+
attributeId: z.ZodString;
|
|
1361
|
+
position: z.ZodOptional<z.ZodNumber>;
|
|
1362
|
+
}, z.core.$strip>>;
|
|
1363
|
+
}, z.core.$strict>;
|
|
1364
|
+
export type AssignAttributesRequest = z.infer<typeof assignAttributesRequestSchema>;
|
|
1365
|
+
export declare const galleryLabelSchema: z.ZodEnum<{
|
|
1366
|
+
base_image: "base_image";
|
|
1367
|
+
small_image: "small_image";
|
|
1368
|
+
thumbnail: "thumbnail";
|
|
1369
|
+
}>;
|
|
1370
|
+
export type GalleryLabel = z.infer<typeof galleryLabelSchema>;
|
|
1371
|
+
export declare const galleryItemSchema: z.ZodObject<{
|
|
1372
|
+
id: z.ZodString;
|
|
1373
|
+
productId: z.ZodString;
|
|
1374
|
+
assetId: z.ZodString;
|
|
1375
|
+
position: z.ZodNumber;
|
|
1376
|
+
labels: z.ZodArray<z.ZodEnum<{
|
|
1377
|
+
base_image: "base_image";
|
|
1378
|
+
small_image: "small_image";
|
|
1379
|
+
thumbnail: "thumbnail";
|
|
1380
|
+
}>>;
|
|
1381
|
+
createdAt: z.ZodString;
|
|
1382
|
+
updatedAt: z.ZodString;
|
|
1383
|
+
}, z.core.$strip>;
|
|
1384
|
+
export type GalleryItem = z.infer<typeof galleryItemSchema>;
|
|
1385
|
+
export declare const createGalleryItemRequestSchema: z.ZodObject<{
|
|
1386
|
+
assetId: z.ZodString;
|
|
1387
|
+
position: z.ZodOptional<z.ZodNumber>;
|
|
1388
|
+
labels: z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
|
1389
|
+
base_image: "base_image";
|
|
1390
|
+
small_image: "small_image";
|
|
1391
|
+
thumbnail: "thumbnail";
|
|
1392
|
+
}>>>;
|
|
1393
|
+
}, z.core.$strict>;
|
|
1394
|
+
export type CreateGalleryItemRequest = z.infer<typeof createGalleryItemRequestSchema>;
|
|
1395
|
+
export declare const updateGalleryItemRequestSchema: z.ZodObject<{
|
|
1396
|
+
position: z.ZodOptional<z.ZodNumber>;
|
|
1397
|
+
labels: z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
|
1398
|
+
base_image: "base_image";
|
|
1399
|
+
small_image: "small_image";
|
|
1400
|
+
thumbnail: "thumbnail";
|
|
1401
|
+
}>>>;
|
|
1402
|
+
}, z.core.$strict>;
|
|
1403
|
+
export type UpdateGalleryItemRequest = z.infer<typeof updateGalleryItemRequestSchema>;
|
|
1404
|
+
export declare const reorderGalleryRequestSchema: z.ZodObject<{
|
|
1405
|
+
orderedGalleryItemIds: z.ZodArray<z.ZodString>;
|
|
1406
|
+
}, z.core.$strict>;
|
|
1407
|
+
export type ReorderGalleryRequest = z.infer<typeof reorderGalleryRequestSchema>;
|
|
1408
|
+
export declare const attachmentTypeSchema: z.ZodObject<{
|
|
1409
|
+
id: z.ZodString;
|
|
1410
|
+
code: z.ZodString;
|
|
1411
|
+
name: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
1412
|
+
position: z.ZodNumber;
|
|
1413
|
+
usageCount: z.ZodNumber;
|
|
1414
|
+
createdAt: z.ZodString;
|
|
1415
|
+
updatedAt: z.ZodString;
|
|
1416
|
+
}, z.core.$strip>;
|
|
1417
|
+
export type AttachmentType = z.infer<typeof attachmentTypeSchema>;
|
|
1418
|
+
export declare const createAttachmentTypeRequestSchema: z.ZodObject<{
|
|
1419
|
+
code: z.ZodString;
|
|
1420
|
+
name: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
1421
|
+
position: z.ZodOptional<z.ZodNumber>;
|
|
1422
|
+
}, z.core.$strict>;
|
|
1423
|
+
export type CreateAttachmentTypeRequest = z.infer<typeof createAttachmentTypeRequestSchema>;
|
|
1424
|
+
export declare const updateAttachmentTypeRequestSchema: z.ZodObject<{
|
|
1425
|
+
code: z.ZodOptional<z.ZodString>;
|
|
1426
|
+
name: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
1427
|
+
position: z.ZodOptional<z.ZodNumber>;
|
|
1428
|
+
}, z.core.$strict>;
|
|
1429
|
+
export type UpdateAttachmentTypeRequest = z.infer<typeof updateAttachmentTypeRequestSchema>;
|
|
1430
|
+
export declare const productAttachmentSchema: z.ZodObject<{
|
|
1431
|
+
id: z.ZodString;
|
|
1432
|
+
productId: z.ZodString;
|
|
1433
|
+
assetId: z.ZodString;
|
|
1434
|
+
attachmentTypeId: z.ZodString;
|
|
1435
|
+
name: z.ZodString;
|
|
1436
|
+
description: z.ZodNullable<z.ZodString>;
|
|
1437
|
+
position: z.ZodNumber;
|
|
1438
|
+
createdAt: z.ZodString;
|
|
1439
|
+
updatedAt: z.ZodString;
|
|
1440
|
+
}, z.core.$strip>;
|
|
1441
|
+
export type ProductAttachment = z.infer<typeof productAttachmentSchema>;
|
|
1442
|
+
export declare const createAttachmentRequestSchema: z.ZodObject<{
|
|
1443
|
+
assetId: z.ZodString;
|
|
1444
|
+
attachmentTypeId: z.ZodString;
|
|
1445
|
+
name: z.ZodString;
|
|
1446
|
+
description: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
1447
|
+
position: z.ZodOptional<z.ZodNumber>;
|
|
1448
|
+
}, z.core.$strict>;
|
|
1449
|
+
export type CreateAttachmentRequest = z.infer<typeof createAttachmentRequestSchema>;
|
|
1450
|
+
export declare const updateAttachmentRequestSchema: z.ZodObject<{
|
|
1451
|
+
attachmentTypeId: z.ZodOptional<z.ZodString>;
|
|
1452
|
+
name: z.ZodOptional<z.ZodString>;
|
|
1453
|
+
description: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
1454
|
+
position: z.ZodOptional<z.ZodNumber>;
|
|
1455
|
+
}, z.core.$strict>;
|
|
1456
|
+
export type UpdateAttachmentRequest = z.infer<typeof updateAttachmentRequestSchema>;
|
|
1457
|
+
/**
|
|
1458
|
+
* A named ordering unit attached to a product (e.g. "Paleta" = 480 pieces).
|
|
1459
|
+
* Managed in the Inventory section of the admin product card; surfaced on the
|
|
1460
|
+
* storefront product page so buyers can order by the unit.
|
|
1461
|
+
*/
|
|
1462
|
+
export declare const packagingUnitSchema: z.ZodObject<{
|
|
1463
|
+
id: z.ZodString;
|
|
1464
|
+
productId: z.ZodString;
|
|
1465
|
+
name: z.ZodString;
|
|
1466
|
+
baseQuantity: z.ZodNumber;
|
|
1467
|
+
position: z.ZodNumber;
|
|
1468
|
+
isDefault: z.ZodBoolean;
|
|
1469
|
+
createdAt: z.ZodString;
|
|
1470
|
+
updatedAt: z.ZodString;
|
|
1471
|
+
}, z.core.$strip>;
|
|
1472
|
+
export type PackagingUnitDto = z.infer<typeof packagingUnitSchema>;
|
|
1473
|
+
export declare const createPackagingUnitRequestSchema: z.ZodObject<{
|
|
1474
|
+
name: z.ZodString;
|
|
1475
|
+
baseQuantity: z.ZodNumber;
|
|
1476
|
+
isDefault: z.ZodOptional<z.ZodBoolean>;
|
|
1477
|
+
position: z.ZodOptional<z.ZodNumber>;
|
|
1478
|
+
}, z.core.$strict>;
|
|
1479
|
+
export type CreatePackagingUnitRequest = z.infer<typeof createPackagingUnitRequestSchema>;
|
|
1480
|
+
export declare const updatePackagingUnitRequestSchema: z.ZodObject<{
|
|
1481
|
+
name: z.ZodOptional<z.ZodString>;
|
|
1482
|
+
baseQuantity: z.ZodOptional<z.ZodNumber>;
|
|
1483
|
+
isDefault: z.ZodOptional<z.ZodBoolean>;
|
|
1484
|
+
position: z.ZodOptional<z.ZodNumber>;
|
|
1485
|
+
}, z.core.$strict>;
|
|
1486
|
+
export type UpdatePackagingUnitRequest = z.infer<typeof updatePackagingUnitRequestSchema>;
|
|
1487
|
+
export declare const reorderPackagingUnitsRequestSchema: z.ZodObject<{
|
|
1488
|
+
orderedIds: z.ZodArray<z.ZodString>;
|
|
1489
|
+
}, z.core.$strict>;
|
|
1490
|
+
export type ReorderPackagingUnitsRequest = z.infer<typeof reorderPackagingUnitsRequestSchema>;
|
|
1491
|
+
export declare const productLinkKindSchema: z.ZodEnum<{
|
|
1492
|
+
related: "related";
|
|
1493
|
+
up_sell: "up_sell";
|
|
1494
|
+
cross_sell: "cross_sell";
|
|
1495
|
+
}>;
|
|
1496
|
+
export type ProductLinkKind = z.infer<typeof productLinkKindSchema>;
|
|
1497
|
+
export declare const productLinkSchema: z.ZodObject<{
|
|
1498
|
+
id: z.ZodString;
|
|
1499
|
+
sourceProductId: z.ZodString;
|
|
1500
|
+
targetProductId: z.ZodString;
|
|
1501
|
+
kind: z.ZodEnum<{
|
|
1502
|
+
related: "related";
|
|
1503
|
+
up_sell: "up_sell";
|
|
1504
|
+
cross_sell: "cross_sell";
|
|
1505
|
+
}>;
|
|
1506
|
+
position: z.ZodNumber;
|
|
1507
|
+
}, z.core.$strip>;
|
|
1508
|
+
export type ProductLink = z.infer<typeof productLinkSchema>;
|
|
1509
|
+
/**
|
|
1510
|
+
* Bulk-create payload (T104). One transaction, all-or-nothing —
|
|
1511
|
+
* partial inserts on a duplicate or self-link MUST roll back the
|
|
1512
|
+
* entire batch (FR + research). Each entry pins its kind so admins
|
|
1513
|
+
* can submit a mixed batch in a single round trip.
|
|
1514
|
+
*/
|
|
1515
|
+
export declare const bulkCreateLinksRequestSchema: z.ZodObject<{
|
|
1516
|
+
links: z.ZodArray<z.ZodObject<{
|
|
1517
|
+
targetProductId: z.ZodString;
|
|
1518
|
+
kind: z.ZodEnum<{
|
|
1519
|
+
related: "related";
|
|
1520
|
+
up_sell: "up_sell";
|
|
1521
|
+
cross_sell: "cross_sell";
|
|
1522
|
+
}>;
|
|
1523
|
+
position: z.ZodOptional<z.ZodNumber>;
|
|
1524
|
+
}, z.core.$strip>>;
|
|
1525
|
+
}, z.core.$strip>;
|
|
1526
|
+
export type BulkCreateLinksRequest = z.infer<typeof bulkCreateLinksRequestSchema>;
|
|
1527
|
+
export declare const reorderLinksRequestSchema: z.ZodObject<{
|
|
1528
|
+
linkIds: z.ZodArray<z.ZodString>;
|
|
1529
|
+
}, z.core.$strip>;
|
|
1530
|
+
export type ReorderLinksRequest = z.infer<typeof reorderLinksRequestSchema>;
|
|
1531
|
+
/**
|
|
1532
|
+
* Storefront-shape link entry (T107) — the listing carries enough Product
|
|
1533
|
+
* fields for a card render without a follow-up fetch. Inactive targets
|
|
1534
|
+
* are filtered out by `listForStorefront` so the storefront never sees
|
|
1535
|
+
* `status='archived'` rows.
|
|
1536
|
+
*/
|
|
1537
|
+
export declare const groupedItemSchema: z.ZodObject<{
|
|
1538
|
+
id: z.ZodString;
|
|
1539
|
+
parentProductId: z.ZodString;
|
|
1540
|
+
childProductId: z.ZodString;
|
|
1541
|
+
quantity: z.ZodNumber;
|
|
1542
|
+
position: z.ZodNumber;
|
|
1543
|
+
}, z.core.$strip>;
|
|
1544
|
+
export type GroupedItem = z.infer<typeof groupedItemSchema>;
|
|
1545
|
+
export declare const createGroupedItemRequestSchema: z.ZodObject<{
|
|
1546
|
+
childProductId: z.ZodString;
|
|
1547
|
+
quantity: z.ZodNumber;
|
|
1548
|
+
position: z.ZodOptional<z.ZodNumber>;
|
|
1549
|
+
}, z.core.$strict>;
|
|
1550
|
+
export type CreateGroupedItemRequest = z.infer<typeof createGroupedItemRequestSchema>;
|
|
1551
|
+
export declare const updateGroupedItemRequestSchema: z.ZodObject<{
|
|
1552
|
+
quantity: z.ZodOptional<z.ZodNumber>;
|
|
1553
|
+
position: z.ZodOptional<z.ZodNumber>;
|
|
1554
|
+
}, z.core.$strict>;
|
|
1555
|
+
export type UpdateGroupedItemRequest = z.infer<typeof updateGroupedItemRequestSchema>;
|
|
1556
|
+
export declare const bundleSlotOptionSchema: z.ZodObject<{
|
|
1557
|
+
id: z.ZodString;
|
|
1558
|
+
slotId: z.ZodString;
|
|
1559
|
+
optionProductId: z.ZodString;
|
|
1560
|
+
defaultQuantity: z.ZodNumber;
|
|
1561
|
+
position: z.ZodNumber;
|
|
1562
|
+
}, z.core.$strip>;
|
|
1563
|
+
export type BundleSlotOption = z.infer<typeof bundleSlotOptionSchema>;
|
|
1564
|
+
export declare const bundleSlotSchema: z.ZodObject<{
|
|
1565
|
+
id: z.ZodString;
|
|
1566
|
+
parentProductId: z.ZodString;
|
|
1567
|
+
name: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
1568
|
+
minQuantity: z.ZodNumber;
|
|
1569
|
+
maxQuantity: z.ZodNumber;
|
|
1570
|
+
position: z.ZodNumber;
|
|
1571
|
+
options: z.ZodArray<z.ZodObject<{
|
|
1572
|
+
id: z.ZodString;
|
|
1573
|
+
slotId: z.ZodString;
|
|
1574
|
+
optionProductId: z.ZodString;
|
|
1575
|
+
defaultQuantity: z.ZodNumber;
|
|
1576
|
+
position: z.ZodNumber;
|
|
1577
|
+
}, z.core.$strip>>;
|
|
1578
|
+
}, z.core.$strip>;
|
|
1579
|
+
export type BundleSlot = z.infer<typeof bundleSlotSchema>;
|
|
1580
|
+
export declare const createBundleSlotRequestSchema: z.ZodObject<{
|
|
1581
|
+
name: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
1582
|
+
minQuantity: z.ZodOptional<z.ZodNumber>;
|
|
1583
|
+
maxQuantity: z.ZodNumber;
|
|
1584
|
+
position: z.ZodOptional<z.ZodNumber>;
|
|
1585
|
+
}, z.core.$strict>;
|
|
1586
|
+
export type CreateBundleSlotRequest = z.infer<typeof createBundleSlotRequestSchema>;
|
|
1587
|
+
export declare const updateBundleSlotRequestSchema: z.ZodObject<{
|
|
1588
|
+
name: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
1589
|
+
minQuantity: z.ZodOptional<z.ZodNumber>;
|
|
1590
|
+
maxQuantity: z.ZodOptional<z.ZodNumber>;
|
|
1591
|
+
position: z.ZodOptional<z.ZodNumber>;
|
|
1592
|
+
}, z.core.$strict>;
|
|
1593
|
+
export type UpdateBundleSlotRequest = z.infer<typeof updateBundleSlotRequestSchema>;
|
|
1594
|
+
export declare const createBundleSlotOptionRequestSchema: z.ZodObject<{
|
|
1595
|
+
optionProductId: z.ZodString;
|
|
1596
|
+
defaultQuantity: z.ZodOptional<z.ZodNumber>;
|
|
1597
|
+
position: z.ZodOptional<z.ZodNumber>;
|
|
1598
|
+
}, z.core.$strict>;
|
|
1599
|
+
export type CreateBundleSlotOptionRequest = z.infer<typeof createBundleSlotOptionRequestSchema>;
|
|
1600
|
+
/**
|
|
1601
|
+
* Buyer's bundle configuration — what the storefront posts to the
|
|
1602
|
+
* `/bundle-configuration/validate` endpoint. One selection per slot,
|
|
1603
|
+
* referencing the chosen option's id and the buyer-picked quantity.
|
|
1604
|
+
*/
|
|
1605
|
+
export declare const bundleConfigurationSelectionSchema: z.ZodObject<{
|
|
1606
|
+
slotId: z.ZodString;
|
|
1607
|
+
optionId: z.ZodString;
|
|
1608
|
+
quantity: z.ZodNumber;
|
|
1609
|
+
}, z.core.$strip>;
|
|
1610
|
+
export type BundleConfigurationSelection = z.infer<typeof bundleConfigurationSelectionSchema>;
|
|
1611
|
+
export declare const validateBundleConfigurationRequestSchema: z.ZodObject<{
|
|
1612
|
+
selections: z.ZodArray<z.ZodObject<{
|
|
1613
|
+
slotId: z.ZodString;
|
|
1614
|
+
optionId: z.ZodString;
|
|
1615
|
+
quantity: z.ZodNumber;
|
|
1616
|
+
}, z.core.$strip>>;
|
|
1617
|
+
}, z.core.$strict>;
|
|
1618
|
+
export type ValidateBundleConfigurationRequest = z.infer<typeof validateBundleConfigurationRequestSchema>;
|
|
1619
|
+
export declare const bundleValidationErrorSchema: z.ZodObject<{
|
|
1620
|
+
code: z.ZodEnum<{
|
|
1621
|
+
MIN_NOT_MET: "MIN_NOT_MET";
|
|
1622
|
+
MAX_EXCEEDED: "MAX_EXCEEDED";
|
|
1623
|
+
UNKNOWN_OPTION: "UNKNOWN_OPTION";
|
|
1624
|
+
}>;
|
|
1625
|
+
slotId: z.ZodOptional<z.ZodString>;
|
|
1626
|
+
message: z.ZodString;
|
|
1627
|
+
}, z.core.$strip>;
|
|
1628
|
+
export type BundleValidationError = z.infer<typeof bundleValidationErrorSchema>;
|
|
1629
|
+
export declare const bundleValidationResultSchema: z.ZodObject<{
|
|
1630
|
+
valid: z.ZodBoolean;
|
|
1631
|
+
errors: z.ZodArray<z.ZodObject<{
|
|
1632
|
+
code: z.ZodEnum<{
|
|
1633
|
+
MIN_NOT_MET: "MIN_NOT_MET";
|
|
1634
|
+
MAX_EXCEEDED: "MAX_EXCEEDED";
|
|
1635
|
+
UNKNOWN_OPTION: "UNKNOWN_OPTION";
|
|
1636
|
+
}>;
|
|
1637
|
+
slotId: z.ZodOptional<z.ZodString>;
|
|
1638
|
+
message: z.ZodString;
|
|
1639
|
+
}, z.core.$strip>>;
|
|
1640
|
+
resolvedSelections: z.ZodArray<z.ZodObject<{
|
|
1641
|
+
slotId: z.ZodString;
|
|
1642
|
+
optionId: z.ZodString;
|
|
1643
|
+
optionProductId: z.ZodString;
|
|
1644
|
+
quantity: z.ZodNumber;
|
|
1645
|
+
}, z.core.$strip>>;
|
|
1646
|
+
}, z.core.$strip>;
|
|
1647
|
+
export type BundleValidationResult = z.infer<typeof bundleValidationResultSchema>;
|
|
1648
|
+
export declare const productLinkSummarySchema: z.ZodObject<{
|
|
1649
|
+
id: z.ZodString;
|
|
1650
|
+
kind: z.ZodEnum<{
|
|
1651
|
+
related: "related";
|
|
1652
|
+
up_sell: "up_sell";
|
|
1653
|
+
cross_sell: "cross_sell";
|
|
1654
|
+
}>;
|
|
1655
|
+
position: z.ZodNumber;
|
|
1656
|
+
product: z.ZodObject<{
|
|
1657
|
+
id: z.ZodString;
|
|
1658
|
+
sku: z.ZodString;
|
|
1659
|
+
slug: z.ZodString;
|
|
1660
|
+
name: z.ZodString;
|
|
1661
|
+
primaryAssetUrl: z.ZodNullable<z.ZodString>;
|
|
1662
|
+
price: z.ZodNullable<z.ZodObject<{
|
|
1663
|
+
amount: z.ZodNumber;
|
|
1664
|
+
currency: z.ZodString;
|
|
1665
|
+
}, z.core.$strip>>;
|
|
1666
|
+
}, z.core.$strip>;
|
|
1667
|
+
}, z.core.$strip>;
|
|
1668
|
+
export type ProductLinkSummary = z.infer<typeof productLinkSummarySchema>;
|
|
1669
|
+
/**
|
|
1670
|
+
* A product as it crosses a module boundary — a plain shape, never the ORM
|
|
1671
|
+
* entity (FR-011). Twenty modules read this row; between them they touch
|
|
1672
|
+
* nearly every column, which is why the record mirrors the table rather than
|
|
1673
|
+
* narrowing it. What it is not is the *class*: a consumer cannot call a method
|
|
1674
|
+
* on it, cannot persist it, and cannot pull a relation off it.
|
|
1675
|
+
*/
|
|
1676
|
+
export interface CatalogProductRecord {
|
|
1677
|
+
id: string;
|
|
1678
|
+
sku: string;
|
|
1679
|
+
slug: string;
|
|
1680
|
+
type: ProductType;
|
|
1681
|
+
status: ProductStatus;
|
|
1682
|
+
/** Per-locale JSONB. Resolve with the caller's language chain. */
|
|
1683
|
+
name: Record<string, string>;
|
|
1684
|
+
description: Record<string, string>;
|
|
1685
|
+
/** Per-product override of the global stock mode; `null` ⇒ inherit. */
|
|
1686
|
+
stockMode: StockMode | null;
|
|
1687
|
+
visibility: ProductVisibility;
|
|
1688
|
+
/** JSONB `{ attributeKey: value }`, validated against the attribute set. */
|
|
1689
|
+
attributeValues: Record<string, unknown>;
|
|
1690
|
+
allowedOrganizationIds: string[];
|
|
1691
|
+
attributeSetId: string;
|
|
1692
|
+
downloadAssetId: string | null;
|
|
1693
|
+
downloadUrl: string | null;
|
|
1694
|
+
createdAt: Date;
|
|
1695
|
+
updatedAt: Date;
|
|
1696
|
+
archivedAt: Date | null;
|
|
1697
|
+
deletedAt: Date | null;
|
|
1698
|
+
manageStock: boolean;
|
|
1699
|
+
backorderEnabled: boolean;
|
|
1700
|
+
lowStockThreshold: number | null;
|
|
1701
|
+
lowStockThresholdMode: 'cumulative' | 'per_warehouse';
|
|
1702
|
+
fulfilmentStrategy: FulfilmentStrategy | null;
|
|
1703
|
+
fulfilmentStrategyWarehouseOrder: string[] | null;
|
|
1704
|
+
}
|
|
1705
|
+
/**
|
|
1706
|
+
* Who is asking for a product — the single input every enforcing read path
|
|
1707
|
+
* needs beyond the row itself (issue #227).
|
|
1708
|
+
*
|
|
1709
|
+
* Two fields rather than one, because `organizationId === null` conflates two
|
|
1710
|
+
* callers that the `logged_in_only` visibility distinguishes: an anonymous
|
|
1711
|
+
* crawler, and a signed-in buyer whose account carries no Organization (the
|
|
1712
|
+
* guest-style Customer of feature 026). The first must not see a
|
|
1713
|
+
* `logged_in_only` row; the second must.
|
|
1714
|
+
*
|
|
1715
|
+
* An `organizationId` is never asserted by the caller: it comes off the
|
|
1716
|
+
* resolved actor — the customer session's Organization, or a bound API key's.
|
|
1717
|
+
*/
|
|
1718
|
+
export interface ProductAudience {
|
|
1719
|
+
/**
|
|
1720
|
+
* The asking buyer's Organization, or `null` when the caller has none.
|
|
1721
|
+
* Matched against `allowed_organization_ids` by membership, never by
|
|
1722
|
+
* prefix or by comparing the array to anything.
|
|
1723
|
+
*/
|
|
1724
|
+
readonly organizationId: string | null;
|
|
1725
|
+
/** `true` for any caller the platform has identified; `false` for the public. */
|
|
1726
|
+
readonly authenticated: boolean;
|
|
1727
|
+
}
|
|
1728
|
+
/**
|
|
1729
|
+
* The most restrictive audience there is. Anything it may see, every other
|
|
1730
|
+
* audience may see too — which is what makes it the right default for a path
|
|
1731
|
+
* that has not yet been taught to resolve its caller, and the right constant
|
|
1732
|
+
* for a test that means "the public".
|
|
1733
|
+
*/
|
|
1734
|
+
export declare const ANONYMOUS_PRODUCT_AUDIENCE: ProductAudience;
|
|
1735
|
+
/**
|
|
1736
|
+
* Does this audience get to see this product?
|
|
1737
|
+
*
|
|
1738
|
+
* **This is the platform's one answer.** `Product.visibility` and
|
|
1739
|
+
* `Product.allowedOrganizationIds` have been persisted, defaulted and
|
|
1740
|
+
* operator-editable since the foundation migration, and until issue #227 a
|
|
1741
|
+
* single read path out of two dozen enforced them — `catalog`'s quick-search,
|
|
1742
|
+
* repaired for issue #174 after a buyer's type-ahead disclosed products
|
|
1743
|
+
* restricted to other organisations. Every other surface answered the question
|
|
1744
|
+
* its own way or not at all, so the repair starts by making the question have
|
|
1745
|
+
* one answer that a listing, a PDP, a search hit, a cart line, a comparison and
|
|
1746
|
+
* a feed row can all reach.
|
|
1747
|
+
*
|
|
1748
|
+
* It lives in `@endora-commerce/contracts` rather than in `catalog` because the record it
|
|
1749
|
+
* reads is already published here: twenty modules hold a
|
|
1750
|
+
* {@link CatalogProductRecord}, both columns are on it, and a predicate over a
|
|
1751
|
+
* published shape needs no port, no manifest edge and no `catalog` on the other
|
|
1752
|
+
* end of a call. A module that holds the row can enforce; a module that cannot
|
|
1753
|
+
* hold the row has nothing to enforce over.
|
|
1754
|
+
*
|
|
1755
|
+
* The rule, in the order it is decided:
|
|
1756
|
+
*
|
|
1757
|
+
* 1. **A non-empty `allowedOrganizationIds` decides alone**, and it restricts
|
|
1758
|
+
* whatever `visibility` says — `public` included. `public` with an
|
|
1759
|
+
* allow-list naming three organisations is a state an operator can save
|
|
1760
|
+
* today, and reading it as "public wins" discloses exactly the rows the
|
|
1761
|
+
* operator named someone else on.
|
|
1762
|
+
* 2. Otherwise the allow-list is empty and the answer is `visibility`'s alone:
|
|
1763
|
+
* `public` to everybody; `logged_in_only` to any authenticated caller;
|
|
1764
|
+
* `organization_restricted` **to nobody**. That last one is the reading
|
|
1765
|
+
* that surprises: the restriction was asked for and names no organisation,
|
|
1766
|
+
* so the permissive reading of it would disclose the row to the whole
|
|
1767
|
+
* world.
|
|
1768
|
+
*
|
|
1769
|
+
* ## The two SQL restatements of this rule, and how they differ
|
|
1770
|
+
*
|
|
1771
|
+
* A predicate over a record cannot be pushed into a query, and two read paths
|
|
1772
|
+
* must filter in SQL rather than after it. So `catalog` states this rule twice
|
|
1773
|
+
* more, in SQL, and the two statements are **not** copies of each other — they
|
|
1774
|
+
* answer for different audiences and are meant to differ (issue #262):
|
|
1775
|
+
*
|
|
1776
|
+
* - **`catalog-quick-search.service.ts`** answers for a **signed-in buyer**.
|
|
1777
|
+
* `CatalogQuickSearchParams.organizationId` is required and there is no
|
|
1778
|
+
* anonymous spelling, so the audience is
|
|
1779
|
+
* `{ organizationId, authenticated: true }` by construction. It is the
|
|
1780
|
+
* restatement where `@>` containment over the JSONB array does real work:
|
|
1781
|
+
* the buyer's id has to be an *element* of the allow-list rather than a
|
|
1782
|
+
* substring of the serialised bag. It is SQL because the statement carries
|
|
1783
|
+
* a `limit`, and a post-filter would hand a buyer a short page — or an
|
|
1784
|
+
* empty one — while visible rows waited behind the restricted ones.
|
|
1785
|
+
* - **`catalog-product-filter.service.ts`'s `sellableFloor`** answers for
|
|
1786
|
+
* {@link ANONYMOUS_PRODUCT_AUDIENCE}, because the port's only consumer is a
|
|
1787
|
+
* product feed and a feed is read by Google. With no organisation to
|
|
1788
|
+
* contain, the containment branch can never match, so that restatement
|
|
1789
|
+
* collapses to two equalities — `visibility = 'public'` and an empty
|
|
1790
|
+
* allow-list. It is SQL because `countSellable` is the number an operator
|
|
1791
|
+
* is shown before saving and `listSellable` is what the next run emits, and
|
|
1792
|
+
* the two must be one query's answer.
|
|
1793
|
+
*
|
|
1794
|
+
* Neither is licensed to drift toward the other: the containment clause would
|
|
1795
|
+
* be dead weight in the feed floor, and the two equalities would hide from a
|
|
1796
|
+
* buyer every row his own organisation is named on. What keeps both honest is
|
|
1797
|
+
* that each has a parity test which **derives** its expectation from this
|
|
1798
|
+
* function over `productVisibilitySchema.options`, so a fourth visibility value
|
|
1799
|
+
* forces every side to be decided rather than letting one keep an accidental
|
|
1800
|
+
* default — this predicate falls through to `return true`, both SQL sites fail
|
|
1801
|
+
* closed:
|
|
1802
|
+
*
|
|
1803
|
+
* - `backend/test/integration/catalog/quick-search-audience-parity.test.ts`
|
|
1804
|
+
* — visibility × (empty, own org, another org, several including own,
|
|
1805
|
+
* a near-miss string) × three viewers;
|
|
1806
|
+
* - `backend/test/integration/catalog/product-filter-port.test.ts`
|
|
1807
|
+
* — visibility × (empty, non-empty) for the anonymous audience, on
|
|
1808
|
+
* `listSellable` and `countSellable` alike.
|
|
1809
|
+
*
|
|
1810
|
+
* `backend/test/unit/catalog/product-visibility-predicate.test.ts` is the truth
|
|
1811
|
+
* table all three are read against.
|
|
1812
|
+
*
|
|
1813
|
+
* Unifying the three into one shared SQL fragment was considered and refused:
|
|
1814
|
+
* the builder would have to live here, and a fragment knows table and column
|
|
1815
|
+
* names — the persistence shape. This package knows API shapes and depends on
|
|
1816
|
+
* `zod` alone (FR-034). Keeping that line is worth more than removing the
|
|
1817
|
+
* duplication, so the duplication is kept and pinned instead.
|
|
1818
|
+
*
|
|
1819
|
+
* What this predicate is **not** is the channel answer. Channel scoping is
|
|
1820
|
+
* Principle XII's, travels through `sales_channel_products` and the sanctioned
|
|
1821
|
+
* bridge accessors, and is a second filter every buyer-facing path owes on top
|
|
1822
|
+
* of this one.
|
|
1823
|
+
*
|
|
1824
|
+
* That second filter has two spellings and neither is here, by an owner ruling
|
|
1825
|
+
* of 2026-08-21 (issue #259): the channel is a property of the **request**, not
|
|
1826
|
+
* of the viewer's relationship to the product, so folding it in would merge two
|
|
1827
|
+
* questions and make this predicate asynchronous. The **view** side spells it
|
|
1828
|
+
* as `CatalogQueryService.filterByChannel`; the **acquisition** side — cart
|
|
1829
|
+
* add, comparison add, a quote line, a saved list, a pasted quick-order SKU —
|
|
1830
|
+
* spells it as `productIdsInRequestChannel` in
|
|
1831
|
+
* `backend/src/kernel/sales-channels/request-channel-assortment.ts`. Every one
|
|
1832
|
+
* of those refuses out-of-assortment with the *same* answer it gives a
|
|
1833
|
+
* restricted row and an absent one, so the pair cannot be used to enumerate an
|
|
1834
|
+
* operator's private assortment.
|
|
1835
|
+
*
|
|
1836
|
+
* **Two re-acquisition paths are exempt, by the same ruling**: `orders`'
|
|
1837
|
+
* reorder and `quote_requests`' `convertToOrder`. Neither names a product the
|
|
1838
|
+
* caller supplied — each rebuilds a cart from lines the buyer already holds a
|
|
1839
|
+
* commitment on, a placed order or a quote the seller approved at agreed
|
|
1840
|
+
* prices — and refusing would strand a buyer holding an approved quote they
|
|
1841
|
+
* cannot act on. Read that as decided, not as the two seams that were missed;
|
|
1842
|
+
* each carries the reason at its own call site, including the second-order
|
|
1843
|
+
* consequence that makes the obvious repair of the first one wrong. Two
|
|
1844
|
+
* operator surfaces are exempt on the operator's-permission ground instead:
|
|
1845
|
+
* `RfqAdminService.createOnBehalf` and `quick_order`'s `'unrestricted'` import
|
|
1846
|
+
* arm, both of which say so where they stand.
|
|
1847
|
+
*/
|
|
1848
|
+
export declare function isProductVisibleTo(product: Pick<CatalogProductRecord, 'visibility' | 'allowedOrganizationIds'>, audience: ProductAudience): boolean;
|
|
1849
|
+
/** A category row, as the eight modules that read one see it. */
|
|
1850
|
+
export interface CatalogCategoryRecord {
|
|
1851
|
+
id: string;
|
|
1852
|
+
parentCategoryId: string | null;
|
|
1853
|
+
name: Record<string, string>;
|
|
1854
|
+
slug: string;
|
|
1855
|
+
sortOrder: number;
|
|
1856
|
+
metaTitleOverride: Record<string, string> | null;
|
|
1857
|
+
metaDescriptionOverride: Record<string, string> | null;
|
|
1858
|
+
customFieldValues: Record<string, unknown>;
|
|
1859
|
+
isActive: boolean;
|
|
1860
|
+
inventoryThresholdHigh: number | null;
|
|
1861
|
+
inventoryThresholdMedium: number | null;
|
|
1862
|
+
inventoryThresholdLow: number | null;
|
|
1863
|
+
mainImageAssetId: string | null;
|
|
1864
|
+
createdAt: Date;
|
|
1865
|
+
updatedAt: Date;
|
|
1866
|
+
deletedAt: Date | null;
|
|
1867
|
+
}
|
|
1868
|
+
/**
|
|
1869
|
+
* One `product ↔ category` assignment, with the category's slug alongside.
|
|
1870
|
+
*
|
|
1871
|
+
* The slug rides on the row because every caller that reads assignments in
|
|
1872
|
+
* bulk is building a projection keyed by product — a search document, a feed
|
|
1873
|
+
* line — and would otherwise follow every assignment with a category lookup.
|
|
1874
|
+
*/
|
|
1875
|
+
export interface CatalogCategoryAssignmentRecord {
|
|
1876
|
+
productId: string;
|
|
1877
|
+
categoryId: string;
|
|
1878
|
+
slug: string;
|
|
1879
|
+
}
|
|
1880
|
+
/** A configurable product's variant row. */
|
|
1881
|
+
export interface CatalogProductVariantRecord {
|
|
1882
|
+
id: string;
|
|
1883
|
+
parentProductId: string;
|
|
1884
|
+
sku: string;
|
|
1885
|
+
variantAttributeValues: Record<string, unknown>;
|
|
1886
|
+
/** Decimal string, or `null` when the variant inherits the parent's price. */
|
|
1887
|
+
priceOverride: string | null;
|
|
1888
|
+
stockLevel: number | null;
|
|
1889
|
+
createdAt: Date;
|
|
1890
|
+
updatedAt: Date;
|
|
1891
|
+
}
|
|
1892
|
+
/** A packaging unit — "box of 12" — a cart line may be placed in. */
|
|
1893
|
+
export interface CatalogPackagingUnitRecord {
|
|
1894
|
+
id: string;
|
|
1895
|
+
productId: string;
|
|
1896
|
+
name: string;
|
|
1897
|
+
baseQuantity: number;
|
|
1898
|
+
position: number;
|
|
1899
|
+
isDefault: boolean;
|
|
1900
|
+
createdAt: Date;
|
|
1901
|
+
updatedAt: Date;
|
|
1902
|
+
}
|
|
1903
|
+
/** A directed product↔product relation (cross-sell, up-sell, related). */
|
|
1904
|
+
export interface CatalogProductLinkRow {
|
|
1905
|
+
id: string;
|
|
1906
|
+
sourceProductId: string;
|
|
1907
|
+
targetProductId: string;
|
|
1908
|
+
kind: ProductLinkKind;
|
|
1909
|
+
position: number;
|
|
1910
|
+
}
|
|
1911
|
+
/** A per-channel / per-language override of one attribute value (feature 022). */
|
|
1912
|
+
export interface CatalogProductValueOverrideRecord {
|
|
1913
|
+
id: string;
|
|
1914
|
+
productId: string;
|
|
1915
|
+
attributeKey: string;
|
|
1916
|
+
channelId: string;
|
|
1917
|
+
languageCode: string | null;
|
|
1918
|
+
/** The stored value, wrapped so `null` and "absent" stay distinguishable. */
|
|
1919
|
+
value: {
|
|
1920
|
+
v: unknown;
|
|
1921
|
+
};
|
|
1922
|
+
}
|
|
1923
|
+
/**
|
|
1924
|
+
* Which products a lookup should consider.
|
|
1925
|
+
*
|
|
1926
|
+
* `liveOnly` excludes soft-deleted rows and `activeOnly` narrows further to
|
|
1927
|
+
* `status === 'active'`. Both default to `false`, which is the wider read —
|
|
1928
|
+
* and the correct default, because an inactive or soft-deleted product still
|
|
1929
|
+
* has to resolve from a historical order, invoice, RFQ or shopping list.
|
|
1930
|
+
*/
|
|
1931
|
+
export interface CatalogProductLookupOptions {
|
|
1932
|
+
liveOnly?: boolean;
|
|
1933
|
+
activeOnly?: boolean;
|
|
1934
|
+
}
|
|
1935
|
+
/**
|
|
1936
|
+
* Container name: `catalogProductReadPort`. Owner: `catalog`.
|
|
1937
|
+
*
|
|
1938
|
+
* Forty-six of `catalog`'s inbound sites are a read of the `Product` entity,
|
|
1939
|
+
* and they reduce to four questions: by id, by ids, by sku, by skus. The rest
|
|
1940
|
+
* of this port is the three neighbouring tables the same callers reach for in
|
|
1941
|
+
* the same breath — variants, packaging units and links — plus the value
|
|
1942
|
+
* overrides the search indexer reads.
|
|
1943
|
+
*
|
|
1944
|
+
* When `catalog` is off every method fails closed, and that is the answer a
|
|
1945
|
+
* cart or an order line should get: pricing a line for a product the platform
|
|
1946
|
+
* will not read is worse than refusing the line.
|
|
1947
|
+
*
|
|
1948
|
+
* Whether `catalog` has an off state at all is its manifest's `activation` to
|
|
1949
|
+
* say, not this line's: a module declaring `nonDeactivatable` never enters one.
|
|
1950
|
+
*/
|
|
1951
|
+
export interface CatalogProductReadPort {
|
|
1952
|
+
findById(id: string, options?: CatalogProductLookupOptions): Promise<CatalogProductRecord | null>;
|
|
1953
|
+
findByIds(ids: readonly string[], options?: CatalogProductLookupOptions): Promise<CatalogProductRecord[]>;
|
|
1954
|
+
findBySku(sku: string, options?: CatalogProductLookupOptions): Promise<CatalogProductRecord | null>;
|
|
1955
|
+
findBySkus(skus: readonly string[], options?: CatalogProductLookupOptions): Promise<CatalogProductRecord[]>;
|
|
1956
|
+
/** `count === ids.length` existence check, without loading the rows. */
|
|
1957
|
+
countByIds(ids: readonly string[]): Promise<number>;
|
|
1958
|
+
/** Every product, ordered by sku — the bulk export and the price-list backfill. */
|
|
1959
|
+
listAll(options?: CatalogProductLookupOptions): Promise<CatalogProductRecord[]>;
|
|
1960
|
+
/** Variants of the given parent products, ordered by sku. */
|
|
1961
|
+
listVariantsByProductIds(productIds: readonly string[]): Promise<CatalogProductVariantRecord[]>;
|
|
1962
|
+
findVariantsBySkus(skus: readonly string[]): Promise<CatalogProductVariantRecord[]>;
|
|
1963
|
+
/** A variant, but only if it belongs to that parent. */
|
|
1964
|
+
findVariantInProduct(parentProductId: string, variantId: string): Promise<CatalogProductVariantRecord | null>;
|
|
1965
|
+
/** A packaging unit, but only if it belongs to that product. */
|
|
1966
|
+
findPackagingUnitInProduct(productId: string, packagingUnitId: string): Promise<CatalogPackagingUnitRecord | null>;
|
|
1967
|
+
/** Links out of the given products, optionally narrowed to one kind. */
|
|
1968
|
+
listLinksBySourceIds(sourceProductIds: readonly string[], kind?: ProductLinkKind): Promise<CatalogProductLinkRow[]>;
|
|
1969
|
+
/** Attribute-value overrides for the given products. */
|
|
1970
|
+
listValueOverridesByProductIds(productIds: readonly string[]): Promise<CatalogProductValueOverrideRecord[]>;
|
|
1971
|
+
}
|
|
1972
|
+
/**
|
|
1973
|
+
* Container name: `catalogCategoryReadPort`. Owner: `catalog`.
|
|
1974
|
+
*
|
|
1975
|
+
* Fourteen inbound sites read the `Category` entity: the inventory threshold
|
|
1976
|
+
* resolver walks it, `price_lists` walks the ancestor chain to resolve a
|
|
1977
|
+
* category rule, `product_feeds` maps the whole tree onto an external
|
|
1978
|
+
* taxonomy, `seo` renders a category page's meta tags.
|
|
1979
|
+
*
|
|
1980
|
+
* `ancestorsOf` is here rather than in `price_lists` because that module walks
|
|
1981
|
+
* the chain with a `findOne` per level today — a loop over the parent pointer
|
|
1982
|
+
* whose depth is data, in a module that does not own the table.
|
|
1983
|
+
*
|
|
1984
|
+
* **Owner off:** the seam fails closed — resolving this port throws
|
|
1985
|
+
* `ModuleDisabledError` and the call answers 503 `MODULE_DISABLED`, so nothing
|
|
1986
|
+
* half-executes. Whether `catalog` has an off state at all is its manifest's
|
|
1987
|
+
* `activation` to say, not this line's: a module declaring
|
|
1988
|
+
* `nonDeactivatable` never enters one.
|
|
1989
|
+
*/
|
|
1990
|
+
export interface CatalogCategoryReadPort {
|
|
1991
|
+
findById(id: string, options?: {
|
|
1992
|
+
liveOnly?: boolean;
|
|
1993
|
+
}): Promise<CatalogCategoryRecord | null>;
|
|
1994
|
+
findByIds(ids: readonly string[], options?: {
|
|
1995
|
+
liveOnly?: boolean;
|
|
1996
|
+
}): Promise<CatalogCategoryRecord[]>;
|
|
1997
|
+
findBySlug(slug: string): Promise<CatalogCategoryRecord | null>;
|
|
1998
|
+
/** `count === ids.length` existence check. */
|
|
1999
|
+
countByIds(ids: readonly string[]): Promise<number>;
|
|
2000
|
+
/** The whole tree, ordered by sort order then slug. */
|
|
2001
|
+
listAll(options?: {
|
|
2002
|
+
liveOnly?: boolean;
|
|
2003
|
+
}): Promise<CatalogCategoryRecord[]>;
|
|
2004
|
+
/** Categories carrying at least one inventory threshold override. */
|
|
2005
|
+
listWithInventoryThresholds(): Promise<CatalogCategoryRecord[]>;
|
|
2006
|
+
/**
|
|
2007
|
+
* The category and its ancestors, nearest-first. Empty when the id does not
|
|
2008
|
+
* resolve. A cycle is impossible — the write path enforces it — but the walk
|
|
2009
|
+
* is bounded anyway, because a corrupt `parent_id` should not hang a request.
|
|
2010
|
+
*/
|
|
2011
|
+
ancestorsOf(categoryId: string): Promise<CatalogCategoryRecord[]>;
|
|
2012
|
+
/**
|
|
2013
|
+
* The category assignments of the given products (feature 075 / D-87).
|
|
2014
|
+
*
|
|
2015
|
+
* `product_categories` is a `catalog` table with no entity class, so the two
|
|
2016
|
+
* modules that needed it joined it in raw SQL — a boundary crossing that
|
|
2017
|
+
* names no import specifier and therefore compiled, gated by nothing.
|
|
2018
|
+
*
|
|
2019
|
+
* `activeOnly` drops assignments to a deactivated category. That is the
|
|
2020
|
+
* narrowing a customer-facing projection wants and the reason the option
|
|
2021
|
+
* exists rather than a hidden filter: an inactive category left in a search
|
|
2022
|
+
* document keeps working as a storefront PLP filter.
|
|
2023
|
+
*/
|
|
2024
|
+
listAssignmentsForProducts(productIds: readonly string[], options?: {
|
|
2025
|
+
activeOnly?: boolean;
|
|
2026
|
+
}): Promise<CatalogCategoryAssignmentRecord[]>;
|
|
2027
|
+
/**
|
|
2028
|
+
* Distinct ids of the products assigned to `categoryId` or to any category
|
|
2029
|
+
* below it.
|
|
2030
|
+
*
|
|
2031
|
+
* The walk is **structural**: it filters neither `isActive` nor `deletedAt`.
|
|
2032
|
+
* The caller is re-projecting a subtree because a category just changed, and
|
|
2033
|
+
* the change that matters most is a deactivation — narrowing to live rows
|
|
2034
|
+
* would return nothing exactly when the stale projections need rewriting.
|
|
2035
|
+
* A caller that wants the live set narrows the rows it gets back.
|
|
2036
|
+
*/
|
|
2037
|
+
listProductIdsInSubtree(categoryId: string): Promise<string[]>;
|
|
2038
|
+
/**
|
|
2039
|
+
* Ids of the products assigned to `categoryId` itself — not to anything below
|
|
2040
|
+
* it (feature 075 / D-87).
|
|
2041
|
+
*
|
|
2042
|
+
* The narrow sibling of {@link listProductIdsInSubtree}, and the two are not
|
|
2043
|
+
* interchangeable: a caller detaching products because one category left the
|
|
2044
|
+
* source tree must touch that category's own assignments and no descendant's,
|
|
2045
|
+
* because a descendant that is still mapped keeps its products.
|
|
2046
|
+
*
|
|
2047
|
+
* **Structural**, like the subtree walk: it filters neither `isActive` nor
|
|
2048
|
+
* `deletedAt`. The assignment is the fact being asked about, and a caller
|
|
2049
|
+
* removing one wants it gone whatever state the product is in.
|
|
2050
|
+
*/
|
|
2051
|
+
listProductIdsInCategory(categoryId: string): Promise<string[]>;
|
|
2052
|
+
/**
|
|
2053
|
+
* Product ids assigned to each requested category **or to any live category
|
|
2054
|
+
* below it**, keyed by the requested id. Every id asked for is present, with
|
|
2055
|
+
* an empty set when nothing matches — so a criterion naming a deleted
|
|
2056
|
+
* category narrows to nothing rather than silently disappearing.
|
|
2057
|
+
*
|
|
2058
|
+
* **Not a batched {@link listProductIdsInSubtree}, and the two are not
|
|
2059
|
+
* interchangeable.** That one is structural, for a caller re-projecting
|
|
2060
|
+
* because a category changed. This one is a *selection*: the descendant walk
|
|
2061
|
+
* skips soft-deleted categories, because a rule that says "everything under
|
|
2062
|
+
* Footwear" must not keep publishing the products of a branch an operator
|
|
2063
|
+
* deleted. It is also **cycle-tolerant** — the walk carries a visited set per
|
|
2064
|
+
* root — where the structural read is a recursive CTE with no guard. The
|
|
2065
|
+
* write path forbids a cycle in `parent_category_id`; its guard is written to
|
|
2066
|
+
* tolerate a *pre-existing* one, so corrupt data is reachable here, and a
|
|
2067
|
+
* caller that assembled this from the structural read would hang.
|
|
2068
|
+
*
|
|
2069
|
+
* No channel scoping: the caller applies its own eligibility floor, which for
|
|
2070
|
+
* a feed is stricter than the storefront's.
|
|
2071
|
+
*
|
|
2072
|
+
* `product_feeds`' criteria compiler is the requirement (FR-025) — it must
|
|
2073
|
+
* evaluate category membership including descendants without learning the
|
|
2074
|
+
* shape of `product_categories` or of the tree. It reached this through a
|
|
2075
|
+
* composition root's closure over an unpublished container name until
|
|
2076
|
+
* `specs/110-instance-repository/` T118c.
|
|
2077
|
+
*/
|
|
2078
|
+
expandCategoryProductIds(categoryIds: readonly string[]): Promise<Map<string, Set<string>>>;
|
|
2079
|
+
/**
|
|
2080
|
+
* How many **live** products sit in each of `categoryIds` — one grouped read,
|
|
2081
|
+
* not a count per id (feature 075 / D-87).
|
|
2082
|
+
*
|
|
2083
|
+
* Live means not soft-deleted: a deleted product is not in the category any
|
|
2084
|
+
* more in any sense an operator means, which is the filter the caller this
|
|
2085
|
+
* replaced had written into its own join. Categories with no live product are
|
|
2086
|
+
* omitted rather than returned as zero, so the caller decides what an absent
|
|
2087
|
+
* count renders as.
|
|
2088
|
+
*/
|
|
2089
|
+
countLiveProductsByCategory(categoryIds: readonly string[]): Promise<CatalogCategoryProductCount[]>;
|
|
2090
|
+
}
|
|
2091
|
+
/** One category's live product count — see `countLiveProductsByCategory`. */
|
|
2092
|
+
export interface CatalogCategoryProductCount {
|
|
2093
|
+
categoryId: string;
|
|
2094
|
+
productCount: number;
|
|
2095
|
+
}
|
|
2096
|
+
/**
|
|
2097
|
+
* One row of a categories import.
|
|
2098
|
+
*
|
|
2099
|
+
* Absent fields are left unchanged on an existing row; `parentSlug: null` means
|
|
2100
|
+
* root. `slug` addresses the row: a slug that exists is updated, one that does
|
|
2101
|
+
* not is created, and a slug introduced earlier in the same call resolves as a
|
|
2102
|
+
* parent for a later one.
|
|
2103
|
+
*/
|
|
2104
|
+
export interface CategoryImportRow {
|
|
2105
|
+
slug: string;
|
|
2106
|
+
parentSlug?: string | null;
|
|
2107
|
+
sortOrder?: number;
|
|
2108
|
+
/** Per-locale, merged into the stored JSONB rather than replacing it. */
|
|
2109
|
+
name?: Record<string, string>;
|
|
2110
|
+
isActive?: boolean;
|
|
2111
|
+
}
|
|
2112
|
+
/**
|
|
2113
|
+
* One row of a products import.
|
|
2114
|
+
*
|
|
2115
|
+
* `sku` addresses an existing product; the import creates none, because a
|
|
2116
|
+
* product needs an attribute set, a type and a slug that a flat sheet does not
|
|
2117
|
+
* carry.
|
|
2118
|
+
*/
|
|
2119
|
+
export interface ProductImportRow {
|
|
2120
|
+
sku: string;
|
|
2121
|
+
status?: ProductStatus;
|
|
2122
|
+
visibility?: ProductVisibility;
|
|
2123
|
+
/** Per-locale, merged into the stored JSONB rather than replacing it. */
|
|
2124
|
+
name?: Record<string, string>;
|
|
2125
|
+
description?: Record<string, string>;
|
|
2126
|
+
}
|
|
2127
|
+
/**
|
|
2128
|
+
* Container name: `catalogBulkImportPort`. Owner: `catalog`.
|
|
2129
|
+
*
|
|
2130
|
+
* All-or-nothing per call: one transaction, one audit row, no partial commits.
|
|
2131
|
+
* A rejected row leaves the whole call applying nothing, which is what makes a
|
|
2132
|
+
* corrected re-upload safe — see {@link BulkImportReport}.
|
|
2133
|
+
*
|
|
2134
|
+
* With `catalog` off the call answers 503 `MODULE_DISABLED`; the caller is
|
|
2135
|
+
* expected to decide presence before offering the surface at all.
|
|
2136
|
+
*
|
|
2137
|
+
* Whether `catalog` has an off state at all is its manifest's `activation` to
|
|
2138
|
+
* say, not this line's: a module declaring `nonDeactivatable` never enters one.
|
|
2139
|
+
*/
|
|
2140
|
+
export interface CatalogBulkImportPort {
|
|
2141
|
+
importCategories(rows: readonly CategoryImportRow[]): Promise<BulkImportReport>;
|
|
2142
|
+
importProducts(rows: readonly ProductImportRow[]): Promise<BulkImportReport>;
|
|
2143
|
+
}
|
|
2144
|
+
export interface CatalogAttributeOptionView {
|
|
2145
|
+
/** `custom_field_options` id. */
|
|
2146
|
+
id: string;
|
|
2147
|
+
value: string;
|
|
2148
|
+
label: Record<string, string>;
|
|
2149
|
+
labelDefault: string;
|
|
2150
|
+
isDefault: boolean;
|
|
2151
|
+
sortOrder: number;
|
|
2152
|
+
createdAt: Date;
|
|
2153
|
+
updatedAt: Date;
|
|
2154
|
+
}
|
|
2155
|
+
/**
|
|
2156
|
+
* The composed attribute view (feature 061,
|
|
2157
|
+
* `contracts/catalog-attribute-view.md`): the `custom_fields` definition and
|
|
2158
|
+
* the `product_attributes` extension row, joined, shaped like the pre-061
|
|
2159
|
+
* `ProductAttribute` so consumer rewires stay mechanical.
|
|
2160
|
+
*/
|
|
2161
|
+
export interface CatalogAttributeView {
|
|
2162
|
+
/** Extension row id — the id the admin API has always exposed. */
|
|
2163
|
+
id: string;
|
|
2164
|
+
/** Backing `custom_field_definitions` id (host `product`). */
|
|
2165
|
+
customFieldDefinitionId: string;
|
|
2166
|
+
key: string;
|
|
2167
|
+
label: Record<string, string>;
|
|
2168
|
+
labelDefault: string;
|
|
2169
|
+
/** Legacy 8-value form, derived bijectively (feature 061 research §R7). */
|
|
2170
|
+
valueType: AttributeValueType;
|
|
2171
|
+
isRequired: boolean;
|
|
2172
|
+
options: CatalogAttributeOptionView[];
|
|
2173
|
+
isSearchable: boolean;
|
|
2174
|
+
isFilterable: boolean;
|
|
2175
|
+
isVariantAxis: boolean;
|
|
2176
|
+
displayAsSlider: boolean;
|
|
2177
|
+
isComparable: boolean;
|
|
2178
|
+
quickSearchable: boolean;
|
|
2179
|
+
isPromoRule: boolean;
|
|
2180
|
+
filterPosition: number;
|
|
2181
|
+
isVisibleOnProductPage: boolean;
|
|
2182
|
+
channelScoped: boolean;
|
|
2183
|
+
languageScoped: boolean;
|
|
2184
|
+
massEditable: boolean;
|
|
2185
|
+
createdAt: Date;
|
|
2186
|
+
updatedAt: Date;
|
|
2187
|
+
}
|
|
2188
|
+
export type CatalogAttributeFlag = 'isSearchable' | 'isFilterable' | 'isVariantAxis' | 'isComparable' | 'quickSearchable' | 'isPromoRule' | 'massEditable' | 'isVisibleOnProductPage';
|
|
2189
|
+
/**
|
|
2190
|
+
* Container name: `catalogAttributeReadPort`. Owner: `catalog`.
|
|
2191
|
+
*
|
|
2192
|
+
* The **only** sanctioned way any module — including `catalog`'s own route
|
|
2193
|
+
* serializers — reads product-attribute definitions (Principle I). `search`,
|
|
2194
|
+
* `comparisons`, `quick_order` and `pim_ergonode` all read it today by
|
|
2195
|
+
* importing the class.
|
|
2196
|
+
*
|
|
2197
|
+
* Freshness: the definitions half rides the custom-fields cache (invalidated
|
|
2198
|
+
* by every committed attribute Command, 5 s TTL fallback); the extension half
|
|
2199
|
+
* is a live query, so flag reads are always fresh.
|
|
2200
|
+
*
|
|
2201
|
+
* **Owner off:** the seam fails closed — resolving this port throws
|
|
2202
|
+
* `ModuleDisabledError` and the call answers 503 `MODULE_DISABLED`, so nothing
|
|
2203
|
+
* half-executes. Whether `catalog` has an off state at all is its manifest's
|
|
2204
|
+
* `activation` to say, not this line's: a module declaring
|
|
2205
|
+
* `nonDeactivatable` never enters one.
|
|
2206
|
+
*/
|
|
2207
|
+
export interface CatalogAttributeReadPort {
|
|
2208
|
+
listAll(): Promise<CatalogAttributeView[]>;
|
|
2209
|
+
getByIdOrKey(idOrKey: string): Promise<CatalogAttributeView | null>;
|
|
2210
|
+
listByFlag(flag: CatalogAttributeFlag): Promise<CatalogAttributeView[]>;
|
|
2211
|
+
/** `attributeKey → optionValue → labels`, for label resolution on read. */
|
|
2212
|
+
optionLabelIndex(): Promise<Map<string, Map<string, CatalogAttributeOptionLabels>>>;
|
|
2213
|
+
}
|
|
2214
|
+
/** The two label forms an option carries: per-locale, and the fallback. */
|
|
2215
|
+
export interface CatalogAttributeOptionLabels {
|
|
2216
|
+
label: Record<string, string>;
|
|
2217
|
+
labelDefault: string;
|
|
2218
|
+
}
|
|
2219
|
+
/** Which of the three quick-search predicates a hit satisfied. */
|
|
2220
|
+
export type CatalogQuickSearchField = 'sku' | 'name' | 'attribute';
|
|
2221
|
+
export interface CatalogQuickSearchParams {
|
|
2222
|
+
/** The raw needle. Matched case-insensitively, as a substring. */
|
|
2223
|
+
q: string;
|
|
2224
|
+
limit: number;
|
|
2225
|
+
/**
|
|
2226
|
+
* The channel the caller resolved for this request. Required, and there is
|
|
2227
|
+
* no "all channels" spelling: a channel is always resolved (feature 053), so
|
|
2228
|
+
* an optional parameter here could only mean "the caller forgot", and the
|
|
2229
|
+
* answer to that must not be the cross-channel catalogue.
|
|
2230
|
+
*/
|
|
2231
|
+
salesChannelId: string;
|
|
2232
|
+
/**
|
|
2233
|
+
* The organisation the buyer is shopping on behalf of. Required, and — like
|
|
2234
|
+
* `salesChannelId` — there is no anonymous spelling: every transacting
|
|
2235
|
+
* customer has an Organization (Constitution XI), and the alternative to
|
|
2236
|
+
* requiring one is a caller that forgets and gets the unrestricted
|
|
2237
|
+
* catalogue. A surface with no signed-in buyer must not call this port.
|
|
2238
|
+
*
|
|
2239
|
+
* See {@link CatalogQuickSearchPort} for what it restricts.
|
|
2240
|
+
*/
|
|
2241
|
+
organizationId: string;
|
|
2242
|
+
}
|
|
2243
|
+
export interface CatalogQuickSearchHit {
|
|
2244
|
+
productId: string;
|
|
2245
|
+
sku: string;
|
|
2246
|
+
slug: string;
|
|
2247
|
+
/** Per-locale JSONB as stored — the caller picks its own language. */
|
|
2248
|
+
name: Record<string, string>;
|
|
2249
|
+
status: ProductStatus;
|
|
2250
|
+
matchedOn: CatalogQuickSearchField[];
|
|
2251
|
+
}
|
|
2252
|
+
/**
|
|
2253
|
+
* Container name: `catalogQuickSearchPort`. Owner: `catalog`.
|
|
2254
|
+
*
|
|
2255
|
+
* The buyer-facing type-ahead behind `quick_order`'s CSV-free entry path
|
|
2256
|
+
* (feature 039 FR-011/FR-013), published here because the predicate is a
|
|
2257
|
+
* catalogue question in every part: which products are active, which are
|
|
2258
|
+
* visible on the channel being shopped, and which attribute values are
|
|
2259
|
+
* searchable at all — the last decided by the `quickSearchable` flag this
|
|
2260
|
+
* module owns, over the `attribute_values` JSONB layout this module owns.
|
|
2261
|
+
*
|
|
2262
|
+
* It exists because `quick_order` was answering it with a hand-written knex
|
|
2263
|
+
* `select` against `products`, which filtered `status = 'active'` and nothing
|
|
2264
|
+
* else (issue #174). No import specifier, so `check:module-boundary` read
|
|
2265
|
+
* clean; and no channel predicate, so a signed-in buyer's type-ahead returned
|
|
2266
|
+
* every active product on the platform whatever channel they were shopping —
|
|
2267
|
+
* Constitution XII, in the one place no static check was looking.
|
|
2268
|
+
*
|
|
2269
|
+
* ## What it restricts, and how strictly
|
|
2270
|
+
*
|
|
2271
|
+
* Channel scoping is the same `sales_channel_products` membership filter this
|
|
2272
|
+
* module's own public listing applies, and it fails closed to the empty set.
|
|
2273
|
+
*
|
|
2274
|
+
* `visibility` and `allowed_organization_ids` are applied too, on the
|
|
2275
|
+
* **restrictive** reading of both columns. A row is disclosed when
|
|
2276
|
+
*
|
|
2277
|
+
* - the buyer's `organizationId` appears in `allowed_organization_ids`; or
|
|
2278
|
+
* - `allowed_organization_ids` is empty **and** `visibility` is not
|
|
2279
|
+
* `organization_restricted`.
|
|
2280
|
+
*
|
|
2281
|
+
* Two consequences are deliberate. A non-empty allow-list restricts **whatever
|
|
2282
|
+
* the `visibility` column says** — `public` with an allow-list naming three
|
|
2283
|
+
* organisations is a state an operator can save today, and reading it as
|
|
2284
|
+
* "public wins" would let a type-ahead disclose exactly the rows the operator
|
|
2285
|
+
* named someone else on. And `organization_restricted` with an **empty**
|
|
2286
|
+
* allow-list is visible to nobody, rather than to everybody.
|
|
2287
|
+
* `logged_in_only` *is* disclosed, because `organizationId` is required: there
|
|
2288
|
+
* is no caller of this port that is not a signed-in buyer.
|
|
2289
|
+
*
|
|
2290
|
+
* A looser reading would differ on precisely those two rows, and only there.
|
|
2291
|
+
*
|
|
2292
|
+
* This is stricter than the rest of the module, and knowingly so. No other read
|
|
2293
|
+
* path in `catalog` enforces either column (the standing platform-wide gap),
|
|
2294
|
+
* but this surface requires a signed-in buyer, discloses SKU, slug and name for
|
|
2295
|
+
* every hit, and hands back an id that `POST /quick-order/build` accepts — so a
|
|
2296
|
+
* restriction an operator set on the product would otherwise be bypassed by
|
|
2297
|
+
* typing three characters. Closing the gap on the remaining surfaces is its own
|
|
2298
|
+
* change; leaving this one open until then is not the safe half of the choice.
|
|
2299
|
+
*
|
|
2300
|
+
* When `catalog` is off the call fails closed: `quick_order` declares `catalog`
|
|
2301
|
+
* in `dependencies`, and a type-ahead that cannot ask the catalogue has nothing
|
|
2302
|
+
* true to answer.
|
|
2303
|
+
*
|
|
2304
|
+
* Whether `catalog` has an off state at all is its manifest's `activation` to
|
|
2305
|
+
* say, not this line's: a module declaring `nonDeactivatable` never enters one.
|
|
2306
|
+
*/
|
|
2307
|
+
export interface CatalogQuickSearchPort {
|
|
2308
|
+
quickSearch(params: CatalogQuickSearchParams): Promise<CatalogQuickSearchHit[]>;
|
|
2309
|
+
}
|
|
2310
|
+
/**
|
|
2311
|
+
* Scope flags for the **system** product attributes — the ones that are not
|
|
2312
|
+
* rows in `product_attributes` and therefore carry no DB-stored scope flags.
|
|
2313
|
+
*
|
|
2314
|
+
* Published as a **constant, not a port** (FR-013): `name` and `description`
|
|
2315
|
+
* are channel- and language-scoped because the product table stores them as
|
|
2316
|
+
* per-locale JSONB, which is a fact about the schema rather than about whether
|
|
2317
|
+
* a module is switched on. `search`'s indexer reads it to decide which
|
|
2318
|
+
* overrides to resolve.
|
|
2319
|
+
*
|
|
2320
|
+
* Adding another system attribute is a one-line change here plus a resolver
|
|
2321
|
+
* consumer. The reserved keys MUST NOT collide with `product_attributes.key`
|
|
2322
|
+
* — enforced at write time by the override-service validator.
|
|
2323
|
+
*/
|
|
2324
|
+
export declare const SYSTEM_ATTRIBUTE_SCOPES: Readonly<Record<string, AttributeScope>>;
|
|
2325
|
+
export type SystemAttributeKey = keyof typeof SYSTEM_ATTRIBUTE_SCOPES;
|
|
2326
|
+
export declare function isSystemAttributeKey(key: string): key is SystemAttributeKey;
|
|
2327
|
+
/**
|
|
2328
|
+
* Resolve the effective scope of an attribute given its key and (for
|
|
2329
|
+
* user-defined attributes) its scope flags. Returns the system-pinned scope
|
|
2330
|
+
* when the key is reserved; falls back to the row's flags otherwise; returns
|
|
2331
|
+
* `{ false, false }` when neither applies (the caller should treat that as
|
|
2332
|
+
* global-only).
|
|
2333
|
+
*/
|
|
2334
|
+
export declare function getAttributeScope(attributeKey: string, productAttributeRow?: {
|
|
2335
|
+
channelScoped: boolean;
|
|
2336
|
+
languageScoped: boolean;
|
|
2337
|
+
} | null): AttributeScope;
|
|
2338
|
+
/** Optional metadata attaching an audit entry to an admin mutation. */
|
|
2339
|
+
export interface CatalogAdminAuditContext {
|
|
2340
|
+
actorAdminUserId: string;
|
|
2341
|
+
impersonatedCustomerAccountId?: string | null;
|
|
2342
|
+
ipAddress?: string | null;
|
|
2343
|
+
userAgent?: string | null;
|
|
2344
|
+
requestId?: string | null;
|
|
2345
|
+
}
|
|
2346
|
+
/**
|
|
2347
|
+
* An attribute option as the write path returns it.
|
|
2348
|
+
*
|
|
2349
|
+
* Distinct from `AttributeOption`, the API DTO above, on one axis: the two
|
|
2350
|
+
* timestamps are `Date`, not an ISO string. That is what an in-process call
|
|
2351
|
+
* hands back, and serialising them here would mean every consumer parsing them
|
|
2352
|
+
* again.
|
|
2353
|
+
*/
|
|
2354
|
+
export interface CatalogAttributeOptionResult {
|
|
2355
|
+
id: string;
|
|
2356
|
+
attributeId: string;
|
|
2357
|
+
value: string;
|
|
2358
|
+
label: Record<string, string>;
|
|
2359
|
+
labelDefault: string;
|
|
2360
|
+
isDefault: boolean;
|
|
2361
|
+
sortOrder: number;
|
|
2362
|
+
createdAt: Date;
|
|
2363
|
+
updatedAt: Date;
|
|
2364
|
+
}
|
|
2365
|
+
/** The eight flags `listAttributesByFlag` accepts — a superset of the read model's. */
|
|
2366
|
+
export type CatalogAdminAttributeFlag = 'isSearchable' | 'isFilterable' | 'isComparable' | 'isVariantAxis' | 'isPromoRule' | 'isVisibleOnProductPage' | 'isRequired' | 'isMassEditable';
|
|
2367
|
+
/**
|
|
2368
|
+
* Container name: `catalogProductWritePort`. Owner: `catalog`.
|
|
2369
|
+
*
|
|
2370
|
+
* `pim_ergonode` is the only consumer, and it is the whole reason this port is
|
|
2371
|
+
* narrow: an import run creates and updates products, attributes and variants,
|
|
2372
|
+
* and touches nothing else on `CatalogAdminService`'s considerable surface.
|
|
2373
|
+
*
|
|
2374
|
+
* `createProduct` and the two variant writes return **records**, where the
|
|
2375
|
+
* service returns entities. That substitution is the point of the port.
|
|
2376
|
+
*
|
|
2377
|
+
* **Owner off:** the seam fails closed — resolving this port throws
|
|
2378
|
+
* `ModuleDisabledError` and the call answers 503 `MODULE_DISABLED`, so nothing
|
|
2379
|
+
* half-executes. Whether `catalog` has an off state at all is its manifest's
|
|
2380
|
+
* `activation` to say, not this line's: a module declaring
|
|
2381
|
+
* `nonDeactivatable` never enters one.
|
|
2382
|
+
*/
|
|
2383
|
+
export interface CatalogProductWritePort {
|
|
2384
|
+
createProduct(req: CreateProductRequest, auditCtx?: CatalogAdminAuditContext): Promise<CatalogProductRecord>;
|
|
2385
|
+
updateProduct(id: string, req: UpdateProductRequest): Promise<CatalogProductRecord>;
|
|
2386
|
+
listAttributes(): Promise<CatalogAttributeView[]>;
|
|
2387
|
+
listAttributesByFlag(flag: CatalogAdminAttributeFlag): Promise<CatalogAttributeView[]>;
|
|
2388
|
+
createAttribute(req: CreateAttributeRequest): Promise<CatalogAttributeView>;
|
|
2389
|
+
updateAttributeByIdOrKey(idOrKey: string, req: UpdateAttributeRequest, auditCtx?: CatalogAdminAuditContext): Promise<CatalogAttributeView>;
|
|
2390
|
+
addAttributeOption(attributeIdOrKey: string, input: {
|
|
2391
|
+
value: string;
|
|
2392
|
+
label?: Record<string, string>;
|
|
2393
|
+
labelDefault: string;
|
|
2394
|
+
isDefault?: boolean;
|
|
2395
|
+
sortOrder?: number;
|
|
2396
|
+
}): Promise<CatalogAttributeOptionResult>;
|
|
2397
|
+
patchAttributeOption(optionId: string, input: {
|
|
2398
|
+
label?: Record<string, string>;
|
|
2399
|
+
labelDefault?: string;
|
|
2400
|
+
isDefault?: boolean;
|
|
2401
|
+
sortOrder?: number;
|
|
2402
|
+
}): Promise<CatalogAttributeOptionResult>;
|
|
2403
|
+
createVariant(parentProductId: string, req: CreateVariantRequest): Promise<CatalogProductVariantRecord>;
|
|
2404
|
+
updateVariant(parentProductId: string, variantId: string, req: UpdateVariantRequest): Promise<CatalogProductVariantRecord>;
|
|
2405
|
+
deleteVariant(parentProductId: string, variantId: string): Promise<void>;
|
|
2406
|
+
}
|
|
2407
|
+
/**
|
|
2408
|
+
* One channel/language override upsert — feature 022 / product-scope-overrides.
|
|
2409
|
+
* Used by PIM importers (feature 089) to land channel-locale-scoped names and
|
|
2410
|
+
* descriptions without reaching `product_value_overrides` directly (Principle XII).
|
|
2411
|
+
*/
|
|
2412
|
+
export interface CatalogProductValueOverrideUpsert {
|
|
2413
|
+
attributeKey: string;
|
|
2414
|
+
channelId: string;
|
|
2415
|
+
languageCode: string | null;
|
|
2416
|
+
value: {
|
|
2417
|
+
v: unknown;
|
|
2418
|
+
};
|
|
2419
|
+
}
|
|
2420
|
+
/**
|
|
2421
|
+
* Container name: `catalogProductValueOverrideWritePort`. Owner: `catalog`.
|
|
2422
|
+
*
|
|
2423
|
+
* Bulk upsert of per-channel / per-language product attribute overrides. The
|
|
2424
|
+
* only consumer today is `pim_unopim` (feature 089 / FR-023); the admin SPA
|
|
2425
|
+
* still goes through `ProductOverridesService` inside catalog's own routes.
|
|
2426
|
+
*
|
|
2427
|
+
* **Owner off:** resolving this port throws `ModuleDisabledError` (503).
|
|
2428
|
+
*/
|
|
2429
|
+
export interface CatalogProductValueOverrideWritePort {
|
|
2430
|
+
applyBulk(productId: string, input: {
|
|
2431
|
+
upserts: readonly CatalogProductValueOverrideUpsert[];
|
|
2432
|
+
}): Promise<void>;
|
|
2433
|
+
}
|
|
2434
|
+
/** The patch `updateCategory` accepts. Absent keys are left alone. */
|
|
2435
|
+
export interface UpdateCategoryInput {
|
|
2436
|
+
parentCategoryId?: string | null;
|
|
2437
|
+
name?: Record<string, string>;
|
|
2438
|
+
slug?: string;
|
|
2439
|
+
sortOrder?: number;
|
|
2440
|
+
/** Feature 013 / US5 — library asset rendered as the storefront main image. */
|
|
2441
|
+
mainImageAssetId?: string | null;
|
|
2442
|
+
/** Feature 055 — validated and merged against the definitions on write. */
|
|
2443
|
+
customFieldValues?: Record<string, unknown>;
|
|
2444
|
+
/**
|
|
2445
|
+
* Feature 068 — activation switch. `false` hides the category from every
|
|
2446
|
+
* customer-facing read while the admin tree keeps listing it.
|
|
2447
|
+
*/
|
|
2448
|
+
isActive?: boolean;
|
|
2449
|
+
}
|
|
2450
|
+
/**
|
|
2451
|
+
* The three display-band thresholds a category may override. Absent keys are
|
|
2452
|
+
* left alone; an explicit `null` clears the override.
|
|
2453
|
+
*/
|
|
2454
|
+
export interface CategoryInventoryThresholdPatch {
|
|
2455
|
+
high?: number | null;
|
|
2456
|
+
medium?: number | null;
|
|
2457
|
+
low?: number | null;
|
|
2458
|
+
}
|
|
2459
|
+
/**
|
|
2460
|
+
* Container name: `catalogCategoryWritePort`. Owner: `catalog`.
|
|
2461
|
+
*
|
|
2462
|
+
* `pim_ergonode` again, and again narrow: an import run lists the tree,
|
|
2463
|
+
* creates the categories it is missing and updates the ones that moved.
|
|
2464
|
+
*
|
|
2465
|
+
* `setInventoryThresholds` is the fourth method and belongs to a different
|
|
2466
|
+
* consumer: `inventory` stores the per-category half of its display-band
|
|
2467
|
+
* thresholds in three columns on this module's `categories` table, and wrote
|
|
2468
|
+
* them by holding the entity. It is deliberately **not** a key on
|
|
2469
|
+
* {@link UpdateCategoryInput}: `update` runs the `category.update` Command,
|
|
2470
|
+
* emits the search-reindex event and writes an audit row, none of which a
|
|
2471
|
+
* threshold patch did or should — `inventory` records one
|
|
2472
|
+
* `low_stock_threshold.update` summary row for the whole patch, and an
|
|
2473
|
+
* operator reading a category's history should not find a rename-shaped entry
|
|
2474
|
+
* for it. The columns' owner is still the question underneath, and the answer
|
|
2475
|
+
* that retires this method is moving them into `inventory_thresholds` with
|
|
2476
|
+
* `scopeKind = 'category'`, which is a data migration and not a cut.
|
|
2477
|
+
*
|
|
2478
|
+
* **Owner off:** the seam fails closed — resolving this port throws
|
|
2479
|
+
* `ModuleDisabledError` and the call answers 503 `MODULE_DISABLED`, so nothing
|
|
2480
|
+
* half-executes. Whether `catalog` has an off state at all is its manifest's
|
|
2481
|
+
* `activation` to say, not this line's: a module declaring
|
|
2482
|
+
* `nonDeactivatable` never enters one.
|
|
2483
|
+
*/
|
|
2484
|
+
export interface CatalogCategoryWritePort {
|
|
2485
|
+
listAll(): Promise<CatalogCategoryRecord[]>;
|
|
2486
|
+
create(input: CreateCategoryRequest): Promise<CatalogCategoryRecord>;
|
|
2487
|
+
update(id: string, input: UpdateCategoryInput): Promise<CatalogCategoryRecord>;
|
|
2488
|
+
/** Rejects an unknown or soft-deleted category with 404 `NOT_FOUND`. */
|
|
2489
|
+
setInventoryThresholds(id: string, patch: CategoryInventoryThresholdPatch): Promise<void>;
|
|
2490
|
+
}
|
|
2491
|
+
/**
|
|
2492
|
+
* Container name: `attributeSetService`. Owner: `catalog`.
|
|
2493
|
+
*
|
|
2494
|
+
* Already returns contract DTOs, so the port is the four methods
|
|
2495
|
+
* `pim_ergonode` calls and nothing else.
|
|
2496
|
+
*
|
|
2497
|
+
* **Owner off:** the seam fails closed — resolving this port throws
|
|
2498
|
+
* `ModuleDisabledError` and the call answers 503 `MODULE_DISABLED`, so nothing
|
|
2499
|
+
* half-executes. Whether `catalog` has an off state at all is its manifest's
|
|
2500
|
+
* `activation` to say, not this line's: a module declaring
|
|
2501
|
+
* `nonDeactivatable` never enters one.
|
|
2502
|
+
*/
|
|
2503
|
+
export interface CatalogAttributeSetPort {
|
|
2504
|
+
listSets(): Promise<AttributeSet[]>;
|
|
2505
|
+
getSetDetail(id: string): Promise<AttributeSetDetail>;
|
|
2506
|
+
createSet(input: CreateAttributeSetRequest): Promise<AttributeSetDetail>;
|
|
2507
|
+
assignAttributes(id: string, input: AssignAttributesRequest): Promise<AttributeSetDetail>;
|
|
2508
|
+
}
|
|
2509
|
+
/**
|
|
2510
|
+
* Container name: `attachmentService`. Owner: `catalog`.
|
|
2511
|
+
*
|
|
2512
|
+
* **Owner off:** the seam fails closed — resolving this port throws
|
|
2513
|
+
* `ModuleDisabledError` and the call answers 503 `MODULE_DISABLED`, so nothing
|
|
2514
|
+
* half-executes. Whether `catalog` has an off state at all is its manifest's
|
|
2515
|
+
* `activation` to say, not this line's: a module declaring
|
|
2516
|
+
* `nonDeactivatable` never enters one.
|
|
2517
|
+
*/
|
|
2518
|
+
export interface CatalogAttachmentPort {
|
|
2519
|
+
listTypes(): Promise<AttachmentType[]>;
|
|
2520
|
+
createType(req: CreateAttachmentTypeRequest): Promise<AttachmentType>;
|
|
2521
|
+
listAttachments(productId: string): Promise<ProductAttachment[]>;
|
|
2522
|
+
createAttachment(productId: string, req: CreateAttachmentRequest): Promise<ProductAttachment>;
|
|
2523
|
+
updateAttachment(productId: string, attachmentId: string, req: UpdateAttachmentRequest): Promise<ProductAttachment>;
|
|
2524
|
+
deleteAttachment(productId: string, attachmentId: string): Promise<void>;
|
|
2525
|
+
}
|
|
2526
|
+
/** Whether a gallery write may silently move a conflicting label off another item. */
|
|
2527
|
+
export interface CatalogGalleryWriteOptions {
|
|
2528
|
+
replaceConflictingLabels: boolean;
|
|
2529
|
+
}
|
|
2530
|
+
/**
|
|
2531
|
+
* One gallery item of a batch read, flattened to the three fields a caller
|
|
2532
|
+
* outside `catalog` builds an image list from: which product it belongs to,
|
|
2533
|
+
* which asset it points at, and where it sits in the operator's order.
|
|
2534
|
+
*
|
|
2535
|
+
* Deliberately not `GalleryItem`. The batch read exists for callers that walk a
|
|
2536
|
+
* page — or a whole sellable catalogue — and the label set, the timestamps and
|
|
2537
|
+
* the item id are all rows or columns those callers do not read; carrying them
|
|
2538
|
+
* would cost a second statement per batch for a field nobody looks at.
|
|
2539
|
+
*/
|
|
2540
|
+
export interface CatalogGalleryBatchItem {
|
|
2541
|
+
productId: string;
|
|
2542
|
+
assetId: string;
|
|
2543
|
+
position: number;
|
|
2544
|
+
}
|
|
2545
|
+
/**
|
|
2546
|
+
* Container name: `galleryService`. Owner: `catalog`.
|
|
2547
|
+
*
|
|
2548
|
+
* **Owner off:** the seam fails closed — resolving this port throws
|
|
2549
|
+
* `ModuleDisabledError` and the call answers 503 `MODULE_DISABLED`, so nothing
|
|
2550
|
+
* half-executes. Whether `catalog` has an off state at all is its manifest's
|
|
2551
|
+
* `activation` to say, not this line's: a module declaring
|
|
2552
|
+
* `nonDeactivatable` never enters one.
|
|
2553
|
+
*/
|
|
2554
|
+
export interface CatalogGalleryPort {
|
|
2555
|
+
list(productId: string): Promise<GalleryItem[]>;
|
|
2556
|
+
/**
|
|
2557
|
+
* The gallery items of a **batch** of products, ordered by product and then
|
|
2558
|
+
* by the operator's position, in one statement.
|
|
2559
|
+
*
|
|
2560
|
+
* `list` cannot serve this caller and it is not a matter of taste: it takes a
|
|
2561
|
+
* single product, verifies it exists, and then runs two more queries, so a
|
|
2562
|
+
* page of 500 products costs 1500 round-trips where this costs one. That is
|
|
2563
|
+
* what kept a raw `select … from gallery_items` inside `product_feeds` — a
|
|
2564
|
+
* boundary crossing that names no import specifier and so compiled (feature
|
|
2565
|
+
* 075 / D-87).
|
|
2566
|
+
*
|
|
2567
|
+
* **A product id that resolves to nothing is data, not an error.** No row
|
|
2568
|
+
* comes back for it and the method does not throw: a caller holding an id
|
|
2569
|
+
* whose product has since been removed asks about the batch it has, not about
|
|
2570
|
+
* the batch it wishes it had. The two absences — "this product has an empty
|
|
2571
|
+
* gallery" and "this product is gone" — are therefore not distinguished here,
|
|
2572
|
+
* because both consumers render them identically (no image) and telling them
|
|
2573
|
+
* apart would need exactly the product-existence probe that makes `list`
|
|
2574
|
+
* unusable for a batch.
|
|
2575
|
+
*/
|
|
2576
|
+
listForProducts(productIds: readonly string[]): Promise<CatalogGalleryBatchItem[]>;
|
|
2577
|
+
/**
|
|
2578
|
+
* The `base_image` url of each of a batch of products — `base_image` only,
|
|
2579
|
+
* with no fallback to `thumbnail` or to the first item by position.
|
|
2580
|
+
*
|
|
2581
|
+
* The returned map holds **one entry per requested id**, `null` where this
|
|
2582
|
+
* module has no `base_image` for it: the product carries no such label, the
|
|
2583
|
+
* product is gone, or the asset row behind the label no longer resolves. A
|
|
2584
|
+
* caller that renders a placeholder for all three (both of today's do) reads
|
|
2585
|
+
* one branch; the map's key set answering the request exactly is what lets it
|
|
2586
|
+
* index without re-checking membership.
|
|
2587
|
+
*
|
|
2588
|
+
* `catalog` answers this from its own `gallery_item_labels` and
|
|
2589
|
+
* `gallery_items` plus the asset read port it already holds, so a consumer
|
|
2590
|
+
* gets the url without joining `assets_library`'s table itself — which is the
|
|
2591
|
+
* third of the three reaches this method retires (feature 075 / D-87).
|
|
2592
|
+
*/
|
|
2593
|
+
baseImageUrls(productIds: readonly string[]): Promise<Map<string, string | null>>;
|
|
2594
|
+
create(productId: string, req: CreateGalleryItemRequest, options: CatalogGalleryWriteOptions): Promise<GalleryItem>;
|
|
2595
|
+
delete(productId: string, itemId: string): Promise<void>;
|
|
2596
|
+
reorder(productId: string, orderedIds: string[]): Promise<void>;
|
|
2597
|
+
}
|
|
2598
|
+
/** One child line of a grouped product. */
|
|
2599
|
+
export interface CatalogGroupedItemRow {
|
|
2600
|
+
id: string;
|
|
2601
|
+
parentProductId: string;
|
|
2602
|
+
childProductId: string;
|
|
2603
|
+
quantity: number;
|
|
2604
|
+
position: number;
|
|
2605
|
+
}
|
|
2606
|
+
/**
|
|
2607
|
+
* Container name: `groupedService`. Owner: `catalog`.
|
|
2608
|
+
*
|
|
2609
|
+
* **Owner off:** the seam fails closed — resolving this port throws
|
|
2610
|
+
* `ModuleDisabledError` and the call answers 503 `MODULE_DISABLED`, so nothing
|
|
2611
|
+
* half-executes. Whether `catalog` has an off state at all is its manifest's
|
|
2612
|
+
* `activation` to say, not this line's: a module declaring
|
|
2613
|
+
* `nonDeactivatable` never enters one.
|
|
2614
|
+
*/
|
|
2615
|
+
export interface CatalogGroupedPort {
|
|
2616
|
+
list(parentProductId: string): Promise<CatalogGroupedItemRow[]>;
|
|
2617
|
+
addItem(parentProductId: string, input: {
|
|
2618
|
+
childProductId: string;
|
|
2619
|
+
quantity: number;
|
|
2620
|
+
position?: number | undefined;
|
|
2621
|
+
}): Promise<CatalogGroupedItemRow>;
|
|
2622
|
+
updateItem(parentProductId: string, itemId: string, input: {
|
|
2623
|
+
quantity?: number | undefined;
|
|
2624
|
+
position?: number | undefined;
|
|
2625
|
+
}): Promise<CatalogGroupedItemRow>;
|
|
2626
|
+
removeItem(parentProductId: string, itemId: string): Promise<void>;
|
|
2627
|
+
}
|
|
2628
|
+
/** A link to create, as the bulk writer takes it. */
|
|
2629
|
+
export interface CatalogCreateProductLinkInput {
|
|
2630
|
+
targetProductId: string;
|
|
2631
|
+
kind: ProductLinkKind;
|
|
2632
|
+
position?: number | undefined;
|
|
2633
|
+
}
|
|
2634
|
+
/**
|
|
2635
|
+
* Container name: `productLinkService`. Owner: `catalog`.
|
|
2636
|
+
*
|
|
2637
|
+
* **Owner off:** the seam fails closed — resolving this port throws
|
|
2638
|
+
* `ModuleDisabledError` and the call answers 503 `MODULE_DISABLED`, so nothing
|
|
2639
|
+
* half-executes. Whether `catalog` has an off state at all is its manifest's
|
|
2640
|
+
* `activation` to say, not this line's: a module declaring
|
|
2641
|
+
* `nonDeactivatable` never enters one.
|
|
2642
|
+
*/
|
|
2643
|
+
export interface CatalogProductLinkPort {
|
|
2644
|
+
listForAdmin(sourceProductId: string, kind?: ProductLinkKind): Promise<CatalogProductLinkRow[]>;
|
|
2645
|
+
bulkCreate(sourceProductId: string, inputs: CatalogCreateProductLinkInput[]): Promise<CatalogProductLinkRow[]>;
|
|
2646
|
+
removeLink(sourceProductId: string, linkId: string): Promise<void>;
|
|
2647
|
+
}
|
|
2648
|
+
/** One option inside a bundle slot, as the admin CRUD surface returns it. */
|
|
2649
|
+
export interface CatalogBundleSlotOptionRow {
|
|
2650
|
+
id: string;
|
|
2651
|
+
slotId: string;
|
|
2652
|
+
optionProductId: string;
|
|
2653
|
+
defaultQuantity: number;
|
|
2654
|
+
position: number;
|
|
2655
|
+
}
|
|
2656
|
+
/** One bundle slot with its options. */
|
|
2657
|
+
export interface CatalogBundleSlotRow {
|
|
2658
|
+
id: string;
|
|
2659
|
+
parentProductId: string;
|
|
2660
|
+
name: Record<string, string>;
|
|
2661
|
+
minQuantity: number;
|
|
2662
|
+
maxQuantity: number;
|
|
2663
|
+
position: number;
|
|
2664
|
+
options: CatalogBundleSlotOptionRow[];
|
|
2665
|
+
}
|
|
2666
|
+
/**
|
|
2667
|
+
* Container name: `bundleService`. Owner: `catalog`.
|
|
2668
|
+
*
|
|
2669
|
+
* `pim_pimcore` writes mappable bundle compositions through this seam
|
|
2670
|
+
* (feature 089 / FR-022) — never against catalog's tables.
|
|
2671
|
+
*/
|
|
2672
|
+
export interface CatalogBundlePort {
|
|
2673
|
+
listSlots(parentProductId: string): Promise<CatalogBundleSlotRow[]>;
|
|
2674
|
+
createSlot(parentProductId: string, input: {
|
|
2675
|
+
name: Record<string, string>;
|
|
2676
|
+
minQuantity?: number | undefined;
|
|
2677
|
+
maxQuantity: number;
|
|
2678
|
+
position?: number | undefined;
|
|
2679
|
+
}): Promise<CatalogBundleSlotRow>;
|
|
2680
|
+
updateSlot(parentProductId: string, slotId: string, input: {
|
|
2681
|
+
name?: Record<string, string> | undefined;
|
|
2682
|
+
minQuantity?: number | undefined;
|
|
2683
|
+
maxQuantity?: number | undefined;
|
|
2684
|
+
position?: number | undefined;
|
|
2685
|
+
}): Promise<CatalogBundleSlotRow>;
|
|
2686
|
+
deleteSlot(parentProductId: string, slotId: string): Promise<void>;
|
|
2687
|
+
addOption(parentProductId: string, slotId: string, input: {
|
|
2688
|
+
optionProductId: string;
|
|
2689
|
+
defaultQuantity?: number | undefined;
|
|
2690
|
+
position?: number | undefined;
|
|
2691
|
+
}): Promise<CatalogBundleSlotOptionRow>;
|
|
2692
|
+
removeOption(parentProductId: string, slotId: string, optionId: string): Promise<void>;
|
|
2693
|
+
}
|
|
2694
|
+
/**
|
|
2695
|
+
* Container name: `packagingUnitService`. Owner: `catalog`.
|
|
2696
|
+
*
|
|
2697
|
+
* `pim_pimcore` writes mappable packaging units through this seam
|
|
2698
|
+
* (feature 089 / FR-026).
|
|
2699
|
+
*/
|
|
2700
|
+
export interface CatalogPackagingPort {
|
|
2701
|
+
list(productId: string): Promise<PackagingUnitDto[]>;
|
|
2702
|
+
create(productId: string, req: CreatePackagingUnitRequest): Promise<PackagingUnitDto>;
|
|
2703
|
+
update(productId: string, unitId: string, req: UpdatePackagingUnitRequest): Promise<PackagingUnitDto>;
|
|
2704
|
+
delete(productId: string, unitId: string): Promise<void>;
|
|
2705
|
+
}
|
|
2706
|
+
/** One attribute with its options, as the promotion rule builder renders it. */
|
|
2707
|
+
export interface CatalogAttributeWithOptions {
|
|
2708
|
+
id: string;
|
|
2709
|
+
key: string;
|
|
2710
|
+
label: Record<string, string>;
|
|
2711
|
+
labelDefault: string;
|
|
2712
|
+
valueType: AttributeValueType;
|
|
2713
|
+
isPromoRule: boolean;
|
|
2714
|
+
options: Array<{
|
|
2715
|
+
value: string;
|
|
2716
|
+
label: Record<string, string>;
|
|
2717
|
+
labelDefault: string;
|
|
2718
|
+
}>;
|
|
2719
|
+
}
|
|
2720
|
+
/**
|
|
2721
|
+
* Container name: `catalogPromoAttributePort`. Owner: `catalog`.
|
|
2722
|
+
*
|
|
2723
|
+
* `promotions` builds its rule editor from these two answers, and reaches
|
|
2724
|
+
* `CatalogQueryService` — the storefront query service, 1400 lines — for them.
|
|
2725
|
+
* The port is the two questions.
|
|
2726
|
+
*
|
|
2727
|
+
* **Owner off:** the seam fails closed — resolving this port throws
|
|
2728
|
+
* `ModuleDisabledError` and the call answers 503 `MODULE_DISABLED`, so nothing
|
|
2729
|
+
* half-executes. Whether `catalog` has an off state at all is its manifest's
|
|
2730
|
+
* `activation` to say, not this line's: a module declaring
|
|
2731
|
+
* `nonDeactivatable` never enters one.
|
|
2732
|
+
*/
|
|
2733
|
+
export interface CatalogPromoAttributePort {
|
|
2734
|
+
promoRuleAttributeKeys(): Promise<string[]>;
|
|
2735
|
+
getAttributeWithOptions(key: string): Promise<CatalogAttributeWithOptions | null>;
|
|
2736
|
+
}
|
|
2737
|
+
/** A scalar a filter condition compares against. */
|
|
2738
|
+
export type CatalogProductFilterValue = string | number | boolean | Date | null;
|
|
2739
|
+
/**
|
|
2740
|
+
* What a condition addresses.
|
|
2741
|
+
*
|
|
2742
|
+
* `column` names one of the six product columns a selection may filter on;
|
|
2743
|
+
* `attribute` addresses one key of `products.attribute_values`, the JSONB bag
|
|
2744
|
+
* that has held product attributes and product custom fields alike since
|
|
2745
|
+
* feature 061.
|
|
2746
|
+
*/
|
|
2747
|
+
export type CatalogProductFilterField = {
|
|
2748
|
+
kind: 'column';
|
|
2749
|
+
column: 'id' | 'sku' | 'type' | 'status' | 'createdAt' | 'updatedAt';
|
|
2750
|
+
} | {
|
|
2751
|
+
kind: 'attribute';
|
|
2752
|
+
key: string;
|
|
2753
|
+
};
|
|
2754
|
+
/**
|
|
2755
|
+
* The operators a condition may use.
|
|
2756
|
+
*
|
|
2757
|
+
* `contains` and `startsWith` are patterns the **owner** builds, so a caller
|
|
2758
|
+
* never writes SQL `LIKE` syntax and the escaping rule has one home. Both match
|
|
2759
|
+
* case-insensitively, as the queries they replace already did.
|
|
2760
|
+
*
|
|
2761
|
+
* **Their value is matched literally.** `%`, `_` and the escape character are
|
|
2762
|
+
* characters, not wildcards: the owner escapes them before building the
|
|
2763
|
+
* pattern, so `contains "50%"` selects the products whose text carries the
|
|
2764
|
+
* three characters `5`, `0`, `%` and not every product with "50" followed by
|
|
2765
|
+
* anything. That is part of this shape rather than one provider's detail — a
|
|
2766
|
+
* caller passes the value as the operator's user typed it and never
|
|
2767
|
+
* pre-escapes, and any provider of {@link CatalogProductFilterPort} owes the
|
|
2768
|
+
* same semantics.
|
|
2769
|
+
*/
|
|
2770
|
+
export type CatalogProductFilterOperator = 'eq' | 'ne' | 'in' | 'nin' | 'gt' | 'gte' | 'lt' | 'lte' | 'contains' | 'startsWith' | 'isNull' | 'isNotNull';
|
|
2771
|
+
export interface CatalogProductFilterCondition {
|
|
2772
|
+
kind: 'condition';
|
|
2773
|
+
field: CatalogProductFilterField;
|
|
2774
|
+
op: CatalogProductFilterOperator;
|
|
2775
|
+
/**
|
|
2776
|
+
* The comparison values. `in` / `nin` read all of them; a range is expressed
|
|
2777
|
+
* as two conditions under an `and` group; every other operator reads the
|
|
2778
|
+
* first; `isNull` and `isNotNull` read none.
|
|
2779
|
+
*/
|
|
2780
|
+
values: readonly CatalogProductFilterValue[];
|
|
2781
|
+
}
|
|
2782
|
+
export interface CatalogProductFilterGroup {
|
|
2783
|
+
kind: 'group';
|
|
2784
|
+
op: 'and' | 'or';
|
|
2785
|
+
children: readonly CatalogProductFilter[];
|
|
2786
|
+
}
|
|
2787
|
+
/**
|
|
2788
|
+
* The two constants a compiler needs and an empty object cannot express.
|
|
2789
|
+
*
|
|
2790
|
+
* `all` constrains nothing; `none` can never be satisfied. They are named
|
|
2791
|
+
* rather than left to `{}`, because inside an `or` branch an empty predicate
|
|
2792
|
+
* collapses the branch instead of matching everything — a superset silently
|
|
2793
|
+
* becoming a subset, which is how a filter drops the rows it was meant to keep.
|
|
2794
|
+
*
|
|
2795
|
+
* Two interfaces rather than one with a two-value `kind`, so `kind` stays a
|
|
2796
|
+
* discriminant a translator can narrow the whole union on.
|
|
2797
|
+
*/
|
|
2798
|
+
export interface CatalogProductFilterAll {
|
|
2799
|
+
kind: 'all';
|
|
2800
|
+
}
|
|
2801
|
+
export interface CatalogProductFilterNone {
|
|
2802
|
+
kind: 'none';
|
|
2803
|
+
}
|
|
2804
|
+
export type CatalogProductFilterConstant = CatalogProductFilterAll | CatalogProductFilterNone;
|
|
2805
|
+
export type CatalogProductFilter = CatalogProductFilterCondition | CatalogProductFilterGroup | CatalogProductFilterAll | CatalogProductFilterNone;
|
|
2806
|
+
/** One keyset page of the products a filter selects. */
|
|
2807
|
+
export interface CatalogSellableProductQuery {
|
|
2808
|
+
/**
|
|
2809
|
+
* The only ids the query may consider — for a feed, the sales channel's
|
|
2810
|
+
* membership, resolved by the caller through the sanctioned bridge accessor
|
|
2811
|
+
* (Principle XII). Required, and an empty list selects nothing: this port has
|
|
2812
|
+
* no "every product in the platform" reading.
|
|
2813
|
+
*/
|
|
2814
|
+
productIds: readonly string[];
|
|
2815
|
+
filter: CatalogProductFilter;
|
|
2816
|
+
/** Keyset cursor. Only ids strictly greater come back; `null` starts at the first. */
|
|
2817
|
+
afterId?: string | null;
|
|
2818
|
+
/** Page size. Defaults to 500, the size the feed pipeline already walks in. */
|
|
2819
|
+
limit?: number;
|
|
2820
|
+
}
|
|
2821
|
+
/**
|
|
2822
|
+
* Container name: `catalogProductFilterPort`. Owner: `catalog`.
|
|
2823
|
+
*
|
|
2824
|
+
* **Sellable** is this module's floor and this module applies it: `status`
|
|
2825
|
+
* `active`, not archived, not soft-deleted, and **visible to
|
|
2826
|
+
* {@link ANONYMOUS_PRODUCT_AUDIENCE}** — `isProductVisibleTo`'s answer for a
|
|
2827
|
+
* caller with no session and no organisation, which is what a product feed's
|
|
2828
|
+
* reader is (issue #259). It is conjoined *with* the caller's filter here, so
|
|
2829
|
+
* no filter a caller can construct widens past it.
|
|
2830
|
+
*
|
|
2831
|
+
* The audience is fixed rather than a parameter because this port has one
|
|
2832
|
+
* consumer and that consumer is a feed: an operator ruled that a feed shows the
|
|
2833
|
+
* prices of the sales channel it is generated for and takes no organisation
|
|
2834
|
+
* into account, so there is no per-buyer reading of it to ask for. A caller
|
|
2835
|
+
* that needs another audience needs a different port, not a wider floor —
|
|
2836
|
+
* `visibility` said `public` alone until issue #259, and a `public` product
|
|
2837
|
+
* carrying a non-empty `allowed_organization_ids` went into a Google Shopping
|
|
2838
|
+
* feed for as long as that was the whole test.
|
|
2839
|
+
*
|
|
2840
|
+
* Rows come back as {@link CatalogProductRecord} in ascending id order, which
|
|
2841
|
+
* is what makes the cursor a keyset rather than an offset: a catalogue that
|
|
2842
|
+
* moves under a long walk cannot make the walk skip a row or repeat one.
|
|
2843
|
+
*
|
|
2844
|
+
* When `catalog` is off both methods fail closed. A feed assembled from a
|
|
2845
|
+
* catalogue the platform is refusing to serve is worse than a run that stops
|
|
2846
|
+
* and says why.
|
|
2847
|
+
*
|
|
2848
|
+
* Whether `catalog` has an off state at all is its manifest's `activation` to
|
|
2849
|
+
* say, not this line's: a module declaring `nonDeactivatable` never enters one.
|
|
2850
|
+
*/
|
|
2851
|
+
export interface CatalogProductFilterPort {
|
|
2852
|
+
listSellable(query: CatalogSellableProductQuery): Promise<CatalogProductRecord[]>;
|
|
2853
|
+
countSellable(query: Omit<CatalogSellableProductQuery, 'afterId' | 'limit'>): Promise<number>;
|
|
2854
|
+
}
|
|
2855
|
+
//# sourceMappingURL=catalog.d.ts.map
|