@sixtyninecommerce/admin 0.10.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5772 -118
- package/dist/auth/index.d.ts +7 -1
- package/dist/auth/index.js +8 -1
- package/dist/catalog/assets.d.ts +120 -8
- package/dist/catalog/assets.js +98 -12
- package/dist/catalog/collections.d.ts +279 -14
- package/dist/catalog/collections.js +246 -15
- package/dist/catalog/documents.d.ts +142 -0
- package/dist/catalog/documents.js +114 -0
- package/dist/catalog/index.d.ts +54 -6
- package/dist/catalog/index.js +10 -1
- package/dist/catalog/metadata.d.ts +244 -0
- package/dist/catalog/metadata.js +220 -0
- package/dist/catalog/products.d.ts +159 -19
- package/dist/catalog/products.js +88 -13
- package/dist/catalog/properties.d.ts +140 -14
- package/dist/catalog/properties.js +65 -1
- package/dist/catalog/recommendations.d.ts +288 -0
- package/dist/catalog/recommendations.js +237 -0
- package/dist/catalog/reviews.d.ts +381 -0
- package/dist/catalog/reviews.js +325 -0
- package/dist/catalog/types.d.ts +17 -1
- package/dist/catalog/types.js +10 -0
- package/dist/catalog/variant-find.d.ts +136 -0
- package/dist/catalog/variant-find.js +239 -0
- package/dist/catalog/variants.d.ts +293 -26
- package/dist/catalog/variants.js +164 -7
- package/dist/catalog/visibility.d.ts +38 -7
- package/dist/catalog/visibility.js +19 -1
- package/dist/client.d.ts +121 -9
- package/dist/client.js +53 -14
- package/dist/content/assets.d.ts +285 -0
- package/dist/content/assets.js +181 -0
- package/dist/content/forms.d.ts +332 -1
- package/dist/content/forms.js +140 -4
- package/dist/content/items.d.ts +292 -0
- package/dist/content/items.js +170 -0
- package/dist/content/menus.d.ts +254 -0
- package/dist/content/menus.js +70 -0
- package/dist/content/strings.d.ts +137 -0
- package/dist/content/strings.js +82 -0
- package/dist/content/types.d.ts +282 -0
- package/dist/content/types.js +100 -0
- package/dist/customers/age-verification.d.ts +66 -0
- package/dist/customers/age-verification.js +79 -0
- package/dist/customers/credit.d.ts +263 -0
- package/dist/customers/credit.js +244 -0
- package/dist/customers/delivery-preferences.d.ts +120 -0
- package/dist/customers/delivery-preferences.js +97 -0
- package/dist/customers/delivery-terms.d.ts +44 -0
- package/dist/customers/delivery-terms.js +32 -0
- package/dist/customers/groups.d.ts +207 -0
- package/dist/customers/groups.js +438 -0
- package/dist/customers/index.d.ts +462 -37
- package/dist/customers/index.js +317 -40
- package/dist/customers/invitation-status.d.ts +57 -0
- package/dist/customers/invitation-status.js +21 -0
- package/dist/customers/notes.d.ts +67 -0
- package/dist/customers/notes.js +51 -0
- package/dist/customers/notification-recipients.d.ts +97 -0
- package/dist/customers/notification-recipients.js +84 -0
- package/dist/customers/saved-lists.d.ts +42 -0
- package/dist/customers/saved-lists.js +61 -0
- package/dist/customers/vat.d.ts +83 -0
- package/dist/customers/vat.js +46 -0
- package/dist/customers/wire.d.ts +20 -0
- package/dist/customers/wire.js +35 -0
- package/dist/documents/ar.d.ts +307 -0
- package/dist/documents/ar.js +254 -0
- package/dist/documents/emails.d.ts +150 -0
- package/dist/documents/emails.js +220 -0
- package/dist/documents/index.d.ts +744 -21
- package/dist/documents/index.js +438 -24
- package/dist/documents/pdf.d.ts +2 -0
- package/dist/documents/pdf.js +11 -0
- package/dist/fulfillments/create.d.ts +167 -0
- package/dist/fulfillments/create.js +216 -0
- package/dist/fulfillments/index.d.ts +163 -11
- package/dist/fulfillments/index.js +135 -6
- package/dist/fulfillments/payment-policy.d.ts +64 -0
- package/dist/fulfillments/payment-policy.js +140 -0
- package/dist/fulfillments/warehouse.d.ts +724 -0
- package/dist/fulfillments/warehouse.js +914 -0
- package/dist/geo/index.d.ts +119 -0
- package/dist/geo/index.js +107 -0
- package/dist/index.d.ts +147 -39
- package/dist/index.js +51 -12
- package/dist/integrations/afas-actions.d.ts +234 -0
- package/dist/integrations/afas-actions.js +310 -0
- package/dist/integrations/afas-types.d.ts +483 -0
- package/dist/integrations/afas-types.js +5 -0
- package/dist/integrations/afas.d.ts +234 -0
- package/dist/integrations/afas.js +290 -0
- package/dist/integrations/connections.d.ts +103 -0
- package/dist/integrations/connections.js +55 -0
- package/dist/integrations/esp.d.ts +313 -0
- package/dist/integrations/esp.js +169 -0
- package/dist/integrations/exact-online-types.d.ts +965 -0
- package/dist/integrations/exact-online-types.js +6 -0
- package/dist/integrations/exact-online.d.ts +784 -0
- package/dist/integrations/exact-online.js +1089 -0
- package/dist/integrations/index.d.ts +44 -3
- package/dist/integrations/index.js +23 -3
- package/dist/integrations/pipeline-discoveries.d.ts +65 -0
- package/dist/integrations/pipeline-discoveries.js +65 -0
- package/dist/integrations/pipeline-keys.d.ts +13 -0
- package/dist/integrations/pipeline-keys.js +22 -0
- package/dist/integrations/pipeline-runs.d.ts +119 -0
- package/dist/integrations/pipeline-runs.js +87 -0
- package/dist/integrations/pipelines.d.ts +87 -15
- package/dist/integrations/pipelines.js +41 -22
- package/dist/integrations/price-import.d.ts +223 -0
- package/dist/integrations/price-import.js +124 -0
- package/dist/integrations/types.d.ts +367 -3
- package/dist/integrations/types.js +4 -3
- package/dist/locations/index.d.ts +66 -0
- package/dist/locations/index.js +31 -0
- package/dist/meta/index.d.ts +172 -0
- package/dist/metafields/index.d.ts +8 -1
- package/dist/metafields/index.js +10 -0
- package/dist/orders/cancel-with-money.d.ts +237 -0
- package/dist/orders/cancel-with-money.js +155 -0
- package/dist/orders/commit-edit.d.ts +23 -1
- package/dist/orders/commit-edit.js +19 -2
- package/dist/orders/deposit-policy.d.ts +3 -1
- package/dist/orders/drafts.d.ts +800 -0
- package/dist/orders/drafts.js +771 -0
- package/dist/orders/fields.d.ts +245 -0
- package/dist/orders/fields.js +188 -0
- package/dist/orders/get.d.ts +29 -19
- package/dist/orders/get.js +17 -8
- package/dist/orders/index.d.ts +66 -15
- package/dist/orders/index.js +25 -2
- package/dist/orders/lifecycle.d.ts +128 -0
- package/dist/orders/lifecycle.js +158 -0
- package/dist/orders/line-price-preview.d.ts +7 -2
- package/dist/orders/list.d.ts +243 -0
- package/dist/orders/list.js +487 -0
- package/dist/orders/manual-discounts.d.ts +13 -5
- package/dist/orders/manual-pricing.d.ts +5 -0
- package/dist/orders/money-view.d.ts +149 -0
- package/dist/orders/money-view.js +99 -0
- package/dist/orders/order-entry.d.ts +20 -7
- package/dist/orders/plan-edit.d.ts +34 -2
- package/dist/orders/plan-edit.js +112 -11
- package/dist/orders/settings.d.ts +201 -0
- package/dist/orders/settings.js +325 -0
- package/dist/orders/status.d.ts +159 -13
- package/dist/orders/status.js +21 -0
- package/dist/orders/surcharges.d.ts +20 -1
- package/dist/orders/surcharges.js +37 -11
- package/dist/payments/account-credit.d.ts +46 -0
- package/dist/payments/account-credit.js +42 -0
- package/dist/payments/ar.d.ts +292 -0
- package/dist/payments/ar.js +223 -0
- package/dist/payments/connected-account.d.ts +47 -0
- package/dist/payments/connected-account.js +61 -0
- package/dist/payments/credit-noted-fields.d.ts +19 -0
- package/dist/payments/credit-noted-fields.js +69 -0
- package/dist/payments/customer-consent.d.ts +30 -0
- package/dist/payments/customer-consent.js +49 -0
- package/dist/payments/index.d.ts +340 -19
- package/dist/payments/index.js +151 -1
- package/dist/payments/methods.d.ts +303 -8
- package/dist/payments/methods.js +337 -7
- package/dist/payments/mollie-methods.d.ts +159 -0
- package/dist/payments/mollie-methods.js +141 -0
- package/dist/payments/payment-links.d.ts +180 -0
- package/dist/payments/payment-links.js +97 -0
- package/dist/payments/provider-keys.d.ts +150 -0
- package/dist/payments/provider-keys.js +118 -0
- package/dist/payments/providers.d.ts +86 -11
- package/dist/payments/providers.js +29 -0
- package/dist/payments/requests.d.ts +147 -0
- package/dist/payments/requests.js +93 -0
- package/dist/payments/store-credit-fields.d.ts +15 -0
- package/dist/payments/store-credit-fields.js +51 -0
- package/dist/pickups/index.d.ts +106 -0
- package/dist/pickups/index.js +108 -0
- package/dist/platform/channels.d.ts +132 -0
- package/dist/platform/channels.js +128 -0
- package/dist/platform/email-gateways.d.ts +165 -0
- package/dist/platform/email-gateways.js +78 -0
- package/dist/platform/geo.d.ts +123 -0
- package/dist/platform/geo.js +144 -0
- package/dist/platform/tax.d.ts +162 -0
- package/dist/platform/tax.js +169 -0
- package/dist/pos/anomalies.d.ts +158 -0
- package/dist/pos/anomalies.js +64 -0
- package/dist/pos/assisted-selling.d.ts +79 -0
- package/dist/pos/assisted-selling.js +38 -0
- package/dist/pos/exchanges.d.ts +108 -0
- package/dist/pos/exchanges.js +22 -0
- package/dist/pos/gift-cards.d.ts +135 -0
- package/dist/pos/gift-cards.js +47 -0
- package/dist/pos/index.d.ts +2370 -58
- package/dist/pos/index.js +854 -7
- package/dist/pos/no-receipt.d.ts +94 -0
- package/dist/pos/no-receipt.js +25 -0
- package/dist/pos/offline-sales.d.ts +228 -0
- package/dist/pos/offline-sales.js +170 -0
- package/dist/pos/pay-by-link.d.ts +143 -0
- package/dist/pos/pay-by-link.js +57 -0
- package/dist/pos/quick-keys.d.ts +103 -0
- package/dist/pos/quick-keys.js +45 -0
- package/dist/pos/reports.d.ts +360 -0
- package/dist/pos/reports.js +62 -0
- package/dist/pos/returns.d.ts +244 -0
- package/dist/pos/returns.js +83 -0
- package/dist/pricing/bulk-coupons.d.ts +139 -0
- package/dist/pricing/bulk-coupons.js +112 -0
- package/dist/pricing/index.d.ts +174 -4
- package/dist/pricing/index.js +174 -1
- package/dist/pricing/price-lists.d.ts +606 -0
- package/dist/pricing/price-lists.js +600 -0
- package/dist/purchasing/alerts.d.ts +104 -0
- package/dist/purchasing/alerts.js +88 -0
- package/dist/purchasing/backorders.d.ts +61 -0
- package/dist/purchasing/backorders.js +92 -0
- package/dist/purchasing/cost.d.ts +110 -0
- package/dist/purchasing/cost.js +86 -0
- package/dist/purchasing/index.d.ts +54 -0
- package/dist/purchasing/index.js +24 -0
- package/dist/purchasing/links.d.ts +263 -0
- package/dist/purchasing/links.js +192 -0
- package/dist/purchasing/purchase-orders.d.ts +551 -0
- package/dist/purchasing/purchase-orders.js +491 -0
- package/dist/purchasing/receipts.d.ts +396 -0
- package/dist/purchasing/receipts.js +287 -0
- package/dist/purchasing/replenishment.d.ts +281 -0
- package/dist/purchasing/replenishment.js +240 -0
- package/dist/purchasing/returns.d.ts +273 -0
- package/dist/purchasing/returns.js +229 -0
- package/dist/purchasing/settings.d.ts +152 -0
- package/dist/purchasing/settings.js +181 -0
- package/dist/purchasing/suppliers.d.ts +476 -0
- package/dist/purchasing/suppliers.js +438 -0
- package/dist/quotes/index.d.ts +518 -0
- package/dist/quotes/index.js +439 -0
- package/dist/reports/index.d.ts +71 -8
- package/dist/reports/index.js +74 -11
- package/dist/returns/index.d.ts +675 -21
- package/dist/returns/index.js +756 -11
- package/dist/search/index.d.ts +76 -1
- package/dist/search/index.js +63 -0
- package/dist/seo/config.d.ts +128 -0
- package/dist/seo/config.js +95 -0
- package/dist/seo/redirects.d.ts +125 -0
- package/dist/seo/redirects.js +60 -1
- package/dist/seo/settings.d.ts +147 -0
- package/dist/seo/settings.js +209 -0
- package/dist/shipping/definitions.d.ts +29 -0
- package/dist/shipping/definitions.js +47 -0
- package/dist/shipping/fulfillment-profiles.d.ts +174 -0
- package/dist/shipping/fulfillment-profiles.js +104 -0
- package/dist/shipping/hendriks.d.ts +97 -0
- package/dist/shipping/hendriks.js +50 -0
- package/dist/shipping/index.d.ts +54 -0
- package/dist/shipping/index.js +27 -0
- package/dist/shipping/methods.d.ts +205 -0
- package/dist/shipping/methods.js +240 -0
- package/dist/shipping/myparcel.d.ts +668 -0
- package/dist/shipping/myparcel.js +466 -0
- package/dist/shipping/parcel-count-suggestion.d.ts +2 -0
- package/dist/shipping/parcel-rule.d.ts +6 -5
- package/dist/shipping/parcel-rule.js +21 -23
- package/dist/shipping/rate-tables.d.ts +324 -0
- package/dist/shipping/rate-tables.js +390 -0
- package/dist/shipping/ship-to-countries.d.ts +75 -0
- package/dist/shipping/ship-to-countries.js +47 -0
- package/dist/stock/by-location.d.ts +86 -0
- package/dist/stock/by-location.js +94 -0
- package/dist/stock/index.d.ts +18 -4
- package/dist/stock/index.js +7 -0
- package/dist/stock/locations.d.ts +144 -0
- package/dist/stock/locations.js +168 -0
- package/dist/stock/settings.d.ts +106 -0
- package/dist/stock/settings.js +103 -0
- package/dist/stock/transfers.d.ts +386 -52
- package/dist/stock/transfers.js +222 -17
- package/dist/stored-value/index.d.ts +312 -11
- package/dist/stored-value/index.js +223 -4
- package/dist/subscriptions/index.d.ts +682 -0
- package/dist/subscriptions/index.js +815 -0
- package/dist/tax/display-policy.d.ts +105 -0
- package/dist/tax/display-policy.js +84 -0
- package/dist/tax/index.d.ts +79 -1
- package/dist/tax/index.js +52 -0
- package/dist/tenant/email-style.d.ts +102 -0
- package/dist/tenant/email-style.js +72 -0
- package/dist/tenant/email-templates.d.ts +287 -0
- package/dist/tenant/email-templates.js +271 -0
- package/dist/tenant/notifications.d.ts +23 -17
- package/dist/tenant/settings-sources.d.ts +1 -1
- package/dist/tenant/time-zone.d.ts +17 -0
- package/dist/tenant/time-zone.js +11 -0
- package/dist/types.d.ts +50 -3
- package/dist/users/index.d.ts +3 -0
- package/dist/users/index.js +2 -0
- package/dist/users/warehouses.d.ts +50 -0
- package/dist/users/warehouses.js +51 -0
- package/package.json +2 -2
package/dist/catalog/index.js
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import { createAssetsModule } from './assets.js';
|
|
2
2
|
import { createCollectionsModule } from './collections.js';
|
|
3
|
+
import { createProductDocumentsModule } from './documents.js';
|
|
3
4
|
import { createFacetsModule } from './facets.js';
|
|
5
|
+
import { createProductMetadataModule } from './metadata.js';
|
|
4
6
|
import { createOptionsModule } from './options.js';
|
|
5
7
|
import { createProductsModule } from './products.js';
|
|
6
|
-
import { createPropertiesModule, syncContentFacets, } from './properties.js';
|
|
8
|
+
import { createPropertiesModule, syncContentFacets, syncContentItemFacets, } from './properties.js';
|
|
9
|
+
import { createRecommendationsModule } from './recommendations.js';
|
|
10
|
+
import { createReviewsModule } from './reviews.js';
|
|
7
11
|
import { createVariantsModule } from './variants.js';
|
|
8
12
|
import { createVisibilityModule } from './visibility.js';
|
|
9
13
|
export function createCatalogModule(transport) {
|
|
@@ -15,7 +19,12 @@ export function createCatalogModule(transport) {
|
|
|
15
19
|
collections: createCollectionsModule(transport),
|
|
16
20
|
assets: createAssetsModule(transport),
|
|
17
21
|
visibility: createVisibilityModule(transport),
|
|
22
|
+
documents: createProductDocumentsModule(transport),
|
|
23
|
+
metadata: createProductMetadataModule(transport),
|
|
18
24
|
properties: createPropertiesModule(transport),
|
|
25
|
+
recommendations: createRecommendationsModule(transport),
|
|
26
|
+
reviews: createReviewsModule(transport),
|
|
19
27
|
syncContentFacets: (propertyId, options) => syncContentFacets(transport, propertyId, options),
|
|
28
|
+
syncContentItemFacets: (contentItemIds, options) => syncContentItemFacets(transport, contentItemIds, options),
|
|
20
29
|
};
|
|
21
30
|
}
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A product's SEO, social and AI-agent metadata (headless spec §9.2 `catalog`: "metadata";
|
|
3
|
+
* W10-10): what the storefront puts in a product page's `<head>`, its share cards and its
|
|
4
|
+
* structured data. One record per product and store; its texts are per language.
|
|
5
|
+
*
|
|
6
|
+
* - **Partial writes.** `upsert` changes only the fields it names. A translation is written per
|
|
7
|
+
* language: a language not sent keeps its values, and a field not sent in a sent language keeps
|
|
8
|
+
* its value (send `null` to clear one).
|
|
9
|
+
* - **Coverage.** `coverage` lists the store's products with their own meta title and description
|
|
10
|
+
* in one language, optionally only those missing one, filtered by the engine BEFORE the page is
|
|
11
|
+
* cut: every page is full and `totalItems` counts the filter.
|
|
12
|
+
* - **Bulk.** `bulkUpsert` writes many products, each through `upsert`'s rules in a transaction
|
|
13
|
+
* of its own and reported on its own (ruling G117).
|
|
14
|
+
*
|
|
15
|
+
* Every record is the store's own: a product of another store is never answered and never
|
|
16
|
+
* written.
|
|
17
|
+
*
|
|
18
|
+
* Permissions: `get` and `coverage` need `ReadCatalog`, the writes `UpdateCatalog`.
|
|
19
|
+
*
|
|
20
|
+
* Refusals, GraphQL errors mapped by `core`:
|
|
21
|
+
* - `PRODUCT_METADATA_INPUT_INVALID` → `ValidationError` (400): an input that breaks a rule (a
|
|
22
|
+
* length, an allowed value, an `https://` URL, an instant without an offset, a language sent
|
|
23
|
+
* twice). `details` names each failure (`field` an RFC 6901 pointer such as
|
|
24
|
+
* `/input/translations/0/seoTitle`, `code` the rule such as `INVALID_FIELD_LENGTH`). Nothing is
|
|
25
|
+
* written.
|
|
26
|
+
* - `ENTITY_NOT_FOUND` → `NotFoundError` (404): `upsert` of a product the store does not hold.
|
|
27
|
+
* - `TRANSLATION_LANGUAGE_NOT_OFFERED` → `ValidationError` (400): a new translation in a language
|
|
28
|
+
* the store does not offer.
|
|
29
|
+
* - `BULK_ACTION_INPUT_INVALID` → `ValidationError` (400): a `bulkUpsert` of no product, more than
|
|
30
|
+
* {@link MAX_BULK_METADATA_EDITS} or one product twice, refused before anything is sent.
|
|
31
|
+
* - `INVALID_DATETIME` → `ValidationError` (400): `metaRobotsUnavailableAfter` without an offset,
|
|
32
|
+
* refused before anything is sent.
|
|
33
|
+
* - `FORBIDDEN` → `PermissionDeniedError` (403) without the permission.
|
|
34
|
+
*
|
|
35
|
+
* Release: `coverage` and `bulkUpsert` need a platform release with `productMetadataCoverage` and
|
|
36
|
+
* `bulkUpsertProductMetadata` (deploy vendure-server first: an older one refuses the document as
|
|
37
|
+
* `GRAPHQL_VALIDATION_FAILED`); on such a release `upsert` also answers a validation failure as an
|
|
38
|
+
* uncoded `INTERNAL_SERVER_ERROR` and writes a row for a product the store does not hold. `get`
|
|
39
|
+
* and `delete` are served by every release this SDK supports. No method deduplicates on
|
|
40
|
+
* `idempotencyKey`; every write is naturally repeatable.
|
|
41
|
+
*/
|
|
42
|
+
import { type Page, type Transport } from '@sixtyninecommerce/core';
|
|
43
|
+
import type { Call, ListOptions } from '../types.js';
|
|
44
|
+
import { type LanguageCode } from './types.js';
|
|
45
|
+
/** How many products one `bulkUpsert` call may name. */
|
|
46
|
+
export declare const MAX_BULK_METADATA_EDITS = 200;
|
|
47
|
+
/** An image the metadata names (the share image, the X/Twitter override). */
|
|
48
|
+
export interface ProductMetadataImage {
|
|
49
|
+
id: string;
|
|
50
|
+
name: string;
|
|
51
|
+
preview: string;
|
|
52
|
+
source: string;
|
|
53
|
+
/** A string on the wire: a newer engine may add a type. */
|
|
54
|
+
type: 'IMAGE' | 'VIDEO' | 'BINARY' | (string & {});
|
|
55
|
+
mimeType: string;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* One language's texts. The four JSON fields are read as the engine stores them; every write
|
|
59
|
+
* checks them (`breadcrumbOverride` `{ label, url }[]` of at most 5, `focusKeywords` up to 10
|
|
60
|
+
* distinct strings, `qaPairs` `{ question, answer }[]` of at most 20), but read them defensively.
|
|
61
|
+
*/
|
|
62
|
+
export interface ProductMetadataTranslation {
|
|
63
|
+
id: string;
|
|
64
|
+
languageCode: LanguageCode;
|
|
65
|
+
seoTitle: string | null;
|
|
66
|
+
seoDescription: string | null;
|
|
67
|
+
canonicalUrl: string | null;
|
|
68
|
+
breadcrumbOverride: unknown;
|
|
69
|
+
focusKeywords: unknown;
|
|
70
|
+
socialTitle: string | null;
|
|
71
|
+
socialDescription: string | null;
|
|
72
|
+
socialImageAlt: string | null;
|
|
73
|
+
twitterTitleOverride: string | null;
|
|
74
|
+
twitterDescriptionOverride: string | null;
|
|
75
|
+
aiSummary: string | null;
|
|
76
|
+
qaPairs: unknown;
|
|
77
|
+
}
|
|
78
|
+
export interface ProductMetadata {
|
|
79
|
+
id: string;
|
|
80
|
+
productId: string;
|
|
81
|
+
channelId: string;
|
|
82
|
+
/** `index` or `noindex`. */
|
|
83
|
+
metaRobotsIndex: string;
|
|
84
|
+
/** `follow` or `nofollow`. */
|
|
85
|
+
metaRobotsFollow: string;
|
|
86
|
+
metaRobotsNoarchive: boolean;
|
|
87
|
+
metaRobotsNosnippet: boolean;
|
|
88
|
+
metaRobotsNoimageindex: boolean;
|
|
89
|
+
/** `none`, `standard` or `large`. */
|
|
90
|
+
metaRobotsMaxImagePreview: string;
|
|
91
|
+
metaRobotsMaxSnippet: number | null;
|
|
92
|
+
metaRobotsMaxVideoPreview: number | null;
|
|
93
|
+
/** ISO-8601 UTC instant after which search engines should drop the page; null when none. */
|
|
94
|
+
metaRobotsUnavailableAfter: string | null;
|
|
95
|
+
socialImageId: string | null;
|
|
96
|
+
socialImage: ProductMetadataImage | null;
|
|
97
|
+
twitterImageOverrideId: string | null;
|
|
98
|
+
twitterImageOverride: ProductMetadataImage | null;
|
|
99
|
+
twitterCardType: string;
|
|
100
|
+
socialOgType: string;
|
|
101
|
+
seoIncludeReviewsInJsonld: boolean;
|
|
102
|
+
aiSummaryAudience: string;
|
|
103
|
+
/** The product's own `{ [botKey]: 'allow' | 'deny' }`; null when it has none. */
|
|
104
|
+
aiBotOverrides: Record<string, unknown> | null;
|
|
105
|
+
qaEmitFaqpageJsonld: boolean;
|
|
106
|
+
hreflangOverrides: unknown;
|
|
107
|
+
/** The product's overrides on top of the store's defaults, as the storefront applies them. */
|
|
108
|
+
resolvedBotDirectives: Record<string, unknown>;
|
|
109
|
+
translations: ProductMetadataTranslation[];
|
|
110
|
+
}
|
|
111
|
+
export interface ProductMetadataTranslationInput {
|
|
112
|
+
languageCode: LanguageCode;
|
|
113
|
+
seoTitle?: string | null;
|
|
114
|
+
seoDescription?: string | null;
|
|
115
|
+
/** An absolute `https://` URL. */
|
|
116
|
+
canonicalUrl?: string | null;
|
|
117
|
+
breadcrumbOverride?: Array<{
|
|
118
|
+
label: string;
|
|
119
|
+
url: string;
|
|
120
|
+
}> | null;
|
|
121
|
+
focusKeywords?: string[] | null;
|
|
122
|
+
socialTitle?: string | null;
|
|
123
|
+
socialDescription?: string | null;
|
|
124
|
+
socialImageAlt?: string | null;
|
|
125
|
+
twitterTitleOverride?: string | null;
|
|
126
|
+
twitterDescriptionOverride?: string | null;
|
|
127
|
+
aiSummary?: string | null;
|
|
128
|
+
qaPairs?: Array<{
|
|
129
|
+
question: string;
|
|
130
|
+
answer: string;
|
|
131
|
+
}> | null;
|
|
132
|
+
}
|
|
133
|
+
/** Only the fields named change. */
|
|
134
|
+
export interface ProductMetadataInput {
|
|
135
|
+
metaRobotsIndex?: 'index' | 'noindex';
|
|
136
|
+
metaRobotsFollow?: 'follow' | 'nofollow';
|
|
137
|
+
metaRobotsNoarchive?: boolean;
|
|
138
|
+
metaRobotsNosnippet?: boolean;
|
|
139
|
+
metaRobotsNoimageindex?: boolean;
|
|
140
|
+
metaRobotsMaxImagePreview?: 'none' | 'standard' | 'large';
|
|
141
|
+
metaRobotsMaxSnippet?: number | null;
|
|
142
|
+
metaRobotsMaxVideoPreview?: number | null;
|
|
143
|
+
/**
|
|
144
|
+
* An ISO-8601 instant WITH an explicit offset (`Z` or `±HH:mm`). One without is refused before
|
|
145
|
+
* the request leaves (`INVALID_DATETIME`).
|
|
146
|
+
*/
|
|
147
|
+
metaRobotsUnavailableAfter?: string | null;
|
|
148
|
+
socialImageId?: string | null;
|
|
149
|
+
twitterImageOverrideId?: string | null;
|
|
150
|
+
twitterCardType?: 'summary' | 'summary_large_image';
|
|
151
|
+
socialOgType?: 'product' | 'website';
|
|
152
|
+
seoIncludeReviewsInJsonld?: boolean;
|
|
153
|
+
aiSummaryAudience?: 'customers' | 'developers' | 'both';
|
|
154
|
+
aiBotOverrides?: Record<string, 'allow' | 'deny'> | null;
|
|
155
|
+
qaEmitFaqpageJsonld?: boolean;
|
|
156
|
+
hreflangOverrides?: Array<{
|
|
157
|
+
language: string;
|
|
158
|
+
country?: string;
|
|
159
|
+
url: string;
|
|
160
|
+
}> | null;
|
|
161
|
+
translations?: ProductMetadataTranslationInput[];
|
|
162
|
+
}
|
|
163
|
+
export type ProductMetadataCoverageFilter = 'ALL' | 'MISSING_TITLE' | 'MISSING_DESCRIPTION';
|
|
164
|
+
export interface ProductMetadataCoverageQuery extends ListOptions {
|
|
165
|
+
/** The language whose meta each row shows, and which the filter judges. */
|
|
166
|
+
languageCode: LanguageCode;
|
|
167
|
+
/** Defaults to `ALL`. A value is missing when it is null or empty. */
|
|
168
|
+
filter?: ProductMetadataCoverageFilter;
|
|
169
|
+
/** Matches the product's name. */
|
|
170
|
+
term?: string;
|
|
171
|
+
}
|
|
172
|
+
/** One product of the coverage list. */
|
|
173
|
+
export interface ProductMetadataCoverageRow {
|
|
174
|
+
productId: string;
|
|
175
|
+
/** The product's name in the request's language. */
|
|
176
|
+
name: string;
|
|
177
|
+
slug: string;
|
|
178
|
+
enabled: boolean;
|
|
179
|
+
/** The product's own meta title in the query's language; null when it has none. */
|
|
180
|
+
seoTitle: string | null;
|
|
181
|
+
/** The product's own meta description in the query's language; null when it has none. */
|
|
182
|
+
seoDescription: string | null;
|
|
183
|
+
}
|
|
184
|
+
export interface ProductMetadataBulkEdit {
|
|
185
|
+
productId: string;
|
|
186
|
+
input: ProductMetadataInput;
|
|
187
|
+
}
|
|
188
|
+
/** One product's outcome in a `bulkUpsert` call. */
|
|
189
|
+
export interface ProductMetadataBulkOutcome {
|
|
190
|
+
productId: string;
|
|
191
|
+
/** `OK`, or `FAILED` (a string on the wire: read anything else as not done). */
|
|
192
|
+
status: 'OK' | 'FAILED' | (string & {});
|
|
193
|
+
/**
|
|
194
|
+
* When FAILED: the single door's own code (`ENTITY_NOT_FOUND`,
|
|
195
|
+
* `PRODUCT_METADATA_INPUT_INVALID`, …); `INTERNAL_SERVER_ERROR` for a fault the engine logged.
|
|
196
|
+
*/
|
|
197
|
+
code: string | null;
|
|
198
|
+
/** When FAILED: the door's sentence. */
|
|
199
|
+
message: string | null;
|
|
200
|
+
}
|
|
201
|
+
export interface ProductMetadataModule {
|
|
202
|
+
/**
|
|
203
|
+
* The product's metadata; null when it has none yet. `NotFoundError` (`PRODUCT_NOT_FOUND`) for
|
|
204
|
+
* a product the store does not hold.
|
|
205
|
+
*
|
|
206
|
+
* @effect read
|
|
207
|
+
*/
|
|
208
|
+
get(productId: string, options?: Call): Promise<ProductMetadata | null>;
|
|
209
|
+
/**
|
|
210
|
+
* Creates the product's metadata or changes the fields named, and answers the whole record.
|
|
211
|
+
*
|
|
212
|
+
* @effect write
|
|
213
|
+
*/
|
|
214
|
+
upsert(productId: string, input: ProductMetadataInput, options?: Call): Promise<ProductMetadata>;
|
|
215
|
+
/**
|
|
216
|
+
* Removes the product's metadata in this store: the storefront falls back to the product's own
|
|
217
|
+
* name and description. Resolves the same way whether or not there was any.
|
|
218
|
+
*
|
|
219
|
+
* @effect destructive
|
|
220
|
+
*/
|
|
221
|
+
delete(productId: string, options?: Call): Promise<void>;
|
|
222
|
+
/**
|
|
223
|
+
* The store's products, name first, each with its own meta in `languageCode`; with a `filter`,
|
|
224
|
+
* only those missing a title (or a description) there. Filtered before paging: pages are full
|
|
225
|
+
* and `totalItems` counts the filter and the term. Never answers a deleted product.
|
|
226
|
+
*
|
|
227
|
+
* @effect read
|
|
228
|
+
*/
|
|
229
|
+
coverage(query: ProductMetadataCoverageQuery): Promise<Page<ProductMetadataCoverageRow>>;
|
|
230
|
+
/**
|
|
231
|
+
* Upserts 1 to {@link MAX_BULK_METADATA_EDITS} products, each through `upsert`'s rules in a
|
|
232
|
+
* transaction of its own, and answers one outcome per product in the order named: a refused
|
|
233
|
+
* product changes nothing and the others still go through. Not keyed: a repeat writes again.
|
|
234
|
+
*
|
|
235
|
+
* @effect write
|
|
236
|
+
*/
|
|
237
|
+
bulkUpsert(edits: readonly ProductMetadataBulkEdit[], options?: Call): Promise<ProductMetadataBulkOutcome[]>;
|
|
238
|
+
}
|
|
239
|
+
export declare const PRODUCT_METADATA_QUERY = "\n query CatalogProductMetadata($productId: ID!) {\n product(id: $productId) {\n id\n metadata { \n id\n productId\n channelId\n metaRobotsIndex\n metaRobotsFollow\n metaRobotsNoarchive\n metaRobotsNosnippet\n metaRobotsNoimageindex\n metaRobotsMaxImagePreview\n metaRobotsMaxSnippet\n metaRobotsMaxVideoPreview\n metaRobotsUnavailableAfter\n socialImageId\n socialImage { \n id\n name\n preview\n source\n type\n mimeType\n }\n twitterImageOverrideId\n twitterImageOverride { \n id\n name\n preview\n source\n type\n mimeType\n }\n twitterCardType\n socialOgType\n seoIncludeReviewsInJsonld\n aiSummaryAudience\n aiBotOverrides\n qaEmitFaqpageJsonld\n hreflangOverrides\n resolvedBotDirectives\n translations {\n id\n languageCode\n seoTitle\n seoDescription\n canonicalUrl\n breadcrumbOverride\n focusKeywords\n socialTitle\n socialDescription\n socialImageAlt\n twitterTitleOverride\n twitterDescriptionOverride\n aiSummary\n qaPairs\n }\n }\n }\n }\n";
|
|
240
|
+
export declare const UPSERT_PRODUCT_METADATA_MUTATION = "\n mutation CatalogUpsertProductMetadata($productId: ID!, $input: ProductMetadataInput!) {\n upsertProductMetadata(productId: $productId, input: $input) { \n id\n productId\n channelId\n metaRobotsIndex\n metaRobotsFollow\n metaRobotsNoarchive\n metaRobotsNosnippet\n metaRobotsNoimageindex\n metaRobotsMaxImagePreview\n metaRobotsMaxSnippet\n metaRobotsMaxVideoPreview\n metaRobotsUnavailableAfter\n socialImageId\n socialImage { \n id\n name\n preview\n source\n type\n mimeType\n }\n twitterImageOverrideId\n twitterImageOverride { \n id\n name\n preview\n source\n type\n mimeType\n }\n twitterCardType\n socialOgType\n seoIncludeReviewsInJsonld\n aiSummaryAudience\n aiBotOverrides\n qaEmitFaqpageJsonld\n hreflangOverrides\n resolvedBotDirectives\n translations {\n id\n languageCode\n seoTitle\n seoDescription\n canonicalUrl\n breadcrumbOverride\n focusKeywords\n socialTitle\n socialDescription\n socialImageAlt\n twitterTitleOverride\n twitterDescriptionOverride\n aiSummary\n qaPairs\n }\n }\n }\n";
|
|
241
|
+
export declare const DELETE_PRODUCT_METADATA_MUTATION = "\n mutation CatalogDeleteProductMetadata($productId: ID!) {\n deleteProductMetadata(productId: $productId) { \n result\n message\n }\n }\n";
|
|
242
|
+
export declare const PRODUCT_METADATA_COVERAGE_QUERY = "\n query CatalogProductMetadataCoverage(\n $languageCode: LanguageCode!\n $filter: ProductMetadataCoverageFilter\n $term: String\n $options: ProductMetadataCoverageListOptions\n ) {\n productMetadataCoverage(\n languageCode: $languageCode\n filter: $filter\n term: $term\n options: $options\n ) {\n items {\n productId\n name\n slug\n enabled\n seoTitle\n seoDescription\n }\n totalItems\n }\n }\n";
|
|
243
|
+
export declare const BULK_UPSERT_PRODUCT_METADATA_MUTATION = "\n mutation CatalogBulkUpsertProductMetadata($edits: [ProductMetadataBulkEdit!]!) {\n bulkUpsertProductMetadata(edits: $edits) {\n items {\n productId\n status\n code\n message\n }\n }\n }\n";
|
|
244
|
+
export declare function createProductMetadataModule(transport: Transport): ProductMetadataModule;
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A product's SEO, social and AI-agent metadata (headless spec §9.2 `catalog`: "metadata";
|
|
3
|
+
* W10-10): what the storefront puts in a product page's `<head>`, its share cards and its
|
|
4
|
+
* structured data. One record per product and store; its texts are per language.
|
|
5
|
+
*
|
|
6
|
+
* - **Partial writes.** `upsert` changes only the fields it names. A translation is written per
|
|
7
|
+
* language: a language not sent keeps its values, and a field not sent in a sent language keeps
|
|
8
|
+
* its value (send `null` to clear one).
|
|
9
|
+
* - **Coverage.** `coverage` lists the store's products with their own meta title and description
|
|
10
|
+
* in one language, optionally only those missing one, filtered by the engine BEFORE the page is
|
|
11
|
+
* cut: every page is full and `totalItems` counts the filter.
|
|
12
|
+
* - **Bulk.** `bulkUpsert` writes many products, each through `upsert`'s rules in a transaction
|
|
13
|
+
* of its own and reported on its own (ruling G117).
|
|
14
|
+
*
|
|
15
|
+
* Every record is the store's own: a product of another store is never answered and never
|
|
16
|
+
* written.
|
|
17
|
+
*
|
|
18
|
+
* Permissions: `get` and `coverage` need `ReadCatalog`, the writes `UpdateCatalog`.
|
|
19
|
+
*
|
|
20
|
+
* Refusals, GraphQL errors mapped by `core`:
|
|
21
|
+
* - `PRODUCT_METADATA_INPUT_INVALID` → `ValidationError` (400): an input that breaks a rule (a
|
|
22
|
+
* length, an allowed value, an `https://` URL, an instant without an offset, a language sent
|
|
23
|
+
* twice). `details` names each failure (`field` an RFC 6901 pointer such as
|
|
24
|
+
* `/input/translations/0/seoTitle`, `code` the rule such as `INVALID_FIELD_LENGTH`). Nothing is
|
|
25
|
+
* written.
|
|
26
|
+
* - `ENTITY_NOT_FOUND` → `NotFoundError` (404): `upsert` of a product the store does not hold.
|
|
27
|
+
* - `TRANSLATION_LANGUAGE_NOT_OFFERED` → `ValidationError` (400): a new translation in a language
|
|
28
|
+
* the store does not offer.
|
|
29
|
+
* - `BULK_ACTION_INPUT_INVALID` → `ValidationError` (400): a `bulkUpsert` of no product, more than
|
|
30
|
+
* {@link MAX_BULK_METADATA_EDITS} or one product twice, refused before anything is sent.
|
|
31
|
+
* - `INVALID_DATETIME` → `ValidationError` (400): `metaRobotsUnavailableAfter` without an offset,
|
|
32
|
+
* refused before anything is sent.
|
|
33
|
+
* - `FORBIDDEN` → `PermissionDeniedError` (403) without the permission.
|
|
34
|
+
*
|
|
35
|
+
* Release: `coverage` and `bulkUpsert` need a platform release with `productMetadataCoverage` and
|
|
36
|
+
* `bulkUpsertProductMetadata` (deploy vendure-server first: an older one refuses the document as
|
|
37
|
+
* `GRAPHQL_VALIDATION_FAILED`); on such a release `upsert` also answers a validation failure as an
|
|
38
|
+
* uncoded `INTERNAL_SERVER_ERROR` and writes a row for a product the store does not hold. `get`
|
|
39
|
+
* and `delete` are served by every release this SDK supports. No method deduplicates on
|
|
40
|
+
* `idempotencyKey`; every write is naturally repeatable.
|
|
41
|
+
*/
|
|
42
|
+
import { NotFoundError, UpstreamError, ValidationError, } from '@sixtyninecommerce/core';
|
|
43
|
+
import { assertDeleted, assertInstant, DELETION_FIELDS, fieldOf, vendureListPage, } from './types.js';
|
|
44
|
+
/** How many products one `bulkUpsert` call may name. */
|
|
45
|
+
export const MAX_BULK_METADATA_EDITS = 200;
|
|
46
|
+
const IMAGE_FIELDS = /* GraphQL */ `
|
|
47
|
+
id
|
|
48
|
+
name
|
|
49
|
+
preview
|
|
50
|
+
source
|
|
51
|
+
type
|
|
52
|
+
mimeType
|
|
53
|
+
`;
|
|
54
|
+
const METADATA_FIELDS = /* GraphQL */ `
|
|
55
|
+
id
|
|
56
|
+
productId
|
|
57
|
+
channelId
|
|
58
|
+
metaRobotsIndex
|
|
59
|
+
metaRobotsFollow
|
|
60
|
+
metaRobotsNoarchive
|
|
61
|
+
metaRobotsNosnippet
|
|
62
|
+
metaRobotsNoimageindex
|
|
63
|
+
metaRobotsMaxImagePreview
|
|
64
|
+
metaRobotsMaxSnippet
|
|
65
|
+
metaRobotsMaxVideoPreview
|
|
66
|
+
metaRobotsUnavailableAfter
|
|
67
|
+
socialImageId
|
|
68
|
+
socialImage { ${IMAGE_FIELDS} }
|
|
69
|
+
twitterImageOverrideId
|
|
70
|
+
twitterImageOverride { ${IMAGE_FIELDS} }
|
|
71
|
+
twitterCardType
|
|
72
|
+
socialOgType
|
|
73
|
+
seoIncludeReviewsInJsonld
|
|
74
|
+
aiSummaryAudience
|
|
75
|
+
aiBotOverrides
|
|
76
|
+
qaEmitFaqpageJsonld
|
|
77
|
+
hreflangOverrides
|
|
78
|
+
resolvedBotDirectives
|
|
79
|
+
translations {
|
|
80
|
+
id
|
|
81
|
+
languageCode
|
|
82
|
+
seoTitle
|
|
83
|
+
seoDescription
|
|
84
|
+
canonicalUrl
|
|
85
|
+
breadcrumbOverride
|
|
86
|
+
focusKeywords
|
|
87
|
+
socialTitle
|
|
88
|
+
socialDescription
|
|
89
|
+
socialImageAlt
|
|
90
|
+
twitterTitleOverride
|
|
91
|
+
twitterDescriptionOverride
|
|
92
|
+
aiSummary
|
|
93
|
+
qaPairs
|
|
94
|
+
}
|
|
95
|
+
`;
|
|
96
|
+
export const PRODUCT_METADATA_QUERY = /* GraphQL */ `
|
|
97
|
+
query CatalogProductMetadata($productId: ID!) {
|
|
98
|
+
product(id: $productId) {
|
|
99
|
+
id
|
|
100
|
+
metadata { ${METADATA_FIELDS} }
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
`;
|
|
104
|
+
export const UPSERT_PRODUCT_METADATA_MUTATION = /* GraphQL */ `
|
|
105
|
+
mutation CatalogUpsertProductMetadata($productId: ID!, $input: ProductMetadataInput!) {
|
|
106
|
+
upsertProductMetadata(productId: $productId, input: $input) { ${METADATA_FIELDS} }
|
|
107
|
+
}
|
|
108
|
+
`;
|
|
109
|
+
export const DELETE_PRODUCT_METADATA_MUTATION = /* GraphQL */ `
|
|
110
|
+
mutation CatalogDeleteProductMetadata($productId: ID!) {
|
|
111
|
+
deleteProductMetadata(productId: $productId) { ${DELETION_FIELDS} }
|
|
112
|
+
}
|
|
113
|
+
`;
|
|
114
|
+
export const PRODUCT_METADATA_COVERAGE_QUERY = /* GraphQL */ `
|
|
115
|
+
query CatalogProductMetadataCoverage(
|
|
116
|
+
$languageCode: LanguageCode!
|
|
117
|
+
$filter: ProductMetadataCoverageFilter
|
|
118
|
+
$term: String
|
|
119
|
+
$options: ProductMetadataCoverageListOptions
|
|
120
|
+
) {
|
|
121
|
+
productMetadataCoverage(
|
|
122
|
+
languageCode: $languageCode
|
|
123
|
+
filter: $filter
|
|
124
|
+
term: $term
|
|
125
|
+
options: $options
|
|
126
|
+
) {
|
|
127
|
+
items {
|
|
128
|
+
productId
|
|
129
|
+
name
|
|
130
|
+
slug
|
|
131
|
+
enabled
|
|
132
|
+
seoTitle
|
|
133
|
+
seoDescription
|
|
134
|
+
}
|
|
135
|
+
totalItems
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
`;
|
|
139
|
+
export const BULK_UPSERT_PRODUCT_METADATA_MUTATION = /* GraphQL */ `
|
|
140
|
+
mutation CatalogBulkUpsertProductMetadata($edits: [ProductMetadataBulkEdit!]!) {
|
|
141
|
+
bulkUpsertProductMetadata(edits: $edits) {
|
|
142
|
+
items {
|
|
143
|
+
productId
|
|
144
|
+
status
|
|
145
|
+
code
|
|
146
|
+
message
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
`;
|
|
151
|
+
function bulkInvalid(message) {
|
|
152
|
+
return new ValidationError({
|
|
153
|
+
code: 'BULK_ACTION_INPUT_INVALID',
|
|
154
|
+
message,
|
|
155
|
+
status: 400,
|
|
156
|
+
service: 'vendure',
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
/** The edits as sent, refused before the request leaves when the engine would refuse them. */
|
|
160
|
+
function bulkEdits(edits) {
|
|
161
|
+
if (!Array.isArray(edits))
|
|
162
|
+
throw bulkInvalid('edits must be a list.');
|
|
163
|
+
if (edits.length === 0)
|
|
164
|
+
throw bulkInvalid('Name at least one product.');
|
|
165
|
+
if (edits.length > MAX_BULK_METADATA_EDITS) {
|
|
166
|
+
throw bulkInvalid(`A bulk upsert takes at most ${String(MAX_BULK_METADATA_EDITS)} products; this one names ${String(edits.length)}.`);
|
|
167
|
+
}
|
|
168
|
+
const ids = edits.map((edit) => String(edit.productId).toLowerCase());
|
|
169
|
+
if (new Set(ids).size !== ids.length)
|
|
170
|
+
throw bulkInvalid('Name each product once.');
|
|
171
|
+
for (const edit of edits) {
|
|
172
|
+
assertInstant('metaRobotsUnavailableAfter', edit.input.metaRobotsUnavailableAfter);
|
|
173
|
+
}
|
|
174
|
+
return edits.map((edit) => ({ productId: edit.productId, input: edit.input }));
|
|
175
|
+
}
|
|
176
|
+
export function createProductMetadataModule(transport) {
|
|
177
|
+
return {
|
|
178
|
+
async get(productId, options) {
|
|
179
|
+
const product = await fieldOf(transport, PRODUCT_METADATA_QUERY, 'product', { productId }, options);
|
|
180
|
+
if (!product) {
|
|
181
|
+
throw new NotFoundError({
|
|
182
|
+
code: 'PRODUCT_NOT_FOUND',
|
|
183
|
+
message: `This store has no product ${productId}.`,
|
|
184
|
+
status: 404,
|
|
185
|
+
service: 'vendure',
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
return product.metadata;
|
|
189
|
+
},
|
|
190
|
+
async upsert(productId, input, options) {
|
|
191
|
+
assertInstant('metaRobotsUnavailableAfter', input.metaRobotsUnavailableAfter);
|
|
192
|
+
return fieldOf(transport, UPSERT_PRODUCT_METADATA_MUTATION, 'upsertProductMetadata', { productId, input }, options);
|
|
193
|
+
},
|
|
194
|
+
async delete(productId, options) {
|
|
195
|
+
const response = await fieldOf(transport, DELETE_PRODUCT_METADATA_MUTATION, 'deleteProductMetadata', { productId }, options);
|
|
196
|
+
assertDeleted('PRODUCT_METADATA_NOT_DELETED', [response]);
|
|
197
|
+
},
|
|
198
|
+
async coverage(query) {
|
|
199
|
+
const { languageCode, filter, term, ...options } = query;
|
|
200
|
+
return vendureListPage(transport, PRODUCT_METADATA_COVERAGE_QUERY, 'productMetadataCoverage', (skip, take) => ({
|
|
201
|
+
languageCode,
|
|
202
|
+
filter: filter ?? 'ALL',
|
|
203
|
+
...(term === undefined || term.trim() === '' ? {} : { term }),
|
|
204
|
+
options: { skip, take },
|
|
205
|
+
}), options);
|
|
206
|
+
},
|
|
207
|
+
async bulkUpsert(edits, options) {
|
|
208
|
+
const data = await fieldOf(transport, BULK_UPSERT_PRODUCT_METADATA_MUTATION, 'bulkUpsertProductMetadata', { edits: bulkEdits(edits) }, options);
|
|
209
|
+
if (data === null) {
|
|
210
|
+
throw new UpstreamError({
|
|
211
|
+
code: 'UNEXPECTED_RESPONSE',
|
|
212
|
+
message: 'The engine answered bulkUpsertProductMetadata with nothing.',
|
|
213
|
+
status: 502,
|
|
214
|
+
service: 'vendure',
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
return data.items;
|
|
218
|
+
},
|
|
219
|
+
};
|
|
220
|
+
}
|