@revenexx/node 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/dist/client.d.mts +25 -0
- package/dist/client.d.ts +25 -0
- package/dist/client.js +39 -18
- package/dist/client.js.map +1 -1
- package/dist/client.mjs +35 -14
- package/dist/client.mjs.map +1 -1
- package/dist/enums/approval-rule-approver-type.d.mts +7 -0
- package/dist/enums/approval-rule-approver-type.d.ts +7 -0
- package/dist/enums/approval-rule-approver-type.js +12 -0
- package/dist/enums/approval-rule-approver-type.js.map +1 -0
- package/dist/enums/approval-rule-approver-type.mjs +11 -0
- package/dist/enums/approval-rule-approver-type.mjs.map +1 -0
- package/dist/enums/approval-rule-condition.d.mts +10 -0
- package/dist/enums/approval-rule-condition.d.ts +10 -0
- package/dist/enums/approval-rule-condition.js +15 -0
- package/dist/enums/approval-rule-condition.js.map +1 -0
- package/dist/enums/approval-rule-condition.mjs +14 -0
- package/dist/enums/approval-rule-condition.mjs.map +1 -0
- package/dist/enums/approval-rule-create-request-approver-type.d.mts +7 -0
- package/dist/enums/approval-rule-create-request-approver-type.d.ts +7 -0
- package/dist/enums/approval-rule-create-request-approver-type.js +12 -0
- package/dist/enums/approval-rule-create-request-approver-type.js.map +1 -0
- package/dist/enums/approval-rule-create-request-approver-type.mjs +11 -0
- package/dist/enums/approval-rule-create-request-approver-type.mjs.map +1 -0
- package/dist/enums/approval-rule-create-request-condition.d.mts +10 -0
- package/dist/enums/approval-rule-create-request-condition.d.ts +10 -0
- package/dist/enums/approval-rule-create-request-condition.js +15 -0
- package/dist/enums/approval-rule-create-request-condition.js.map +1 -0
- package/dist/enums/approval-rule-create-request-condition.mjs +14 -0
- package/dist/enums/approval-rule-create-request-condition.mjs.map +1 -0
- package/dist/enums/approval-rule-create-request-effect.d.mts +7 -0
- package/dist/enums/approval-rule-create-request-effect.d.ts +7 -0
- package/dist/enums/approval-rule-create-request-effect.js +12 -0
- package/dist/enums/approval-rule-create-request-effect.js.map +1 -0
- package/dist/enums/approval-rule-create-request-effect.mjs +11 -0
- package/dist/enums/approval-rule-create-request-effect.mjs.map +1 -0
- package/dist/enums/approval-rule-effect.d.mts +7 -0
- package/dist/enums/approval-rule-effect.d.ts +7 -0
- package/dist/enums/approval-rule-effect.js +12 -0
- package/dist/enums/approval-rule-effect.js.map +1 -0
- package/dist/enums/approval-rule-effect.mjs +11 -0
- package/dist/enums/approval-rule-effect.mjs.map +1 -0
- package/dist/enums/approval-rule-update-request-approver-type.d.mts +7 -0
- package/dist/enums/approval-rule-update-request-approver-type.d.ts +7 -0
- package/dist/enums/approval-rule-update-request-approver-type.js +12 -0
- package/dist/enums/approval-rule-update-request-approver-type.js.map +1 -0
- package/dist/enums/approval-rule-update-request-approver-type.mjs +11 -0
- package/dist/enums/approval-rule-update-request-approver-type.mjs.map +1 -0
- package/dist/enums/approval-rule-update-request-condition.d.mts +10 -0
- package/dist/enums/approval-rule-update-request-condition.d.ts +10 -0
- package/dist/enums/approval-rule-update-request-condition.js +15 -0
- package/dist/enums/approval-rule-update-request-condition.js.map +1 -0
- package/dist/enums/approval-rule-update-request-condition.mjs +14 -0
- package/dist/enums/approval-rule-update-request-condition.mjs.map +1 -0
- package/dist/enums/approval-rule-update-request-effect.d.mts +7 -0
- package/dist/enums/approval-rule-update-request-effect.d.ts +7 -0
- package/dist/enums/approval-rule-update-request-effect.js +12 -0
- package/dist/enums/approval-rule-update-request-effect.js.map +1 -0
- package/dist/enums/approval-rule-update-request-effect.mjs +11 -0
- package/dist/enums/approval-rule-update-request-effect.mjs.map +1 -0
- package/dist/enums/approver-type.d.mts +7 -0
- package/dist/enums/approver-type.d.ts +7 -0
- package/dist/enums/approver-type.js +12 -0
- package/dist/enums/approver-type.js.map +1 -0
- package/dist/enums/approver-type.mjs +11 -0
- package/dist/enums/approver-type.mjs.map +1 -0
- package/dist/enums/condition.d.mts +10 -0
- package/dist/enums/condition.d.ts +10 -0
- package/dist/enums/condition.js +15 -0
- package/dist/enums/condition.js.map +1 -0
- package/dist/enums/condition.mjs +14 -0
- package/dist/enums/condition.mjs.map +1 -0
- package/dist/enums/effect.d.mts +7 -0
- package/dist/enums/effect.d.ts +7 -0
- package/dist/enums/effect.js +12 -0
- package/dist/enums/effect.js.map +1 -0
- package/dist/enums/effect.mjs +11 -0
- package/dist/enums/effect.mjs.map +1 -0
- package/dist/enums/pending-approval-approver-type.d.mts +7 -0
- package/dist/enums/pending-approval-approver-type.d.ts +7 -0
- package/dist/enums/pending-approval-approver-type.js +12 -0
- package/dist/enums/pending-approval-approver-type.js.map +1 -0
- package/dist/enums/pending-approval-approver-type.mjs +11 -0
- package/dist/enums/pending-approval-approver-type.mjs.map +1 -0
- package/dist/enums/pending-approval-status.d.mts +7 -0
- package/dist/enums/pending-approval-status.d.ts +7 -0
- package/dist/enums/pending-approval-status.js +12 -0
- package/dist/enums/pending-approval-status.js.map +1 -0
- package/dist/enums/pending-approval-status.mjs +11 -0
- package/dist/enums/pending-approval-status.mjs.map +1 -0
- package/dist/enums/procurement-purchase-request-items-create-type.d.mts +7 -0
- package/dist/enums/procurement-purchase-request-items-create-type.d.ts +7 -0
- package/dist/enums/procurement-purchase-request-items-create-type.js +12 -0
- package/dist/enums/procurement-purchase-request-items-create-type.js.map +1 -0
- package/dist/enums/procurement-purchase-request-items-create-type.mjs +11 -0
- package/dist/enums/procurement-purchase-request-items-create-type.mjs.map +1 -0
- package/dist/enums/purchase-request-event-name.d.mts +12 -0
- package/dist/enums/purchase-request-event-name.d.ts +12 -0
- package/dist/enums/purchase-request-event-name.js +17 -0
- package/dist/enums/purchase-request-event-name.js.map +1 -0
- package/dist/enums/purchase-request-event-name.mjs +16 -0
- package/dist/enums/purchase-request-event-name.mjs.map +1 -0
- package/dist/enums/purchase-request-item-create-request-type.d.mts +7 -0
- package/dist/enums/purchase-request-item-create-request-type.d.ts +7 -0
- package/dist/enums/purchase-request-item-create-request-type.js +12 -0
- package/dist/enums/purchase-request-item-create-request-type.js.map +1 -0
- package/dist/enums/purchase-request-item-create-request-type.mjs +11 -0
- package/dist/enums/purchase-request-item-create-request-type.mjs.map +1 -0
- package/dist/enums/purchase-request-item-type.d.mts +7 -0
- package/dist/enums/purchase-request-item-type.d.ts +7 -0
- package/dist/enums/purchase-request-item-type.js +12 -0
- package/dist/enums/purchase-request-item-type.js.map +1 -0
- package/dist/enums/purchase-request-item-type.mjs +11 -0
- package/dist/enums/purchase-request-item-type.mjs.map +1 -0
- package/dist/enums/purchase-request-item-update-request-type.d.mts +7 -0
- package/dist/enums/purchase-request-item-update-request-type.d.ts +7 -0
- package/dist/enums/purchase-request-item-update-request-type.js +12 -0
- package/dist/enums/purchase-request-item-update-request-type.js.map +1 -0
- package/dist/enums/purchase-request-item-update-request-type.mjs +11 -0
- package/dist/enums/purchase-request-item-update-request-type.mjs.map +1 -0
- package/dist/enums/purchase-request-status.d.mts +9 -0
- package/dist/enums/purchase-request-status.d.ts +9 -0
- package/dist/enums/purchase-request-status.js +14 -0
- package/dist/enums/purchase-request-status.js.map +1 -0
- package/dist/enums/purchase-request-status.mjs +13 -0
- package/dist/enums/purchase-request-status.mjs.map +1 -0
- package/dist/enums/submit-item-type.d.mts +7 -0
- package/dist/enums/submit-item-type.d.ts +7 -0
- package/dist/enums/submit-item-type.js +12 -0
- package/dist/enums/submit-item-type.js.map +1 -0
- package/dist/enums/submit-item-type.mjs +11 -0
- package/dist/enums/submit-item-type.mjs.map +1 -0
- package/dist/enums/submit-result-outcome.d.mts +9 -0
- package/dist/enums/submit-result-outcome.d.ts +9 -0
- package/dist/enums/submit-result-outcome.js +14 -0
- package/dist/enums/submit-result-outcome.js.map +1 -0
- package/dist/enums/submit-result-outcome.mjs +13 -0
- package/dist/enums/submit-result-outcome.mjs.map +1 -0
- package/dist/index.d.mts +23 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +115 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +23 -0
- package/dist/index.mjs.map +1 -1
- package/dist/inputFile.js +1 -2
- package/dist/inputFile.js.map +1 -1
- package/dist/inputFile.mjs +0 -1
- package/dist/inputFile.mjs.map +1 -1
- package/dist/models.d.mts +1027 -36
- package/dist/models.d.ts +1027 -36
- package/dist/operator.js +243 -204
- package/dist/operator.js.map +1 -1
- package/dist/operator.mjs +242 -203
- package/dist/operator.mjs.map +1 -1
- package/dist/permission.js +58 -48
- package/dist/permission.js.map +1 -1
- package/dist/permission.mjs +58 -48
- package/dist/permission.mjs.map +1 -1
- package/dist/query.js +525 -422
- package/dist/query.js.map +1 -1
- package/dist/query.mjs +524 -421
- package/dist/query.mjs.map +1 -1
- package/dist/services/apps.d.mts +18 -0
- package/dist/services/apps.d.ts +18 -0
- package/dist/services/avatars.d.mts +18 -0
- package/dist/services/avatars.d.ts +18 -0
- package/dist/services/carts-io.d.mts +46 -28
- package/dist/services/carts-io.d.ts +46 -28
- package/dist/services/carts-io.js.map +1 -1
- package/dist/services/carts-io.mjs.map +1 -1
- package/dist/services/carts-items.d.mts +42 -24
- package/dist/services/carts-items.d.ts +42 -24
- package/dist/services/carts-items.js.map +1 -1
- package/dist/services/carts-items.mjs.map +1 -1
- package/dist/services/carts.d.mts +70 -52
- package/dist/services/carts.d.ts +70 -52
- package/dist/services/carts.js.map +1 -1
- package/dist/services/carts.mjs.map +1 -1
- package/dist/services/channels.d.mts +64 -46
- package/dist/services/channels.d.ts +64 -46
- package/dist/services/channels.js +1 -1
- package/dist/services/channels.js.map +1 -1
- package/dist/services/channels.mjs +1 -1
- package/dist/services/channels.mjs.map +1 -1
- package/dist/services/cost-centers.d.mts +18 -0
- package/dist/services/cost-centers.d.ts +18 -0
- package/dist/services/customers-contacts.d.mts +62 -44
- package/dist/services/customers-contacts.d.ts +62 -44
- package/dist/services/customers-contacts.js.map +1 -1
- package/dist/services/customers-contacts.mjs.map +1 -1
- package/dist/services/customers-organizations.d.mts +58 -40
- package/dist/services/customers-organizations.d.ts +58 -40
- package/dist/services/customers-organizations.js.map +1 -1
- package/dist/services/customers-organizations.mjs.map +1 -1
- package/dist/services/customers-roles.d.mts +26 -8
- package/dist/services/customers-roles.d.ts +26 -8
- package/dist/services/customers-roles.js.map +1 -1
- package/dist/services/customers-roles.mjs.map +1 -1
- package/dist/services/customers-segments.d.mts +62 -44
- package/dist/services/customers-segments.d.ts +62 -44
- package/dist/services/customers-segments.js.map +1 -1
- package/dist/services/customers-segments.mjs.map +1 -1
- package/dist/services/customers-value-lists.d.mts +90 -72
- package/dist/services/customers-value-lists.d.ts +90 -72
- package/dist/services/customers-value-lists.js.map +1 -1
- package/dist/services/customers-value-lists.mjs.map +1 -1
- package/dist/services/customers.d.mts +78 -60
- package/dist/services/customers.d.ts +78 -60
- package/dist/services/customers.js.map +1 -1
- package/dist/services/customers.mjs.map +1 -1
- package/dist/services/events.d.mts +18 -0
- package/dist/services/events.d.ts +18 -0
- package/dist/services/forms.d.mts +66 -48
- package/dist/services/forms.d.ts +66 -48
- package/dist/services/forms.js.map +1 -1
- package/dist/services/forms.mjs.map +1 -1
- package/dist/services/health.d.mts +18 -0
- package/dist/services/health.d.ts +18 -0
- package/dist/services/inventories-locations.d.mts +38 -20
- package/dist/services/inventories-locations.d.ts +38 -20
- package/dist/services/inventories-locations.js.map +1 -1
- package/dist/services/inventories-locations.mjs.map +1 -1
- package/dist/services/inventories-reservations.d.mts +38 -20
- package/dist/services/inventories-reservations.d.ts +38 -20
- package/dist/services/inventories-reservations.js.map +1 -1
- package/dist/services/inventories-reservations.mjs.map +1 -1
- package/dist/services/inventories-stock.d.mts +70 -52
- package/dist/services/inventories-stock.d.ts +70 -52
- package/dist/services/inventories-stock.js.map +1 -1
- package/dist/services/inventories-stock.mjs.map +1 -1
- package/dist/services/io.d.mts +66 -48
- package/dist/services/io.d.ts +66 -48
- package/dist/services/io.js +2 -2
- package/dist/services/io.js.map +1 -1
- package/dist/services/io.mjs +2 -2
- package/dist/services/io.mjs.map +1 -1
- package/dist/services/locale.d.mts +18 -0
- package/dist/services/locale.d.ts +18 -0
- package/dist/services/markets.d.mts +122 -104
- package/dist/services/markets.d.ts +122 -104
- package/dist/services/markets.js.map +1 -1
- package/dist/services/markets.mjs.map +1 -1
- package/dist/services/messaging.d.mts +194 -176
- package/dist/services/messaging.d.ts +194 -176
- package/dist/services/messaging.js +3 -3
- package/dist/services/messaging.js.map +1 -1
- package/dist/services/messaging.mjs +3 -3
- package/dist/services/messaging.mjs.map +1 -1
- package/dist/services/orderlists.d.mts +96 -78
- package/dist/services/orderlists.d.ts +96 -78
- package/dist/services/orderlists.js +1 -1
- package/dist/services/orderlists.js.map +1 -1
- package/dist/services/orderlists.mjs +1 -1
- package/dist/services/orderlists.mjs.map +1 -1
- package/dist/services/orders.d.mts +114 -96
- package/dist/services/orders.d.ts +114 -96
- package/dist/services/orders.js.map +1 -1
- package/dist/services/orders.mjs.map +1 -1
- package/dist/services/pages-collaboration.d.mts +34 -16
- package/dist/services/pages-collaboration.d.ts +34 -16
- package/dist/services/pages-collaboration.js.map +1 -1
- package/dist/services/pages-collaboration.mjs.map +1 -1
- package/dist/services/pages-delivery.d.mts +26 -8
- package/dist/services/pages-delivery.d.ts +26 -8
- package/dist/services/pages-delivery.js.map +1 -1
- package/dist/services/pages-delivery.mjs.map +1 -1
- package/dist/services/pages-editor.d.mts +34 -16
- package/dist/services/pages-editor.d.ts +34 -16
- package/dist/services/pages-editor.js.map +1 -1
- package/dist/services/pages-editor.mjs.map +1 -1
- package/dist/services/pages.d.mts +82 -64
- package/dist/services/pages.d.ts +82 -64
- package/dist/services/pages.js.map +1 -1
- package/dist/services/pages.mjs.map +1 -1
- package/dist/services/payments-ledger.d.mts +54 -36
- package/dist/services/payments-ledger.d.ts +54 -36
- package/dist/services/payments-ledger.js.map +1 -1
- package/dist/services/payments-ledger.mjs.map +1 -1
- package/dist/services/payments-methods.d.mts +34 -16
- package/dist/services/payments-methods.d.ts +34 -16
- package/dist/services/payments-methods.js.map +1 -1
- package/dist/services/payments-methods.mjs.map +1 -1
- package/dist/services/payments-providers.d.mts +38 -20
- package/dist/services/payments-providers.d.ts +38 -20
- package/dist/services/payments-providers.js.map +1 -1
- package/dist/services/payments-providers.mjs.map +1 -1
- package/dist/services/prices.d.mts +86 -68
- package/dist/services/prices.d.ts +86 -68
- package/dist/services/prices.js.map +1 -1
- package/dist/services/prices.mjs.map +1 -1
- package/dist/services/procurement.d.mts +991 -0
- package/dist/services/procurement.d.ts +991 -0
- package/dist/services/procurement.js +1185 -0
- package/dist/services/procurement.js.map +1 -0
- package/dist/services/procurement.mjs +1184 -0
- package/dist/services/procurement.mjs.map +1 -0
- package/dist/services/products-assets.d.mts +34 -16
- package/dist/services/products-assets.d.ts +34 -16
- package/dist/services/products-assets.js.map +1 -1
- package/dist/services/products-assets.mjs.map +1 -1
- package/dist/services/products-categories.d.mts +66 -48
- package/dist/services/products-categories.d.ts +66 -48
- package/dist/services/products-categories.js.map +1 -1
- package/dist/services/products-categories.mjs.map +1 -1
- package/dist/services/products-data-model.d.mts +166 -148
- package/dist/services/products-data-model.d.ts +166 -148
- package/dist/services/products-data-model.js.map +1 -1
- package/dist/services/products-data-model.mjs.map +1 -1
- package/dist/services/products-references.d.mts +50 -32
- package/dist/services/products-references.d.ts +50 -32
- package/dist/services/products-references.js.map +1 -1
- package/dist/services/products-references.mjs.map +1 -1
- package/dist/services/products.d.mts +70 -52
- package/dist/services/products.d.ts +70 -52
- package/dist/services/products.js.map +1 -1
- package/dist/services/products.mjs.map +1 -1
- package/dist/services/search.d.mts +40 -22
- package/dist/services/search.d.ts +40 -22
- package/dist/services/search.js +1 -1
- package/dist/services/search.js.map +1 -1
- package/dist/services/search.mjs +1 -1
- package/dist/services/search.mjs.map +1 -1
- package/dist/services/settings.d.mts +18 -0
- package/dist/services/settings.d.ts +18 -0
- package/dist/services/shipping-carriers.d.mts +42 -24
- package/dist/services/shipping-carriers.d.ts +42 -24
- package/dist/services/shipping-carriers.js.map +1 -1
- package/dist/services/shipping-carriers.mjs.map +1 -1
- package/dist/services/shipping-methods.d.mts +70 -52
- package/dist/services/shipping-methods.d.ts +70 -52
- package/dist/services/shipping-methods.js.map +1 -1
- package/dist/services/shipping-methods.mjs.map +1 -1
- package/dist/services/shipping-value-lists.d.mts +62 -44
- package/dist/services/shipping-value-lists.d.ts +62 -44
- package/dist/services/shipping-value-lists.js.map +1 -1
- package/dist/services/shipping-value-lists.mjs.map +1 -1
- package/dist/services/sites.d.mts +18 -0
- package/dist/services/sites.d.ts +18 -0
- package/dist/services/storage.d.mts +18 -0
- package/dist/services/storage.d.ts +18 -0
- package/package.json +6 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/services/products.ts"],"names":[],"mappings":"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","sourcesContent":["import { RevenexxException, Client, type Payload, UploadProgress } from '../client';\nimport type { Models } from '../models';\n\nimport { Kind } from '../enums/kind';\nimport { ProductsKind } from '../enums/products-kind';\n\nexport class Products {\n client: Client;\n\n constructor(client: Client) {\n this.client = client;\n }\n\n /**\n * The catalog itself. A product row carries only what every product has — SKU, kind, family, enabled, tax class — and everything the tenant modelled lives in the `attribute_values` jsonb document, keyed by attribute CODE inside one of four scope buckets (common, per locale, per channel, per channel and locale). `label` is a generated column, maintained by the database so a grid of twenty thousand rows can sort and filter on a name with no join. `kind` says where the row sits in the variant hierarchy: a `model` carries what its variants share and is never sold itself.\n * \n * Every column of `products` is an exact-match query parameter, `order` sorts by one column, and `limit`/`offset` page through `page.total`. A query key that is NOT a column is dropped rather than refused, and the `filter` object echoes the ones that were understood — that echo is the only way to tell an unfiltered answer from an empty one. It reads rows exactly as they are stored: no join is resolved, no jsonb value is unpacked, and soft-deleted products are included — filter on `deleted_at` to read the live catalog, or use `GET /products/grid`, which excludes them.\n *\n * @param {number} params.limit - Page size (default 50, max 200). A larger value is clamped rather than refused.\n * @param {number} params.offset - Row offset for pagination (default 0). Page with `page.total` and `page.hasMore`.\n * @param {string} params.order - Sort by one column: 'column' | 'column.asc' | 'column.desc'. A bare column sorts ascending. Anything else is refused with 400.\n * @param {string} params.id - Exact match on `id`. The row's own id, generated by the database. A client never sends one; it reads one back and uses it in the path of every later call.\n * @param {string} params.sku - Exact match on `sku`. The merchant's own article number — unique per tenant, and the value every integration (ERP, shop, feed, price list) joins on. The one identifier a person types, and the fallback this app shows when the catalog holds no name.\n * @param {Kind} params.kind - Exact match on `kind`. Where the product sits in the variant hierarchy. 'simple' stands on its own. 'model' carries the values its variants share and is never sold itself. 'variant' carries the axis values and points at its model through `parent_id`.\n * @param {string} params.parentId - Exact match on `parent_id`. The product MODEL this variant belongs to. Only a `variant` carries one. Deleting the model leaves its variants behind with a null parent rather than deleting them.\n * @param {string} params.familyId - Exact match on `family_id`. The family that decides which attributes this product HAS. Without one nothing is required, completeness cannot be computed and the display name never resolves — `POST /products/{id}/family` is the call that sets it and computes completeness in the same step.\n * @param {string} params.familyVariantId - Exact match on `family_variant_id`. Which variant structure of the family this product follows — the axes it splits on. Null on a simple product.\n * @param {boolean} params.enabled - Exact match on `enabled`. Whether the product is offered. A create defaults it from the `new_products_enabled_by_default` tenant setting rather than blindly to true, so an import does not publish twenty thousand unfinished products the moment it lands. An explicit value in the body always wins.\n * @param {string} params.taxClass - Exact match on `tax_class`. The tax class key the prices app resolves a VAT rate from. Free text here — the vocabulary belongs to the app that prices, and `POST /products/batch` exists to hand exactly this column to it in bulk.\n * @param {string} params.attributeValues - Exact match on `attribute_values`. Every attribute value the record carries, in ONE jsonb document — the core of an attribute-driven PIM. A record's properties are not columns here: they are rows in `attributes`, selected per family by `family_attributes`, and their values live under their attribute CODE inside this object. The whole jsonb document is compared, serialized as JSON — this is equality, not a path or containment query, and `null` cannot be matched this way. A value that does not parse as JSON is refused with 400 `invalid_value`, naming this filter, before the request reaches the data plane.\n * @param {string} params.label - Exact match on `label`. The display name, maintained by the DATABASE so a grid of twenty thousand rows can sort and filter on a name with no join. It is the first of `attribute_values.common.name`, `…common.label`, the `de`/`en`/`de_DE`/`en_US` locale buckets, `…common.manufacturer_aid`, and finally the SKU — so a value is ALWAYS present, and a label equal to the SKU means the catalog holds no name for this product. A generated column: it cannot be written, and a create or update that names it has it dropped rather than refused. The family-aware answer, which can consult `families.label_attribute` and report where the name came from, is `POST /products/labels`.\n * @param {string} params.quantifiedAssociations - Exact match on `quantified_associations`. The import-side mirror of associations that carry a quantity — a bundle, a bill of materials, a spare-parts set. NOTHING IN THIS APP READS OR WRITES IT: no route produces it, no route consumes it, and it is null on every product this app has created. The surface that IS served is relational — `product_associations`, whose `quantity` column holds the number, guarded by `association_types.is_quantified`. The whole jsonb document is compared, serialized as JSON — this is equality, not a path or containment query, and `null` cannot be matched this way. A value that does not parse as JSON is refused with 400 `invalid_value`, naming this filter, before the request reaches the data plane.\n * @param {string} params.completeness - Exact match on `completeness`. How much of what this product's family REQUIRES it actually carries — the number a merchandiser works down. `required` counts the attributes the family marks `is_required`, `filled` how many of those carry a value in ANY bucket, `ratio` is filled/required between 0 and 1 (a family that requires nothing is 1, not undefined), `missing` lists the codes with no value anywhere, sorted, and `computed_at` is when it was measured. The whole jsonb document is compared, serialized as JSON — this is equality, not a path or containment query, and `null` cannot be matched this way. A value that does not parse as JSON is refused with 400 `invalid_value`, naming this filter, before the request reaches the data plane.\n * @param {string} params.createdAt - Exact match on `created_at`. When the row was created. Server-set — it is not part of any request body.\n * @param {string} params.updatedAt - Exact match on `updated_at`. When the row was last written. Server-set — it is not part of any request body.\n * @param {string} params.deletedAt - Exact match on `deleted_at`. When the product was soft-deleted. `GET /products/grid` and every category-rule evaluation exclude a row that carries one; `GET /products` does NOT — filter on it to read the live catalog.\n * @throws {RevenexxException}\n * @returns {Promise<{}>}\n */\n productsList(params?: { limit?: number, offset?: number, order?: string, id?: string, sku?: string, kind?: Kind, parentId?: string, familyId?: string, familyVariantId?: string, enabled?: boolean, taxClass?: string, attributeValues?: string, label?: string, quantifiedAssociations?: string, completeness?: string, createdAt?: string, updatedAt?: string, deletedAt?: string }): Promise<{}>;\n /**\n * The catalog itself. A product row carries only what every product has — SKU, kind, family, enabled, tax class — and everything the tenant modelled lives in the `attribute_values` jsonb document, keyed by attribute CODE inside one of four scope buckets (common, per locale, per channel, per channel and locale). `label` is a generated column, maintained by the database so a grid of twenty thousand rows can sort and filter on a name with no join. `kind` says where the row sits in the variant hierarchy: a `model` carries what its variants share and is never sold itself.\n * \n * Every column of `products` is an exact-match query parameter, `order` sorts by one column, and `limit`/`offset` page through `page.total`. A query key that is NOT a column is dropped rather than refused, and the `filter` object echoes the ones that were understood — that echo is the only way to tell an unfiltered answer from an empty one. It reads rows exactly as they are stored: no join is resolved, no jsonb value is unpacked, and soft-deleted products are included — filter on `deleted_at` to read the live catalog, or use `GET /products/grid`, which excludes them.\n *\n * @param {number} limit - Page size (default 50, max 200). A larger value is clamped rather than refused.\n * @param {number} offset - Row offset for pagination (default 0). Page with `page.total` and `page.hasMore`.\n * @param {string} order - Sort by one column: 'column' | 'column.asc' | 'column.desc'. A bare column sorts ascending. Anything else is refused with 400.\n * @param {string} id - Exact match on `id`. The row's own id, generated by the database. A client never sends one; it reads one back and uses it in the path of every later call.\n * @param {string} sku - Exact match on `sku`. The merchant's own article number — unique per tenant, and the value every integration (ERP, shop, feed, price list) joins on. The one identifier a person types, and the fallback this app shows when the catalog holds no name.\n * @param {Kind} kind - Exact match on `kind`. Where the product sits in the variant hierarchy. 'simple' stands on its own. 'model' carries the values its variants share and is never sold itself. 'variant' carries the axis values and points at its model through `parent_id`.\n * @param {string} parentId - Exact match on `parent_id`. The product MODEL this variant belongs to. Only a `variant` carries one. Deleting the model leaves its variants behind with a null parent rather than deleting them.\n * @param {string} familyId - Exact match on `family_id`. The family that decides which attributes this product HAS. Without one nothing is required, completeness cannot be computed and the display name never resolves — `POST /products/{id}/family` is the call that sets it and computes completeness in the same step.\n * @param {string} familyVariantId - Exact match on `family_variant_id`. Which variant structure of the family this product follows — the axes it splits on. Null on a simple product.\n * @param {boolean} enabled - Exact match on `enabled`. Whether the product is offered. A create defaults it from the `new_products_enabled_by_default` tenant setting rather than blindly to true, so an import does not publish twenty thousand unfinished products the moment it lands. An explicit value in the body always wins.\n * @param {string} taxClass - Exact match on `tax_class`. The tax class key the prices app resolves a VAT rate from. Free text here — the vocabulary belongs to the app that prices, and `POST /products/batch` exists to hand exactly this column to it in bulk.\n * @param {string} attributeValues - Exact match on `attribute_values`. Every attribute value the record carries, in ONE jsonb document — the core of an attribute-driven PIM. A record's properties are not columns here: they are rows in `attributes`, selected per family by `family_attributes`, and their values live under their attribute CODE inside this object. The whole jsonb document is compared, serialized as JSON — this is equality, not a path or containment query, and `null` cannot be matched this way. A value that does not parse as JSON is refused with 400 `invalid_value`, naming this filter, before the request reaches the data plane.\n * @param {string} label - Exact match on `label`. The display name, maintained by the DATABASE so a grid of twenty thousand rows can sort and filter on a name with no join. It is the first of `attribute_values.common.name`, `…common.label`, the `de`/`en`/`de_DE`/`en_US` locale buckets, `…common.manufacturer_aid`, and finally the SKU — so a value is ALWAYS present, and a label equal to the SKU means the catalog holds no name for this product. A generated column: it cannot be written, and a create or update that names it has it dropped rather than refused. The family-aware answer, which can consult `families.label_attribute` and report where the name came from, is `POST /products/labels`.\n * @param {string} quantifiedAssociations - Exact match on `quantified_associations`. The import-side mirror of associations that carry a quantity — a bundle, a bill of materials, a spare-parts set. NOTHING IN THIS APP READS OR WRITES IT: no route produces it, no route consumes it, and it is null on every product this app has created. The surface that IS served is relational — `product_associations`, whose `quantity` column holds the number, guarded by `association_types.is_quantified`. The whole jsonb document is compared, serialized as JSON — this is equality, not a path or containment query, and `null` cannot be matched this way. A value that does not parse as JSON is refused with 400 `invalid_value`, naming this filter, before the request reaches the data plane.\n * @param {string} completeness - Exact match on `completeness`. How much of what this product's family REQUIRES it actually carries — the number a merchandiser works down. `required` counts the attributes the family marks `is_required`, `filled` how many of those carry a value in ANY bucket, `ratio` is filled/required between 0 and 1 (a family that requires nothing is 1, not undefined), `missing` lists the codes with no value anywhere, sorted, and `computed_at` is when it was measured. The whole jsonb document is compared, serialized as JSON — this is equality, not a path or containment query, and `null` cannot be matched this way. A value that does not parse as JSON is refused with 400 `invalid_value`, naming this filter, before the request reaches the data plane.\n * @param {string} createdAt - Exact match on `created_at`. When the row was created. Server-set — it is not part of any request body.\n * @param {string} updatedAt - Exact match on `updated_at`. When the row was last written. Server-set — it is not part of any request body.\n * @param {string} deletedAt - Exact match on `deleted_at`. When the product was soft-deleted. `GET /products/grid` and every category-rule evaluation exclude a row that carries one; `GET /products` does NOT — filter on it to read the live catalog.\n * @throws {RevenexxException}\n * @returns {Promise<{}>}\n * @deprecated Use the object parameter style method for a better developer experience.\n */\n productsList(limit?: number, offset?: number, order?: string, id?: string, sku?: string, kind?: Kind, parentId?: string, familyId?: string, familyVariantId?: string, enabled?: boolean, taxClass?: string, attributeValues?: string, label?: string, quantifiedAssociations?: string, completeness?: string, createdAt?: string, updatedAt?: string, deletedAt?: string): Promise<{}>;\n productsList(\n paramsOrFirst?: { limit?: number, offset?: number, order?: string, id?: string, sku?: string, kind?: Kind, parentId?: string, familyId?: string, familyVariantId?: string, enabled?: boolean, taxClass?: string, attributeValues?: string, label?: string, quantifiedAssociations?: string, completeness?: string, createdAt?: string, updatedAt?: string, deletedAt?: string } | number,\n ...rest: [(number)?, (string)?, (string)?, (string)?, (Kind)?, (string)?, (string)?, (string)?, (boolean)?, (string)?, (string)?, (string)?, (string)?, (string)?, (string)?, (string)?, (string)?] \n ): Promise<{}> {\n let params: { limit?: number, offset?: number, order?: string, id?: string, sku?: string, kind?: Kind, parentId?: string, familyId?: string, familyVariantId?: string, enabled?: boolean, taxClass?: string, attributeValues?: string, label?: string, quantifiedAssociations?: string, completeness?: string, createdAt?: string, updatedAt?: string, deletedAt?: string };\n \n if (!paramsOrFirst || (paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst))) {\n params = (paramsOrFirst || {}) as { limit?: number, offset?: number, order?: string, id?: string, sku?: string, kind?: Kind, parentId?: string, familyId?: string, familyVariantId?: string, enabled?: boolean, taxClass?: string, attributeValues?: string, label?: string, quantifiedAssociations?: string, completeness?: string, createdAt?: string, updatedAt?: string, deletedAt?: string };\n } else {\n params = {\n limit: paramsOrFirst as number,\n offset: rest[0] as number,\n order: rest[1] as string,\n id: rest[2] as string,\n sku: rest[3] as string,\n kind: rest[4] as Kind,\n parentId: rest[5] as string,\n familyId: rest[6] as string,\n familyVariantId: rest[7] as string,\n enabled: rest[8] as boolean,\n taxClass: rest[9] as string,\n attributeValues: rest[10] as string,\n label: rest[11] as string,\n quantifiedAssociations: rest[12] as string,\n completeness: rest[13] as string,\n createdAt: rest[14] as string,\n updatedAt: rest[15] as string,\n deletedAt: rest[16] as string \n };\n }\n \n const limit = params.limit;\n const offset = params.offset;\n const order = params.order;\n const id = params.id;\n const sku = params.sku;\n const kind = params.kind;\n const parentId = params.parentId;\n const familyId = params.familyId;\n const familyVariantId = params.familyVariantId;\n const enabled = params.enabled;\n const taxClass = params.taxClass;\n const attributeValues = params.attributeValues;\n const label = params.label;\n const quantifiedAssociations = params.quantifiedAssociations;\n const completeness = params.completeness;\n const createdAt = params.createdAt;\n const updatedAt = params.updatedAt;\n const deletedAt = params.deletedAt;\n\n\n const apiPath = '/v1/products';\n const apiPayload: Payload = {};\n if (typeof limit !== 'undefined') {\n apiPayload['limit'] = limit;\n }\n if (typeof offset !== 'undefined') {\n apiPayload['offset'] = offset;\n }\n if (typeof order !== 'undefined') {\n apiPayload['order'] = order;\n }\n if (typeof id !== 'undefined') {\n apiPayload['id'] = id;\n }\n if (typeof sku !== 'undefined') {\n apiPayload['sku'] = sku;\n }\n if (typeof kind !== 'undefined') {\n apiPayload['kind'] = kind;\n }\n if (typeof parentId !== 'undefined') {\n apiPayload['parent_id'] = parentId;\n }\n if (typeof familyId !== 'undefined') {\n apiPayload['family_id'] = familyId;\n }\n if (typeof familyVariantId !== 'undefined') {\n apiPayload['family_variant_id'] = familyVariantId;\n }\n if (typeof enabled !== 'undefined') {\n apiPayload['enabled'] = enabled;\n }\n if (typeof taxClass !== 'undefined') {\n apiPayload['tax_class'] = taxClass;\n }\n if (typeof attributeValues !== 'undefined') {\n apiPayload['attribute_values'] = attributeValues;\n }\n if (typeof label !== 'undefined') {\n apiPayload['label'] = label;\n }\n if (typeof quantifiedAssociations !== 'undefined') {\n apiPayload['quantified_associations'] = quantifiedAssociations;\n }\n if (typeof completeness !== 'undefined') {\n apiPayload['completeness'] = completeness;\n }\n if (typeof createdAt !== 'undefined') {\n apiPayload['created_at'] = createdAt;\n }\n if (typeof updatedAt !== 'undefined') {\n apiPayload['updated_at'] = updatedAt;\n }\n if (typeof deletedAt !== 'undefined') {\n apiPayload['deleted_at'] = deletedAt;\n }\n const uri = new URL(this.client.config.endpoint + apiPath);\n\n const apiHeaders: { [header: string]: string } = {\n }\n\n return this.client.call(\n 'get',\n uri,\n apiHeaders,\n apiPayload,\n );\n }\n\n /**\n * Creates one product and answers 201 with the stored row, including the id and the timestamps the database filled in — a client never sends an id, it reads one back and uses it in the path of every later call.\n * \n * The catalog itself. A product row carries only what every product has — SKU, kind, family, enabled, tax class — and everything the tenant modelled lives in the `attribute_values` jsonb document, keyed by attribute CODE inside one of four scope buckets (common, per locale, per channel, per channel and locale). `label` is a generated column, maintained by the database so a grid of twenty thousand rows can sort and filter on a name with no join. `kind` says where the row sits in the variant hierarchy: a `model` carries what its variants share and is never sold itself.\n * \n * `sku` is the only column the database refuses the row without; everything else has a default or is nullable. A second row with the same `sku` answers 409. This app owns the create: `enabled` defaults from the `new_products_enabled_by_default` tenant setting rather than blindly to true, so an import cannot publish twenty thousand unfinished products the moment it lands, and a product that names no family gets the `default_product_family` one. An explicit value in the body always wins over both.\n *\n * @param {string} params.sku - The merchant's own article number — unique per tenant, and the value every integration (ERP, shop, feed, price list) joins on. The one identifier a person types, and the fallback this app shows when the catalog holds no name.\n * @param {object} params.attributeValues - Every attribute value the record carries, in ONE jsonb document — the core of an attribute-driven PIM. A record's properties are not columns here: they are rows in `attributes`, selected per family by `family_attributes`, and their values live under their attribute CODE inside this object.\n\nFour buckets, and an attribute's own flags decide which one it writes to:\n\n `common` the attribute is neither localizable nor scopable — one value, full stop.\n `{\"common\": {\"net_weight\": 2.4, \"colour\": \"black\"}}`\n `locale_specific` `localizable`: one value per language tag.\n `{\"locale_specific\": {\"de_DE\": {\"name\": \"Akku-Bohrschrauber\"}}}`\n `channel_specific` `scopable`: one value per channel.\n `{\"channel_specific\": {\"b2b\": {\"minimum_order_quantity\": 6}}}`\n `channel_locale_specific` both: one value per channel AND language tag.\n `{\"channel_locale_specific\": {\"b2b\": {\"de_DE\": {\"description\": \"…\"}}}}`\n\nA reader takes the most specific bucket that carries the code and falls back through locale, then channel, then `common`. `common` is always last and always consulted, because early imports wrote everything there whatever an attribute's flags said — a reader that skipped it reports an imported catalog as empty. `GET /products/attribute-schema` answers, per field, the exact path a value belongs at (`storage.path`) and that full fallback order (`from`), so no client has to re-derive any of this.\n\nThe value itself is whatever the attribute's `type` implies: a string, a number, a boolean, an option CODE for a select (never its label), a list of codes for a multi-select, `{\"amount\": …, \"unit\": …}` for a measure, a list of `{\"amount\": …, \"currency\": …}` for a price, an asset code for media.\n\nDefaults to `{}`, and an empty object is a normal state — a record nobody has enriched yet. The declared type also admits an array only because every jsonb column of this app shares one mapping; an array is not meaningful here and every reader in this app treats a non-object as empty.\n * @param {object} params.completeness - How much of what this product's family REQUIRES it actually carries — the number a merchandiser works down. `required` counts the attributes the family marks `is_required`, `filled` how many of those carry a value in ANY bucket, `ratio` is filled/required between 0 and 1 (a family that requires nothing is 1, not undefined), `missing` lists the codes with no value anywhere, sorted, and `computed_at` is when it was measured.\n\nWritten only by `POST /products/{id}/completeness` and by `POST /products/{id}/family`; a plain create or update never touches it, so it is null until one of the two has run. It also stays null for a product with no family — there is nothing to measure it against, and 0 % would be a lie.\n * @param {string} params.deletedAt - When the product was soft-deleted. `GET /products/grid` and every category-rule evaluation exclude a row that carries one; `GET /products` does NOT — filter on it to read the live catalog.\n * @param {boolean} params.enabled - Whether the product is offered. A create defaults it from the `new_products_enabled_by_default` tenant setting rather than blindly to true, so an import does not publish twenty thousand unfinished products the moment it lands. An explicit value in the body always wins.\n * @param {string} params.familyId - The family that decides which attributes this product HAS. Without one nothing is required, completeness cannot be computed and the display name never resolves — `POST /products/{id}/family` is the call that sets it and computes completeness in the same step.\n * @param {string} params.familyVariantId - Which variant structure of the family this product follows — the axes it splits on. Null on a simple product.\n * @param {ProductsKind} params.kind - Where the product sits in the variant hierarchy. 'simple' stands on its own. 'model' carries the values its variants share and is never sold itself. 'variant' carries the axis values and points at its model through `parent_id`.\n * @param {string} params.parentId - The product MODEL this variant belongs to. Only a `variant` carries one. Deleting the model leaves its variants behind with a null parent rather than deleting them.\n * @param {object} params.quantifiedAssociations - The import-side mirror of associations that carry a quantity — a bundle, a bill of materials, a spare-parts set. NOTHING IN THIS APP READS OR WRITES IT: no route produces it, no route consumes it, and it is null on every product this app has created. The surface that IS served is relational — `product_associations`, whose `quantity` column holds the number, guarded by `association_types.is_quantified`.\n\nIt exists because a PIM import (Akeneo, BMEcat) carries these in one blob keyed by association type code, and the column lets that document round-trip instead of being dropped. The database enforces no shape on it, so what a reader finds is whatever the importer wrote; the example is the conventional form.\n * @param {string} params.taxClass - The tax class key the prices app resolves a VAT rate from. Free text here — the vocabulary belongs to the app that prices, and `POST /products/batch` exists to hand exactly this column to it in bulk.\n * @throws {RevenexxException}\n * @returns {Promise<Models.Error>}\n */\n productsCreate(params: { sku: string, attributeValues?: object, completeness?: object, deletedAt?: string, enabled?: boolean, familyId?: string, familyVariantId?: string, kind?: ProductsKind, parentId?: string, quantifiedAssociations?: object, taxClass?: string }): Promise<Models.Error>;\n /**\n * Creates one product and answers 201 with the stored row, including the id and the timestamps the database filled in — a client never sends an id, it reads one back and uses it in the path of every later call.\n * \n * The catalog itself. A product row carries only what every product has — SKU, kind, family, enabled, tax class — and everything the tenant modelled lives in the `attribute_values` jsonb document, keyed by attribute CODE inside one of four scope buckets (common, per locale, per channel, per channel and locale). `label` is a generated column, maintained by the database so a grid of twenty thousand rows can sort and filter on a name with no join. `kind` says where the row sits in the variant hierarchy: a `model` carries what its variants share and is never sold itself.\n * \n * `sku` is the only column the database refuses the row without; everything else has a default or is nullable. A second row with the same `sku` answers 409. This app owns the create: `enabled` defaults from the `new_products_enabled_by_default` tenant setting rather than blindly to true, so an import cannot publish twenty thousand unfinished products the moment it lands, and a product that names no family gets the `default_product_family` one. An explicit value in the body always wins over both.\n *\n * @param {string} sku - The merchant's own article number — unique per tenant, and the value every integration (ERP, shop, feed, price list) joins on. The one identifier a person types, and the fallback this app shows when the catalog holds no name.\n * @param {object} attributeValues - Every attribute value the record carries, in ONE jsonb document — the core of an attribute-driven PIM. A record's properties are not columns here: they are rows in `attributes`, selected per family by `family_attributes`, and their values live under their attribute CODE inside this object.\n\nFour buckets, and an attribute's own flags decide which one it writes to:\n\n `common` the attribute is neither localizable nor scopable — one value, full stop.\n `{\"common\": {\"net_weight\": 2.4, \"colour\": \"black\"}}`\n `locale_specific` `localizable`: one value per language tag.\n `{\"locale_specific\": {\"de_DE\": {\"name\": \"Akku-Bohrschrauber\"}}}`\n `channel_specific` `scopable`: one value per channel.\n `{\"channel_specific\": {\"b2b\": {\"minimum_order_quantity\": 6}}}`\n `channel_locale_specific` both: one value per channel AND language tag.\n `{\"channel_locale_specific\": {\"b2b\": {\"de_DE\": {\"description\": \"…\"}}}}`\n\nA reader takes the most specific bucket that carries the code and falls back through locale, then channel, then `common`. `common` is always last and always consulted, because early imports wrote everything there whatever an attribute's flags said — a reader that skipped it reports an imported catalog as empty. `GET /products/attribute-schema` answers, per field, the exact path a value belongs at (`storage.path`) and that full fallback order (`from`), so no client has to re-derive any of this.\n\nThe value itself is whatever the attribute's `type` implies: a string, a number, a boolean, an option CODE for a select (never its label), a list of codes for a multi-select, `{\"amount\": …, \"unit\": …}` for a measure, a list of `{\"amount\": …, \"currency\": …}` for a price, an asset code for media.\n\nDefaults to `{}`, and an empty object is a normal state — a record nobody has enriched yet. The declared type also admits an array only because every jsonb column of this app shares one mapping; an array is not meaningful here and every reader in this app treats a non-object as empty.\n * @param {object} completeness - How much of what this product's family REQUIRES it actually carries — the number a merchandiser works down. `required` counts the attributes the family marks `is_required`, `filled` how many of those carry a value in ANY bucket, `ratio` is filled/required between 0 and 1 (a family that requires nothing is 1, not undefined), `missing` lists the codes with no value anywhere, sorted, and `computed_at` is when it was measured.\n\nWritten only by `POST /products/{id}/completeness` and by `POST /products/{id}/family`; a plain create or update never touches it, so it is null until one of the two has run. It also stays null for a product with no family — there is nothing to measure it against, and 0 % would be a lie.\n * @param {string} deletedAt - When the product was soft-deleted. `GET /products/grid` and every category-rule evaluation exclude a row that carries one; `GET /products` does NOT — filter on it to read the live catalog.\n * @param {boolean} enabled - Whether the product is offered. A create defaults it from the `new_products_enabled_by_default` tenant setting rather than blindly to true, so an import does not publish twenty thousand unfinished products the moment it lands. An explicit value in the body always wins.\n * @param {string} familyId - The family that decides which attributes this product HAS. Without one nothing is required, completeness cannot be computed and the display name never resolves — `POST /products/{id}/family` is the call that sets it and computes completeness in the same step.\n * @param {string} familyVariantId - Which variant structure of the family this product follows — the axes it splits on. Null on a simple product.\n * @param {ProductsKind} kind - Where the product sits in the variant hierarchy. 'simple' stands on its own. 'model' carries the values its variants share and is never sold itself. 'variant' carries the axis values and points at its model through `parent_id`.\n * @param {string} parentId - The product MODEL this variant belongs to. Only a `variant` carries one. Deleting the model leaves its variants behind with a null parent rather than deleting them.\n * @param {object} quantifiedAssociations - The import-side mirror of associations that carry a quantity — a bundle, a bill of materials, a spare-parts set. NOTHING IN THIS APP READS OR WRITES IT: no route produces it, no route consumes it, and it is null on every product this app has created. The surface that IS served is relational — `product_associations`, whose `quantity` column holds the number, guarded by `association_types.is_quantified`.\n\nIt exists because a PIM import (Akeneo, BMEcat) carries these in one blob keyed by association type code, and the column lets that document round-trip instead of being dropped. The database enforces no shape on it, so what a reader finds is whatever the importer wrote; the example is the conventional form.\n * @param {string} taxClass - The tax class key the prices app resolves a VAT rate from. Free text here — the vocabulary belongs to the app that prices, and `POST /products/batch` exists to hand exactly this column to it in bulk.\n * @throws {RevenexxException}\n * @returns {Promise<Models.Error>}\n * @deprecated Use the object parameter style method for a better developer experience.\n */\n productsCreate(sku: string, attributeValues?: object, completeness?: object, deletedAt?: string, enabled?: boolean, familyId?: string, familyVariantId?: string, kind?: ProductsKind, parentId?: string, quantifiedAssociations?: object, taxClass?: string): Promise<Models.Error>;\n productsCreate(\n paramsOrFirst: { sku: string, attributeValues?: object, completeness?: object, deletedAt?: string, enabled?: boolean, familyId?: string, familyVariantId?: string, kind?: ProductsKind, parentId?: string, quantifiedAssociations?: object, taxClass?: string } | string,\n ...rest: [(object)?, (object)?, (string)?, (boolean)?, (string)?, (string)?, (ProductsKind)?, (string)?, (object)?, (string)?] \n ): Promise<Models.Error> {\n let params: { sku: string, attributeValues?: object, completeness?: object, deletedAt?: string, enabled?: boolean, familyId?: string, familyVariantId?: string, kind?: ProductsKind, parentId?: string, quantifiedAssociations?: object, taxClass?: string };\n \n if ((paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst))) {\n params = (paramsOrFirst || {}) as { sku: string, attributeValues?: object, completeness?: object, deletedAt?: string, enabled?: boolean, familyId?: string, familyVariantId?: string, kind?: ProductsKind, parentId?: string, quantifiedAssociations?: object, taxClass?: string };\n } else {\n params = {\n sku: paramsOrFirst as string,\n attributeValues: rest[0] as object,\n completeness: rest[1] as object,\n deletedAt: rest[2] as string,\n enabled: rest[3] as boolean,\n familyId: rest[4] as string,\n familyVariantId: rest[5] as string,\n kind: rest[6] as ProductsKind,\n parentId: rest[7] as string,\n quantifiedAssociations: rest[8] as object,\n taxClass: rest[9] as string \n };\n }\n \n const sku = params.sku;\n const attributeValues = params.attributeValues;\n const completeness = params.completeness;\n const deletedAt = params.deletedAt;\n const enabled = params.enabled;\n const familyId = params.familyId;\n const familyVariantId = params.familyVariantId;\n const kind = params.kind;\n const parentId = params.parentId;\n const quantifiedAssociations = params.quantifiedAssociations;\n const taxClass = params.taxClass;\n\n if (typeof sku === 'undefined') {\n throw new RevenexxException('Missing required parameter: \"sku\"');\n }\n\n const apiPath = '/v1/products';\n const apiPayload: Payload = {};\n if (typeof attributeValues !== 'undefined') {\n apiPayload['attribute_values'] = attributeValues;\n }\n if (typeof completeness !== 'undefined') {\n apiPayload['completeness'] = completeness;\n }\n if (typeof deletedAt !== 'undefined') {\n apiPayload['deleted_at'] = deletedAt;\n }\n if (typeof enabled !== 'undefined') {\n apiPayload['enabled'] = enabled;\n }\n if (typeof familyId !== 'undefined') {\n apiPayload['family_id'] = familyId;\n }\n if (typeof familyVariantId !== 'undefined') {\n apiPayload['family_variant_id'] = familyVariantId;\n }\n if (typeof kind !== 'undefined') {\n apiPayload['kind'] = kind;\n }\n if (typeof parentId !== 'undefined') {\n apiPayload['parent_id'] = parentId;\n }\n if (typeof quantifiedAssociations !== 'undefined') {\n apiPayload['quantified_associations'] = quantifiedAssociations;\n }\n if (typeof sku !== 'undefined') {\n apiPayload['sku'] = sku;\n }\n if (typeof taxClass !== 'undefined') {\n apiPayload['tax_class'] = taxClass;\n }\n const uri = new URL(this.client.config.endpoint + apiPath);\n\n const apiHeaders: { [header: string]: string } = {\n 'content-type': 'application/json',\n }\n\n return this.client.call(\n 'post',\n uri,\n apiHeaders,\n apiPayload,\n );\n }\n\n /**\n * Answers four fields — id, sku, tax_class and the resolved display name — for a list of ids and/or SKUs in ONE call. It exists for the app on the other side of a product reference: the prices app holds SKUs and needs a tax class, a feed builder holds ids and needs names, and neither should page through the catalog or fire a request per line. Ask by either identifier or both; the two are unioned and a product named twice comes back once.\n * \n * It answers what it FOUND: an id or SKU that names nothing is simply absent from `items` rather than an error, so compare the length of what you sent with what came back if a miss matters. It is not a general product read — for the whole row use `GET /products/{id}`, and for a scannable list use `GET /products/grid`.\n *\n * @param {string[]} params.ids - Product ids, when the caller already holds them.\n * @param {string[]} params.skus - Product SKUs — the identifier a foreign system carries, which is why this route exists at all.\n * @throws {RevenexxException}\n * @returns {Promise<{}>}\n */\n productsBatch(params?: { ids?: string[], skus?: string[] }): Promise<{}>;\n /**\n * Answers four fields — id, sku, tax_class and the resolved display name — for a list of ids and/or SKUs in ONE call. It exists for the app on the other side of a product reference: the prices app holds SKUs and needs a tax class, a feed builder holds ids and needs names, and neither should page through the catalog or fire a request per line. Ask by either identifier or both; the two are unioned and a product named twice comes back once.\n * \n * It answers what it FOUND: an id or SKU that names nothing is simply absent from `items` rather than an error, so compare the length of what you sent with what came back if a miss matters. It is not a general product read — for the whole row use `GET /products/{id}`, and for a scannable list use `GET /products/grid`.\n *\n * @param {string[]} ids - Product ids, when the caller already holds them.\n * @param {string[]} skus - Product SKUs — the identifier a foreign system carries, which is why this route exists at all.\n * @throws {RevenexxException}\n * @returns {Promise<{}>}\n * @deprecated Use the object parameter style method for a better developer experience.\n */\n productsBatch(ids?: string[], skus?: string[]): Promise<{}>;\n productsBatch(\n paramsOrFirst?: { ids?: string[], skus?: string[] } | string[],\n ...rest: [(string[])?] \n ): Promise<{}> {\n let params: { ids?: string[], skus?: string[] };\n \n if (!paramsOrFirst || (paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst))) {\n params = (paramsOrFirst || {}) as { ids?: string[], skus?: string[] };\n } else {\n params = {\n ids: paramsOrFirst as string[],\n skus: rest[0] as string[] \n };\n }\n \n const ids = params.ids;\n const skus = params.skus;\n\n\n const apiPath = '/v1/products/batch';\n const apiPayload: Payload = {};\n if (typeof ids !== 'undefined') {\n apiPayload['ids'] = ids;\n }\n if (typeof skus !== 'undefined') {\n apiPayload['skus'] = skus;\n }\n const uri = new URL(this.client.config.endpoint + apiPath);\n\n const apiHeaders: { [header: string]: string } = {\n 'content-type': 'application/json',\n }\n\n return this.client.call(\n 'post',\n uri,\n apiHeaders,\n apiPayload,\n );\n }\n\n /**\n * The list a merchant can actually scan, as opposed to `GET /products`, which answers SKUs and a jsonb blob. Every row arrives already flattened: its resolved display name and where that name came from, its family code, its stored completeness, and the value of every attribute the catalog marks `usable_in_grid` — no join, no second call. `q` is a case-insensitive substring of the stored `label` column, which falls back to the SKU, so one box finds a product by either. Soft-deleted products are excluded here, unlike `GET /products`.\n * \n * It filters on `q`, `kind`, `enabled` and `family_id`, and on NOTHING ELSE — a query parameter it does not accept is refused with 400 rather than dropped. That matters because of `filters`: the array reports the attributes marked `is_filterable`, which is what a filter bar should OFFER, and it is not a query surface. Filtering on an attribute value is not offered by this API at all — the values live inside a four-bucket jsonb document and are read through a fallback chain, so it is a feature with a design of its own rather than a parameter that was forgotten.\n *\n * @param {number} params.limit - Page size (default 50, max 200). A larger value is clamped rather than refused.\n * @param {number} params.offset - Row offset for pagination (default 0). Page with `page.total` and `page.hasMore`.\n * @param {string} params.order - Sort by one column: 'column' | 'column.asc' | 'column.desc'. A bare column sorts ascending. Anything else is refused with 400.\n * @param {string} params.q - Case-insensitive substring of the display name (or the SKU, when there is no name).\n * @param {Kind} params.kind - Restrict to one product kind.\n * @param {boolean} params.enabled - Restrict to enabled or disabled products.\n * @param {string} params.familyId - Restrict to one family. A family id that does not exist is not an error here — it simply matches nothing.\n * @throws {RevenexxException}\n * @returns {Promise<Models.Error>}\n */\n productsGrid(params?: { limit?: number, offset?: number, order?: string, q?: string, kind?: Kind, enabled?: boolean, familyId?: string }): Promise<Models.Error>;\n /**\n * The list a merchant can actually scan, as opposed to `GET /products`, which answers SKUs and a jsonb blob. Every row arrives already flattened: its resolved display name and where that name came from, its family code, its stored completeness, and the value of every attribute the catalog marks `usable_in_grid` — no join, no second call. `q` is a case-insensitive substring of the stored `label` column, which falls back to the SKU, so one box finds a product by either. Soft-deleted products are excluded here, unlike `GET /products`.\n * \n * It filters on `q`, `kind`, `enabled` and `family_id`, and on NOTHING ELSE — a query parameter it does not accept is refused with 400 rather than dropped. That matters because of `filters`: the array reports the attributes marked `is_filterable`, which is what a filter bar should OFFER, and it is not a query surface. Filtering on an attribute value is not offered by this API at all — the values live inside a four-bucket jsonb document and are read through a fallback chain, so it is a feature with a design of its own rather than a parameter that was forgotten.\n *\n * @param {number} limit - Page size (default 50, max 200). A larger value is clamped rather than refused.\n * @param {number} offset - Row offset for pagination (default 0). Page with `page.total` and `page.hasMore`.\n * @param {string} order - Sort by one column: 'column' | 'column.asc' | 'column.desc'. A bare column sorts ascending. Anything else is refused with 400.\n * @param {string} q - Case-insensitive substring of the display name (or the SKU, when there is no name).\n * @param {Kind} kind - Restrict to one product kind.\n * @param {boolean} enabled - Restrict to enabled or disabled products.\n * @param {string} familyId - Restrict to one family. A family id that does not exist is not an error here — it simply matches nothing.\n * @throws {RevenexxException}\n * @returns {Promise<Models.Error>}\n * @deprecated Use the object parameter style method for a better developer experience.\n */\n productsGrid(limit?: number, offset?: number, order?: string, q?: string, kind?: Kind, enabled?: boolean, familyId?: string): Promise<Models.Error>;\n productsGrid(\n paramsOrFirst?: { limit?: number, offset?: number, order?: string, q?: string, kind?: Kind, enabled?: boolean, familyId?: string } | number,\n ...rest: [(number)?, (string)?, (string)?, (Kind)?, (boolean)?, (string)?] \n ): Promise<Models.Error> {\n let params: { limit?: number, offset?: number, order?: string, q?: string, kind?: Kind, enabled?: boolean, familyId?: string };\n \n if (!paramsOrFirst || (paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst))) {\n params = (paramsOrFirst || {}) as { limit?: number, offset?: number, order?: string, q?: string, kind?: Kind, enabled?: boolean, familyId?: string };\n } else {\n params = {\n limit: paramsOrFirst as number,\n offset: rest[0] as number,\n order: rest[1] as string,\n q: rest[2] as string,\n kind: rest[3] as Kind,\n enabled: rest[4] as boolean,\n familyId: rest[5] as string \n };\n }\n \n const limit = params.limit;\n const offset = params.offset;\n const order = params.order;\n const q = params.q;\n const kind = params.kind;\n const enabled = params.enabled;\n const familyId = params.familyId;\n\n\n const apiPath = '/v1/products/grid';\n const apiPayload: Payload = {};\n if (typeof limit !== 'undefined') {\n apiPayload['limit'] = limit;\n }\n if (typeof offset !== 'undefined') {\n apiPayload['offset'] = offset;\n }\n if (typeof order !== 'undefined') {\n apiPayload['order'] = order;\n }\n if (typeof q !== 'undefined') {\n apiPayload['q'] = q;\n }\n if (typeof kind !== 'undefined') {\n apiPayload['kind'] = kind;\n }\n if (typeof enabled !== 'undefined') {\n apiPayload['enabled'] = enabled;\n }\n if (typeof familyId !== 'undefined') {\n apiPayload['family_id'] = familyId;\n }\n const uri = new URL(this.client.config.endpoint + apiPath);\n\n const apiHeaders: { [header: string]: string } = {\n }\n\n return this.client.call(\n 'get',\n uri,\n apiHeaders,\n apiPayload,\n );\n }\n\n /**\n * What is this product CALLED? A product's name is an attribute rather than a column, and which attribute it is, is per family — so no plain read can answer it. This resolves up to 500 products at once, by id and/or SKU: it reads families.label_attribute (falling back to the default_label_attribute setting, then to the conventional `name`) and looks the value up through the scoped attribute_values document — common, then locale_specific in the label_locales order, then the channel buckets.\n * \n * It reports WHERE the name was found, which is the half that matters: `source: \"sku\"` means the catalog holds no name for this product and the SKU is standing in for one, so show it as a missing name rather than as a name. Writes nothing, and answers only what it found.\n *\n * @param {string[]} params.ids - Product ids to name. At most 500.\n * @param {string[]} params.skus - Product SKUs to name. At most 500.\n * @throws {RevenexxException}\n * @returns {Promise<Models.Error>}\n */\n productsLabels(params?: { ids?: string[], skus?: string[] }): Promise<Models.Error>;\n /**\n * What is this product CALLED? A product's name is an attribute rather than a column, and which attribute it is, is per family — so no plain read can answer it. This resolves up to 500 products at once, by id and/or SKU: it reads families.label_attribute (falling back to the default_label_attribute setting, then to the conventional `name`) and looks the value up through the scoped attribute_values document — common, then locale_specific in the label_locales order, then the channel buckets.\n * \n * It reports WHERE the name was found, which is the half that matters: `source: \"sku\"` means the catalog holds no name for this product and the SKU is standing in for one, so show it as a missing name rather than as a name. Writes nothing, and answers only what it found.\n *\n * @param {string[]} ids - Product ids to name. At most 500.\n * @param {string[]} skus - Product SKUs to name. At most 500.\n * @throws {RevenexxException}\n * @returns {Promise<Models.Error>}\n * @deprecated Use the object parameter style method for a better developer experience.\n */\n productsLabels(ids?: string[], skus?: string[]): Promise<Models.Error>;\n productsLabels(\n paramsOrFirst?: { ids?: string[], skus?: string[] } | string[],\n ...rest: [(string[])?] \n ): Promise<Models.Error> {\n let params: { ids?: string[], skus?: string[] };\n \n if (!paramsOrFirst || (paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst))) {\n params = (paramsOrFirst || {}) as { ids?: string[], skus?: string[] };\n } else {\n params = {\n ids: paramsOrFirst as string[],\n skus: rest[0] as string[] \n };\n }\n \n const ids = params.ids;\n const skus = params.skus;\n\n\n const apiPath = '/v1/products/labels';\n const apiPayload: Payload = {};\n if (typeof ids !== 'undefined') {\n apiPayload['ids'] = ids;\n }\n if (typeof skus !== 'undefined') {\n apiPayload['skus'] = skus;\n }\n const uri = new URL(this.client.config.endpoint + apiPath);\n\n const apiHeaders: { [header: string]: string } = {\n 'content-type': 'application/json',\n }\n\n return this.client.call(\n 'post',\n uri,\n apiHeaders,\n apiPayload,\n );\n }\n\n /**\n * One relation from one product to another, of a declared type: this drill's accessories, this bundle's parts, this article's cross-sells. `quantity` is the number in \"this bundle contains 4 casters\" and is meaningful only when the association type carries `is_quantified`. This relational surface is the one this app serves; the `products.quantified_associations` column is an importer's blob that no route here reads or writes.\n * \n * Every column of `product_associations` is an exact-match query parameter, `order` sorts by one column, and `limit`/`offset` page through `page.total`. A query key that is NOT a column is dropped rather than refused, and the `filter` object echoes the ones that were understood — that echo is the only way to tell an unfiltered answer from an empty one. It reads rows exactly as they are stored: no join is resolved, no jsonb value is unpacked.\n * \n * Answered from the gateway's tenant cache for up to 30 minutes and dropped the moment this entity is written, because the data model changes weekly at most and every product page asks the same question.\n *\n * @param {number} params.limit - Page size (default 50, max 200). A larger value is clamped rather than refused.\n * @param {number} params.offset - Row offset for pagination (default 0). Page with `page.total` and `page.hasMore`.\n * @param {string} params.order - Sort by one column: 'column' | 'column.asc' | 'column.desc'. A bare column sorts ascending. Anything else is refused with 400.\n * @param {string} params.id - Exact match on `id`. The row's own id, generated by the database. A client never sends one; it reads one back and uses it in the path of every later call.\n * @param {string} params.productId - Exact match on `product_id`. The product the relation starts at — the one whose detail page shows it.\n * @param {string} params.associationTypeId - Exact match on `association_type_id`. Which kind of relation this is — the `association_types` row.\n * @param {string} params.targetProductId - Exact match on `target_product_id`. The product the relation points at — the accessory, the spare part, the cross-sell.\n * @param {number} params.quantity - Exact match on `quantity`. How many of the target belong to the source — the 4 in \"this bundle contains 4 casters\". Only meaningful when the association type carries `is_quantified`; null on an ordinary cross-sell.\n * @param {number} params.position - Exact match on `position`. Order in which the targets are shown, ascending.\n * @param {string} params.createdAt - Exact match on `created_at`. When the row was created. Server-set — it is not part of any request body.\n * @throws {RevenexxException}\n * @returns {Promise<{}>}\n */\n productsProductAssociationsList(params?: { limit?: number, offset?: number, order?: string, id?: string, productId?: string, associationTypeId?: string, targetProductId?: string, quantity?: number, position?: number, createdAt?: string }): Promise<{}>;\n /**\n * One relation from one product to another, of a declared type: this drill's accessories, this bundle's parts, this article's cross-sells. `quantity` is the number in \"this bundle contains 4 casters\" and is meaningful only when the association type carries `is_quantified`. This relational surface is the one this app serves; the `products.quantified_associations` column is an importer's blob that no route here reads or writes.\n * \n * Every column of `product_associations` is an exact-match query parameter, `order` sorts by one column, and `limit`/`offset` page through `page.total`. A query key that is NOT a column is dropped rather than refused, and the `filter` object echoes the ones that were understood — that echo is the only way to tell an unfiltered answer from an empty one. It reads rows exactly as they are stored: no join is resolved, no jsonb value is unpacked.\n * \n * Answered from the gateway's tenant cache for up to 30 minutes and dropped the moment this entity is written, because the data model changes weekly at most and every product page asks the same question.\n *\n * @param {number} limit - Page size (default 50, max 200). A larger value is clamped rather than refused.\n * @param {number} offset - Row offset for pagination (default 0). Page with `page.total` and `page.hasMore`.\n * @param {string} order - Sort by one column: 'column' | 'column.asc' | 'column.desc'. A bare column sorts ascending. Anything else is refused with 400.\n * @param {string} id - Exact match on `id`. The row's own id, generated by the database. A client never sends one; it reads one back and uses it in the path of every later call.\n * @param {string} productId - Exact match on `product_id`. The product the relation starts at — the one whose detail page shows it.\n * @param {string} associationTypeId - Exact match on `association_type_id`. Which kind of relation this is — the `association_types` row.\n * @param {string} targetProductId - Exact match on `target_product_id`. The product the relation points at — the accessory, the spare part, the cross-sell.\n * @param {number} quantity - Exact match on `quantity`. How many of the target belong to the source — the 4 in \"this bundle contains 4 casters\". Only meaningful when the association type carries `is_quantified`; null on an ordinary cross-sell.\n * @param {number} position - Exact match on `position`. Order in which the targets are shown, ascending.\n * @param {string} createdAt - Exact match on `created_at`. When the row was created. Server-set — it is not part of any request body.\n * @throws {RevenexxException}\n * @returns {Promise<{}>}\n * @deprecated Use the object parameter style method for a better developer experience.\n */\n productsProductAssociationsList(limit?: number, offset?: number, order?: string, id?: string, productId?: string, associationTypeId?: string, targetProductId?: string, quantity?: number, position?: number, createdAt?: string): Promise<{}>;\n productsProductAssociationsList(\n paramsOrFirst?: { limit?: number, offset?: number, order?: string, id?: string, productId?: string, associationTypeId?: string, targetProductId?: string, quantity?: number, position?: number, createdAt?: string } | number,\n ...rest: [(number)?, (string)?, (string)?, (string)?, (string)?, (string)?, (number)?, (number)?, (string)?] \n ): Promise<{}> {\n let params: { limit?: number, offset?: number, order?: string, id?: string, productId?: string, associationTypeId?: string, targetProductId?: string, quantity?: number, position?: number, createdAt?: string };\n \n if (!paramsOrFirst || (paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst))) {\n params = (paramsOrFirst || {}) as { limit?: number, offset?: number, order?: string, id?: string, productId?: string, associationTypeId?: string, targetProductId?: string, quantity?: number, position?: number, createdAt?: string };\n } else {\n params = {\n limit: paramsOrFirst as number,\n offset: rest[0] as number,\n order: rest[1] as string,\n id: rest[2] as string,\n productId: rest[3] as string,\n associationTypeId: rest[4] as string,\n targetProductId: rest[5] as string,\n quantity: rest[6] as number,\n position: rest[7] as number,\n createdAt: rest[8] as string \n };\n }\n \n const limit = params.limit;\n const offset = params.offset;\n const order = params.order;\n const id = params.id;\n const productId = params.productId;\n const associationTypeId = params.associationTypeId;\n const targetProductId = params.targetProductId;\n const quantity = params.quantity;\n const position = params.position;\n const createdAt = params.createdAt;\n\n\n const apiPath = '/v1/products/product_associations';\n const apiPayload: Payload = {};\n if (typeof limit !== 'undefined') {\n apiPayload['limit'] = limit;\n }\n if (typeof offset !== 'undefined') {\n apiPayload['offset'] = offset;\n }\n if (typeof order !== 'undefined') {\n apiPayload['order'] = order;\n }\n if (typeof id !== 'undefined') {\n apiPayload['id'] = id;\n }\n if (typeof productId !== 'undefined') {\n apiPayload['product_id'] = productId;\n }\n if (typeof associationTypeId !== 'undefined') {\n apiPayload['association_type_id'] = associationTypeId;\n }\n if (typeof targetProductId !== 'undefined') {\n apiPayload['target_product_id'] = targetProductId;\n }\n if (typeof quantity !== 'undefined') {\n apiPayload['quantity'] = quantity;\n }\n if (typeof position !== 'undefined') {\n apiPayload['position'] = position;\n }\n if (typeof createdAt !== 'undefined') {\n apiPayload['created_at'] = createdAt;\n }\n const uri = new URL(this.client.config.endpoint + apiPath);\n\n const apiHeaders: { [header: string]: string } = {\n }\n\n return this.client.call(\n 'get',\n uri,\n apiHeaders,\n apiPayload,\n );\n }\n\n /**\n * Creates one product association and answers 201 with the stored row, including the id and the timestamps the database filled in — a client never sends an id, it reads one back and uses it in the path of every later call.\n * \n * One relation from one product to another, of a declared type: this drill's accessories, this bundle's parts, this article's cross-sells. `quantity` is the number in \"this bundle contains 4 casters\" and is meaningful only when the association type carries `is_quantified`. This relational surface is the one this app serves; the `products.quantified_associations` column is an importer's blob that no route here reads or writes.\n * \n * `product_id`, `association_type_id`, `target_product_id` are the only columns the database refuses the row without; everything else has a default or is nullable. A second row with the same `product_id`, `association_type_id`, `target_product_id` answers 409.\n *\n * @param {string} params.associationTypeId - Which kind of relation this is — the `association_types` row.\n * @param {string} params.productId - The product the relation starts at — the one whose detail page shows it.\n * @param {string} params.targetProductId - The product the relation points at — the accessory, the spare part, the cross-sell.\n * @param {number} params.position - Order in which the targets are shown, ascending.\n * @param {number} params.quantity - How many of the target belong to the source — the 4 in \"this bundle contains 4 casters\". Only meaningful when the association type carries `is_quantified`; null on an ordinary cross-sell.\n * @throws {RevenexxException}\n * @returns {Promise<Models.Error>}\n */\n productsProductAssociationsCreate(params: { associationTypeId: string, productId: string, targetProductId: string, position?: number, quantity?: number }): Promise<Models.Error>;\n /**\n * Creates one product association and answers 201 with the stored row, including the id and the timestamps the database filled in — a client never sends an id, it reads one back and uses it in the path of every later call.\n * \n * One relation from one product to another, of a declared type: this drill's accessories, this bundle's parts, this article's cross-sells. `quantity` is the number in \"this bundle contains 4 casters\" and is meaningful only when the association type carries `is_quantified`. This relational surface is the one this app serves; the `products.quantified_associations` column is an importer's blob that no route here reads or writes.\n * \n * `product_id`, `association_type_id`, `target_product_id` are the only columns the database refuses the row without; everything else has a default or is nullable. A second row with the same `product_id`, `association_type_id`, `target_product_id` answers 409.\n *\n * @param {string} associationTypeId - Which kind of relation this is — the `association_types` row.\n * @param {string} productId - The product the relation starts at — the one whose detail page shows it.\n * @param {string} targetProductId - The product the relation points at — the accessory, the spare part, the cross-sell.\n * @param {number} position - Order in which the targets are shown, ascending.\n * @param {number} quantity - How many of the target belong to the source — the 4 in \"this bundle contains 4 casters\". Only meaningful when the association type carries `is_quantified`; null on an ordinary cross-sell.\n * @throws {RevenexxException}\n * @returns {Promise<Models.Error>}\n * @deprecated Use the object parameter style method for a better developer experience.\n */\n productsProductAssociationsCreate(associationTypeId: string, productId: string, targetProductId: string, position?: number, quantity?: number): Promise<Models.Error>;\n productsProductAssociationsCreate(\n paramsOrFirst: { associationTypeId: string, productId: string, targetProductId: string, position?: number, quantity?: number } | string,\n ...rest: [(string)?, (string)?, (number)?, (number)?] \n ): Promise<Models.Error> {\n let params: { associationTypeId: string, productId: string, targetProductId: string, position?: number, quantity?: number };\n \n if ((paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst))) {\n params = (paramsOrFirst || {}) as { associationTypeId: string, productId: string, targetProductId: string, position?: number, quantity?: number };\n } else {\n params = {\n associationTypeId: paramsOrFirst as string,\n productId: rest[0] as string,\n targetProductId: rest[1] as string,\n position: rest[2] as number,\n quantity: rest[3] as number \n };\n }\n \n const associationTypeId = params.associationTypeId;\n const productId = params.productId;\n const targetProductId = params.targetProductId;\n const position = params.position;\n const quantity = params.quantity;\n\n if (typeof associationTypeId === 'undefined') {\n throw new RevenexxException('Missing required parameter: \"associationTypeId\"');\n }\n if (typeof productId === 'undefined') {\n throw new RevenexxException('Missing required parameter: \"productId\"');\n }\n if (typeof targetProductId === 'undefined') {\n throw new RevenexxException('Missing required parameter: \"targetProductId\"');\n }\n\n const apiPath = '/v1/products/product_associations';\n const apiPayload: Payload = {};\n if (typeof associationTypeId !== 'undefined') {\n apiPayload['association_type_id'] = associationTypeId;\n }\n if (typeof position !== 'undefined') {\n apiPayload['position'] = position;\n }\n if (typeof productId !== 'undefined') {\n apiPayload['product_id'] = productId;\n }\n if (typeof quantity !== 'undefined') {\n apiPayload['quantity'] = quantity;\n }\n if (typeof targetProductId !== 'undefined') {\n apiPayload['target_product_id'] = targetProductId;\n }\n const uri = new URL(this.client.config.endpoint + apiPath);\n\n const apiHeaders: { [header: string]: string } = {\n 'content-type': 'application/json',\n }\n\n return this.client.call(\n 'post',\n uri,\n apiHeaders,\n apiPayload,\n );\n }\n\n /**\n * Deletes one product association by id. It is a hard delete — the row is gone, and the answer is a confirmation rather than a result to branch on.\n * \n * Nothing in this schema references it, so nothing else changes.\n * \n * An id no product association of this tenant carries answers 404; there is no 409, because every foreign key pointing at this entity resolves itself on delete rather than blocking one.\n *\n * @param {string} params.id - The `product_associations` row to address, by id. It names a row THIS TENANT holds, so no example is published — a uuid this app invented would document a call that answers 404, and a real one would be another tenant's data. Read one from `GET /v1/products/product_associations`. An id no product association of this tenant carries answers 404; a malformed one answers 400 before the route is reached.\n * @throws {RevenexxException}\n * @returns {Promise<Models.Error>}\n */\n productsProductAssociationsDelete(params: { id: string }): Promise<Models.Error>;\n /**\n * Deletes one product association by id. It is a hard delete — the row is gone, and the answer is a confirmation rather than a result to branch on.\n * \n * Nothing in this schema references it, so nothing else changes.\n * \n * An id no product association of this tenant carries answers 404; there is no 409, because every foreign key pointing at this entity resolves itself on delete rather than blocking one.\n *\n * @param {string} id - The `product_associations` row to address, by id. It names a row THIS TENANT holds, so no example is published — a uuid this app invented would document a call that answers 404, and a real one would be another tenant's data. Read one from `GET /v1/products/product_associations`. An id no product association of this tenant carries answers 404; a malformed one answers 400 before the route is reached.\n * @throws {RevenexxException}\n * @returns {Promise<Models.Error>}\n * @deprecated Use the object parameter style method for a better developer experience.\n */\n productsProductAssociationsDelete(id: string): Promise<Models.Error>;\n productsProductAssociationsDelete(\n paramsOrFirst: { id: string } | string \n ): Promise<Models.Error> {\n let params: { id: string };\n \n if ((paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst))) {\n params = (paramsOrFirst || {}) as { id: string };\n } else {\n params = {\n id: paramsOrFirst as string \n };\n }\n \n const id = params.id;\n\n if (typeof id === 'undefined') {\n throw new RevenexxException('Missing required parameter: \"id\"');\n }\n\n const apiPath = '/v1/products/product_associations/{id}'.replace('{id}', id);\n const apiPayload: Payload = {};\n const uri = new URL(this.client.config.endpoint + apiPath);\n\n const apiHeaders: { [header: string]: string } = {\n }\n\n return this.client.call(\n 'delete',\n uri,\n apiHeaders,\n apiPayload,\n );\n }\n\n /**\n * Reads one product association by its id — the whole row, every column, as it is stored.\n * \n * One relation from one product to another, of a declared type: this drill's accessories, this bundle's parts, this article's cross-sells. `quantity` is the number in \"this bundle contains 4 casters\" and is meaningful only when the association type carries `is_quantified`. This relational surface is the one this app serves; the `products.quantified_associations` column is an importer's blob that no route here reads or writes.\n * \n * An id no product association of this tenant carries answers 404, and so does one belonging to another tenant: row-level security makes that row invisible rather than forbidden. A malformed id answers 400 before the route is reached.\n * \n * Answered from the gateway's tenant cache for up to 30 minutes and dropped the moment this entity is written, because the data model changes weekly at most and every product page asks the same question.\n *\n * @param {string} params.id - The `product_associations` row to address, by id. It names a row THIS TENANT holds, so no example is published — a uuid this app invented would document a call that answers 404, and a real one would be another tenant's data. Read one from `GET /v1/products/product_associations`. An id no product association of this tenant carries answers 404; a malformed one answers 400 before the route is reached.\n * @throws {RevenexxException}\n * @returns {Promise<Models.Error>}\n */\n productsProductAssociationsGet(params: { id: string }): Promise<Models.Error>;\n /**\n * Reads one product association by its id — the whole row, every column, as it is stored.\n * \n * One relation from one product to another, of a declared type: this drill's accessories, this bundle's parts, this article's cross-sells. `quantity` is the number in \"this bundle contains 4 casters\" and is meaningful only when the association type carries `is_quantified`. This relational surface is the one this app serves; the `products.quantified_associations` column is an importer's blob that no route here reads or writes.\n * \n * An id no product association of this tenant carries answers 404, and so does one belonging to another tenant: row-level security makes that row invisible rather than forbidden. A malformed id answers 400 before the route is reached.\n * \n * Answered from the gateway's tenant cache for up to 30 minutes and dropped the moment this entity is written, because the data model changes weekly at most and every product page asks the same question.\n *\n * @param {string} id - The `product_associations` row to address, by id. It names a row THIS TENANT holds, so no example is published — a uuid this app invented would document a call that answers 404, and a real one would be another tenant's data. Read one from `GET /v1/products/product_associations`. An id no product association of this tenant carries answers 404; a malformed one answers 400 before the route is reached.\n * @throws {RevenexxException}\n * @returns {Promise<Models.Error>}\n * @deprecated Use the object parameter style method for a better developer experience.\n */\n productsProductAssociationsGet(id: string): Promise<Models.Error>;\n productsProductAssociationsGet(\n paramsOrFirst: { id: string } | string \n ): Promise<Models.Error> {\n let params: { id: string };\n \n if ((paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst))) {\n params = (paramsOrFirst || {}) as { id: string };\n } else {\n params = {\n id: paramsOrFirst as string \n };\n }\n \n const id = params.id;\n\n if (typeof id === 'undefined') {\n throw new RevenexxException('Missing required parameter: \"id\"');\n }\n\n const apiPath = '/v1/products/product_associations/{id}'.replace('{id}', id);\n const apiPayload: Payload = {};\n const uri = new URL(this.client.config.endpoint + apiPath);\n\n const apiHeaders: { [header: string]: string } = {\n }\n\n return this.client.call(\n 'get',\n uri,\n apiHeaders,\n apiPayload,\n );\n }\n\n /**\n * Updates one product association by id. A partial patch: the body names only the columns to change and every column it leaves out keeps its current value, so there is no read-modify-write and no way to blank a field by forgetting it.\n * \n * One relation from one product to another, of a declared type: this drill's accessories, this bundle's parts, this article's cross-sells. `quantity` is the number in \"this bundle contains 4 casters\" and is meaningful only when the association type carries `is_quantified`. This relational surface is the one this app serves; the `products.quantified_associations` column is an importer's blob that no route here reads or writes.\n * \n * A body that names nothing writable is refused with 400 rather than answered as a no-op, an id nobody carries answers 404, and a value that collides on `product_id`, `association_type_id`, `target_product_id` answers 409.\n *\n * @param {string} params.id - The `product_associations` row to address, by id. It names a row THIS TENANT holds, so no example is published — a uuid this app invented would document a call that answers 404, and a real one would be another tenant's data. Read one from `GET /v1/products/product_associations`. An id no product association of this tenant carries answers 404; a malformed one answers 400 before the route is reached.\n * @param {string} params.associationTypeId - Which kind of relation this is — the `association_types` row.\n * @param {number} params.position - Order in which the targets are shown, ascending.\n * @param {string} params.productId - The product the relation starts at — the one whose detail page shows it.\n * @param {number} params.quantity - How many of the target belong to the source — the 4 in \"this bundle contains 4 casters\". Only meaningful when the association type carries `is_quantified`; null on an ordinary cross-sell.\n * @param {string} params.targetProductId - The product the relation points at — the accessory, the spare part, the cross-sell.\n * @throws {RevenexxException}\n * @returns {Promise<Models.Error>}\n */\n productsProductAssociationsUpdate(params: { id: string, associationTypeId?: string, position?: number, productId?: string, quantity?: number, targetProductId?: string }): Promise<Models.Error>;\n /**\n * Updates one product association by id. A partial patch: the body names only the columns to change and every column it leaves out keeps its current value, so there is no read-modify-write and no way to blank a field by forgetting it.\n * \n * One relation from one product to another, of a declared type: this drill's accessories, this bundle's parts, this article's cross-sells. `quantity` is the number in \"this bundle contains 4 casters\" and is meaningful only when the association type carries `is_quantified`. This relational surface is the one this app serves; the `products.quantified_associations` column is an importer's blob that no route here reads or writes.\n * \n * A body that names nothing writable is refused with 400 rather than answered as a no-op, an id nobody carries answers 404, and a value that collides on `product_id`, `association_type_id`, `target_product_id` answers 409.\n *\n * @param {string} id - The `product_associations` row to address, by id. It names a row THIS TENANT holds, so no example is published — a uuid this app invented would document a call that answers 404, and a real one would be another tenant's data. Read one from `GET /v1/products/product_associations`. An id no product association of this tenant carries answers 404; a malformed one answers 400 before the route is reached.\n * @param {string} associationTypeId - Which kind of relation this is — the `association_types` row.\n * @param {number} position - Order in which the targets are shown, ascending.\n * @param {string} productId - The product the relation starts at — the one whose detail page shows it.\n * @param {number} quantity - How many of the target belong to the source — the 4 in \"this bundle contains 4 casters\". Only meaningful when the association type carries `is_quantified`; null on an ordinary cross-sell.\n * @param {string} targetProductId - The product the relation points at — the accessory, the spare part, the cross-sell.\n * @throws {RevenexxException}\n * @returns {Promise<Models.Error>}\n * @deprecated Use the object parameter style method for a better developer experience.\n */\n productsProductAssociationsUpdate(id: string, associationTypeId?: string, position?: number, productId?: string, quantity?: number, targetProductId?: string): Promise<Models.Error>;\n productsProductAssociationsUpdate(\n paramsOrFirst: { id: string, associationTypeId?: string, position?: number, productId?: string, quantity?: number, targetProductId?: string } | string,\n ...rest: [(string)?, (number)?, (string)?, (number)?, (string)?] \n ): Promise<Models.Error> {\n let params: { id: string, associationTypeId?: string, position?: number, productId?: string, quantity?: number, targetProductId?: string };\n \n if ((paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst))) {\n params = (paramsOrFirst || {}) as { id: string, associationTypeId?: string, position?: number, productId?: string, quantity?: number, targetProductId?: string };\n } else {\n params = {\n id: paramsOrFirst as string,\n associationTypeId: rest[0] as string,\n position: rest[1] as number,\n productId: rest[2] as string,\n quantity: rest[3] as number,\n targetProductId: rest[4] as string \n };\n }\n \n const id = params.id;\n const associationTypeId = params.associationTypeId;\n const position = params.position;\n const productId = params.productId;\n const quantity = params.quantity;\n const targetProductId = params.targetProductId;\n\n if (typeof id === 'undefined') {\n throw new RevenexxException('Missing required parameter: \"id\"');\n }\n\n const apiPath = '/v1/products/product_associations/{id}'.replace('{id}', id);\n const apiPayload: Payload = {};\n if (typeof associationTypeId !== 'undefined') {\n apiPayload['association_type_id'] = associationTypeId;\n }\n if (typeof position !== 'undefined') {\n apiPayload['position'] = position;\n }\n if (typeof productId !== 'undefined') {\n apiPayload['product_id'] = productId;\n }\n if (typeof quantity !== 'undefined') {\n apiPayload['quantity'] = quantity;\n }\n if (typeof targetProductId !== 'undefined') {\n apiPayload['target_product_id'] = targetProductId;\n }\n const uri = new URL(this.client.config.endpoint + apiPath);\n\n const apiHeaders: { [header: string]: string } = {\n 'content-type': 'application/json',\n }\n\n return this.client.call(\n 'put',\n uri,\n apiHeaders,\n apiPayload,\n );\n }\n\n /**\n * The index of the enums this app ENFORCES — `product-kinds`, `membership-sources`, `rule-matches`, `asset-sources` — served by the app that owns the CHECK constraint each one is parsed out of, so a UI never has to keep its own copy of a status map and watch it drift. Names and titles only: fetch one by name for its values, badge tones and descriptions.\n * \n * The set is a fixed property of this app rather than tenant data, so it is the same list for every tenant. `attributes.type` is deliberately absent: it carries no CHECK, because the whole point of an attribute-driven PIM is that the type list is data an integrator extends.\n *\n * @throws {RevenexxException}\n * @returns {Promise<{}>}\n */\n productsVocabulariesList(): Promise<{}> {\n\n const apiPath = '/v1/products/vocabularies';\n const apiPayload: Payload = {};\n const uri = new URL(this.client.config.endpoint + apiPath);\n\n const apiHeaders: { [header: string]: string } = {\n }\n\n return this.client.call(\n 'get',\n uri,\n apiHeaders,\n apiPayload,\n );\n }\n\n /**\n * One vocabulary with every value it admits, each with a title, a description and the badge tone a UI should paint it in. The value set is parsed out of the CHECK constraint in schema.json, so what is served IS what is enforced. Labels are curated on top and can only add words and colour — a permitted value nobody labelled still appears, titled from its own key.\n *\n * @param {string} params.name - The vocabulary name, as listed by GET /products/vocabularies.\n * @throws {RevenexxException}\n * @returns {Promise<Models.Error>}\n */\n productsVocabulariesGet(params: { name: string }): Promise<Models.Error>;\n /**\n * One vocabulary with every value it admits, each with a title, a description and the badge tone a UI should paint it in. The value set is parsed out of the CHECK constraint in schema.json, so what is served IS what is enforced. Labels are curated on top and can only add words and colour — a permitted value nobody labelled still appears, titled from its own key.\n *\n * @param {string} name - The vocabulary name, as listed by GET /products/vocabularies.\n * @throws {RevenexxException}\n * @returns {Promise<Models.Error>}\n * @deprecated Use the object parameter style method for a better developer experience.\n */\n productsVocabulariesGet(name: string): Promise<Models.Error>;\n productsVocabulariesGet(\n paramsOrFirst: { name: string } | string \n ): Promise<Models.Error> {\n let params: { name: string };\n \n if ((paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst))) {\n params = (paramsOrFirst || {}) as { name: string };\n } else {\n params = {\n name: paramsOrFirst as string \n };\n }\n \n const name = params.name;\n\n if (typeof name === 'undefined') {\n throw new RevenexxException('Missing required parameter: \"name\"');\n }\n\n const apiPath = '/v1/products/vocabularies/{name}'.replace('{name}', name);\n const apiPayload: Payload = {};\n const uri = new URL(this.client.config.endpoint + apiPath);\n\n const apiHeaders: { [header: string]: string } = {\n }\n\n return this.client.call(\n 'get',\n uri,\n apiHeaders,\n apiPayload,\n );\n }\n\n /**\n * Deletes one product by id. It is a hard delete — the row is gone, and the answer is a confirmation rather than a result to branch on.\n * \n * It takes what hangs off it: product category memberships (`product_id`), product associations (`product_id` and `target_product_id`) are deleted with it. `products.parent_id` is set to null instead, so the rows that pointed at it survive the delete rather than going with it.\n * \n * An id no product of this tenant carries answers 404; there is no 409, because every foreign key pointing at this entity resolves itself on delete rather than blocking one. `products.deleted_at` is a SOFT-delete marker that the grid and every category-rule evaluation honour, but no route in this app ever writes it — to soft-delete instead, `PUT /products/{id}` with a `deleted_at`.\n *\n * @param {string} params.id - The `products` row to address, by id. It names a row THIS TENANT holds, so no example is published — a uuid this app invented would document a call that answers 404, and a real one would be another tenant's data. Read one from `GET /v1/products`. An id no product of this tenant carries answers 404; a malformed one answers 400 before the route is reached.\n * @throws {RevenexxException}\n * @returns {Promise<Models.Error>}\n */\n productsDelete(params: { id: string }): Promise<Models.Error>;\n /**\n * Deletes one product by id. It is a hard delete — the row is gone, and the answer is a confirmation rather than a result to branch on.\n * \n * It takes what hangs off it: product category memberships (`product_id`), product associations (`product_id` and `target_product_id`) are deleted with it. `products.parent_id` is set to null instead, so the rows that pointed at it survive the delete rather than going with it.\n * \n * An id no product of this tenant carries answers 404; there is no 409, because every foreign key pointing at this entity resolves itself on delete rather than blocking one. `products.deleted_at` is a SOFT-delete marker that the grid and every category-rule evaluation honour, but no route in this app ever writes it — to soft-delete instead, `PUT /products/{id}` with a `deleted_at`.\n *\n * @param {string} id - The `products` row to address, by id. It names a row THIS TENANT holds, so no example is published — a uuid this app invented would document a call that answers 404, and a real one would be another tenant's data. Read one from `GET /v1/products`. An id no product of this tenant carries answers 404; a malformed one answers 400 before the route is reached.\n * @throws {RevenexxException}\n * @returns {Promise<Models.Error>}\n * @deprecated Use the object parameter style method for a better developer experience.\n */\n productsDelete(id: string): Promise<Models.Error>;\n productsDelete(\n paramsOrFirst: { id: string } | string \n ): Promise<Models.Error> {\n let params: { id: string };\n \n if ((paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst))) {\n params = (paramsOrFirst || {}) as { id: string };\n } else {\n params = {\n id: paramsOrFirst as string \n };\n }\n \n const id = params.id;\n\n if (typeof id === 'undefined') {\n throw new RevenexxException('Missing required parameter: \"id\"');\n }\n\n const apiPath = '/v1/products/{id}'.replace('{id}', id);\n const apiPayload: Payload = {};\n const uri = new URL(this.client.config.endpoint + apiPath);\n\n const apiHeaders: { [header: string]: string } = {\n }\n\n return this.client.call(\n 'delete',\n uri,\n apiHeaders,\n apiPayload,\n );\n }\n\n /**\n * Reads one product by its id — the whole row, every column, as it is stored.\n * \n * The catalog itself. A product row carries only what every product has — SKU, kind, family, enabled, tax class — and everything the tenant modelled lives in the `attribute_values` jsonb document, keyed by attribute CODE inside one of four scope buckets (common, per locale, per channel, per channel and locale). `label` is a generated column, maintained by the database so a grid of twenty thousand rows can sort and filter on a name with no join. `kind` says where the row sits in the variant hierarchy: a `model` carries what its variants share and is never sold itself.\n * \n * An id no product of this tenant carries answers 404, and so does one belonging to another tenant: row-level security makes that row invisible rather than forbidden. A malformed id answers 400 before the route is reached. Nothing is resolved for you here — for the display name, the family code and the grid attributes already unpacked, use `GET /products/grid` or `POST /products/labels`.\n *\n * @param {string} params.id - The `products` row to address, by id. It names a row THIS TENANT holds, so no example is published — a uuid this app invented would document a call that answers 404, and a real one would be another tenant's data. Read one from `GET /v1/products`. An id no product of this tenant carries answers 404; a malformed one answers 400 before the route is reached.\n * @throws {RevenexxException}\n * @returns {Promise<Models.Error>}\n */\n productsGet(params: { id: string }): Promise<Models.Error>;\n /**\n * Reads one product by its id — the whole row, every column, as it is stored.\n * \n * The catalog itself. A product row carries only what every product has — SKU, kind, family, enabled, tax class — and everything the tenant modelled lives in the `attribute_values` jsonb document, keyed by attribute CODE inside one of four scope buckets (common, per locale, per channel, per channel and locale). `label` is a generated column, maintained by the database so a grid of twenty thousand rows can sort and filter on a name with no join. `kind` says where the row sits in the variant hierarchy: a `model` carries what its variants share and is never sold itself.\n * \n * An id no product of this tenant carries answers 404, and so does one belonging to another tenant: row-level security makes that row invisible rather than forbidden. A malformed id answers 400 before the route is reached. Nothing is resolved for you here — for the display name, the family code and the grid attributes already unpacked, use `GET /products/grid` or `POST /products/labels`.\n *\n * @param {string} id - The `products` row to address, by id. It names a row THIS TENANT holds, so no example is published — a uuid this app invented would document a call that answers 404, and a real one would be another tenant's data. Read one from `GET /v1/products`. An id no product of this tenant carries answers 404; a malformed one answers 400 before the route is reached.\n * @throws {RevenexxException}\n * @returns {Promise<Models.Error>}\n * @deprecated Use the object parameter style method for a better developer experience.\n */\n productsGet(id: string): Promise<Models.Error>;\n productsGet(\n paramsOrFirst: { id: string } | string \n ): Promise<Models.Error> {\n let params: { id: string };\n \n if ((paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst))) {\n params = (paramsOrFirst || {}) as { id: string };\n } else {\n params = {\n id: paramsOrFirst as string \n };\n }\n \n const id = params.id;\n\n if (typeof id === 'undefined') {\n throw new RevenexxException('Missing required parameter: \"id\"');\n }\n\n const apiPath = '/v1/products/{id}'.replace('{id}', id);\n const apiPayload: Payload = {};\n const uri = new URL(this.client.config.endpoint + apiPath);\n\n const apiHeaders: { [header: string]: string } = {\n }\n\n return this.client.call(\n 'get',\n uri,\n apiHeaders,\n apiPayload,\n );\n }\n\n /**\n * Updates one product by id. A partial patch: the body names only the columns to change and every column it leaves out keeps its current value, so there is no read-modify-write and no way to blank a field by forgetting it.\n * \n * The catalog itself. A product row carries only what every product has — SKU, kind, family, enabled, tax class — and everything the tenant modelled lives in the `attribute_values` jsonb document, keyed by attribute CODE inside one of four scope buckets (common, per locale, per channel, per channel and locale). `label` is a generated column, maintained by the database so a grid of twenty thousand rows can sort and filter on a name with no join. `kind` says where the row sits in the variant hierarchy: a `model` carries what its variants share and is never sold itself.\n * \n * A body that names nothing writable is refused with 400 rather than answered as a no-op, an id nobody carries answers 404, and a value that collides on `sku` answers 409. `label` is a generated column: naming it is dropped rather than refused, and `completeness` is written by the two metadata routes, not here.\n *\n * @param {string} params.id - The `products` row to address, by id. It names a row THIS TENANT holds, so no example is published — a uuid this app invented would document a call that answers 404, and a real one would be another tenant's data. Read one from `GET /v1/products`. An id no product of this tenant carries answers 404; a malformed one answers 400 before the route is reached.\n * @param {object} params.attributeValues - Every attribute value the record carries, in ONE jsonb document — the core of an attribute-driven PIM. A record's properties are not columns here: they are rows in `attributes`, selected per family by `family_attributes`, and their values live under their attribute CODE inside this object.\n\nFour buckets, and an attribute's own flags decide which one it writes to:\n\n `common` the attribute is neither localizable nor scopable — one value, full stop.\n `{\"common\": {\"net_weight\": 2.4, \"colour\": \"black\"}}`\n `locale_specific` `localizable`: one value per language tag.\n `{\"locale_specific\": {\"de_DE\": {\"name\": \"Akku-Bohrschrauber\"}}}`\n `channel_specific` `scopable`: one value per channel.\n `{\"channel_specific\": {\"b2b\": {\"minimum_order_quantity\": 6}}}`\n `channel_locale_specific` both: one value per channel AND language tag.\n `{\"channel_locale_specific\": {\"b2b\": {\"de_DE\": {\"description\": \"…\"}}}}`\n\nA reader takes the most specific bucket that carries the code and falls back through locale, then channel, then `common`. `common` is always last and always consulted, because early imports wrote everything there whatever an attribute's flags said — a reader that skipped it reports an imported catalog as empty. `GET /products/attribute-schema` answers, per field, the exact path a value belongs at (`storage.path`) and that full fallback order (`from`), so no client has to re-derive any of this.\n\nThe value itself is whatever the attribute's `type` implies: a string, a number, a boolean, an option CODE for a select (never its label), a list of codes for a multi-select, `{\"amount\": …, \"unit\": …}` for a measure, a list of `{\"amount\": …, \"currency\": …}` for a price, an asset code for media.\n\nDefaults to `{}`, and an empty object is a normal state — a record nobody has enriched yet. The declared type also admits an array only because every jsonb column of this app shares one mapping; an array is not meaningful here and every reader in this app treats a non-object as empty.\n * @param {object} params.completeness - How much of what this product's family REQUIRES it actually carries — the number a merchandiser works down. `required` counts the attributes the family marks `is_required`, `filled` how many of those carry a value in ANY bucket, `ratio` is filled/required between 0 and 1 (a family that requires nothing is 1, not undefined), `missing` lists the codes with no value anywhere, sorted, and `computed_at` is when it was measured.\n\nWritten only by `POST /products/{id}/completeness` and by `POST /products/{id}/family`; a plain create or update never touches it, so it is null until one of the two has run. It also stays null for a product with no family — there is nothing to measure it against, and 0 % would be a lie.\n * @param {string} params.deletedAt - When the product was soft-deleted. `GET /products/grid` and every category-rule evaluation exclude a row that carries one; `GET /products` does NOT — filter on it to read the live catalog.\n * @param {boolean} params.enabled - Whether the product is offered. A create defaults it from the `new_products_enabled_by_default` tenant setting rather than blindly to true, so an import does not publish twenty thousand unfinished products the moment it lands. An explicit value in the body always wins.\n * @param {string} params.familyId - The family that decides which attributes this product HAS. Without one nothing is required, completeness cannot be computed and the display name never resolves — `POST /products/{id}/family` is the call that sets it and computes completeness in the same step.\n * @param {string} params.familyVariantId - Which variant structure of the family this product follows — the axes it splits on. Null on a simple product.\n * @param {ProductsKind} params.kind - Where the product sits in the variant hierarchy. 'simple' stands on its own. 'model' carries the values its variants share and is never sold itself. 'variant' carries the axis values and points at its model through `parent_id`.\n * @param {string} params.parentId - The product MODEL this variant belongs to. Only a `variant` carries one. Deleting the model leaves its variants behind with a null parent rather than deleting them.\n * @param {object} params.quantifiedAssociations - The import-side mirror of associations that carry a quantity — a bundle, a bill of materials, a spare-parts set. NOTHING IN THIS APP READS OR WRITES IT: no route produces it, no route consumes it, and it is null on every product this app has created. The surface that IS served is relational — `product_associations`, whose `quantity` column holds the number, guarded by `association_types.is_quantified`.\n\nIt exists because a PIM import (Akeneo, BMEcat) carries these in one blob keyed by association type code, and the column lets that document round-trip instead of being dropped. The database enforces no shape on it, so what a reader finds is whatever the importer wrote; the example is the conventional form.\n * @param {string} params.sku - The merchant's own article number — unique per tenant, and the value every integration (ERP, shop, feed, price list) joins on. The one identifier a person types, and the fallback this app shows when the catalog holds no name.\n * @param {string} params.taxClass - The tax class key the prices app resolves a VAT rate from. Free text here — the vocabulary belongs to the app that prices, and `POST /products/batch` exists to hand exactly this column to it in bulk.\n * @throws {RevenexxException}\n * @returns {Promise<Models.Error>}\n */\n productsUpdate(params: { id: string, attributeValues?: object, completeness?: object, deletedAt?: string, enabled?: boolean, familyId?: string, familyVariantId?: string, kind?: ProductsKind, parentId?: string, quantifiedAssociations?: object, sku?: string, taxClass?: string }): Promise<Models.Error>;\n /**\n * Updates one product by id. A partial patch: the body names only the columns to change and every column it leaves out keeps its current value, so there is no read-modify-write and no way to blank a field by forgetting it.\n * \n * The catalog itself. A product row carries only what every product has — SKU, kind, family, enabled, tax class — and everything the tenant modelled lives in the `attribute_values` jsonb document, keyed by attribute CODE inside one of four scope buckets (common, per locale, per channel, per channel and locale). `label` is a generated column, maintained by the database so a grid of twenty thousand rows can sort and filter on a name with no join. `kind` says where the row sits in the variant hierarchy: a `model` carries what its variants share and is never sold itself.\n * \n * A body that names nothing writable is refused with 400 rather than answered as a no-op, an id nobody carries answers 404, and a value that collides on `sku` answers 409. `label` is a generated column: naming it is dropped rather than refused, and `completeness` is written by the two metadata routes, not here.\n *\n * @param {string} id - The `products` row to address, by id. It names a row THIS TENANT holds, so no example is published — a uuid this app invented would document a call that answers 404, and a real one would be another tenant's data. Read one from `GET /v1/products`. An id no product of this tenant carries answers 404; a malformed one answers 400 before the route is reached.\n * @param {object} attributeValues - Every attribute value the record carries, in ONE jsonb document — the core of an attribute-driven PIM. A record's properties are not columns here: they are rows in `attributes`, selected per family by `family_attributes`, and their values live under their attribute CODE inside this object.\n\nFour buckets, and an attribute's own flags decide which one it writes to:\n\n `common` the attribute is neither localizable nor scopable — one value, full stop.\n `{\"common\": {\"net_weight\": 2.4, \"colour\": \"black\"}}`\n `locale_specific` `localizable`: one value per language tag.\n `{\"locale_specific\": {\"de_DE\": {\"name\": \"Akku-Bohrschrauber\"}}}`\n `channel_specific` `scopable`: one value per channel.\n `{\"channel_specific\": {\"b2b\": {\"minimum_order_quantity\": 6}}}`\n `channel_locale_specific` both: one value per channel AND language tag.\n `{\"channel_locale_specific\": {\"b2b\": {\"de_DE\": {\"description\": \"…\"}}}}`\n\nA reader takes the most specific bucket that carries the code and falls back through locale, then channel, then `common`. `common` is always last and always consulted, because early imports wrote everything there whatever an attribute's flags said — a reader that skipped it reports an imported catalog as empty. `GET /products/attribute-schema` answers, per field, the exact path a value belongs at (`storage.path`) and that full fallback order (`from`), so no client has to re-derive any of this.\n\nThe value itself is whatever the attribute's `type` implies: a string, a number, a boolean, an option CODE for a select (never its label), a list of codes for a multi-select, `{\"amount\": …, \"unit\": …}` for a measure, a list of `{\"amount\": …, \"currency\": …}` for a price, an asset code for media.\n\nDefaults to `{}`, and an empty object is a normal state — a record nobody has enriched yet. The declared type also admits an array only because every jsonb column of this app shares one mapping; an array is not meaningful here and every reader in this app treats a non-object as empty.\n * @param {object} completeness - How much of what this product's family REQUIRES it actually carries — the number a merchandiser works down. `required` counts the attributes the family marks `is_required`, `filled` how many of those carry a value in ANY bucket, `ratio` is filled/required between 0 and 1 (a family that requires nothing is 1, not undefined), `missing` lists the codes with no value anywhere, sorted, and `computed_at` is when it was measured.\n\nWritten only by `POST /products/{id}/completeness` and by `POST /products/{id}/family`; a plain create or update never touches it, so it is null until one of the two has run. It also stays null for a product with no family — there is nothing to measure it against, and 0 % would be a lie.\n * @param {string} deletedAt - When the product was soft-deleted. `GET /products/grid` and every category-rule evaluation exclude a row that carries one; `GET /products` does NOT — filter on it to read the live catalog.\n * @param {boolean} enabled - Whether the product is offered. A create defaults it from the `new_products_enabled_by_default` tenant setting rather than blindly to true, so an import does not publish twenty thousand unfinished products the moment it lands. An explicit value in the body always wins.\n * @param {string} familyId - The family that decides which attributes this product HAS. Without one nothing is required, completeness cannot be computed and the display name never resolves — `POST /products/{id}/family` is the call that sets it and computes completeness in the same step.\n * @param {string} familyVariantId - Which variant structure of the family this product follows — the axes it splits on. Null on a simple product.\n * @param {ProductsKind} kind - Where the product sits in the variant hierarchy. 'simple' stands on its own. 'model' carries the values its variants share and is never sold itself. 'variant' carries the axis values and points at its model through `parent_id`.\n * @param {string} parentId - The product MODEL this variant belongs to. Only a `variant` carries one. Deleting the model leaves its variants behind with a null parent rather than deleting them.\n * @param {object} quantifiedAssociations - The import-side mirror of associations that carry a quantity — a bundle, a bill of materials, a spare-parts set. NOTHING IN THIS APP READS OR WRITES IT: no route produces it, no route consumes it, and it is null on every product this app has created. The surface that IS served is relational — `product_associations`, whose `quantity` column holds the number, guarded by `association_types.is_quantified`.\n\nIt exists because a PIM import (Akeneo, BMEcat) carries these in one blob keyed by association type code, and the column lets that document round-trip instead of being dropped. The database enforces no shape on it, so what a reader finds is whatever the importer wrote; the example is the conventional form.\n * @param {string} sku - The merchant's own article number — unique per tenant, and the value every integration (ERP, shop, feed, price list) joins on. The one identifier a person types, and the fallback this app shows when the catalog holds no name.\n * @param {string} taxClass - The tax class key the prices app resolves a VAT rate from. Free text here — the vocabulary belongs to the app that prices, and `POST /products/batch` exists to hand exactly this column to it in bulk.\n * @throws {RevenexxException}\n * @returns {Promise<Models.Error>}\n * @deprecated Use the object parameter style method for a better developer experience.\n */\n productsUpdate(id: string, attributeValues?: object, completeness?: object, deletedAt?: string, enabled?: boolean, familyId?: string, familyVariantId?: string, kind?: ProductsKind, parentId?: string, quantifiedAssociations?: object, sku?: string, taxClass?: string): Promise<Models.Error>;\n productsUpdate(\n paramsOrFirst: { id: string, attributeValues?: object, completeness?: object, deletedAt?: string, enabled?: boolean, familyId?: string, familyVariantId?: string, kind?: ProductsKind, parentId?: string, quantifiedAssociations?: object, sku?: string, taxClass?: string } | string,\n ...rest: [(object)?, (object)?, (string)?, (boolean)?, (string)?, (string)?, (ProductsKind)?, (string)?, (object)?, (string)?, (string)?] \n ): Promise<Models.Error> {\n let params: { id: string, attributeValues?: object, completeness?: object, deletedAt?: string, enabled?: boolean, familyId?: string, familyVariantId?: string, kind?: ProductsKind, parentId?: string, quantifiedAssociations?: object, sku?: string, taxClass?: string };\n \n if ((paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst))) {\n params = (paramsOrFirst || {}) as { id: string, attributeValues?: object, completeness?: object, deletedAt?: string, enabled?: boolean, familyId?: string, familyVariantId?: string, kind?: ProductsKind, parentId?: string, quantifiedAssociations?: object, sku?: string, taxClass?: string };\n } else {\n params = {\n id: paramsOrFirst as string,\n attributeValues: rest[0] as object,\n completeness: rest[1] as object,\n deletedAt: rest[2] as string,\n enabled: rest[3] as boolean,\n familyId: rest[4] as string,\n familyVariantId: rest[5] as string,\n kind: rest[6] as ProductsKind,\n parentId: rest[7] as string,\n quantifiedAssociations: rest[8] as object,\n sku: rest[9] as string,\n taxClass: rest[10] as string \n };\n }\n \n const id = params.id;\n const attributeValues = params.attributeValues;\n const completeness = params.completeness;\n const deletedAt = params.deletedAt;\n const enabled = params.enabled;\n const familyId = params.familyId;\n const familyVariantId = params.familyVariantId;\n const kind = params.kind;\n const parentId = params.parentId;\n const quantifiedAssociations = params.quantifiedAssociations;\n const sku = params.sku;\n const taxClass = params.taxClass;\n\n if (typeof id === 'undefined') {\n throw new RevenexxException('Missing required parameter: \"id\"');\n }\n\n const apiPath = '/v1/products/{id}'.replace('{id}', id);\n const apiPayload: Payload = {};\n if (typeof attributeValues !== 'undefined') {\n apiPayload['attribute_values'] = attributeValues;\n }\n if (typeof completeness !== 'undefined') {\n apiPayload['completeness'] = completeness;\n }\n if (typeof deletedAt !== 'undefined') {\n apiPayload['deleted_at'] = deletedAt;\n }\n if (typeof enabled !== 'undefined') {\n apiPayload['enabled'] = enabled;\n }\n if (typeof familyId !== 'undefined') {\n apiPayload['family_id'] = familyId;\n }\n if (typeof familyVariantId !== 'undefined') {\n apiPayload['family_variant_id'] = familyVariantId;\n }\n if (typeof kind !== 'undefined') {\n apiPayload['kind'] = kind;\n }\n if (typeof parentId !== 'undefined') {\n apiPayload['parent_id'] = parentId;\n }\n if (typeof quantifiedAssociations !== 'undefined') {\n apiPayload['quantified_associations'] = quantifiedAssociations;\n }\n if (typeof sku !== 'undefined') {\n apiPayload['sku'] = sku;\n }\n if (typeof taxClass !== 'undefined') {\n apiPayload['tax_class'] = taxClass;\n }\n const uri = new URL(this.client.config.endpoint + apiPath);\n\n const apiHeaders: { [header: string]: string } = {\n 'content-type': 'application/json',\n }\n\n return this.client.call(\n 'put',\n uri,\n apiHeaders,\n apiPayload,\n );\n }\n\n /**\n * How much of what its family REQUIRES does this product actually carry — the number a merchandiser works down. products.completeness is jsonb that nothing had ever written. This computes it from family_attributes (is_required) against the product's own scoped attribute_values and stores the result. A product with no family answers 400 rather than an invented 0 % — it has nothing to be measured against.\n *\n * @param {string} params.id - The `products` row to address, by id. It names a row THIS TENANT holds, so no example is published — a uuid this app invented would document a call that answers 404, and a real one would be another tenant's data. Read one from `GET /v1/products`. An id no product of this tenant carries answers 404; a malformed one answers 400 before the route is reached.\n * @param {object} params.data - Request body\n * @throws {RevenexxException}\n * @returns {Promise<Models.Error>}\n */\n productsCompleteness(params: { id: string, data: object }): Promise<Models.Error>;\n /**\n * How much of what its family REQUIRES does this product actually carry — the number a merchandiser works down. products.completeness is jsonb that nothing had ever written. This computes it from family_attributes (is_required) against the product's own scoped attribute_values and stores the result. A product with no family answers 400 rather than an invented 0 % — it has nothing to be measured against.\n *\n * @param {string} id - The `products` row to address, by id. It names a row THIS TENANT holds, so no example is published — a uuid this app invented would document a call that answers 404, and a real one would be another tenant's data. Read one from `GET /v1/products`. An id no product of this tenant carries answers 404; a malformed one answers 400 before the route is reached.\n * @param {object} data - Request body\n * @throws {RevenexxException}\n * @returns {Promise<Models.Error>}\n * @deprecated Use the object parameter style method for a better developer experience.\n */\n productsCompleteness(id: string, data: object): Promise<Models.Error>;\n productsCompleteness(\n paramsOrFirst: { id: string, data: object } | string,\n ...rest: [(object)?] \n ): Promise<Models.Error> {\n let params: { id: string, data: object };\n \n if ((paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst))) {\n params = (paramsOrFirst || {}) as { id: string, data: object };\n } else {\n params = {\n id: paramsOrFirst as string,\n data: rest[0] as object \n };\n }\n \n const id = params.id;\n const data = params.data;\n\n if (typeof id === 'undefined') {\n throw new RevenexxException('Missing required parameter: \"id\"');\n }\n if (typeof data === 'undefined') {\n throw new RevenexxException('Missing required parameter: \"data\"');\n }\n\n const apiPath = '/v1/products/{id}/completeness'.replace('{id}', id);\n const apiPayload: Payload = {};\n if (typeof data !== 'undefined') {\n Object.assign(apiPayload, data);\n }\n const uri = new URL(this.client.config.endpoint + apiPath);\n\n const apiHeaders: { [header: string]: string } = {\n 'content-type': 'application/json',\n }\n\n return this.client.call(\n 'post',\n uri,\n apiHeaders,\n apiPayload,\n );\n }\n\n /**\n * Names the family in the body — by `family_id` or by `family_code`, whichever the caller holds — and computes the product's completeness in the same call. The step every family-driven surface waits on: a product with no family has no required attributes, so its completeness cannot be computed and its family's label attribute never resolves. Assigning the family recomputes and STORES products.completeness immediately, so the metadata cannot go stale between the two operations.\n *\n * @param {string} params.id - The `products` row to address, by id. It names a row THIS TENANT holds, so no example is published — a uuid this app invented would document a call that answers 404, and a real one would be another tenant's data. Read one from `GET /v1/products`. An id no product of this tenant carries answers 404; a malformed one answers 400 before the route is reached.\n * @param {string} params.familyCode - Alternative to family_id — a `families.code` this tenant holds, from `GET /products/families`. No example: a code is tenant data, and any value published here names a family somebody does not have.\n * @param {string} params.familyId - The family to assign.\n * @throws {RevenexxException}\n * @returns {Promise<Models.Error>}\n */\n productsFamilyAssign(params: { id: string, familyCode?: string, familyId?: string }): Promise<Models.Error>;\n /**\n * Names the family in the body — by `family_id` or by `family_code`, whichever the caller holds — and computes the product's completeness in the same call. The step every family-driven surface waits on: a product with no family has no required attributes, so its completeness cannot be computed and its family's label attribute never resolves. Assigning the family recomputes and STORES products.completeness immediately, so the metadata cannot go stale between the two operations.\n *\n * @param {string} id - The `products` row to address, by id. It names a row THIS TENANT holds, so no example is published — a uuid this app invented would document a call that answers 404, and a real one would be another tenant's data. Read one from `GET /v1/products`. An id no product of this tenant carries answers 404; a malformed one answers 400 before the route is reached.\n * @param {string} familyCode - Alternative to family_id — a `families.code` this tenant holds, from `GET /products/families`. No example: a code is tenant data, and any value published here names a family somebody does not have.\n * @param {string} familyId - The family to assign.\n * @throws {RevenexxException}\n * @returns {Promise<Models.Error>}\n * @deprecated Use the object parameter style method for a better developer experience.\n */\n productsFamilyAssign(id: string, familyCode?: string, familyId?: string): Promise<Models.Error>;\n productsFamilyAssign(\n paramsOrFirst: { id: string, familyCode?: string, familyId?: string } | string,\n ...rest: [(string)?, (string)?] \n ): Promise<Models.Error> {\n let params: { id: string, familyCode?: string, familyId?: string };\n \n if ((paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst))) {\n params = (paramsOrFirst || {}) as { id: string, familyCode?: string, familyId?: string };\n } else {\n params = {\n id: paramsOrFirst as string,\n familyCode: rest[0] as string,\n familyId: rest[1] as string \n };\n }\n \n const id = params.id;\n const familyCode = params.familyCode;\n const familyId = params.familyId;\n\n if (typeof id === 'undefined') {\n throw new RevenexxException('Missing required parameter: \"id\"');\n }\n\n const apiPath = '/v1/products/{id}/family'.replace('{id}', id);\n const apiPayload: Payload = {};\n if (typeof familyCode !== 'undefined') {\n apiPayload['family_code'] = familyCode;\n }\n if (typeof familyId !== 'undefined') {\n apiPayload['family_id'] = familyId;\n }\n const uri = new URL(this.client.config.endpoint + apiPath);\n\n const apiHeaders: { [header: string]: string } = {\n 'content-type': 'application/json',\n }\n\n return this.client.call(\n 'post',\n uri,\n apiHeaders,\n apiPayload,\n );\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/services/products.ts"],"names":[],"mappings":"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","sourcesContent":["import { RevenexxException, Client, type Payload, UploadProgress } from '../client';\nimport type { Models } from '../models';\n\nimport { Kind } from '../enums/kind';\nimport { ProductsKind } from '../enums/products-kind';\n\nexport class Products {\n client: Client;\n\n constructor(client: Client) {\n this.client = client;\n }\n\n /**\n * The catalog itself. A product row carries only what every product has — SKU, kind, family, enabled, tax class — and everything the tenant modelled lives in the `attribute_values` jsonb document, keyed by attribute CODE inside one of four scope buckets (common, per locale, per channel, per channel and locale). `label` is a generated column, maintained by the database so a grid of twenty thousand rows can sort and filter on a name with no join. `kind` says where the row sits in the variant hierarchy: a `model` carries what its variants share and is never sold itself.\n * \n * Every column of `products` is an exact-match query parameter, `order` sorts by one column, and `limit`/`offset` page through `page.total`. A query key that is NOT a column is dropped rather than refused, and the `filter` object echoes the ones that were understood — that echo is the only way to tell an unfiltered answer from an empty one. It reads rows exactly as they are stored: no join is resolved, no jsonb value is unpacked, and soft-deleted products are included — filter on `deleted_at` to read the live catalog, or use `GET /products/grid`, which excludes them.\n *\n * @param {number} params.limit - Page size (default 50, max 200). A larger value is clamped rather than refused.\n * @param {number} params.offset - Row offset for pagination (default 0). Page with `page.total` and `page.hasMore`.\n * @param {string} params.order - Sort by one column: 'column' | 'column.asc' | 'column.desc'. A bare column sorts ascending. Anything else is refused with 400.\n * @param {string} params.id - Exact match on `id`. The row's own id, generated by the database. A client never sends one; it reads one back and uses it in the path of every later call.\n * @param {string} params.sku - Exact match on `sku`. The merchant's own article number — unique per tenant, and the value every integration (ERP, shop, feed, price list) joins on. The one identifier a person types, and the fallback this app shows when the catalog holds no name.\n * @param {Kind} params.kind - Exact match on `kind`. Where the product sits in the variant hierarchy. 'simple' stands on its own. 'model' carries the values its variants share and is never sold itself. 'variant' carries the axis values and points at its model through `parent_id`.\n * @param {string} params.parentId - Exact match on `parent_id`. The product MODEL this variant belongs to. Only a `variant` carries one. Deleting the model leaves its variants behind with a null parent rather than deleting them.\n * @param {string} params.familyId - Exact match on `family_id`. The family that decides which attributes this product HAS. Without one nothing is required, completeness cannot be computed and the display name never resolves — `POST /products/{id}/family` is the call that sets it and computes completeness in the same step.\n * @param {string} params.familyVariantId - Exact match on `family_variant_id`. Which variant structure of the family this product follows — the axes it splits on. Null on a simple product.\n * @param {boolean} params.enabled - Exact match on `enabled`. Whether the product is offered. A create defaults it from the `new_products_enabled_by_default` tenant setting rather than blindly to true, so an import does not publish twenty thousand unfinished products the moment it lands. An explicit value in the body always wins.\n * @param {string} params.taxClass - Exact match on `tax_class`. The tax class key the prices app resolves a VAT rate from. Free text here — the vocabulary belongs to the app that prices, and `POST /products/batch` exists to hand exactly this column to it in bulk.\n * @param {string} params.attributeValues - Exact match on `attribute_values`. Every attribute value the record carries, in ONE jsonb document — the core of an attribute-driven PIM. A record's properties are not columns here: they are rows in `attributes`, selected per family by `family_attributes`, and their values live under their attribute CODE inside this object. The whole jsonb document is compared, serialized as JSON — this is equality, not a path or containment query, and `null` cannot be matched this way. A value that does not parse as JSON is refused with 400 `invalid_value`, naming this filter, before the request reaches the data plane.\n * @param {string} params.label - Exact match on `label`. The display name, maintained by the DATABASE so a grid of twenty thousand rows can sort and filter on a name with no join. It is the first of `attribute_values.common.name`, `…common.label`, the `de`/`en`/`de_DE`/`en_US` locale buckets, `…common.manufacturer_aid`, and finally the SKU — so a value is ALWAYS present, and a label equal to the SKU means the catalog holds no name for this product. A generated column: it cannot be written, and a create or update that names it has it dropped rather than refused. The family-aware answer, which can consult `families.label_attribute` and report where the name came from, is `POST /products/labels`.\n * @param {string} params.quantifiedAssociations - Exact match on `quantified_associations`. The import-side mirror of associations that carry a quantity — a bundle, a bill of materials, a spare-parts set. NOTHING IN THIS APP READS OR WRITES IT: no route produces it, no route consumes it, and it is null on every product this app has created. The surface that IS served is relational — `product_associations`, whose `quantity` column holds the number, guarded by `association_types.is_quantified`. The whole jsonb document is compared, serialized as JSON — this is equality, not a path or containment query, and `null` cannot be matched this way. A value that does not parse as JSON is refused with 400 `invalid_value`, naming this filter, before the request reaches the data plane.\n * @param {string} params.completeness - Exact match on `completeness`. How much of what this product's family REQUIRES it actually carries — the number a merchandiser works down. `required` counts the attributes the family marks `is_required`, `filled` how many of those carry a value in ANY bucket, `ratio` is filled/required between 0 and 1 (a family that requires nothing is 1, not undefined), `missing` lists the codes with no value anywhere, sorted, and `computed_at` is when it was measured. The whole jsonb document is compared, serialized as JSON — this is equality, not a path or containment query, and `null` cannot be matched this way. A value that does not parse as JSON is refused with 400 `invalid_value`, naming this filter, before the request reaches the data plane.\n * @param {string} params.createdAt - Exact match on `created_at`. When the row was created. Server-set — it is not part of any request body.\n * @param {string} params.updatedAt - Exact match on `updated_at`. When the row was last written. Server-set — it is not part of any request body.\n * @param {string} params.deletedAt - Exact match on `deleted_at`. When the product was soft-deleted. `GET /products/grid` and every category-rule evaluation exclude a row that carries one; `GET /products` does NOT — filter on it to read the live catalog.\n * @throws {RevenexxException}\n * @returns {Promise<{}>}\n */\n productsList(params?: { limit?: number, offset?: number, order?: string, id?: string, sku?: string, kind?: Kind, parentId?: string, familyId?: string, familyVariantId?: string, enabled?: boolean, taxClass?: string, attributeValues?: string, label?: string, quantifiedAssociations?: string, completeness?: string, createdAt?: string, updatedAt?: string, deletedAt?: string }): Promise<{}>;\n /**\n * The catalog itself. A product row carries only what every product has — SKU, kind, family, enabled, tax class — and everything the tenant modelled lives in the `attribute_values` jsonb document, keyed by attribute CODE inside one of four scope buckets (common, per locale, per channel, per channel and locale). `label` is a generated column, maintained by the database so a grid of twenty thousand rows can sort and filter on a name with no join. `kind` says where the row sits in the variant hierarchy: a `model` carries what its variants share and is never sold itself.\n * \n * Every column of `products` is an exact-match query parameter, `order` sorts by one column, and `limit`/`offset` page through `page.total`. A query key that is NOT a column is dropped rather than refused, and the `filter` object echoes the ones that were understood — that echo is the only way to tell an unfiltered answer from an empty one. It reads rows exactly as they are stored: no join is resolved, no jsonb value is unpacked, and soft-deleted products are included — filter on `deleted_at` to read the live catalog, or use `GET /products/grid`, which excludes them.\n *\n * @param {number} limit - Page size (default 50, max 200). A larger value is clamped rather than refused.\n * @param {number} offset - Row offset for pagination (default 0). Page with `page.total` and `page.hasMore`.\n * @param {string} order - Sort by one column: 'column' | 'column.asc' | 'column.desc'. A bare column sorts ascending. Anything else is refused with 400.\n * @param {string} id - Exact match on `id`. The row's own id, generated by the database. A client never sends one; it reads one back and uses it in the path of every later call.\n * @param {string} sku - Exact match on `sku`. The merchant's own article number — unique per tenant, and the value every integration (ERP, shop, feed, price list) joins on. The one identifier a person types, and the fallback this app shows when the catalog holds no name.\n * @param {Kind} kind - Exact match on `kind`. Where the product sits in the variant hierarchy. 'simple' stands on its own. 'model' carries the values its variants share and is never sold itself. 'variant' carries the axis values and points at its model through `parent_id`.\n * @param {string} parentId - Exact match on `parent_id`. The product MODEL this variant belongs to. Only a `variant` carries one. Deleting the model leaves its variants behind with a null parent rather than deleting them.\n * @param {string} familyId - Exact match on `family_id`. The family that decides which attributes this product HAS. Without one nothing is required, completeness cannot be computed and the display name never resolves — `POST /products/{id}/family` is the call that sets it and computes completeness in the same step.\n * @param {string} familyVariantId - Exact match on `family_variant_id`. Which variant structure of the family this product follows — the axes it splits on. Null on a simple product.\n * @param {boolean} enabled - Exact match on `enabled`. Whether the product is offered. A create defaults it from the `new_products_enabled_by_default` tenant setting rather than blindly to true, so an import does not publish twenty thousand unfinished products the moment it lands. An explicit value in the body always wins.\n * @param {string} taxClass - Exact match on `tax_class`. The tax class key the prices app resolves a VAT rate from. Free text here — the vocabulary belongs to the app that prices, and `POST /products/batch` exists to hand exactly this column to it in bulk.\n * @param {string} attributeValues - Exact match on `attribute_values`. Every attribute value the record carries, in ONE jsonb document — the core of an attribute-driven PIM. A record's properties are not columns here: they are rows in `attributes`, selected per family by `family_attributes`, and their values live under their attribute CODE inside this object. The whole jsonb document is compared, serialized as JSON — this is equality, not a path or containment query, and `null` cannot be matched this way. A value that does not parse as JSON is refused with 400 `invalid_value`, naming this filter, before the request reaches the data plane.\n * @param {string} label - Exact match on `label`. The display name, maintained by the DATABASE so a grid of twenty thousand rows can sort and filter on a name with no join. It is the first of `attribute_values.common.name`, `…common.label`, the `de`/`en`/`de_DE`/`en_US` locale buckets, `…common.manufacturer_aid`, and finally the SKU — so a value is ALWAYS present, and a label equal to the SKU means the catalog holds no name for this product. A generated column: it cannot be written, and a create or update that names it has it dropped rather than refused. The family-aware answer, which can consult `families.label_attribute` and report where the name came from, is `POST /products/labels`.\n * @param {string} quantifiedAssociations - Exact match on `quantified_associations`. The import-side mirror of associations that carry a quantity — a bundle, a bill of materials, a spare-parts set. NOTHING IN THIS APP READS OR WRITES IT: no route produces it, no route consumes it, and it is null on every product this app has created. The surface that IS served is relational — `product_associations`, whose `quantity` column holds the number, guarded by `association_types.is_quantified`. The whole jsonb document is compared, serialized as JSON — this is equality, not a path or containment query, and `null` cannot be matched this way. A value that does not parse as JSON is refused with 400 `invalid_value`, naming this filter, before the request reaches the data plane.\n * @param {string} completeness - Exact match on `completeness`. How much of what this product's family REQUIRES it actually carries — the number a merchandiser works down. `required` counts the attributes the family marks `is_required`, `filled` how many of those carry a value in ANY bucket, `ratio` is filled/required between 0 and 1 (a family that requires nothing is 1, not undefined), `missing` lists the codes with no value anywhere, sorted, and `computed_at` is when it was measured. The whole jsonb document is compared, serialized as JSON — this is equality, not a path or containment query, and `null` cannot be matched this way. A value that does not parse as JSON is refused with 400 `invalid_value`, naming this filter, before the request reaches the data plane.\n * @param {string} createdAt - Exact match on `created_at`. When the row was created. Server-set — it is not part of any request body.\n * @param {string} updatedAt - Exact match on `updated_at`. When the row was last written. Server-set — it is not part of any request body.\n * @param {string} deletedAt - Exact match on `deleted_at`. When the product was soft-deleted. `GET /products/grid` and every category-rule evaluation exclude a row that carries one; `GET /products` does NOT — filter on it to read the live catalog.\n * @throws {RevenexxException}\n * @returns {Promise<{}>}\n * @deprecated Use the object parameter style method for a better developer experience.\n */\n productsList(limit?: number, offset?: number, order?: string, id?: string, sku?: string, kind?: Kind, parentId?: string, familyId?: string, familyVariantId?: string, enabled?: boolean, taxClass?: string, attributeValues?: string, label?: string, quantifiedAssociations?: string, completeness?: string, createdAt?: string, updatedAt?: string, deletedAt?: string): Promise<{}>;\n productsList(\n paramsOrFirst?: { limit?: number, offset?: number, order?: string, id?: string, sku?: string, kind?: Kind, parentId?: string, familyId?: string, familyVariantId?: string, enabled?: boolean, taxClass?: string, attributeValues?: string, label?: string, quantifiedAssociations?: string, completeness?: string, createdAt?: string, updatedAt?: string, deletedAt?: string } | number,\n ...rest: [(number)?, (string)?, (string)?, (string)?, (Kind)?, (string)?, (string)?, (string)?, (boolean)?, (string)?, (string)?, (string)?, (string)?, (string)?, (string)?, (string)?, (string)?] \n ): Promise<{}> {\n let params: { limit?: number, offset?: number, order?: string, id?: string, sku?: string, kind?: Kind, parentId?: string, familyId?: string, familyVariantId?: string, enabled?: boolean, taxClass?: string, attributeValues?: string, label?: string, quantifiedAssociations?: string, completeness?: string, createdAt?: string, updatedAt?: string, deletedAt?: string };\n \n if (!paramsOrFirst || (paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst))) {\n params = (paramsOrFirst || {}) as { limit?: number, offset?: number, order?: string, id?: string, sku?: string, kind?: Kind, parentId?: string, familyId?: string, familyVariantId?: string, enabled?: boolean, taxClass?: string, attributeValues?: string, label?: string, quantifiedAssociations?: string, completeness?: string, createdAt?: string, updatedAt?: string, deletedAt?: string };\n } else {\n params = {\n limit: paramsOrFirst as number,\n offset: rest[0] as number,\n order: rest[1] as string,\n id: rest[2] as string,\n sku: rest[3] as string,\n kind: rest[4] as Kind,\n parentId: rest[5] as string,\n familyId: rest[6] as string,\n familyVariantId: rest[7] as string,\n enabled: rest[8] as boolean,\n taxClass: rest[9] as string,\n attributeValues: rest[10] as string,\n label: rest[11] as string,\n quantifiedAssociations: rest[12] as string,\n completeness: rest[13] as string,\n createdAt: rest[14] as string,\n updatedAt: rest[15] as string,\n deletedAt: rest[16] as string \n };\n }\n \n const limit = params.limit;\n const offset = params.offset;\n const order = params.order;\n const id = params.id;\n const sku = params.sku;\n const kind = params.kind;\n const parentId = params.parentId;\n const familyId = params.familyId;\n const familyVariantId = params.familyVariantId;\n const enabled = params.enabled;\n const taxClass = params.taxClass;\n const attributeValues = params.attributeValues;\n const label = params.label;\n const quantifiedAssociations = params.quantifiedAssociations;\n const completeness = params.completeness;\n const createdAt = params.createdAt;\n const updatedAt = params.updatedAt;\n const deletedAt = params.deletedAt;\n\n\n const apiPath = '/v1/products';\n const apiPayload: Payload = {};\n if (typeof limit !== 'undefined') {\n apiPayload['limit'] = limit;\n }\n if (typeof offset !== 'undefined') {\n apiPayload['offset'] = offset;\n }\n if (typeof order !== 'undefined') {\n apiPayload['order'] = order;\n }\n if (typeof id !== 'undefined') {\n apiPayload['id'] = id;\n }\n if (typeof sku !== 'undefined') {\n apiPayload['sku'] = sku;\n }\n if (typeof kind !== 'undefined') {\n apiPayload['kind'] = kind;\n }\n if (typeof parentId !== 'undefined') {\n apiPayload['parent_id'] = parentId;\n }\n if (typeof familyId !== 'undefined') {\n apiPayload['family_id'] = familyId;\n }\n if (typeof familyVariantId !== 'undefined') {\n apiPayload['family_variant_id'] = familyVariantId;\n }\n if (typeof enabled !== 'undefined') {\n apiPayload['enabled'] = enabled;\n }\n if (typeof taxClass !== 'undefined') {\n apiPayload['tax_class'] = taxClass;\n }\n if (typeof attributeValues !== 'undefined') {\n apiPayload['attribute_values'] = attributeValues;\n }\n if (typeof label !== 'undefined') {\n apiPayload['label'] = label;\n }\n if (typeof quantifiedAssociations !== 'undefined') {\n apiPayload['quantified_associations'] = quantifiedAssociations;\n }\n if (typeof completeness !== 'undefined') {\n apiPayload['completeness'] = completeness;\n }\n if (typeof createdAt !== 'undefined') {\n apiPayload['created_at'] = createdAt;\n }\n if (typeof updatedAt !== 'undefined') {\n apiPayload['updated_at'] = updatedAt;\n }\n if (typeof deletedAt !== 'undefined') {\n apiPayload['deleted_at'] = deletedAt;\n }\n const uri = new URL(this.client.config.endpoint + apiPath);\n\n const apiHeaders: { [header: string]: string } = {\n }\n\n return this.client.call(\n 'get',\n uri,\n apiHeaders,\n apiPayload,\n );\n }\n\n /**\n * Creates one product and answers 201 with the stored row, including the id and the timestamps the database filled in — a client never sends an id, it reads one back and uses it in the path of every later call.\n * \n * The catalog itself. A product row carries only what every product has — SKU, kind, family, enabled, tax class — and everything the tenant modelled lives in the `attribute_values` jsonb document, keyed by attribute CODE inside one of four scope buckets (common, per locale, per channel, per channel and locale). `label` is a generated column, maintained by the database so a grid of twenty thousand rows can sort and filter on a name with no join. `kind` says where the row sits in the variant hierarchy: a `model` carries what its variants share and is never sold itself.\n * \n * `sku` is the only column the database refuses the row without; everything else has a default or is nullable. A second row with the same `sku` answers 409. This app owns the create: `enabled` defaults from the `new_products_enabled_by_default` tenant setting rather than blindly to true, so an import cannot publish twenty thousand unfinished products the moment it lands, and a product that names no family gets the `default_product_family` one. An explicit value in the body always wins over both.\n *\n * @param {string} params.sku - The merchant's own article number — unique per tenant, and the value every integration (ERP, shop, feed, price list) joins on. The one identifier a person types, and the fallback this app shows when the catalog holds no name.\n * @param {object} params.attributeValues - Every attribute value the record carries, in ONE jsonb document — the core of an attribute-driven PIM. A record's properties are not columns here: they are rows in `attributes`, selected per family by `family_attributes`, and their values live under their attribute CODE inside this object.\n\nFour buckets, and an attribute's own flags decide which one it writes to:\n\n `common` the attribute is neither localizable nor scopable — one value, full stop.\n `{\"common\": {\"net_weight\": 2.4, \"colour\": \"black\"}}`\n `locale_specific` `localizable`: one value per language tag.\n `{\"locale_specific\": {\"de_DE\": {\"name\": \"Akku-Bohrschrauber\"}}}`\n `channel_specific` `scopable`: one value per channel.\n `{\"channel_specific\": {\"b2b\": {\"minimum_order_quantity\": 6}}}`\n `channel_locale_specific` both: one value per channel AND language tag.\n `{\"channel_locale_specific\": {\"b2b\": {\"de_DE\": {\"description\": \"…\"}}}}`\n\nA reader takes the most specific bucket that carries the code and falls back through locale, then channel, then `common`. `common` is always last and always consulted, because early imports wrote everything there whatever an attribute's flags said — a reader that skipped it reports an imported catalog as empty. `GET /products/attribute-schema` answers, per field, the exact path a value belongs at (`storage.path`) and that full fallback order (`from`), so no client has to re-derive any of this.\n\nThe value itself is whatever the attribute's `type` implies: a string, a number, a boolean, an option CODE for a select (never its label), a list of codes for a multi-select, `{\"amount\": …, \"unit\": …}` for a measure, a list of `{\"amount\": …, \"currency\": …}` for a price, an asset code for media.\n\nDefaults to `{}`, and an empty object is a normal state — a record nobody has enriched yet. The declared type also admits an array only because every jsonb column of this app shares one mapping; an array is not meaningful here and every reader in this app treats a non-object as empty.\n * @param {object} params.completeness - How much of what this product's family REQUIRES it actually carries — the number a merchandiser works down. `required` counts the attributes the family marks `is_required`, `filled` how many of those carry a value in ANY bucket, `ratio` is filled/required between 0 and 1 (a family that requires nothing is 1, not undefined), `missing` lists the codes with no value anywhere, sorted, and `computed_at` is when it was measured.\n\nWritten only by `POST /products/{id}/completeness` and by `POST /products/{id}/family`; a plain create or update never touches it, so it is null until one of the two has run. It also stays null for a product with no family — there is nothing to measure it against, and 0 % would be a lie.\n * @param {string} params.deletedAt - When the product was soft-deleted. `GET /products/grid` and every category-rule evaluation exclude a row that carries one; `GET /products` does NOT — filter on it to read the live catalog.\n * @param {boolean} params.enabled - Whether the product is offered. A create defaults it from the `new_products_enabled_by_default` tenant setting rather than blindly to true, so an import does not publish twenty thousand unfinished products the moment it lands. An explicit value in the body always wins.\n * @param {string} params.familyId - The family that decides which attributes this product HAS. Without one nothing is required, completeness cannot be computed and the display name never resolves — `POST /products/{id}/family` is the call that sets it and computes completeness in the same step.\n * @param {string} params.familyVariantId - Which variant structure of the family this product follows — the axes it splits on. Null on a simple product.\n * @param {ProductsKind} params.kind - Where the product sits in the variant hierarchy. 'simple' stands on its own. 'model' carries the values its variants share and is never sold itself. 'variant' carries the axis values and points at its model through `parent_id`.\n * @param {string} params.parentId - The product MODEL this variant belongs to. Only a `variant` carries one. Deleting the model leaves its variants behind with a null parent rather than deleting them.\n * @param {object} params.quantifiedAssociations - The import-side mirror of associations that carry a quantity — a bundle, a bill of materials, a spare-parts set. NOTHING IN THIS APP READS OR WRITES IT: no route produces it, no route consumes it, and it is null on every product this app has created. The surface that IS served is relational — `product_associations`, whose `quantity` column holds the number, guarded by `association_types.is_quantified`.\n\nIt exists because a PIM import (Akeneo, BMEcat) carries these in one blob keyed by association type code, and the column lets that document round-trip instead of being dropped. The database enforces no shape on it, so what a reader finds is whatever the importer wrote; the example is the conventional form.\n * @param {string} params.taxClass - The tax class key the prices app resolves a VAT rate from. Free text here — the vocabulary belongs to the app that prices, and `POST /products/batch` exists to hand exactly this column to it in bulk.\n * @throws {RevenexxException}\n * @returns {Promise<Models.Products>}\n */\n productsCreate(params: { sku: string, attributeValues?: object, completeness?: object, deletedAt?: string, enabled?: boolean, familyId?: string, familyVariantId?: string, kind?: ProductsKind, parentId?: string, quantifiedAssociations?: object, taxClass?: string }): Promise<Models.Products>;\n /**\n * Creates one product and answers 201 with the stored row, including the id and the timestamps the database filled in — a client never sends an id, it reads one back and uses it in the path of every later call.\n * \n * The catalog itself. A product row carries only what every product has — SKU, kind, family, enabled, tax class — and everything the tenant modelled lives in the `attribute_values` jsonb document, keyed by attribute CODE inside one of four scope buckets (common, per locale, per channel, per channel and locale). `label` is a generated column, maintained by the database so a grid of twenty thousand rows can sort and filter on a name with no join. `kind` says where the row sits in the variant hierarchy: a `model` carries what its variants share and is never sold itself.\n * \n * `sku` is the only column the database refuses the row without; everything else has a default or is nullable. A second row with the same `sku` answers 409. This app owns the create: `enabled` defaults from the `new_products_enabled_by_default` tenant setting rather than blindly to true, so an import cannot publish twenty thousand unfinished products the moment it lands, and a product that names no family gets the `default_product_family` one. An explicit value in the body always wins over both.\n *\n * @param {string} sku - The merchant's own article number — unique per tenant, and the value every integration (ERP, shop, feed, price list) joins on. The one identifier a person types, and the fallback this app shows when the catalog holds no name.\n * @param {object} attributeValues - Every attribute value the record carries, in ONE jsonb document — the core of an attribute-driven PIM. A record's properties are not columns here: they are rows in `attributes`, selected per family by `family_attributes`, and their values live under their attribute CODE inside this object.\n\nFour buckets, and an attribute's own flags decide which one it writes to:\n\n `common` the attribute is neither localizable nor scopable — one value, full stop.\n `{\"common\": {\"net_weight\": 2.4, \"colour\": \"black\"}}`\n `locale_specific` `localizable`: one value per language tag.\n `{\"locale_specific\": {\"de_DE\": {\"name\": \"Akku-Bohrschrauber\"}}}`\n `channel_specific` `scopable`: one value per channel.\n `{\"channel_specific\": {\"b2b\": {\"minimum_order_quantity\": 6}}}`\n `channel_locale_specific` both: one value per channel AND language tag.\n `{\"channel_locale_specific\": {\"b2b\": {\"de_DE\": {\"description\": \"…\"}}}}`\n\nA reader takes the most specific bucket that carries the code and falls back through locale, then channel, then `common`. `common` is always last and always consulted, because early imports wrote everything there whatever an attribute's flags said — a reader that skipped it reports an imported catalog as empty. `GET /products/attribute-schema` answers, per field, the exact path a value belongs at (`storage.path`) and that full fallback order (`from`), so no client has to re-derive any of this.\n\nThe value itself is whatever the attribute's `type` implies: a string, a number, a boolean, an option CODE for a select (never its label), a list of codes for a multi-select, `{\"amount\": …, \"unit\": …}` for a measure, a list of `{\"amount\": …, \"currency\": …}` for a price, an asset code for media.\n\nDefaults to `{}`, and an empty object is a normal state — a record nobody has enriched yet. The declared type also admits an array only because every jsonb column of this app shares one mapping; an array is not meaningful here and every reader in this app treats a non-object as empty.\n * @param {object} completeness - How much of what this product's family REQUIRES it actually carries — the number a merchandiser works down. `required` counts the attributes the family marks `is_required`, `filled` how many of those carry a value in ANY bucket, `ratio` is filled/required between 0 and 1 (a family that requires nothing is 1, not undefined), `missing` lists the codes with no value anywhere, sorted, and `computed_at` is when it was measured.\n\nWritten only by `POST /products/{id}/completeness` and by `POST /products/{id}/family`; a plain create or update never touches it, so it is null until one of the two has run. It also stays null for a product with no family — there is nothing to measure it against, and 0 % would be a lie.\n * @param {string} deletedAt - When the product was soft-deleted. `GET /products/grid` and every category-rule evaluation exclude a row that carries one; `GET /products` does NOT — filter on it to read the live catalog.\n * @param {boolean} enabled - Whether the product is offered. A create defaults it from the `new_products_enabled_by_default` tenant setting rather than blindly to true, so an import does not publish twenty thousand unfinished products the moment it lands. An explicit value in the body always wins.\n * @param {string} familyId - The family that decides which attributes this product HAS. Without one nothing is required, completeness cannot be computed and the display name never resolves — `POST /products/{id}/family` is the call that sets it and computes completeness in the same step.\n * @param {string} familyVariantId - Which variant structure of the family this product follows — the axes it splits on. Null on a simple product.\n * @param {ProductsKind} kind - Where the product sits in the variant hierarchy. 'simple' stands on its own. 'model' carries the values its variants share and is never sold itself. 'variant' carries the axis values and points at its model through `parent_id`.\n * @param {string} parentId - The product MODEL this variant belongs to. Only a `variant` carries one. Deleting the model leaves its variants behind with a null parent rather than deleting them.\n * @param {object} quantifiedAssociations - The import-side mirror of associations that carry a quantity — a bundle, a bill of materials, a spare-parts set. NOTHING IN THIS APP READS OR WRITES IT: no route produces it, no route consumes it, and it is null on every product this app has created. The surface that IS served is relational — `product_associations`, whose `quantity` column holds the number, guarded by `association_types.is_quantified`.\n\nIt exists because a PIM import (Akeneo, BMEcat) carries these in one blob keyed by association type code, and the column lets that document round-trip instead of being dropped. The database enforces no shape on it, so what a reader finds is whatever the importer wrote; the example is the conventional form.\n * @param {string} taxClass - The tax class key the prices app resolves a VAT rate from. Free text here — the vocabulary belongs to the app that prices, and `POST /products/batch` exists to hand exactly this column to it in bulk.\n * @throws {RevenexxException}\n * @returns {Promise<Models.Products>}\n * @deprecated Use the object parameter style method for a better developer experience.\n */\n productsCreate(sku: string, attributeValues?: object, completeness?: object, deletedAt?: string, enabled?: boolean, familyId?: string, familyVariantId?: string, kind?: ProductsKind, parentId?: string, quantifiedAssociations?: object, taxClass?: string): Promise<Models.Products>;\n productsCreate(\n paramsOrFirst: { sku: string, attributeValues?: object, completeness?: object, deletedAt?: string, enabled?: boolean, familyId?: string, familyVariantId?: string, kind?: ProductsKind, parentId?: string, quantifiedAssociations?: object, taxClass?: string } | string,\n ...rest: [(object)?, (object)?, (string)?, (boolean)?, (string)?, (string)?, (ProductsKind)?, (string)?, (object)?, (string)?] \n ): Promise<Models.Products> {\n let params: { sku: string, attributeValues?: object, completeness?: object, deletedAt?: string, enabled?: boolean, familyId?: string, familyVariantId?: string, kind?: ProductsKind, parentId?: string, quantifiedAssociations?: object, taxClass?: string };\n \n if ((paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst))) {\n params = (paramsOrFirst || {}) as { sku: string, attributeValues?: object, completeness?: object, deletedAt?: string, enabled?: boolean, familyId?: string, familyVariantId?: string, kind?: ProductsKind, parentId?: string, quantifiedAssociations?: object, taxClass?: string };\n } else {\n params = {\n sku: paramsOrFirst as string,\n attributeValues: rest[0] as object,\n completeness: rest[1] as object,\n deletedAt: rest[2] as string,\n enabled: rest[3] as boolean,\n familyId: rest[4] as string,\n familyVariantId: rest[5] as string,\n kind: rest[6] as ProductsKind,\n parentId: rest[7] as string,\n quantifiedAssociations: rest[8] as object,\n taxClass: rest[9] as string \n };\n }\n \n const sku = params.sku;\n const attributeValues = params.attributeValues;\n const completeness = params.completeness;\n const deletedAt = params.deletedAt;\n const enabled = params.enabled;\n const familyId = params.familyId;\n const familyVariantId = params.familyVariantId;\n const kind = params.kind;\n const parentId = params.parentId;\n const quantifiedAssociations = params.quantifiedAssociations;\n const taxClass = params.taxClass;\n\n if (typeof sku === 'undefined') {\n throw new RevenexxException('Missing required parameter: \"sku\"');\n }\n\n const apiPath = '/v1/products';\n const apiPayload: Payload = {};\n if (typeof attributeValues !== 'undefined') {\n apiPayload['attribute_values'] = attributeValues;\n }\n if (typeof completeness !== 'undefined') {\n apiPayload['completeness'] = completeness;\n }\n if (typeof deletedAt !== 'undefined') {\n apiPayload['deleted_at'] = deletedAt;\n }\n if (typeof enabled !== 'undefined') {\n apiPayload['enabled'] = enabled;\n }\n if (typeof familyId !== 'undefined') {\n apiPayload['family_id'] = familyId;\n }\n if (typeof familyVariantId !== 'undefined') {\n apiPayload['family_variant_id'] = familyVariantId;\n }\n if (typeof kind !== 'undefined') {\n apiPayload['kind'] = kind;\n }\n if (typeof parentId !== 'undefined') {\n apiPayload['parent_id'] = parentId;\n }\n if (typeof quantifiedAssociations !== 'undefined') {\n apiPayload['quantified_associations'] = quantifiedAssociations;\n }\n if (typeof sku !== 'undefined') {\n apiPayload['sku'] = sku;\n }\n if (typeof taxClass !== 'undefined') {\n apiPayload['tax_class'] = taxClass;\n }\n const uri = new URL(this.client.config.endpoint + apiPath);\n\n const apiHeaders: { [header: string]: string } = {\n 'content-type': 'application/json',\n }\n\n return this.client.call(\n 'post',\n uri,\n apiHeaders,\n apiPayload,\n );\n }\n\n /**\n * Answers four fields — id, sku, tax_class and the resolved display name — for a list of ids and/or SKUs in ONE call. It exists for the app on the other side of a product reference: the prices app holds SKUs and needs a tax class, a feed builder holds ids and needs names, and neither should page through the catalog or fire a request per line. Ask by either identifier or both; the two are unioned and a product named twice comes back once.\n * \n * It answers what it FOUND: an id or SKU that names nothing is simply absent from `items` rather than an error, so compare the length of what you sent with what came back if a miss matters. It is not a general product read — for the whole row use `GET /products/{id}`, and for a scannable list use `GET /products/grid`.\n *\n * @param {string[]} params.ids - Product ids, when the caller already holds them.\n * @param {string[]} params.skus - Product SKUs — the identifier a foreign system carries, which is why this route exists at all.\n * @throws {RevenexxException}\n * @returns {Promise<{}>}\n */\n productsBatch(params?: { ids?: string[], skus?: string[] }): Promise<{}>;\n /**\n * Answers four fields — id, sku, tax_class and the resolved display name — for a list of ids and/or SKUs in ONE call. It exists for the app on the other side of a product reference: the prices app holds SKUs and needs a tax class, a feed builder holds ids and needs names, and neither should page through the catalog or fire a request per line. Ask by either identifier or both; the two are unioned and a product named twice comes back once.\n * \n * It answers what it FOUND: an id or SKU that names nothing is simply absent from `items` rather than an error, so compare the length of what you sent with what came back if a miss matters. It is not a general product read — for the whole row use `GET /products/{id}`, and for a scannable list use `GET /products/grid`.\n *\n * @param {string[]} ids - Product ids, when the caller already holds them.\n * @param {string[]} skus - Product SKUs — the identifier a foreign system carries, which is why this route exists at all.\n * @throws {RevenexxException}\n * @returns {Promise<{}>}\n * @deprecated Use the object parameter style method for a better developer experience.\n */\n productsBatch(ids?: string[], skus?: string[]): Promise<{}>;\n productsBatch(\n paramsOrFirst?: { ids?: string[], skus?: string[] } | string[],\n ...rest: [(string[])?] \n ): Promise<{}> {\n let params: { ids?: string[], skus?: string[] };\n \n if (!paramsOrFirst || (paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst))) {\n params = (paramsOrFirst || {}) as { ids?: string[], skus?: string[] };\n } else {\n params = {\n ids: paramsOrFirst as string[],\n skus: rest[0] as string[] \n };\n }\n \n const ids = params.ids;\n const skus = params.skus;\n\n\n const apiPath = '/v1/products/batch';\n const apiPayload: Payload = {};\n if (typeof ids !== 'undefined') {\n apiPayload['ids'] = ids;\n }\n if (typeof skus !== 'undefined') {\n apiPayload['skus'] = skus;\n }\n const uri = new URL(this.client.config.endpoint + apiPath);\n\n const apiHeaders: { [header: string]: string } = {\n 'content-type': 'application/json',\n }\n\n return this.client.call(\n 'post',\n uri,\n apiHeaders,\n apiPayload,\n );\n }\n\n /**\n * The list a merchant can actually scan, as opposed to `GET /products`, which answers SKUs and a jsonb blob. Every row arrives already flattened: its resolved display name and where that name came from, its family code, its stored completeness, and the value of every attribute the catalog marks `usable_in_grid` — no join, no second call. `q` is a case-insensitive substring of the stored `label` column, which falls back to the SKU, so one box finds a product by either. Soft-deleted products are excluded here, unlike `GET /products`.\n * \n * It filters on `q`, `kind`, `enabled` and `family_id`, and on NOTHING ELSE — a query parameter it does not accept is refused with 400 rather than dropped. That matters because of `filters`: the array reports the attributes marked `is_filterable`, which is what a filter bar should OFFER, and it is not a query surface. Filtering on an attribute value is not offered by this API at all — the values live inside a four-bucket jsonb document and are read through a fallback chain, so it is a feature with a design of its own rather than a parameter that was forgotten.\n *\n * @param {number} params.limit - Page size (default 50, max 200). A larger value is clamped rather than refused.\n * @param {number} params.offset - Row offset for pagination (default 0). Page with `page.total` and `page.hasMore`.\n * @param {string} params.order - Sort by one column: 'column' | 'column.asc' | 'column.desc'. A bare column sorts ascending. Anything else is refused with 400.\n * @param {string} params.q - Case-insensitive substring of the display name (or the SKU, when there is no name).\n * @param {Kind} params.kind - Restrict to one product kind.\n * @param {boolean} params.enabled - Restrict to enabled or disabled products.\n * @param {string} params.familyId - Restrict to one family. A family id that does not exist is not an error here — it simply matches nothing.\n * @throws {RevenexxException}\n * @returns {Promise<{}>}\n */\n productsGrid(params?: { limit?: number, offset?: number, order?: string, q?: string, kind?: Kind, enabled?: boolean, familyId?: string }): Promise<{}>;\n /**\n * The list a merchant can actually scan, as opposed to `GET /products`, which answers SKUs and a jsonb blob. Every row arrives already flattened: its resolved display name and where that name came from, its family code, its stored completeness, and the value of every attribute the catalog marks `usable_in_grid` — no join, no second call. `q` is a case-insensitive substring of the stored `label` column, which falls back to the SKU, so one box finds a product by either. Soft-deleted products are excluded here, unlike `GET /products`.\n * \n * It filters on `q`, `kind`, `enabled` and `family_id`, and on NOTHING ELSE — a query parameter it does not accept is refused with 400 rather than dropped. That matters because of `filters`: the array reports the attributes marked `is_filterable`, which is what a filter bar should OFFER, and it is not a query surface. Filtering on an attribute value is not offered by this API at all — the values live inside a four-bucket jsonb document and are read through a fallback chain, so it is a feature with a design of its own rather than a parameter that was forgotten.\n *\n * @param {number} limit - Page size (default 50, max 200). A larger value is clamped rather than refused.\n * @param {number} offset - Row offset for pagination (default 0). Page with `page.total` and `page.hasMore`.\n * @param {string} order - Sort by one column: 'column' | 'column.asc' | 'column.desc'. A bare column sorts ascending. Anything else is refused with 400.\n * @param {string} q - Case-insensitive substring of the display name (or the SKU, when there is no name).\n * @param {Kind} kind - Restrict to one product kind.\n * @param {boolean} enabled - Restrict to enabled or disabled products.\n * @param {string} familyId - Restrict to one family. A family id that does not exist is not an error here — it simply matches nothing.\n * @throws {RevenexxException}\n * @returns {Promise<{}>}\n * @deprecated Use the object parameter style method for a better developer experience.\n */\n productsGrid(limit?: number, offset?: number, order?: string, q?: string, kind?: Kind, enabled?: boolean, familyId?: string): Promise<{}>;\n productsGrid(\n paramsOrFirst?: { limit?: number, offset?: number, order?: string, q?: string, kind?: Kind, enabled?: boolean, familyId?: string } | number,\n ...rest: [(number)?, (string)?, (string)?, (Kind)?, (boolean)?, (string)?] \n ): Promise<{}> {\n let params: { limit?: number, offset?: number, order?: string, q?: string, kind?: Kind, enabled?: boolean, familyId?: string };\n \n if (!paramsOrFirst || (paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst))) {\n params = (paramsOrFirst || {}) as { limit?: number, offset?: number, order?: string, q?: string, kind?: Kind, enabled?: boolean, familyId?: string };\n } else {\n params = {\n limit: paramsOrFirst as number,\n offset: rest[0] as number,\n order: rest[1] as string,\n q: rest[2] as string,\n kind: rest[3] as Kind,\n enabled: rest[4] as boolean,\n familyId: rest[5] as string \n };\n }\n \n const limit = params.limit;\n const offset = params.offset;\n const order = params.order;\n const q = params.q;\n const kind = params.kind;\n const enabled = params.enabled;\n const familyId = params.familyId;\n\n\n const apiPath = '/v1/products/grid';\n const apiPayload: Payload = {};\n if (typeof limit !== 'undefined') {\n apiPayload['limit'] = limit;\n }\n if (typeof offset !== 'undefined') {\n apiPayload['offset'] = offset;\n }\n if (typeof order !== 'undefined') {\n apiPayload['order'] = order;\n }\n if (typeof q !== 'undefined') {\n apiPayload['q'] = q;\n }\n if (typeof kind !== 'undefined') {\n apiPayload['kind'] = kind;\n }\n if (typeof enabled !== 'undefined') {\n apiPayload['enabled'] = enabled;\n }\n if (typeof familyId !== 'undefined') {\n apiPayload['family_id'] = familyId;\n }\n const uri = new URL(this.client.config.endpoint + apiPath);\n\n const apiHeaders: { [header: string]: string } = {\n }\n\n return this.client.call(\n 'get',\n uri,\n apiHeaders,\n apiPayload,\n );\n }\n\n /**\n * What is this product CALLED? A product's name is an attribute rather than a column, and which attribute it is, is per family — so no plain read can answer it. This resolves up to 500 products at once, by id and/or SKU: it reads families.label_attribute (falling back to the default_label_attribute setting, then to the conventional `name`) and looks the value up through the scoped attribute_values document — common, then locale_specific in the label_locales order, then the channel buckets.\n * \n * It reports WHERE the name was found, which is the half that matters: `source: \"sku\"` means the catalog holds no name for this product and the SKU is standing in for one, so show it as a missing name rather than as a name. Writes nothing, and answers only what it found.\n *\n * @param {string[]} params.ids - Product ids to name. At most 500.\n * @param {string[]} params.skus - Product SKUs to name. At most 500.\n * @throws {RevenexxException}\n * @returns {Promise<{}>}\n */\n productsLabels(params?: { ids?: string[], skus?: string[] }): Promise<{}>;\n /**\n * What is this product CALLED? A product's name is an attribute rather than a column, and which attribute it is, is per family — so no plain read can answer it. This resolves up to 500 products at once, by id and/or SKU: it reads families.label_attribute (falling back to the default_label_attribute setting, then to the conventional `name`) and looks the value up through the scoped attribute_values document — common, then locale_specific in the label_locales order, then the channel buckets.\n * \n * It reports WHERE the name was found, which is the half that matters: `source: \"sku\"` means the catalog holds no name for this product and the SKU is standing in for one, so show it as a missing name rather than as a name. Writes nothing, and answers only what it found.\n *\n * @param {string[]} ids - Product ids to name. At most 500.\n * @param {string[]} skus - Product SKUs to name. At most 500.\n * @throws {RevenexxException}\n * @returns {Promise<{}>}\n * @deprecated Use the object parameter style method for a better developer experience.\n */\n productsLabels(ids?: string[], skus?: string[]): Promise<{}>;\n productsLabels(\n paramsOrFirst?: { ids?: string[], skus?: string[] } | string[],\n ...rest: [(string[])?] \n ): Promise<{}> {\n let params: { ids?: string[], skus?: string[] };\n \n if (!paramsOrFirst || (paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst))) {\n params = (paramsOrFirst || {}) as { ids?: string[], skus?: string[] };\n } else {\n params = {\n ids: paramsOrFirst as string[],\n skus: rest[0] as string[] \n };\n }\n \n const ids = params.ids;\n const skus = params.skus;\n\n\n const apiPath = '/v1/products/labels';\n const apiPayload: Payload = {};\n if (typeof ids !== 'undefined') {\n apiPayload['ids'] = ids;\n }\n if (typeof skus !== 'undefined') {\n apiPayload['skus'] = skus;\n }\n const uri = new URL(this.client.config.endpoint + apiPath);\n\n const apiHeaders: { [header: string]: string } = {\n 'content-type': 'application/json',\n }\n\n return this.client.call(\n 'post',\n uri,\n apiHeaders,\n apiPayload,\n );\n }\n\n /**\n * One relation from one product to another, of a declared type: this drill's accessories, this bundle's parts, this article's cross-sells. `quantity` is the number in \"this bundle contains 4 casters\" and is meaningful only when the association type carries `is_quantified`. This relational surface is the one this app serves; the `products.quantified_associations` column is an importer's blob that no route here reads or writes.\n * \n * Every column of `product_associations` is an exact-match query parameter, `order` sorts by one column, and `limit`/`offset` page through `page.total`. A query key that is NOT a column is dropped rather than refused, and the `filter` object echoes the ones that were understood — that echo is the only way to tell an unfiltered answer from an empty one. It reads rows exactly as they are stored: no join is resolved, no jsonb value is unpacked.\n * \n * Answered from the gateway's tenant cache for up to 30 minutes and dropped the moment this entity is written, because the data model changes weekly at most and every product page asks the same question.\n *\n * @param {number} params.limit - Page size (default 50, max 200). A larger value is clamped rather than refused.\n * @param {number} params.offset - Row offset for pagination (default 0). Page with `page.total` and `page.hasMore`.\n * @param {string} params.order - Sort by one column: 'column' | 'column.asc' | 'column.desc'. A bare column sorts ascending. Anything else is refused with 400.\n * @param {string} params.id - Exact match on `id`. The row's own id, generated by the database. A client never sends one; it reads one back and uses it in the path of every later call.\n * @param {string} params.productId - Exact match on `product_id`. The product the relation starts at — the one whose detail page shows it.\n * @param {string} params.associationTypeId - Exact match on `association_type_id`. Which kind of relation this is — the `association_types` row.\n * @param {string} params.targetProductId - Exact match on `target_product_id`. The product the relation points at — the accessory, the spare part, the cross-sell.\n * @param {number} params.quantity - Exact match on `quantity`. How many of the target belong to the source — the 4 in \"this bundle contains 4 casters\". Only meaningful when the association type carries `is_quantified`; null on an ordinary cross-sell.\n * @param {number} params.position - Exact match on `position`. Order in which the targets are shown, ascending.\n * @param {string} params.createdAt - Exact match on `created_at`. When the row was created. Server-set — it is not part of any request body.\n * @throws {RevenexxException}\n * @returns {Promise<{}>}\n */\n productsProductAssociationsList(params?: { limit?: number, offset?: number, order?: string, id?: string, productId?: string, associationTypeId?: string, targetProductId?: string, quantity?: number, position?: number, createdAt?: string }): Promise<{}>;\n /**\n * One relation from one product to another, of a declared type: this drill's accessories, this bundle's parts, this article's cross-sells. `quantity` is the number in \"this bundle contains 4 casters\" and is meaningful only when the association type carries `is_quantified`. This relational surface is the one this app serves; the `products.quantified_associations` column is an importer's blob that no route here reads or writes.\n * \n * Every column of `product_associations` is an exact-match query parameter, `order` sorts by one column, and `limit`/`offset` page through `page.total`. A query key that is NOT a column is dropped rather than refused, and the `filter` object echoes the ones that were understood — that echo is the only way to tell an unfiltered answer from an empty one. It reads rows exactly as they are stored: no join is resolved, no jsonb value is unpacked.\n * \n * Answered from the gateway's tenant cache for up to 30 minutes and dropped the moment this entity is written, because the data model changes weekly at most and every product page asks the same question.\n *\n * @param {number} limit - Page size (default 50, max 200). A larger value is clamped rather than refused.\n * @param {number} offset - Row offset for pagination (default 0). Page with `page.total` and `page.hasMore`.\n * @param {string} order - Sort by one column: 'column' | 'column.asc' | 'column.desc'. A bare column sorts ascending. Anything else is refused with 400.\n * @param {string} id - Exact match on `id`. The row's own id, generated by the database. A client never sends one; it reads one back and uses it in the path of every later call.\n * @param {string} productId - Exact match on `product_id`. The product the relation starts at — the one whose detail page shows it.\n * @param {string} associationTypeId - Exact match on `association_type_id`. Which kind of relation this is — the `association_types` row.\n * @param {string} targetProductId - Exact match on `target_product_id`. The product the relation points at — the accessory, the spare part, the cross-sell.\n * @param {number} quantity - Exact match on `quantity`. How many of the target belong to the source — the 4 in \"this bundle contains 4 casters\". Only meaningful when the association type carries `is_quantified`; null on an ordinary cross-sell.\n * @param {number} position - Exact match on `position`. Order in which the targets are shown, ascending.\n * @param {string} createdAt - Exact match on `created_at`. When the row was created. Server-set — it is not part of any request body.\n * @throws {RevenexxException}\n * @returns {Promise<{}>}\n * @deprecated Use the object parameter style method for a better developer experience.\n */\n productsProductAssociationsList(limit?: number, offset?: number, order?: string, id?: string, productId?: string, associationTypeId?: string, targetProductId?: string, quantity?: number, position?: number, createdAt?: string): Promise<{}>;\n productsProductAssociationsList(\n paramsOrFirst?: { limit?: number, offset?: number, order?: string, id?: string, productId?: string, associationTypeId?: string, targetProductId?: string, quantity?: number, position?: number, createdAt?: string } | number,\n ...rest: [(number)?, (string)?, (string)?, (string)?, (string)?, (string)?, (number)?, (number)?, (string)?] \n ): Promise<{}> {\n let params: { limit?: number, offset?: number, order?: string, id?: string, productId?: string, associationTypeId?: string, targetProductId?: string, quantity?: number, position?: number, createdAt?: string };\n \n if (!paramsOrFirst || (paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst))) {\n params = (paramsOrFirst || {}) as { limit?: number, offset?: number, order?: string, id?: string, productId?: string, associationTypeId?: string, targetProductId?: string, quantity?: number, position?: number, createdAt?: string };\n } else {\n params = {\n limit: paramsOrFirst as number,\n offset: rest[0] as number,\n order: rest[1] as string,\n id: rest[2] as string,\n productId: rest[3] as string,\n associationTypeId: rest[4] as string,\n targetProductId: rest[5] as string,\n quantity: rest[6] as number,\n position: rest[7] as number,\n createdAt: rest[8] as string \n };\n }\n \n const limit = params.limit;\n const offset = params.offset;\n const order = params.order;\n const id = params.id;\n const productId = params.productId;\n const associationTypeId = params.associationTypeId;\n const targetProductId = params.targetProductId;\n const quantity = params.quantity;\n const position = params.position;\n const createdAt = params.createdAt;\n\n\n const apiPath = '/v1/products/product_associations';\n const apiPayload: Payload = {};\n if (typeof limit !== 'undefined') {\n apiPayload['limit'] = limit;\n }\n if (typeof offset !== 'undefined') {\n apiPayload['offset'] = offset;\n }\n if (typeof order !== 'undefined') {\n apiPayload['order'] = order;\n }\n if (typeof id !== 'undefined') {\n apiPayload['id'] = id;\n }\n if (typeof productId !== 'undefined') {\n apiPayload['product_id'] = productId;\n }\n if (typeof associationTypeId !== 'undefined') {\n apiPayload['association_type_id'] = associationTypeId;\n }\n if (typeof targetProductId !== 'undefined') {\n apiPayload['target_product_id'] = targetProductId;\n }\n if (typeof quantity !== 'undefined') {\n apiPayload['quantity'] = quantity;\n }\n if (typeof position !== 'undefined') {\n apiPayload['position'] = position;\n }\n if (typeof createdAt !== 'undefined') {\n apiPayload['created_at'] = createdAt;\n }\n const uri = new URL(this.client.config.endpoint + apiPath);\n\n const apiHeaders: { [header: string]: string } = {\n }\n\n return this.client.call(\n 'get',\n uri,\n apiHeaders,\n apiPayload,\n );\n }\n\n /**\n * Creates one product association and answers 201 with the stored row, including the id and the timestamps the database filled in — a client never sends an id, it reads one back and uses it in the path of every later call.\n * \n * One relation from one product to another, of a declared type: this drill's accessories, this bundle's parts, this article's cross-sells. `quantity` is the number in \"this bundle contains 4 casters\" and is meaningful only when the association type carries `is_quantified`. This relational surface is the one this app serves; the `products.quantified_associations` column is an importer's blob that no route here reads or writes.\n * \n * `product_id`, `association_type_id`, `target_product_id` are the only columns the database refuses the row without; everything else has a default or is nullable. A second row with the same `product_id`, `association_type_id`, `target_product_id` answers 409.\n *\n * @param {string} params.associationTypeId - Which kind of relation this is — the `association_types` row.\n * @param {string} params.productId - The product the relation starts at — the one whose detail page shows it.\n * @param {string} params.targetProductId - The product the relation points at — the accessory, the spare part, the cross-sell.\n * @param {number} params.position - Order in which the targets are shown, ascending.\n * @param {number} params.quantity - How many of the target belong to the source — the 4 in \"this bundle contains 4 casters\". Only meaningful when the association type carries `is_quantified`; null on an ordinary cross-sell.\n * @throws {RevenexxException}\n * @returns {Promise<Models.ProductAssociations>}\n */\n productsProductAssociationsCreate(params: { associationTypeId: string, productId: string, targetProductId: string, position?: number, quantity?: number }): Promise<Models.ProductAssociations>;\n /**\n * Creates one product association and answers 201 with the stored row, including the id and the timestamps the database filled in — a client never sends an id, it reads one back and uses it in the path of every later call.\n * \n * One relation from one product to another, of a declared type: this drill's accessories, this bundle's parts, this article's cross-sells. `quantity` is the number in \"this bundle contains 4 casters\" and is meaningful only when the association type carries `is_quantified`. This relational surface is the one this app serves; the `products.quantified_associations` column is an importer's blob that no route here reads or writes.\n * \n * `product_id`, `association_type_id`, `target_product_id` are the only columns the database refuses the row without; everything else has a default or is nullable. A second row with the same `product_id`, `association_type_id`, `target_product_id` answers 409.\n *\n * @param {string} associationTypeId - Which kind of relation this is — the `association_types` row.\n * @param {string} productId - The product the relation starts at — the one whose detail page shows it.\n * @param {string} targetProductId - The product the relation points at — the accessory, the spare part, the cross-sell.\n * @param {number} position - Order in which the targets are shown, ascending.\n * @param {number} quantity - How many of the target belong to the source — the 4 in \"this bundle contains 4 casters\". Only meaningful when the association type carries `is_quantified`; null on an ordinary cross-sell.\n * @throws {RevenexxException}\n * @returns {Promise<Models.ProductAssociations>}\n * @deprecated Use the object parameter style method for a better developer experience.\n */\n productsProductAssociationsCreate(associationTypeId: string, productId: string, targetProductId: string, position?: number, quantity?: number): Promise<Models.ProductAssociations>;\n productsProductAssociationsCreate(\n paramsOrFirst: { associationTypeId: string, productId: string, targetProductId: string, position?: number, quantity?: number } | string,\n ...rest: [(string)?, (string)?, (number)?, (number)?] \n ): Promise<Models.ProductAssociations> {\n let params: { associationTypeId: string, productId: string, targetProductId: string, position?: number, quantity?: number };\n \n if ((paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst))) {\n params = (paramsOrFirst || {}) as { associationTypeId: string, productId: string, targetProductId: string, position?: number, quantity?: number };\n } else {\n params = {\n associationTypeId: paramsOrFirst as string,\n productId: rest[0] as string,\n targetProductId: rest[1] as string,\n position: rest[2] as number,\n quantity: rest[3] as number \n };\n }\n \n const associationTypeId = params.associationTypeId;\n const productId = params.productId;\n const targetProductId = params.targetProductId;\n const position = params.position;\n const quantity = params.quantity;\n\n if (typeof associationTypeId === 'undefined') {\n throw new RevenexxException('Missing required parameter: \"associationTypeId\"');\n }\n if (typeof productId === 'undefined') {\n throw new RevenexxException('Missing required parameter: \"productId\"');\n }\n if (typeof targetProductId === 'undefined') {\n throw new RevenexxException('Missing required parameter: \"targetProductId\"');\n }\n\n const apiPath = '/v1/products/product_associations';\n const apiPayload: Payload = {};\n if (typeof associationTypeId !== 'undefined') {\n apiPayload['association_type_id'] = associationTypeId;\n }\n if (typeof position !== 'undefined') {\n apiPayload['position'] = position;\n }\n if (typeof productId !== 'undefined') {\n apiPayload['product_id'] = productId;\n }\n if (typeof quantity !== 'undefined') {\n apiPayload['quantity'] = quantity;\n }\n if (typeof targetProductId !== 'undefined') {\n apiPayload['target_product_id'] = targetProductId;\n }\n const uri = new URL(this.client.config.endpoint + apiPath);\n\n const apiHeaders: { [header: string]: string } = {\n 'content-type': 'application/json',\n }\n\n return this.client.call(\n 'post',\n uri,\n apiHeaders,\n apiPayload,\n );\n }\n\n /**\n * Deletes one product association by id. It is a hard delete — the row is gone, and the answer is a confirmation rather than a result to branch on.\n * \n * Nothing in this schema references it, so nothing else changes.\n * \n * An id no product association of this tenant carries answers 404; there is no 409, because every foreign key pointing at this entity resolves itself on delete rather than blocking one.\n *\n * @param {string} params.id - The `product_associations` row to address, by id. It names a row THIS TENANT holds, so no example is published — a uuid this app invented would document a call that answers 404, and a real one would be another tenant's data. Read one from `GET /v1/products/product_associations`. An id no product association of this tenant carries answers 404; a malformed one answers 400 before the route is reached.\n * @throws {RevenexxException}\n * @returns {Promise<{}>}\n */\n productsProductAssociationsDelete(params: { id: string }): Promise<{}>;\n /**\n * Deletes one product association by id. It is a hard delete — the row is gone, and the answer is a confirmation rather than a result to branch on.\n * \n * Nothing in this schema references it, so nothing else changes.\n * \n * An id no product association of this tenant carries answers 404; there is no 409, because every foreign key pointing at this entity resolves itself on delete rather than blocking one.\n *\n * @param {string} id - The `product_associations` row to address, by id. It names a row THIS TENANT holds, so no example is published — a uuid this app invented would document a call that answers 404, and a real one would be another tenant's data. Read one from `GET /v1/products/product_associations`. An id no product association of this tenant carries answers 404; a malformed one answers 400 before the route is reached.\n * @throws {RevenexxException}\n * @returns {Promise<{}>}\n * @deprecated Use the object parameter style method for a better developer experience.\n */\n productsProductAssociationsDelete(id: string): Promise<{}>;\n productsProductAssociationsDelete(\n paramsOrFirst: { id: string } | string \n ): Promise<{}> {\n let params: { id: string };\n \n if ((paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst))) {\n params = (paramsOrFirst || {}) as { id: string };\n } else {\n params = {\n id: paramsOrFirst as string \n };\n }\n \n const id = params.id;\n\n if (typeof id === 'undefined') {\n throw new RevenexxException('Missing required parameter: \"id\"');\n }\n\n const apiPath = '/v1/products/product_associations/{id}'.replace('{id}', id);\n const apiPayload: Payload = {};\n const uri = new URL(this.client.config.endpoint + apiPath);\n\n const apiHeaders: { [header: string]: string } = {\n }\n\n return this.client.call(\n 'delete',\n uri,\n apiHeaders,\n apiPayload,\n );\n }\n\n /**\n * Reads one product association by its id — the whole row, every column, as it is stored.\n * \n * One relation from one product to another, of a declared type: this drill's accessories, this bundle's parts, this article's cross-sells. `quantity` is the number in \"this bundle contains 4 casters\" and is meaningful only when the association type carries `is_quantified`. This relational surface is the one this app serves; the `products.quantified_associations` column is an importer's blob that no route here reads or writes.\n * \n * An id no product association of this tenant carries answers 404, and so does one belonging to another tenant: row-level security makes that row invisible rather than forbidden. A malformed id answers 400 before the route is reached.\n * \n * Answered from the gateway's tenant cache for up to 30 minutes and dropped the moment this entity is written, because the data model changes weekly at most and every product page asks the same question.\n *\n * @param {string} params.id - The `product_associations` row to address, by id. It names a row THIS TENANT holds, so no example is published — a uuid this app invented would document a call that answers 404, and a real one would be another tenant's data. Read one from `GET /v1/products/product_associations`. An id no product association of this tenant carries answers 404; a malformed one answers 400 before the route is reached.\n * @throws {RevenexxException}\n * @returns {Promise<Models.ProductAssociations>}\n */\n productsProductAssociationsGet(params: { id: string }): Promise<Models.ProductAssociations>;\n /**\n * Reads one product association by its id — the whole row, every column, as it is stored.\n * \n * One relation from one product to another, of a declared type: this drill's accessories, this bundle's parts, this article's cross-sells. `quantity` is the number in \"this bundle contains 4 casters\" and is meaningful only when the association type carries `is_quantified`. This relational surface is the one this app serves; the `products.quantified_associations` column is an importer's blob that no route here reads or writes.\n * \n * An id no product association of this tenant carries answers 404, and so does one belonging to another tenant: row-level security makes that row invisible rather than forbidden. A malformed id answers 400 before the route is reached.\n * \n * Answered from the gateway's tenant cache for up to 30 minutes and dropped the moment this entity is written, because the data model changes weekly at most and every product page asks the same question.\n *\n * @param {string} id - The `product_associations` row to address, by id. It names a row THIS TENANT holds, so no example is published — a uuid this app invented would document a call that answers 404, and a real one would be another tenant's data. Read one from `GET /v1/products/product_associations`. An id no product association of this tenant carries answers 404; a malformed one answers 400 before the route is reached.\n * @throws {RevenexxException}\n * @returns {Promise<Models.ProductAssociations>}\n * @deprecated Use the object parameter style method for a better developer experience.\n */\n productsProductAssociationsGet(id: string): Promise<Models.ProductAssociations>;\n productsProductAssociationsGet(\n paramsOrFirst: { id: string } | string \n ): Promise<Models.ProductAssociations> {\n let params: { id: string };\n \n if ((paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst))) {\n params = (paramsOrFirst || {}) as { id: string };\n } else {\n params = {\n id: paramsOrFirst as string \n };\n }\n \n const id = params.id;\n\n if (typeof id === 'undefined') {\n throw new RevenexxException('Missing required parameter: \"id\"');\n }\n\n const apiPath = '/v1/products/product_associations/{id}'.replace('{id}', id);\n const apiPayload: Payload = {};\n const uri = new URL(this.client.config.endpoint + apiPath);\n\n const apiHeaders: { [header: string]: string } = {\n }\n\n return this.client.call(\n 'get',\n uri,\n apiHeaders,\n apiPayload,\n );\n }\n\n /**\n * Updates one product association by id. A partial patch: the body names only the columns to change and every column it leaves out keeps its current value, so there is no read-modify-write and no way to blank a field by forgetting it.\n * \n * One relation from one product to another, of a declared type: this drill's accessories, this bundle's parts, this article's cross-sells. `quantity` is the number in \"this bundle contains 4 casters\" and is meaningful only when the association type carries `is_quantified`. This relational surface is the one this app serves; the `products.quantified_associations` column is an importer's blob that no route here reads or writes.\n * \n * A body that names nothing writable is refused with 400 rather than answered as a no-op, an id nobody carries answers 404, and a value that collides on `product_id`, `association_type_id`, `target_product_id` answers 409.\n *\n * @param {string} params.id - The `product_associations` row to address, by id. It names a row THIS TENANT holds, so no example is published — a uuid this app invented would document a call that answers 404, and a real one would be another tenant's data. Read one from `GET /v1/products/product_associations`. An id no product association of this tenant carries answers 404; a malformed one answers 400 before the route is reached.\n * @param {string} params.associationTypeId - Which kind of relation this is — the `association_types` row.\n * @param {number} params.position - Order in which the targets are shown, ascending.\n * @param {string} params.productId - The product the relation starts at — the one whose detail page shows it.\n * @param {number} params.quantity - How many of the target belong to the source — the 4 in \"this bundle contains 4 casters\". Only meaningful when the association type carries `is_quantified`; null on an ordinary cross-sell.\n * @param {string} params.targetProductId - The product the relation points at — the accessory, the spare part, the cross-sell.\n * @throws {RevenexxException}\n * @returns {Promise<Models.ProductAssociations>}\n */\n productsProductAssociationsUpdate(params: { id: string, associationTypeId?: string, position?: number, productId?: string, quantity?: number, targetProductId?: string }): Promise<Models.ProductAssociations>;\n /**\n * Updates one product association by id. A partial patch: the body names only the columns to change and every column it leaves out keeps its current value, so there is no read-modify-write and no way to blank a field by forgetting it.\n * \n * One relation from one product to another, of a declared type: this drill's accessories, this bundle's parts, this article's cross-sells. `quantity` is the number in \"this bundle contains 4 casters\" and is meaningful only when the association type carries `is_quantified`. This relational surface is the one this app serves; the `products.quantified_associations` column is an importer's blob that no route here reads or writes.\n * \n * A body that names nothing writable is refused with 400 rather than answered as a no-op, an id nobody carries answers 404, and a value that collides on `product_id`, `association_type_id`, `target_product_id` answers 409.\n *\n * @param {string} id - The `product_associations` row to address, by id. It names a row THIS TENANT holds, so no example is published — a uuid this app invented would document a call that answers 404, and a real one would be another tenant's data. Read one from `GET /v1/products/product_associations`. An id no product association of this tenant carries answers 404; a malformed one answers 400 before the route is reached.\n * @param {string} associationTypeId - Which kind of relation this is — the `association_types` row.\n * @param {number} position - Order in which the targets are shown, ascending.\n * @param {string} productId - The product the relation starts at — the one whose detail page shows it.\n * @param {number} quantity - How many of the target belong to the source — the 4 in \"this bundle contains 4 casters\". Only meaningful when the association type carries `is_quantified`; null on an ordinary cross-sell.\n * @param {string} targetProductId - The product the relation points at — the accessory, the spare part, the cross-sell.\n * @throws {RevenexxException}\n * @returns {Promise<Models.ProductAssociations>}\n * @deprecated Use the object parameter style method for a better developer experience.\n */\n productsProductAssociationsUpdate(id: string, associationTypeId?: string, position?: number, productId?: string, quantity?: number, targetProductId?: string): Promise<Models.ProductAssociations>;\n productsProductAssociationsUpdate(\n paramsOrFirst: { id: string, associationTypeId?: string, position?: number, productId?: string, quantity?: number, targetProductId?: string } | string,\n ...rest: [(string)?, (number)?, (string)?, (number)?, (string)?] \n ): Promise<Models.ProductAssociations> {\n let params: { id: string, associationTypeId?: string, position?: number, productId?: string, quantity?: number, targetProductId?: string };\n \n if ((paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst))) {\n params = (paramsOrFirst || {}) as { id: string, associationTypeId?: string, position?: number, productId?: string, quantity?: number, targetProductId?: string };\n } else {\n params = {\n id: paramsOrFirst as string,\n associationTypeId: rest[0] as string,\n position: rest[1] as number,\n productId: rest[2] as string,\n quantity: rest[3] as number,\n targetProductId: rest[4] as string \n };\n }\n \n const id = params.id;\n const associationTypeId = params.associationTypeId;\n const position = params.position;\n const productId = params.productId;\n const quantity = params.quantity;\n const targetProductId = params.targetProductId;\n\n if (typeof id === 'undefined') {\n throw new RevenexxException('Missing required parameter: \"id\"');\n }\n\n const apiPath = '/v1/products/product_associations/{id}'.replace('{id}', id);\n const apiPayload: Payload = {};\n if (typeof associationTypeId !== 'undefined') {\n apiPayload['association_type_id'] = associationTypeId;\n }\n if (typeof position !== 'undefined') {\n apiPayload['position'] = position;\n }\n if (typeof productId !== 'undefined') {\n apiPayload['product_id'] = productId;\n }\n if (typeof quantity !== 'undefined') {\n apiPayload['quantity'] = quantity;\n }\n if (typeof targetProductId !== 'undefined') {\n apiPayload['target_product_id'] = targetProductId;\n }\n const uri = new URL(this.client.config.endpoint + apiPath);\n\n const apiHeaders: { [header: string]: string } = {\n 'content-type': 'application/json',\n }\n\n return this.client.call(\n 'put',\n uri,\n apiHeaders,\n apiPayload,\n );\n }\n\n /**\n * The index of the enums this app ENFORCES — `product-kinds`, `membership-sources`, `rule-matches`, `asset-sources` — served by the app that owns the CHECK constraint each one is parsed out of, so a UI never has to keep its own copy of a status map and watch it drift. Names and titles only: fetch one by name for its values, badge tones and descriptions.\n * \n * The set is a fixed property of this app rather than tenant data, so it is the same list for every tenant. `attributes.type` is deliberately absent: it carries no CHECK, because the whole point of an attribute-driven PIM is that the type list is data an integrator extends.\n *\n * @throws {RevenexxException}\n * @returns {Promise<{}>}\n */\n productsVocabulariesList(): Promise<{}> {\n\n const apiPath = '/v1/products/vocabularies';\n const apiPayload: Payload = {};\n const uri = new URL(this.client.config.endpoint + apiPath);\n\n const apiHeaders: { [header: string]: string } = {\n }\n\n return this.client.call(\n 'get',\n uri,\n apiHeaders,\n apiPayload,\n );\n }\n\n /**\n * One vocabulary with every value it admits, each with a title, a description and the badge tone a UI should paint it in. The value set is parsed out of the CHECK constraint in schema.json, so what is served IS what is enforced. Labels are curated on top and can only add words and colour — a permitted value nobody labelled still appears, titled from its own key.\n *\n * @param {string} params.name - The vocabulary name, as listed by GET /products/vocabularies.\n * @throws {RevenexxException}\n * @returns {Promise<{}>}\n */\n productsVocabulariesGet(params: { name: string }): Promise<{}>;\n /**\n * One vocabulary with every value it admits, each with a title, a description and the badge tone a UI should paint it in. The value set is parsed out of the CHECK constraint in schema.json, so what is served IS what is enforced. Labels are curated on top and can only add words and colour — a permitted value nobody labelled still appears, titled from its own key.\n *\n * @param {string} name - The vocabulary name, as listed by GET /products/vocabularies.\n * @throws {RevenexxException}\n * @returns {Promise<{}>}\n * @deprecated Use the object parameter style method for a better developer experience.\n */\n productsVocabulariesGet(name: string): Promise<{}>;\n productsVocabulariesGet(\n paramsOrFirst: { name: string } | string \n ): Promise<{}> {\n let params: { name: string };\n \n if ((paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst))) {\n params = (paramsOrFirst || {}) as { name: string };\n } else {\n params = {\n name: paramsOrFirst as string \n };\n }\n \n const name = params.name;\n\n if (typeof name === 'undefined') {\n throw new RevenexxException('Missing required parameter: \"name\"');\n }\n\n const apiPath = '/v1/products/vocabularies/{name}'.replace('{name}', name);\n const apiPayload: Payload = {};\n const uri = new URL(this.client.config.endpoint + apiPath);\n\n const apiHeaders: { [header: string]: string } = {\n }\n\n return this.client.call(\n 'get',\n uri,\n apiHeaders,\n apiPayload,\n );\n }\n\n /**\n * Deletes one product by id. It is a hard delete — the row is gone, and the answer is a confirmation rather than a result to branch on.\n * \n * It takes what hangs off it: product category memberships (`product_id`), product associations (`product_id` and `target_product_id`) are deleted with it. `products.parent_id` is set to null instead, so the rows that pointed at it survive the delete rather than going with it.\n * \n * An id no product of this tenant carries answers 404; there is no 409, because every foreign key pointing at this entity resolves itself on delete rather than blocking one. `products.deleted_at` is a SOFT-delete marker that the grid and every category-rule evaluation honour, but no route in this app ever writes it — to soft-delete instead, `PUT /products/{id}` with a `deleted_at`.\n *\n * @param {string} params.id - The `products` row to address, by id. It names a row THIS TENANT holds, so no example is published — a uuid this app invented would document a call that answers 404, and a real one would be another tenant's data. Read one from `GET /v1/products`. An id no product of this tenant carries answers 404; a malformed one answers 400 before the route is reached.\n * @throws {RevenexxException}\n * @returns {Promise<{}>}\n */\n productsDelete(params: { id: string }): Promise<{}>;\n /**\n * Deletes one product by id. It is a hard delete — the row is gone, and the answer is a confirmation rather than a result to branch on.\n * \n * It takes what hangs off it: product category memberships (`product_id`), product associations (`product_id` and `target_product_id`) are deleted with it. `products.parent_id` is set to null instead, so the rows that pointed at it survive the delete rather than going with it.\n * \n * An id no product of this tenant carries answers 404; there is no 409, because every foreign key pointing at this entity resolves itself on delete rather than blocking one. `products.deleted_at` is a SOFT-delete marker that the grid and every category-rule evaluation honour, but no route in this app ever writes it — to soft-delete instead, `PUT /products/{id}` with a `deleted_at`.\n *\n * @param {string} id - The `products` row to address, by id. It names a row THIS TENANT holds, so no example is published — a uuid this app invented would document a call that answers 404, and a real one would be another tenant's data. Read one from `GET /v1/products`. An id no product of this tenant carries answers 404; a malformed one answers 400 before the route is reached.\n * @throws {RevenexxException}\n * @returns {Promise<{}>}\n * @deprecated Use the object parameter style method for a better developer experience.\n */\n productsDelete(id: string): Promise<{}>;\n productsDelete(\n paramsOrFirst: { id: string } | string \n ): Promise<{}> {\n let params: { id: string };\n \n if ((paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst))) {\n params = (paramsOrFirst || {}) as { id: string };\n } else {\n params = {\n id: paramsOrFirst as string \n };\n }\n \n const id = params.id;\n\n if (typeof id === 'undefined') {\n throw new RevenexxException('Missing required parameter: \"id\"');\n }\n\n const apiPath = '/v1/products/{id}'.replace('{id}', id);\n const apiPayload: Payload = {};\n const uri = new URL(this.client.config.endpoint + apiPath);\n\n const apiHeaders: { [header: string]: string } = {\n }\n\n return this.client.call(\n 'delete',\n uri,\n apiHeaders,\n apiPayload,\n );\n }\n\n /**\n * Reads one product by its id — the whole row, every column, as it is stored.\n * \n * The catalog itself. A product row carries only what every product has — SKU, kind, family, enabled, tax class — and everything the tenant modelled lives in the `attribute_values` jsonb document, keyed by attribute CODE inside one of four scope buckets (common, per locale, per channel, per channel and locale). `label` is a generated column, maintained by the database so a grid of twenty thousand rows can sort and filter on a name with no join. `kind` says where the row sits in the variant hierarchy: a `model` carries what its variants share and is never sold itself.\n * \n * An id no product of this tenant carries answers 404, and so does one belonging to another tenant: row-level security makes that row invisible rather than forbidden. A malformed id answers 400 before the route is reached. Nothing is resolved for you here — for the display name, the family code and the grid attributes already unpacked, use `GET /products/grid` or `POST /products/labels`.\n *\n * @param {string} params.id - The `products` row to address, by id. It names a row THIS TENANT holds, so no example is published — a uuid this app invented would document a call that answers 404, and a real one would be another tenant's data. Read one from `GET /v1/products`. An id no product of this tenant carries answers 404; a malformed one answers 400 before the route is reached.\n * @throws {RevenexxException}\n * @returns {Promise<Models.Products>}\n */\n productsGet(params: { id: string }): Promise<Models.Products>;\n /**\n * Reads one product by its id — the whole row, every column, as it is stored.\n * \n * The catalog itself. A product row carries only what every product has — SKU, kind, family, enabled, tax class — and everything the tenant modelled lives in the `attribute_values` jsonb document, keyed by attribute CODE inside one of four scope buckets (common, per locale, per channel, per channel and locale). `label` is a generated column, maintained by the database so a grid of twenty thousand rows can sort and filter on a name with no join. `kind` says where the row sits in the variant hierarchy: a `model` carries what its variants share and is never sold itself.\n * \n * An id no product of this tenant carries answers 404, and so does one belonging to another tenant: row-level security makes that row invisible rather than forbidden. A malformed id answers 400 before the route is reached. Nothing is resolved for you here — for the display name, the family code and the grid attributes already unpacked, use `GET /products/grid` or `POST /products/labels`.\n *\n * @param {string} id - The `products` row to address, by id. It names a row THIS TENANT holds, so no example is published — a uuid this app invented would document a call that answers 404, and a real one would be another tenant's data. Read one from `GET /v1/products`. An id no product of this tenant carries answers 404; a malformed one answers 400 before the route is reached.\n * @throws {RevenexxException}\n * @returns {Promise<Models.Products>}\n * @deprecated Use the object parameter style method for a better developer experience.\n */\n productsGet(id: string): Promise<Models.Products>;\n productsGet(\n paramsOrFirst: { id: string } | string \n ): Promise<Models.Products> {\n let params: { id: string };\n \n if ((paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst))) {\n params = (paramsOrFirst || {}) as { id: string };\n } else {\n params = {\n id: paramsOrFirst as string \n };\n }\n \n const id = params.id;\n\n if (typeof id === 'undefined') {\n throw new RevenexxException('Missing required parameter: \"id\"');\n }\n\n const apiPath = '/v1/products/{id}'.replace('{id}', id);\n const apiPayload: Payload = {};\n const uri = new URL(this.client.config.endpoint + apiPath);\n\n const apiHeaders: { [header: string]: string } = {\n }\n\n return this.client.call(\n 'get',\n uri,\n apiHeaders,\n apiPayload,\n );\n }\n\n /**\n * Updates one product by id. A partial patch: the body names only the columns to change and every column it leaves out keeps its current value, so there is no read-modify-write and no way to blank a field by forgetting it.\n * \n * The catalog itself. A product row carries only what every product has — SKU, kind, family, enabled, tax class — and everything the tenant modelled lives in the `attribute_values` jsonb document, keyed by attribute CODE inside one of four scope buckets (common, per locale, per channel, per channel and locale). `label` is a generated column, maintained by the database so a grid of twenty thousand rows can sort and filter on a name with no join. `kind` says where the row sits in the variant hierarchy: a `model` carries what its variants share and is never sold itself.\n * \n * A body that names nothing writable is refused with 400 rather than answered as a no-op, an id nobody carries answers 404, and a value that collides on `sku` answers 409. `label` is a generated column: naming it is dropped rather than refused, and `completeness` is written by the two metadata routes, not here.\n *\n * @param {string} params.id - The `products` row to address, by id. It names a row THIS TENANT holds, so no example is published — a uuid this app invented would document a call that answers 404, and a real one would be another tenant's data. Read one from `GET /v1/products`. An id no product of this tenant carries answers 404; a malformed one answers 400 before the route is reached.\n * @param {object} params.attributeValues - Every attribute value the record carries, in ONE jsonb document — the core of an attribute-driven PIM. A record's properties are not columns here: they are rows in `attributes`, selected per family by `family_attributes`, and their values live under their attribute CODE inside this object.\n\nFour buckets, and an attribute's own flags decide which one it writes to:\n\n `common` the attribute is neither localizable nor scopable — one value, full stop.\n `{\"common\": {\"net_weight\": 2.4, \"colour\": \"black\"}}`\n `locale_specific` `localizable`: one value per language tag.\n `{\"locale_specific\": {\"de_DE\": {\"name\": \"Akku-Bohrschrauber\"}}}`\n `channel_specific` `scopable`: one value per channel.\n `{\"channel_specific\": {\"b2b\": {\"minimum_order_quantity\": 6}}}`\n `channel_locale_specific` both: one value per channel AND language tag.\n `{\"channel_locale_specific\": {\"b2b\": {\"de_DE\": {\"description\": \"…\"}}}}`\n\nA reader takes the most specific bucket that carries the code and falls back through locale, then channel, then `common`. `common` is always last and always consulted, because early imports wrote everything there whatever an attribute's flags said — a reader that skipped it reports an imported catalog as empty. `GET /products/attribute-schema` answers, per field, the exact path a value belongs at (`storage.path`) and that full fallback order (`from`), so no client has to re-derive any of this.\n\nThe value itself is whatever the attribute's `type` implies: a string, a number, a boolean, an option CODE for a select (never its label), a list of codes for a multi-select, `{\"amount\": …, \"unit\": …}` for a measure, a list of `{\"amount\": …, \"currency\": …}` for a price, an asset code for media.\n\nDefaults to `{}`, and an empty object is a normal state — a record nobody has enriched yet. The declared type also admits an array only because every jsonb column of this app shares one mapping; an array is not meaningful here and every reader in this app treats a non-object as empty.\n * @param {object} params.completeness - How much of what this product's family REQUIRES it actually carries — the number a merchandiser works down. `required` counts the attributes the family marks `is_required`, `filled` how many of those carry a value in ANY bucket, `ratio` is filled/required between 0 and 1 (a family that requires nothing is 1, not undefined), `missing` lists the codes with no value anywhere, sorted, and `computed_at` is when it was measured.\n\nWritten only by `POST /products/{id}/completeness` and by `POST /products/{id}/family`; a plain create or update never touches it, so it is null until one of the two has run. It also stays null for a product with no family — there is nothing to measure it against, and 0 % would be a lie.\n * @param {string} params.deletedAt - When the product was soft-deleted. `GET /products/grid` and every category-rule evaluation exclude a row that carries one; `GET /products` does NOT — filter on it to read the live catalog.\n * @param {boolean} params.enabled - Whether the product is offered. A create defaults it from the `new_products_enabled_by_default` tenant setting rather than blindly to true, so an import does not publish twenty thousand unfinished products the moment it lands. An explicit value in the body always wins.\n * @param {string} params.familyId - The family that decides which attributes this product HAS. Without one nothing is required, completeness cannot be computed and the display name never resolves — `POST /products/{id}/family` is the call that sets it and computes completeness in the same step.\n * @param {string} params.familyVariantId - Which variant structure of the family this product follows — the axes it splits on. Null on a simple product.\n * @param {ProductsKind} params.kind - Where the product sits in the variant hierarchy. 'simple' stands on its own. 'model' carries the values its variants share and is never sold itself. 'variant' carries the axis values and points at its model through `parent_id`.\n * @param {string} params.parentId - The product MODEL this variant belongs to. Only a `variant` carries one. Deleting the model leaves its variants behind with a null parent rather than deleting them.\n * @param {object} params.quantifiedAssociations - The import-side mirror of associations that carry a quantity — a bundle, a bill of materials, a spare-parts set. NOTHING IN THIS APP READS OR WRITES IT: no route produces it, no route consumes it, and it is null on every product this app has created. The surface that IS served is relational — `product_associations`, whose `quantity` column holds the number, guarded by `association_types.is_quantified`.\n\nIt exists because a PIM import (Akeneo, BMEcat) carries these in one blob keyed by association type code, and the column lets that document round-trip instead of being dropped. The database enforces no shape on it, so what a reader finds is whatever the importer wrote; the example is the conventional form.\n * @param {string} params.sku - The merchant's own article number — unique per tenant, and the value every integration (ERP, shop, feed, price list) joins on. The one identifier a person types, and the fallback this app shows when the catalog holds no name.\n * @param {string} params.taxClass - The tax class key the prices app resolves a VAT rate from. Free text here — the vocabulary belongs to the app that prices, and `POST /products/batch` exists to hand exactly this column to it in bulk.\n * @throws {RevenexxException}\n * @returns {Promise<Models.Products>}\n */\n productsUpdate(params: { id: string, attributeValues?: object, completeness?: object, deletedAt?: string, enabled?: boolean, familyId?: string, familyVariantId?: string, kind?: ProductsKind, parentId?: string, quantifiedAssociations?: object, sku?: string, taxClass?: string }): Promise<Models.Products>;\n /**\n * Updates one product by id. A partial patch: the body names only the columns to change and every column it leaves out keeps its current value, so there is no read-modify-write and no way to blank a field by forgetting it.\n * \n * The catalog itself. A product row carries only what every product has — SKU, kind, family, enabled, tax class — and everything the tenant modelled lives in the `attribute_values` jsonb document, keyed by attribute CODE inside one of four scope buckets (common, per locale, per channel, per channel and locale). `label` is a generated column, maintained by the database so a grid of twenty thousand rows can sort and filter on a name with no join. `kind` says where the row sits in the variant hierarchy: a `model` carries what its variants share and is never sold itself.\n * \n * A body that names nothing writable is refused with 400 rather than answered as a no-op, an id nobody carries answers 404, and a value that collides on `sku` answers 409. `label` is a generated column: naming it is dropped rather than refused, and `completeness` is written by the two metadata routes, not here.\n *\n * @param {string} id - The `products` row to address, by id. It names a row THIS TENANT holds, so no example is published — a uuid this app invented would document a call that answers 404, and a real one would be another tenant's data. Read one from `GET /v1/products`. An id no product of this tenant carries answers 404; a malformed one answers 400 before the route is reached.\n * @param {object} attributeValues - Every attribute value the record carries, in ONE jsonb document — the core of an attribute-driven PIM. A record's properties are not columns here: they are rows in `attributes`, selected per family by `family_attributes`, and their values live under their attribute CODE inside this object.\n\nFour buckets, and an attribute's own flags decide which one it writes to:\n\n `common` the attribute is neither localizable nor scopable — one value, full stop.\n `{\"common\": {\"net_weight\": 2.4, \"colour\": \"black\"}}`\n `locale_specific` `localizable`: one value per language tag.\n `{\"locale_specific\": {\"de_DE\": {\"name\": \"Akku-Bohrschrauber\"}}}`\n `channel_specific` `scopable`: one value per channel.\n `{\"channel_specific\": {\"b2b\": {\"minimum_order_quantity\": 6}}}`\n `channel_locale_specific` both: one value per channel AND language tag.\n `{\"channel_locale_specific\": {\"b2b\": {\"de_DE\": {\"description\": \"…\"}}}}`\n\nA reader takes the most specific bucket that carries the code and falls back through locale, then channel, then `common`. `common` is always last and always consulted, because early imports wrote everything there whatever an attribute's flags said — a reader that skipped it reports an imported catalog as empty. `GET /products/attribute-schema` answers, per field, the exact path a value belongs at (`storage.path`) and that full fallback order (`from`), so no client has to re-derive any of this.\n\nThe value itself is whatever the attribute's `type` implies: a string, a number, a boolean, an option CODE for a select (never its label), a list of codes for a multi-select, `{\"amount\": …, \"unit\": …}` for a measure, a list of `{\"amount\": …, \"currency\": …}` for a price, an asset code for media.\n\nDefaults to `{}`, and an empty object is a normal state — a record nobody has enriched yet. The declared type also admits an array only because every jsonb column of this app shares one mapping; an array is not meaningful here and every reader in this app treats a non-object as empty.\n * @param {object} completeness - How much of what this product's family REQUIRES it actually carries — the number a merchandiser works down. `required` counts the attributes the family marks `is_required`, `filled` how many of those carry a value in ANY bucket, `ratio` is filled/required between 0 and 1 (a family that requires nothing is 1, not undefined), `missing` lists the codes with no value anywhere, sorted, and `computed_at` is when it was measured.\n\nWritten only by `POST /products/{id}/completeness` and by `POST /products/{id}/family`; a plain create or update never touches it, so it is null until one of the two has run. It also stays null for a product with no family — there is nothing to measure it against, and 0 % would be a lie.\n * @param {string} deletedAt - When the product was soft-deleted. `GET /products/grid` and every category-rule evaluation exclude a row that carries one; `GET /products` does NOT — filter on it to read the live catalog.\n * @param {boolean} enabled - Whether the product is offered. A create defaults it from the `new_products_enabled_by_default` tenant setting rather than blindly to true, so an import does not publish twenty thousand unfinished products the moment it lands. An explicit value in the body always wins.\n * @param {string} familyId - The family that decides which attributes this product HAS. Without one nothing is required, completeness cannot be computed and the display name never resolves — `POST /products/{id}/family` is the call that sets it and computes completeness in the same step.\n * @param {string} familyVariantId - Which variant structure of the family this product follows — the axes it splits on. Null on a simple product.\n * @param {ProductsKind} kind - Where the product sits in the variant hierarchy. 'simple' stands on its own. 'model' carries the values its variants share and is never sold itself. 'variant' carries the axis values and points at its model through `parent_id`.\n * @param {string} parentId - The product MODEL this variant belongs to. Only a `variant` carries one. Deleting the model leaves its variants behind with a null parent rather than deleting them.\n * @param {object} quantifiedAssociations - The import-side mirror of associations that carry a quantity — a bundle, a bill of materials, a spare-parts set. NOTHING IN THIS APP READS OR WRITES IT: no route produces it, no route consumes it, and it is null on every product this app has created. The surface that IS served is relational — `product_associations`, whose `quantity` column holds the number, guarded by `association_types.is_quantified`.\n\nIt exists because a PIM import (Akeneo, BMEcat) carries these in one blob keyed by association type code, and the column lets that document round-trip instead of being dropped. The database enforces no shape on it, so what a reader finds is whatever the importer wrote; the example is the conventional form.\n * @param {string} sku - The merchant's own article number — unique per tenant, and the value every integration (ERP, shop, feed, price list) joins on. The one identifier a person types, and the fallback this app shows when the catalog holds no name.\n * @param {string} taxClass - The tax class key the prices app resolves a VAT rate from. Free text here — the vocabulary belongs to the app that prices, and `POST /products/batch` exists to hand exactly this column to it in bulk.\n * @throws {RevenexxException}\n * @returns {Promise<Models.Products>}\n * @deprecated Use the object parameter style method for a better developer experience.\n */\n productsUpdate(id: string, attributeValues?: object, completeness?: object, deletedAt?: string, enabled?: boolean, familyId?: string, familyVariantId?: string, kind?: ProductsKind, parentId?: string, quantifiedAssociations?: object, sku?: string, taxClass?: string): Promise<Models.Products>;\n productsUpdate(\n paramsOrFirst: { id: string, attributeValues?: object, completeness?: object, deletedAt?: string, enabled?: boolean, familyId?: string, familyVariantId?: string, kind?: ProductsKind, parentId?: string, quantifiedAssociations?: object, sku?: string, taxClass?: string } | string,\n ...rest: [(object)?, (object)?, (string)?, (boolean)?, (string)?, (string)?, (ProductsKind)?, (string)?, (object)?, (string)?, (string)?] \n ): Promise<Models.Products> {\n let params: { id: string, attributeValues?: object, completeness?: object, deletedAt?: string, enabled?: boolean, familyId?: string, familyVariantId?: string, kind?: ProductsKind, parentId?: string, quantifiedAssociations?: object, sku?: string, taxClass?: string };\n \n if ((paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst))) {\n params = (paramsOrFirst || {}) as { id: string, attributeValues?: object, completeness?: object, deletedAt?: string, enabled?: boolean, familyId?: string, familyVariantId?: string, kind?: ProductsKind, parentId?: string, quantifiedAssociations?: object, sku?: string, taxClass?: string };\n } else {\n params = {\n id: paramsOrFirst as string,\n attributeValues: rest[0] as object,\n completeness: rest[1] as object,\n deletedAt: rest[2] as string,\n enabled: rest[3] as boolean,\n familyId: rest[4] as string,\n familyVariantId: rest[5] as string,\n kind: rest[6] as ProductsKind,\n parentId: rest[7] as string,\n quantifiedAssociations: rest[8] as object,\n sku: rest[9] as string,\n taxClass: rest[10] as string \n };\n }\n \n const id = params.id;\n const attributeValues = params.attributeValues;\n const completeness = params.completeness;\n const deletedAt = params.deletedAt;\n const enabled = params.enabled;\n const familyId = params.familyId;\n const familyVariantId = params.familyVariantId;\n const kind = params.kind;\n const parentId = params.parentId;\n const quantifiedAssociations = params.quantifiedAssociations;\n const sku = params.sku;\n const taxClass = params.taxClass;\n\n if (typeof id === 'undefined') {\n throw new RevenexxException('Missing required parameter: \"id\"');\n }\n\n const apiPath = '/v1/products/{id}'.replace('{id}', id);\n const apiPayload: Payload = {};\n if (typeof attributeValues !== 'undefined') {\n apiPayload['attribute_values'] = attributeValues;\n }\n if (typeof completeness !== 'undefined') {\n apiPayload['completeness'] = completeness;\n }\n if (typeof deletedAt !== 'undefined') {\n apiPayload['deleted_at'] = deletedAt;\n }\n if (typeof enabled !== 'undefined') {\n apiPayload['enabled'] = enabled;\n }\n if (typeof familyId !== 'undefined') {\n apiPayload['family_id'] = familyId;\n }\n if (typeof familyVariantId !== 'undefined') {\n apiPayload['family_variant_id'] = familyVariantId;\n }\n if (typeof kind !== 'undefined') {\n apiPayload['kind'] = kind;\n }\n if (typeof parentId !== 'undefined') {\n apiPayload['parent_id'] = parentId;\n }\n if (typeof quantifiedAssociations !== 'undefined') {\n apiPayload['quantified_associations'] = quantifiedAssociations;\n }\n if (typeof sku !== 'undefined') {\n apiPayload['sku'] = sku;\n }\n if (typeof taxClass !== 'undefined') {\n apiPayload['tax_class'] = taxClass;\n }\n const uri = new URL(this.client.config.endpoint + apiPath);\n\n const apiHeaders: { [header: string]: string } = {\n 'content-type': 'application/json',\n }\n\n return this.client.call(\n 'put',\n uri,\n apiHeaders,\n apiPayload,\n );\n }\n\n /**\n * How much of what its family REQUIRES does this product actually carry — the number a merchandiser works down. products.completeness is jsonb that nothing had ever written. This computes it from family_attributes (is_required) against the product's own scoped attribute_values and stores the result. A product with no family answers 400 rather than an invented 0 % — it has nothing to be measured against.\n *\n * @param {string} params.id - The `products` row to address, by id. It names a row THIS TENANT holds, so no example is published — a uuid this app invented would document a call that answers 404, and a real one would be another tenant's data. Read one from `GET /v1/products`. An id no product of this tenant carries answers 404; a malformed one answers 400 before the route is reached.\n * @param {object} params.data - Request body\n * @throws {RevenexxException}\n * @returns {Promise<{}>}\n */\n productsCompleteness(params: { id: string, data: object }): Promise<{}>;\n /**\n * How much of what its family REQUIRES does this product actually carry — the number a merchandiser works down. products.completeness is jsonb that nothing had ever written. This computes it from family_attributes (is_required) against the product's own scoped attribute_values and stores the result. A product with no family answers 400 rather than an invented 0 % — it has nothing to be measured against.\n *\n * @param {string} id - The `products` row to address, by id. It names a row THIS TENANT holds, so no example is published — a uuid this app invented would document a call that answers 404, and a real one would be another tenant's data. Read one from `GET /v1/products`. An id no product of this tenant carries answers 404; a malformed one answers 400 before the route is reached.\n * @param {object} data - Request body\n * @throws {RevenexxException}\n * @returns {Promise<{}>}\n * @deprecated Use the object parameter style method for a better developer experience.\n */\n productsCompleteness(id: string, data: object): Promise<{}>;\n productsCompleteness(\n paramsOrFirst: { id: string, data: object } | string,\n ...rest: [(object)?] \n ): Promise<{}> {\n let params: { id: string, data: object };\n \n if ((paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst))) {\n params = (paramsOrFirst || {}) as { id: string, data: object };\n } else {\n params = {\n id: paramsOrFirst as string,\n data: rest[0] as object \n };\n }\n \n const id = params.id;\n const data = params.data;\n\n if (typeof id === 'undefined') {\n throw new RevenexxException('Missing required parameter: \"id\"');\n }\n if (typeof data === 'undefined') {\n throw new RevenexxException('Missing required parameter: \"data\"');\n }\n\n const apiPath = '/v1/products/{id}/completeness'.replace('{id}', id);\n const apiPayload: Payload = {};\n if (typeof data !== 'undefined') {\n Object.assign(apiPayload, data);\n }\n const uri = new URL(this.client.config.endpoint + apiPath);\n\n const apiHeaders: { [header: string]: string } = {\n 'content-type': 'application/json',\n }\n\n return this.client.call(\n 'post',\n uri,\n apiHeaders,\n apiPayload,\n );\n }\n\n /**\n * Names the family in the body — by `family_id` or by `family_code`, whichever the caller holds — and computes the product's completeness in the same call. The step every family-driven surface waits on: a product with no family has no required attributes, so its completeness cannot be computed and its family's label attribute never resolves. Assigning the family recomputes and STORES products.completeness immediately, so the metadata cannot go stale between the two operations.\n *\n * @param {string} params.id - The `products` row to address, by id. It names a row THIS TENANT holds, so no example is published — a uuid this app invented would document a call that answers 404, and a real one would be another tenant's data. Read one from `GET /v1/products`. An id no product of this tenant carries answers 404; a malformed one answers 400 before the route is reached.\n * @param {string} params.familyCode - Alternative to family_id — a `families.code` this tenant holds, from `GET /products/families`. No example: a code is tenant data, and any value published here names a family somebody does not have.\n * @param {string} params.familyId - The family to assign.\n * @throws {RevenexxException}\n * @returns {Promise<{}>}\n */\n productsFamilyAssign(params: { id: string, familyCode?: string, familyId?: string }): Promise<{}>;\n /**\n * Names the family in the body — by `family_id` or by `family_code`, whichever the caller holds — and computes the product's completeness in the same call. The step every family-driven surface waits on: a product with no family has no required attributes, so its completeness cannot be computed and its family's label attribute never resolves. Assigning the family recomputes and STORES products.completeness immediately, so the metadata cannot go stale between the two operations.\n *\n * @param {string} id - The `products` row to address, by id. It names a row THIS TENANT holds, so no example is published — a uuid this app invented would document a call that answers 404, and a real one would be another tenant's data. Read one from `GET /v1/products`. An id no product of this tenant carries answers 404; a malformed one answers 400 before the route is reached.\n * @param {string} familyCode - Alternative to family_id — a `families.code` this tenant holds, from `GET /products/families`. No example: a code is tenant data, and any value published here names a family somebody does not have.\n * @param {string} familyId - The family to assign.\n * @throws {RevenexxException}\n * @returns {Promise<{}>}\n * @deprecated Use the object parameter style method for a better developer experience.\n */\n productsFamilyAssign(id: string, familyCode?: string, familyId?: string): Promise<{}>;\n productsFamilyAssign(\n paramsOrFirst: { id: string, familyCode?: string, familyId?: string } | string,\n ...rest: [(string)?, (string)?] \n ): Promise<{}> {\n let params: { id: string, familyCode?: string, familyId?: string };\n \n if ((paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst))) {\n params = (paramsOrFirst || {}) as { id: string, familyCode?: string, familyId?: string };\n } else {\n params = {\n id: paramsOrFirst as string,\n familyCode: rest[0] as string,\n familyId: rest[1] as string \n };\n }\n \n const id = params.id;\n const familyCode = params.familyCode;\n const familyId = params.familyId;\n\n if (typeof id === 'undefined') {\n throw new RevenexxException('Missing required parameter: \"id\"');\n }\n\n const apiPath = '/v1/products/{id}/family'.replace('{id}', id);\n const apiPayload: Payload = {};\n if (typeof familyCode !== 'undefined') {\n apiPayload['family_code'] = familyCode;\n }\n if (typeof familyId !== 'undefined') {\n apiPayload['family_id'] = familyId;\n }\n const uri = new URL(this.client.config.endpoint + apiPath);\n\n const apiHeaders: { [header: string]: string } = {\n 'content-type': 'application/json',\n }\n\n return this.client.call(\n 'post',\n uri,\n apiHeaders,\n apiPayload,\n );\n }\n}\n"]}
|