This is page 16 of 43. Use http://codebase.md/taurgis/sfcc-dev-mcp?lines=false&page={x} to view the full context. # Directory Structure ``` ├── .DS_Store ├── .github │ ├── dependabot.yml │ ├── instructions │ │ ├── mcp-node-tests.instructions.md │ │ └── mcp-yml-tests.instructions.md │ ├── ISSUE_TEMPLATE │ │ ├── bug_report.yml │ │ ├── config.yml │ │ ├── documentation.yml │ │ ├── feature_request.yml │ │ └── question.yml │ ├── PULL_REQUEST_TEMPLATE │ │ ├── bug_fix.md │ │ ├── documentation.md │ │ └── new_tool.md │ ├── pull_request_template.md │ └── workflows │ ├── ci.yml │ ├── deploy-pages.yml │ ├── publish.yml │ └── update-docs.yml ├── .gitignore ├── .husky │ └── pre-commit ├── aegis.config.docs-only.json ├── aegis.config.json ├── aegis.config.with-dw.json ├── AGENTS.md ├── ai-instructions │ ├── claude-desktop │ │ └── claude_custom_instructions.md │ ├── cursor │ │ └── .cursor │ │ └── rules │ │ ├── debugging-workflows.mdc │ │ ├── hooks-development.mdc │ │ ├── isml-templates.mdc │ │ ├── job-framework.mdc │ │ ├── performance-optimization.mdc │ │ ├── scapi-endpoints.mdc │ │ ├── security-patterns.mdc │ │ ├── sfcc-development.mdc │ │ ├── sfra-controllers.mdc │ │ ├── sfra-models.mdc │ │ ├── system-objects.mdc │ │ └── testing-patterns.mdc │ └── github-copilot │ └── copilot-instructions.md ├── CHANGELOG.md ├── CONTRIBUTING.md ├── docs │ ├── best-practices │ │ ├── cartridge_creation.md │ │ ├── isml_templates.md │ │ ├── job_framework.md │ │ ├── localserviceregistry.md │ │ ├── ocapi_hooks.md │ │ ├── performance.md │ │ ├── scapi_custom_endpoint.md │ │ ├── scapi_hooks.md │ │ ├── security.md │ │ ├── sfra_client_side_js.md │ │ ├── sfra_controllers.md │ │ ├── sfra_models.md │ │ └── sfra_scss.md │ ├── dw_campaign │ │ ├── ABTest.md │ │ ├── ABTestMgr.md │ │ ├── ABTestSegment.md │ │ ├── AmountDiscount.md │ │ ├── ApproachingDiscount.md │ │ ├── BonusChoiceDiscount.md │ │ ├── BonusDiscount.md │ │ ├── Campaign.md │ │ ├── CampaignMgr.md │ │ ├── CampaignStatusCodes.md │ │ ├── Coupon.md │ │ ├── CouponMgr.md │ │ ├── CouponRedemption.md │ │ ├── CouponStatusCodes.md │ │ ├── Discount.md │ │ ├── DiscountPlan.md │ │ ├── FixedPriceDiscount.md │ │ ├── FixedPriceShippingDiscount.md │ │ ├── FreeDiscount.md │ │ ├── FreeShippingDiscount.md │ │ ├── PercentageDiscount.md │ │ ├── PercentageOptionDiscount.md │ │ ├── PriceBookPriceDiscount.md │ │ ├── Promotion.md │ │ ├── PromotionMgr.md │ │ ├── PromotionPlan.md │ │ ├── SlotContent.md │ │ ├── SourceCodeGroup.md │ │ ├── SourceCodeInfo.md │ │ ├── SourceCodeStatusCodes.md │ │ └── TotalFixedPriceDiscount.md │ ├── dw_catalog │ │ ├── Catalog.md │ │ ├── CatalogMgr.md │ │ ├── Category.md │ │ ├── CategoryAssignment.md │ │ ├── CategoryLink.md │ │ ├── PriceBook.md │ │ ├── PriceBookMgr.md │ │ ├── Product.md │ │ ├── ProductActiveData.md │ │ ├── ProductAttributeModel.md │ │ ├── ProductAvailabilityLevels.md │ │ ├── ProductAvailabilityModel.md │ │ ├── ProductInventoryList.md │ │ ├── ProductInventoryMgr.md │ │ ├── ProductInventoryRecord.md │ │ ├── ProductLink.md │ │ ├── ProductMgr.md │ │ ├── ProductOption.md │ │ ├── ProductOptionModel.md │ │ ├── ProductOptionValue.md │ │ ├── ProductPriceInfo.md │ │ ├── ProductPriceModel.md │ │ ├── ProductPriceTable.md │ │ ├── ProductSearchHit.md │ │ ├── ProductSearchModel.md │ │ ├── ProductSearchRefinementDefinition.md │ │ ├── ProductSearchRefinements.md │ │ ├── ProductSearchRefinementValue.md │ │ ├── ProductVariationAttribute.md │ │ ├── ProductVariationAttributeValue.md │ │ ├── ProductVariationModel.md │ │ ├── Recommendation.md │ │ ├── SearchModel.md │ │ ├── SearchRefinementDefinition.md │ │ ├── SearchRefinements.md │ │ ├── SearchRefinementValue.md │ │ ├── SortingOption.md │ │ ├── SortingRule.md │ │ ├── Store.md │ │ ├── StoreGroup.md │ │ ├── StoreInventoryFilter.md │ │ ├── StoreInventoryFilterValue.md │ │ ├── StoreMgr.md │ │ ├── Variant.md │ │ └── VariationGroup.md │ ├── dw_content │ │ ├── Content.md │ │ ├── ContentMgr.md │ │ ├── ContentSearchModel.md │ │ ├── ContentSearchRefinementDefinition.md │ │ ├── ContentSearchRefinements.md │ │ ├── ContentSearchRefinementValue.md │ │ ├── Folder.md │ │ ├── Library.md │ │ ├── MarkupText.md │ │ └── MediaFile.md │ ├── dw_crypto │ │ ├── CertificateRef.md │ │ ├── CertificateUtils.md │ │ ├── Cipher.md │ │ ├── Encoding.md │ │ ├── JWE.md │ │ ├── JWEHeader.md │ │ ├── JWS.md │ │ ├── JWSHeader.md │ │ ├── KeyRef.md │ │ ├── Mac.md │ │ ├── MessageDigest.md │ │ ├── SecureRandom.md │ │ ├── Signature.md │ │ ├── WeakCipher.md │ │ ├── WeakMac.md │ │ ├── WeakMessageDigest.md │ │ ├── WeakSignature.md │ │ └── X509Certificate.md │ ├── dw_customer │ │ ├── AddressBook.md │ │ ├── AgentUserMgr.md │ │ ├── AgentUserStatusCodes.md │ │ ├── AuthenticationStatus.md │ │ ├── Credentials.md │ │ ├── Customer.md │ │ ├── CustomerActiveData.md │ │ ├── CustomerAddress.md │ │ ├── CustomerCDPData.md │ │ ├── CustomerContextMgr.md │ │ ├── CustomerGroup.md │ │ ├── CustomerList.md │ │ ├── CustomerMgr.md │ │ ├── CustomerPasswordConstraints.md │ │ ├── CustomerPaymentInstrument.md │ │ ├── CustomerStatusCodes.md │ │ ├── EncryptedObject.md │ │ ├── ExternalProfile.md │ │ ├── OrderHistory.md │ │ ├── ProductList.md │ │ ├── ProductListItem.md │ │ ├── ProductListItemPurchase.md │ │ ├── ProductListMgr.md │ │ ├── ProductListRegistrant.md │ │ ├── Profile.md │ │ └── Wallet.md │ ├── dw_extensions.applepay │ │ ├── ApplePayHookResult.md │ │ └── ApplePayHooks.md │ ├── dw_extensions.facebook │ │ ├── FacebookFeedHooks.md │ │ └── FacebookProduct.md │ ├── dw_extensions.paymentrequest │ │ ├── PaymentRequestHookResult.md │ │ └── PaymentRequestHooks.md │ ├── dw_extensions.payments │ │ ├── SalesforceBancontactPaymentDetails.md │ │ ├── SalesforceCardPaymentDetails.md │ │ ├── SalesforceEpsPaymentDetails.md │ │ ├── SalesforceIdealPaymentDetails.md │ │ ├── SalesforceKlarnaPaymentDetails.md │ │ ├── SalesforcePaymentDetails.md │ │ ├── SalesforcePaymentIntent.md │ │ ├── SalesforcePaymentMethod.md │ │ ├── SalesforcePaymentRequest.md │ │ ├── SalesforcePaymentsHooks.md │ │ ├── SalesforcePaymentsMgr.md │ │ ├── SalesforcePaymentsSiteConfiguration.md │ │ ├── SalesforcePayPalOrder.md │ │ ├── SalesforcePayPalOrderAddress.md │ │ ├── SalesforcePayPalOrderPayer.md │ │ ├── SalesforcePayPalPaymentDetails.md │ │ ├── SalesforceSepaDebitPaymentDetails.md │ │ └── SalesforceVenmoPaymentDetails.md │ ├── dw_extensions.pinterest │ │ ├── PinterestAvailability.md │ │ ├── PinterestFeedHooks.md │ │ ├── PinterestOrder.md │ │ ├── PinterestOrderHooks.md │ │ └── PinterestProduct.md │ ├── dw_io │ │ ├── CSVStreamReader.md │ │ ├── CSVStreamWriter.md │ │ ├── File.md │ │ ├── FileReader.md │ │ ├── FileWriter.md │ │ ├── InputStream.md │ │ ├── OutputStream.md │ │ ├── PrintWriter.md │ │ ├── RandomAccessFileReader.md │ │ ├── Reader.md │ │ ├── StringWriter.md │ │ ├── Writer.md │ │ ├── XMLIndentingStreamWriter.md │ │ ├── XMLStreamConstants.md │ │ ├── XMLStreamReader.md │ │ └── XMLStreamWriter.md │ ├── dw_job │ │ ├── JobExecution.md │ │ └── JobStepExecution.md │ ├── dw_net │ │ ├── FTPClient.md │ │ ├── FTPFileInfo.md │ │ ├── HTTPClient.md │ │ ├── HTTPRequestPart.md │ │ ├── Mail.md │ │ ├── SFTPClient.md │ │ ├── SFTPFileInfo.md │ │ ├── WebDAVClient.md │ │ └── WebDAVFileInfo.md │ ├── dw_object │ │ ├── ActiveData.md │ │ ├── CustomAttributes.md │ │ ├── CustomObject.md │ │ ├── CustomObjectMgr.md │ │ ├── Extensible.md │ │ ├── ExtensibleObject.md │ │ ├── Note.md │ │ ├── ObjectAttributeDefinition.md │ │ ├── ObjectAttributeGroup.md │ │ ├── ObjectAttributeValueDefinition.md │ │ ├── ObjectTypeDefinition.md │ │ ├── PersistentObject.md │ │ ├── SimpleExtensible.md │ │ └── SystemObjectMgr.md │ ├── dw_order │ │ ├── AbstractItem.md │ │ ├── AbstractItemCtnr.md │ │ ├── Appeasement.md │ │ ├── AppeasementItem.md │ │ ├── Basket.md │ │ ├── BasketMgr.md │ │ ├── BonusDiscountLineItem.md │ │ ├── CouponLineItem.md │ │ ├── CreateAgentBasketLimitExceededException.md │ │ ├── CreateBasketFromOrderException.md │ │ ├── CreateCouponLineItemException.md │ │ ├── CreateOrderException.md │ │ ├── CreateTemporaryBasketLimitExceededException.md │ │ ├── GiftCertificate.md │ │ ├── GiftCertificateLineItem.md │ │ ├── GiftCertificateMgr.md │ │ ├── GiftCertificateStatusCodes.md │ │ ├── Invoice.md │ │ ├── InvoiceItem.md │ │ ├── LineItem.md │ │ ├── LineItemCtnr.md │ │ ├── Order.md │ │ ├── OrderAddress.md │ │ ├── OrderItem.md │ │ ├── OrderMgr.md │ │ ├── OrderPaymentInstrument.md │ │ ├── OrderProcessStatusCodes.md │ │ ├── PaymentCard.md │ │ ├── PaymentInstrument.md │ │ ├── PaymentMethod.md │ │ ├── PaymentMgr.md │ │ ├── PaymentProcessor.md │ │ ├── PaymentStatusCodes.md │ │ ├── PaymentTransaction.md │ │ ├── PriceAdjustment.md │ │ ├── PriceAdjustmentLimitTypes.md │ │ ├── ProductLineItem.md │ │ ├── ProductShippingCost.md │ │ ├── ProductShippingLineItem.md │ │ ├── ProductShippingModel.md │ │ ├── Return.md │ │ ├── ReturnCase.md │ │ ├── ReturnCaseItem.md │ │ ├── ReturnItem.md │ │ ├── Shipment.md │ │ ├── ShipmentShippingCost.md │ │ ├── ShipmentShippingModel.md │ │ ├── ShippingLineItem.md │ │ ├── ShippingLocation.md │ │ ├── ShippingMethod.md │ │ ├── ShippingMgr.md │ │ ├── ShippingOrder.md │ │ ├── ShippingOrderItem.md │ │ ├── SumItem.md │ │ ├── TaxGroup.md │ │ ├── TaxItem.md │ │ ├── TaxMgr.md │ │ ├── TrackingInfo.md │ │ └── TrackingRef.md │ ├── dw_order.hooks │ │ ├── CalculateHooks.md │ │ ├── OrderHooks.md │ │ ├── PaymentHooks.md │ │ ├── ReturnHooks.md │ │ └── ShippingOrderHooks.md │ ├── dw_rpc │ │ ├── SOAPUtil.md │ │ ├── Stub.md │ │ └── WebReference.md │ ├── dw_suggest │ │ ├── BrandSuggestions.md │ │ ├── CategorySuggestions.md │ │ ├── ContentSuggestions.md │ │ ├── CustomSuggestions.md │ │ ├── ProductSuggestions.md │ │ ├── SearchPhraseSuggestions.md │ │ ├── SuggestedCategory.md │ │ ├── SuggestedContent.md │ │ ├── SuggestedPhrase.md │ │ ├── SuggestedProduct.md │ │ ├── SuggestedTerm.md │ │ ├── SuggestedTerms.md │ │ ├── Suggestions.md │ │ └── SuggestModel.md │ ├── dw_svc │ │ ├── FTPService.md │ │ ├── FTPServiceDefinition.md │ │ ├── HTTPFormService.md │ │ ├── HTTPFormServiceDefinition.md │ │ ├── HTTPService.md │ │ ├── HTTPServiceDefinition.md │ │ ├── LocalServiceRegistry.md │ │ ├── Result.md │ │ ├── Service.md │ │ ├── ServiceCallback.md │ │ ├── ServiceConfig.md │ │ ├── ServiceCredential.md │ │ ├── ServiceDefinition.md │ │ ├── ServiceProfile.md │ │ ├── ServiceRegistry.md │ │ ├── SOAPService.md │ │ └── SOAPServiceDefinition.md │ ├── dw_system │ │ ├── AgentUserStatusCodes.md │ │ ├── Cache.md │ │ ├── CacheMgr.md │ │ ├── HookMgr.md │ │ ├── InternalObject.md │ │ ├── JobProcessMonitor.md │ │ ├── Log.md │ │ ├── Logger.md │ │ ├── LogNDC.md │ │ ├── OrganizationPreferences.md │ │ ├── Pipeline.md │ │ ├── PipelineDictionary.md │ │ ├── RemoteInclude.md │ │ ├── Request.md │ │ ├── RequestHooks.md │ │ ├── Response.md │ │ ├── RESTErrorResponse.md │ │ ├── RESTResponseMgr.md │ │ ├── RESTSuccessResponse.md │ │ ├── SearchStatus.md │ │ ├── Session.md │ │ ├── Site.md │ │ ├── SitePreferences.md │ │ ├── Status.md │ │ ├── StatusItem.md │ │ ├── System.md │ │ └── Transaction.md │ ├── dw_util │ │ ├── ArrayList.md │ │ ├── Assert.md │ │ ├── BigInteger.md │ │ ├── Bytes.md │ │ ├── Calendar.md │ │ ├── Collection.md │ │ ├── Currency.md │ │ ├── DateUtils.md │ │ ├── Decimal.md │ │ ├── FilteringCollection.md │ │ ├── Geolocation.md │ │ ├── HashMap.md │ │ ├── HashSet.md │ │ ├── Iterator.md │ │ ├── LinkedHashMap.md │ │ ├── LinkedHashSet.md │ │ ├── List.md │ │ ├── Locale.md │ │ ├── Map.md │ │ ├── MapEntry.md │ │ ├── MappingKey.md │ │ ├── MappingMgr.md │ │ ├── PropertyComparator.md │ │ ├── SecureEncoder.md │ │ ├── SecureFilter.md │ │ ├── SeekableIterator.md │ │ ├── Set.md │ │ ├── SortedMap.md │ │ ├── SortedSet.md │ │ ├── StringUtils.md │ │ ├── Template.md │ │ └── UUIDUtils.md │ ├── dw_value │ │ ├── EnumValue.md │ │ ├── MimeEncodedText.md │ │ ├── Money.md │ │ └── Quantity.md │ ├── dw_web │ │ ├── ClickStream.md │ │ ├── ClickStreamEntry.md │ │ ├── Cookie.md │ │ ├── Cookies.md │ │ ├── CSRFProtection.md │ │ ├── Form.md │ │ ├── FormAction.md │ │ ├── FormElement.md │ │ ├── FormElementValidationResult.md │ │ ├── FormField.md │ │ ├── FormFieldOption.md │ │ ├── FormFieldOptions.md │ │ ├── FormGroup.md │ │ ├── FormList.md │ │ ├── FormListItem.md │ │ ├── Forms.md │ │ ├── HttpParameter.md │ │ ├── HttpParameterMap.md │ │ ├── LoopIterator.md │ │ ├── PageMetaData.md │ │ ├── PageMetaTag.md │ │ ├── PagingModel.md │ │ ├── Resource.md │ │ ├── URL.md │ │ ├── URLAction.md │ │ ├── URLParameter.md │ │ ├── URLRedirect.md │ │ ├── URLRedirectMgr.md │ │ └── URLUtils.md │ ├── sfra │ │ ├── account.md │ │ ├── address.md │ │ ├── billing.md │ │ ├── cart.md │ │ ├── categories.md │ │ ├── content.md │ │ ├── locale.md │ │ ├── order.md │ │ ├── payment.md │ │ ├── price-default.md │ │ ├── price-range.md │ │ ├── price-tiered.md │ │ ├── product-bundle.md │ │ ├── product-full.md │ │ ├── product-line-items.md │ │ ├── product-search.md │ │ ├── product-tile.md │ │ ├── querystring.md │ │ ├── render.md │ │ ├── request.md │ │ ├── response.md │ │ ├── server.md │ │ ├── shipping.md │ │ ├── store.md │ │ ├── stores.md │ │ └── totals.md │ └── TopLevel │ ├── APIException.md │ ├── arguments.md │ ├── Array.md │ ├── ArrayBuffer.md │ ├── BigInt.md │ ├── Boolean.md │ ├── ConversionError.md │ ├── DataView.md │ ├── Date.md │ ├── Error.md │ ├── ES6Iterator.md │ ├── EvalError.md │ ├── Fault.md │ ├── Float32Array.md │ ├── Float64Array.md │ ├── Function.md │ ├── Generator.md │ ├── global.md │ ├── Int16Array.md │ ├── Int32Array.md │ ├── Int8Array.md │ ├── InternalError.md │ ├── IOError.md │ ├── Iterable.md │ ├── Iterator.md │ ├── JSON.md │ ├── Map.md │ ├── Math.md │ ├── Module.md │ ├── Namespace.md │ ├── Number.md │ ├── Object.md │ ├── QName.md │ ├── RangeError.md │ ├── ReferenceError.md │ ├── RegExp.md │ ├── Set.md │ ├── StopIteration.md │ ├── String.md │ ├── Symbol.md │ ├── SyntaxError.md │ ├── SystemError.md │ ├── TypeError.md │ ├── Uint16Array.md │ ├── Uint32Array.md │ ├── Uint8Array.md │ ├── Uint8ClampedArray.md │ ├── URIError.md │ ├── WeakMap.md │ ├── WeakSet.md │ ├── XML.md │ ├── XMLList.md │ └── XMLStreamError.md ├── docs-site │ ├── .gitignore │ ├── App.tsx │ ├── components │ │ ├── Badge.tsx │ │ ├── BreadcrumbSchema.tsx │ │ ├── CodeBlock.tsx │ │ ├── Collapsible.tsx │ │ ├── ConfigBuilder.tsx │ │ ├── ConfigHero.tsx │ │ ├── ConfigModeTabs.tsx │ │ ├── icons.tsx │ │ ├── Layout.tsx │ │ ├── LightCodeContainer.tsx │ │ ├── NewcomerCTA.tsx │ │ ├── NextStepsStrip.tsx │ │ ├── OnThisPage.tsx │ │ ├── Search.tsx │ │ ├── SEO.tsx │ │ ├── Sidebar.tsx │ │ ├── StructuredData.tsx │ │ ├── ToolCard.tsx │ │ ├── ToolFilters.tsx │ │ ├── Typography.tsx │ │ └── VersionBadge.tsx │ ├── constants.tsx │ ├── index.html │ ├── main.tsx │ ├── metadata.json │ ├── package-lock.json │ ├── package.json │ ├── pages │ │ ├── AIInterfacesPage.tsx │ │ ├── ConfigurationPage.tsx │ │ ├── DevelopmentPage.tsx │ │ ├── ExamplesPage.tsx │ │ ├── FeaturesPage.tsx │ │ ├── HomePage.tsx │ │ ├── SecurityPage.tsx │ │ ├── ToolsPage.tsx │ │ └── TroubleshootingPage.tsx │ ├── postcss.config.js │ ├── public │ │ ├── .well-known │ │ │ └── security.txt │ │ ├── 404.html │ │ ├── android-chrome-192x192.png │ │ ├── android-chrome-512x512.png │ │ ├── apple-touch-icon.png │ │ ├── explain-product-pricing-methods-no-mcp.png │ │ ├── explain-product-pricing-methods.png │ │ ├── favicon-16x16.png │ │ ├── favicon-32x32.png │ │ ├── favicon.ico │ │ ├── llms.txt │ │ ├── robots.txt │ │ ├── site.webmanifest │ │ └── sitemap.xml │ ├── README.md │ ├── scripts │ │ ├── generate-search-index.js │ │ ├── generate-sitemap.js │ │ └── search-dev.js │ ├── src │ │ └── styles │ │ ├── input.css │ │ └── prism-theme.css │ ├── tailwind.config.js │ ├── tsconfig.json │ ├── types.ts │ ├── utils │ │ ├── search.ts │ │ └── toolsData.ts │ └── vite.config.ts ├── eslint.config.js ├── jest.config.js ├── LICENSE ├── package-lock.json ├── package.json ├── README.md ├── scripts │ └── convert-docs.js ├── SECURITY.md ├── server.json ├── src │ ├── clients │ │ ├── base │ │ │ ├── http-client.ts │ │ │ ├── oauth-token.ts │ │ │ └── ocapi-auth-client.ts │ │ ├── best-practices-client.ts │ │ ├── cartridge-generation-client.ts │ │ ├── docs │ │ │ ├── class-content-parser.ts │ │ │ ├── class-name-resolver.ts │ │ │ ├── documentation-scanner.ts │ │ │ ├── index.ts │ │ │ └── referenced-types-extractor.ts │ │ ├── docs-client.ts │ │ ├── log-client.ts │ │ ├── logs │ │ │ ├── index.ts │ │ │ ├── log-analyzer.ts │ │ │ ├── log-client.ts │ │ │ ├── log-constants.ts │ │ │ ├── log-file-discovery.ts │ │ │ ├── log-file-reader.ts │ │ │ ├── log-formatter.ts │ │ │ ├── log-processor.ts │ │ │ ├── log-types.ts │ │ │ └── webdav-client-manager.ts │ │ ├── ocapi │ │ │ ├── code-versions-client.ts │ │ │ ├── site-preferences-client.ts │ │ │ └── system-objects-client.ts │ │ ├── ocapi-client.ts │ │ └── sfra-client.ts │ ├── config │ │ ├── configuration-factory.ts │ │ └── dw-json-loader.ts │ ├── core │ │ ├── handlers │ │ │ ├── abstract-log-tool-handler.ts │ │ │ ├── base-handler.ts │ │ │ ├── best-practices-handler.ts │ │ │ ├── cartridge-handler.ts │ │ │ ├── client-factory.ts │ │ │ ├── code-version-handler.ts │ │ │ ├── docs-handler.ts │ │ │ ├── job-log-handler.ts │ │ │ ├── job-log-tool-config.ts │ │ │ ├── log-handler.ts │ │ │ ├── log-tool-config.ts │ │ │ ├── sfra-handler.ts │ │ │ ├── system-object-handler.ts │ │ │ └── validation-helpers.ts │ │ ├── server.ts │ │ └── tool-definitions.ts │ ├── index.ts │ ├── main.ts │ ├── services │ │ ├── file-system-service.ts │ │ ├── index.ts │ │ └── path-service.ts │ ├── tool-configs │ │ ├── best-practices-tool-config.ts │ │ ├── cartridge-tool-config.ts │ │ ├── code-version-tool-config.ts │ │ ├── docs-tool-config.ts │ │ ├── job-log-tool-config.ts │ │ ├── log-tool-config.ts │ │ ├── sfra-tool-config.ts │ │ └── system-object-tool-config.ts │ ├── types │ │ └── types.ts │ └── utils │ ├── cache.ts │ ├── job-log-tool-config.ts │ ├── job-log-utils.ts │ ├── log-cache.ts │ ├── log-tool-config.ts │ ├── log-tool-constants.ts │ ├── log-tool-utils.ts │ ├── logger.ts │ ├── ocapi-url-builder.ts │ ├── path-resolver.ts │ ├── query-builder.ts │ ├── utils.ts │ └── validator.ts ├── tests │ ├── __mocks__ │ │ ├── docs-client.ts │ │ ├── src │ │ │ └── clients │ │ │ └── base │ │ │ └── http-client.js │ │ └── webdav.js │ ├── base-handler.test.ts │ ├── base-http-client.test.ts │ ├── best-practices-handler.test.ts │ ├── cache.test.ts │ ├── cartridge-handler.test.ts │ ├── class-content-parser.test.ts │ ├── class-name-resolver.test.ts │ ├── client-factory.test.ts │ ├── code-version-handler.test.ts │ ├── code-versions-client.test.ts │ ├── config.test.ts │ ├── configuration-factory.test.ts │ ├── docs-handler.test.ts │ ├── documentation-scanner.test.ts │ ├── file-system-service.test.ts │ ├── job-log-handler.test.ts │ ├── job-log-utils.test.ts │ ├── log-client.test.ts │ ├── log-handler.test.ts │ ├── log-processor.test.ts │ ├── logger.test.ts │ ├── mcp │ │ ├── AGENTS.md │ │ ├── node │ │ │ ├── activate-code-version-advanced.full-mode.programmatic.test.js │ │ │ ├── code-versions.full-mode.programmatic.test.js │ │ │ ├── generate-cartridge-structure.docs-only.programmatic.test.js │ │ │ ├── get-available-best-practice-guides.docs-only.programmatic.test.js │ │ │ ├── get-available-sfra-documents.programmatic.test.js │ │ │ ├── get-best-practice-guide.docs-only.programmatic.test.js │ │ │ ├── get-hook-reference.docs-only.programmatic.test.js │ │ │ ├── get-job-execution-summary.full-mode.programmatic.test.js │ │ │ ├── get-job-log-entries.full-mode.programmatic.test.js │ │ │ ├── get-latest-debug.full-mode.programmatic.test.js │ │ │ ├── get-latest-error.full-mode.programmatic.test.js │ │ │ ├── get-latest-info.full-mode.programmatic.test.js │ │ │ ├── get-latest-job-log-files.full-mode.programmatic.test.js │ │ │ ├── get-latest-warn.full-mode.programmatic.test.js │ │ │ ├── get-log-file-contents.full-mode.programmatic.test.js │ │ │ ├── get-sfcc-class-documentation.docs-only.programmatic.test.js │ │ │ ├── get-sfcc-class-info.docs-only.programmatic.test.js │ │ │ ├── get-sfra-categories.docs-only.programmatic.test.js │ │ │ ├── get-sfra-document.programmatic.test.js │ │ │ ├── get-sfra-documents-by-category.docs-only.programmatic.test.js │ │ │ ├── get-system-object-definition.full-mode.programmatic.test.js │ │ │ ├── get-system-object-definitions.docs-only.programmatic.test.js │ │ │ ├── get-system-object-definitions.full-mode.programmatic.test.js │ │ │ ├── list-log-files.full-mode.programmatic.test.js │ │ │ ├── list-sfcc-classes.docs-only.programmatic.test.js │ │ │ ├── search-best-practices.docs-only.programmatic.test.js │ │ │ ├── search-custom-object-attribute-definitions.full-mode.programmatic.test.js │ │ │ ├── search-job-logs-by-name.full-mode.programmatic.test.js │ │ │ ├── search-job-logs.full-mode.programmatic.test.js │ │ │ ├── search-logs.full-mode.programmatic.test.js │ │ │ ├── search-sfcc-classes.docs-only.programmatic.test.js │ │ │ ├── search-sfcc-methods.docs-only.programmatic.test.js │ │ │ ├── search-sfra-documentation.docs-only.programmatic.test.js │ │ │ ├── search-site-preferences.full-mode.programmatic.test.js │ │ │ ├── search-system-object-attribute-definitions.full-mode.programmatic.test.js │ │ │ ├── search-system-object-attribute-groups.full-mode.programmatic.test.js │ │ │ ├── summarize-logs.full-mode.programmatic.test.js │ │ │ ├── tools.docs-only.programmatic.test.js │ │ │ └── tools.full-mode.programmatic.test.js │ │ ├── README.md │ │ ├── test-fixtures │ │ │ └── dw.json │ │ └── yaml │ │ ├── activate-code-version.docs-only.test.mcp.yml │ │ ├── activate-code-version.full-mode.test.mcp.yml │ │ ├── get_latest_error.test.mcp.yml │ │ ├── get-available-best-practice-guides.docs-only.test.mcp.yml │ │ ├── get-available-best-practice-guides.full-mode.test.mcp.yml │ │ ├── get-available-sfra-documents.docs-only.test.mcp.yml │ │ ├── get-available-sfra-documents.full-mode.test.mcp.yml │ │ ├── get-best-practice-guide.docs-only.test.mcp.yml │ │ ├── get-best-practice-guide.full-mode.test.mcp.yml │ │ ├── get-code-versions.docs-only.test.mcp.yml │ │ ├── get-code-versions.full-mode.test.mcp.yml │ │ ├── get-hook-reference.docs-only.test.mcp.yml │ │ ├── get-hook-reference.full-mode.test.mcp.yml │ │ ├── get-job-execution-summary.full-mode.test.mcp.yml │ │ ├── get-job-log-entries.full-mode.test.mcp.yml │ │ ├── get-latest-debug.full-mode.test.mcp.yml │ │ ├── get-latest-error.full-mode.test.mcp.yml │ │ ├── get-latest-info.full-mode.test.mcp.yml │ │ ├── get-latest-job-log-files.full-mode.test.mcp.yml │ │ ├── get-latest-warn.full-mode.test.mcp.yml │ │ ├── get-log-file-contents.full-mode.test.mcp.yml │ │ ├── get-sfcc-class-documentation.docs-only.test.mcp.yml │ │ ├── get-sfcc-class-documentation.full-mode.test.mcp.yml │ │ ├── get-sfcc-class-info.docs-only.test.mcp.yml │ │ ├── get-sfcc-class-info.full-mode.test.mcp.yml │ │ ├── get-sfra-categories.docs-only.test.mcp.yml │ │ ├── get-sfra-categories.full-mode.test.mcp.yml │ │ ├── get-sfra-document.docs-only.test.mcp.yml │ │ ├── get-sfra-document.full-mode.test.mcp.yml │ │ ├── get-sfra-documents-by-category.docs-only.test.mcp.yml │ │ ├── get-sfra-documents-by-category.full-mode.test.mcp.yml │ │ ├── get-system-object-definition.docs-only.test.mcp.yml │ │ ├── get-system-object-definition.full-mode.test.mcp.yml │ │ ├── get-system-object-definitions.docs-only.test.mcp.yml │ │ ├── get-system-object-definitions.full-mode.test.mcp.yml │ │ ├── list-log-files.full-mode.test.mcp.yml │ │ ├── list-sfcc-classes.docs-only.test.mcp.yml │ │ ├── list-sfcc-classes.full-mode.test.mcp.yml │ │ ├── search-best-practices.docs-only.test.mcp.yml │ │ ├── search-best-practices.full-mode.test.mcp.yml │ │ ├── search-custom-object-attribute-definitions.docs-only.test.mcp.yml │ │ ├── search-custom-object-attribute-definitions.test.mcp.yml │ │ ├── search-job-logs-by-name.full-mode.test.mcp.yml │ │ ├── search-job-logs.full-mode.test.mcp.yml │ │ ├── search-logs.full-mode.test.mcp.yml │ │ ├── search-sfcc-classes.docs-only.test.mcp.yml │ │ ├── search-sfcc-classes.full-mode.test.mcp.yml │ │ ├── search-sfcc-methods.docs-only.test.mcp.yml │ │ ├── search-sfcc-methods.full-mode.test.mcp.yml │ │ ├── search-sfra-documentation.docs-only.test.mcp.yml │ │ ├── search-sfra-documentation.full-mode.test.mcp.yml │ │ ├── search-site-preferences.docs-only.test.mcp.yml │ │ ├── search-site-preferences.full-mode.test.mcp.yml │ │ ├── search-system-object-attribute-definitions.docs-only.test.mcp.yml │ │ ├── search-system-object-attribute-definitions.full-mode.test.mcp.yml │ │ ├── search-system-object-attribute-groups.docs-only.test.mcp.yml │ │ ├── search-system-object-attribute-groups.full-mode.test.mcp.yml │ │ ├── summarize-logs.full-mode.test.mcp.yml │ │ ├── tools.docs-only.test.mcp.yml │ │ └── tools.full-mode.test.mcp.yml │ ├── oauth-token.test.ts │ ├── ocapi-auth-client.test.ts │ ├── ocapi-client.test.ts │ ├── path-service.test.ts │ ├── query-builder.test.ts │ ├── referenced-types-extractor.test.ts │ ├── servers │ │ ├── sfcc-mock-server │ │ │ ├── mock-data │ │ │ │ └── ocapi │ │ │ │ ├── code-versions.json │ │ │ │ ├── custom-object-attributes-customapi.json │ │ │ │ ├── custom-object-attributes-globalsettings.json │ │ │ │ ├── custom-object-attributes-versionhistory.json │ │ │ │ ├── site-preferences-ccv.json │ │ │ │ ├── site-preferences-fastforward.json │ │ │ │ ├── site-preferences-sfra.json │ │ │ │ ├── site-preferences-storefront.json │ │ │ │ ├── site-preferences-system.json │ │ │ │ ├── system-object-attribute-groups-campaign.json │ │ │ │ ├── system-object-attribute-groups-category.json │ │ │ │ ├── system-object-attribute-groups-order.json │ │ │ │ ├── system-object-attribute-groups-product.json │ │ │ │ ├── system-object-attribute-groups-sitepreferences.json │ │ │ │ ├── system-object-attributes-customeraddress.json │ │ │ │ ├── system-object-attributes-product-expanded.json │ │ │ │ ├── system-object-attributes-product.json │ │ │ │ ├── system-object-definition-category.json │ │ │ │ ├── system-object-definition-customer.json │ │ │ │ ├── system-object-definition-customeraddress.json │ │ │ │ ├── system-object-definition-order.json │ │ │ │ ├── system-object-definition-product.json │ │ │ │ ├── system-object-definitions-old.json │ │ │ │ └── system-object-definitions.json │ │ │ ├── package-lock.json │ │ │ ├── package.json │ │ │ ├── README.md │ │ │ ├── scripts │ │ │ │ └── setup-logs.js │ │ │ ├── server.js │ │ │ └── src │ │ │ ├── app.js │ │ │ ├── config │ │ │ │ └── server-config.js │ │ │ ├── middleware │ │ │ │ ├── auth.js │ │ │ │ ├── cors.js │ │ │ │ └── logging.js │ │ │ ├── routes │ │ │ │ ├── ocapi │ │ │ │ │ ├── code-versions-handler.js │ │ │ │ │ ├── oauth-handler.js │ │ │ │ │ ├── ocapi-error-utils.js │ │ │ │ │ ├── ocapi-utils.js │ │ │ │ │ ├── site-preferences-handler.js │ │ │ │ │ └── system-objects-handler.js │ │ │ │ ├── ocapi.js │ │ │ │ └── webdav.js │ │ │ └── utils │ │ │ ├── mock-data-loader.js │ │ │ └── webdav-xml.js │ │ └── sfcc-mock-server-manager.ts │ ├── sfcc-mock-server.test.ts │ ├── site-preferences-client.test.ts │ ├── system-objects-client.test.ts │ ├── utils.test.ts │ ├── validation-helpers.test.ts │ └── validator.test.ts ├── tsconfig.json └── tsconfig.test.json ``` # Files -------------------------------------------------------------------------------- /docs/dw_net/Mail.md: -------------------------------------------------------------------------------- ```markdown ## Package: dw.net # Class Mail ## Inheritance Hierarchy - Object - dw.net.Mail ## Description This class is used to send an email with either plain text or MimeEncodedText content. Recipient data (from, to, cc, bcc) and subject are specified using setter methods. When the send() method is invoked, the email is put into an internal queue and sent asynchronously. Note: when this class is used with sensitive data, be careful in persisting sensitive information to disk. The following example script sends an email with MimeEncodedText content: function sendMail() { var template: Template = new dw.util.Template("myTemplate.isml"); var o: Map = new dw.util.HashMap(); o.put("customer","customer"); o.put("product","product"); var content: MimeEncodedText = template.render(o); var mail: Mail = new dw.net.Mail(); mail.addTo("[email protected]"); mail.setFrom("[email protected]"); mail.setSubject("Example Email"); mail.setContent(content); mail.send();//returns either Status.ERROR or Status.OK, mail might not be sent yet, when this method returns } See Sending email via scripts or hooks in the documentation for additional examples. ## Properties ### bcc **Type:** List Gets the bcc address List. ### cc **Type:** List Gets the cc address List. ### from **Type:** String Gets the email address to use as the from address for the email. ### replyTo **Type:** List (Read Only) Gets the replyTo address List. ### subject **Type:** String Gets the subject of the email. ### to **Type:** List Gets the to address List where the email is sent. ## Constructor Summary Mail() ## Method Summary ### addAttachment **Signature:** `addAttachment(file : File) : Mail` Adds a file attachment to the email. ### addBcc **Signature:** `addBcc(bcc : String) : Mail` Adds an address to the bcc List. ### addCc **Signature:** `addCc(cc : String) : Mail` Adds an address to the cc List. ### addReplyTo **Signature:** `addReplyTo(replyTo : String) : Mail` Adds an address to the replyTo List. ### addTo **Signature:** `addTo(to : String) : Mail` Adds an address to the to address List. ### getBcc **Signature:** `getBcc() : List` Gets the bcc address List. ### getCc **Signature:** `getCc() : List` Gets the cc address List. ### getFrom **Signature:** `getFrom() : String` Gets the email address to use as the from address for the email. ### getReplyTo **Signature:** `getReplyTo() : List` Gets the replyTo address List. ### getSubject **Signature:** `getSubject() : String` Gets the subject of the email. ### getTo **Signature:** `getTo() : List` Gets the to address List where the email is sent. ### send **Signature:** `send() : Status` prepares an email that is queued to the internal mail system for delivery. ### setBcc **Signature:** `setBcc(bcc : List) : Mail` Sets the bcc address List. ### setCc **Signature:** `setCc(cc : List) : Mail` Sets the cc address List where the email is sent. ### setContent **Signature:** `setContent(content : String) : Mail` Mandatory Sets the email content. ### setContent **Signature:** `setContent(content : String, mimeType : String, encoding : String) : Mail` Mandatory Sets the email content, MIME type, and encoding. ### setContent **Signature:** `setContent(mimeEncodedText : MimeEncodedText) : Mail` Mandatory Uses MimeEncodedText to set the content, MIME type and encoding. ### setFrom **Signature:** `setFrom(from : String) : Mail` Mandatory Sets the sender address for this email. ### setListUnsubscribe **Signature:** `setListUnsubscribe(listUnsubscribe : String) : Mail` Sets the List-Unsubscribe header value to work with List-Unsubscribe-Post to allow integration with an externally-managed mailing list. ### setListUnsubscribePost **Signature:** `setListUnsubscribePost(listUnsubscribePost : String) : Mail` Sets the List-Unsubscribe-Post header value. ### setSubject **Signature:** `setSubject(subject : String) : Mail` Mandatory sets the subject for the email. ### setTo **Signature:** `setTo(to : List) : Mail` Sets the to address List where the email is sent. ### validateAddress **Signature:** `static validateAddress(address : String) : boolean` Validates the address that is sent as parameter. ## Constructor Detail ## Method Detail ## Method Details ### addAttachment **Signature:** `addAttachment(file : File) : Mail` **Description:** Adds a file attachment to the email. This method is restricted to Job context only. **Parameters:** - `file`: The file to be attached to the email. Must not be null and must exist. **Returns:** this Mail object **Throws:** IllegalArgumentException - if the file is null, doesn't exist, or is not a file --- ### addBcc **Signature:** `addBcc(bcc : String) : Mail` **Description:** Adds an address to the bcc List. Address must conform to the RFC822 standard. **Parameters:** - `bcc`: new bcc address to add to bcc address List. **Returns:** this Mail object. --- ### addCc **Signature:** `addCc(cc : String) : Mail` **Description:** Adds an address to the cc List. The address must conform to RFC822 standard. **Parameters:** - `cc`: new cc address to be added to cc address List. **Returns:** this Mail object. --- ### addReplyTo **Signature:** `addReplyTo(replyTo : String) : Mail` **Description:** Adds an address to the replyTo List. Address must conform to the RFC822 standard. **Parameters:** - `replyTo`: new replyTo address to add to replyTo address List. **Returns:** this Mail object. **Throws:** IllegalArgumentException - if the email address is invalid --- ### addTo **Signature:** `addTo(to : String) : Mail` **Description:** Adds an address to the to address List. The address must conform to the RFC822 standard. **Parameters:** - `to`: email address to add to the to address List. **Returns:** this Mail object. --- ### getBcc **Signature:** `getBcc() : List` **Description:** Gets the bcc address List. **Returns:** bcc address List or empty List if no bcc addresses are set. --- ### getCc **Signature:** `getCc() : List` **Description:** Gets the cc address List. **Returns:** cc address List or empty List if no cc addresses are set. --- ### getFrom **Signature:** `getFrom() : String` **Description:** Gets the email address to use as the from address for the email. **Returns:** the from address for this mail or null if no from address is set yet. --- ### getReplyTo **Signature:** `getReplyTo() : List` **Description:** Gets the replyTo address List. **Returns:** replyTo address List or empty List if no replyTo addresses are set. --- ### getSubject **Signature:** `getSubject() : String` **Description:** Gets the subject of the email. **Returns:** subject or null if no subject is set yet. --- ### getTo **Signature:** `getTo() : List` **Description:** Gets the to address List where the email is sent. **Returns:** to address List or empty List if no to addresses are set. --- ### send **Signature:** `send() : Status` **Description:** prepares an email that is queued to the internal mail system for delivery. **Returns:** Status which tells if the mail could be successfully queued ( Status.OK) or not ( Status.ERROR). If an error is raised, more information about the reason for the failure can be found within the log files. If the mandatory fields from, content, and subject are empty an IllegalArgumentException is raised. An IllegalArgumentException is raised if neither to, cc nor bcc are set. --- ### setBcc **Signature:** `setBcc(bcc : List) : Mail` **Description:** Sets the bcc address List. If there are already bcc addresses they are overwritten. **Parameters:** - `bcc`: list of Strings representing RFC822 compliant email addresses. List replaces any previously set list of addresses. Throws an exception if the given list is null. **Returns:** this Mail object. --- ### setCc **Signature:** `setCc(cc : List) : Mail` **Description:** Sets the cc address List where the email is sent. If there are already cc addresses set, they are overwritten. The address(es) must conform to the RFC822 standard. **Parameters:** - `cc`: List of Strings representing RFC822 compliant email addresses. This List replaces any previously set List of addresses. Throws an exception if the given List is null. **Returns:** this Mail object --- ### setContent **Signature:** `setContent(content : String) : Mail` **Description:** Mandatory Sets the email content. The MIME type is set to "text/plain;charset=UTF-8" and encoding set to "UTF-8". **Parameters:** - `content`: String containing the content of the email. **Returns:** this Mail object. --- ### setContent **Signature:** `setContent(content : String, mimeType : String, encoding : String) : Mail` **Description:** Mandatory Sets the email content, MIME type, and encoding. No validation of MIME type and encoding is done. It is the responsibility of the caller to specify a valid MIME type and encoding. **Parameters:** - `content`: String containing the content of the mail - `mimeType`: mime type of the content. For example "text/plain;charset=UTF-8" or "text/html" - `encoding`: character encoding of the email content. For example UTF-8-8 **Returns:** this Mail object. --- ### setContent **Signature:** `setContent(mimeEncodedText : MimeEncodedText) : Mail` **Description:** Mandatory Uses MimeEncodedText to set the content, MIME type and encoding. **Parameters:** - `mimeEncodedText`: MimeEncodedText from which the content, MIME type, and encoding information is extracted. **Returns:** this Mail object. --- ### setFrom **Signature:** `setFrom(from : String) : Mail` **Description:** Mandatory Sets the sender address for this email. The address must conform to the RFC822 standard. **Parameters:** - `from`: String containing a RFC822 compliant email address **Returns:** this Mail object. --- ### setListUnsubscribe **Signature:** `setListUnsubscribe(listUnsubscribe : String) : Mail` **Description:** Sets the List-Unsubscribe header value to work with List-Unsubscribe-Post to allow integration with an externally-managed mailing list. **Parameters:** - `listUnsubscribe`: The List-Unsubscribe header value, e.g., "<https://example.com/unsubscribe>" **Returns:** this Mail object --- ### setListUnsubscribePost **Signature:** `setListUnsubscribePost(listUnsubscribePost : String) : Mail` **Description:** Sets the List-Unsubscribe-Post header value. This header supports one-click unsubscribe functionality. **Parameters:** - `listUnsubscribePost`: The List-Unsubscribe-Post header value, typically "List-Unsubscribe=One-Click" **Returns:** this Mail object --- ### setSubject **Signature:** `setSubject(subject : String) : Mail` **Description:** Mandatory sets the subject for the email. If the subject is not set or set to null at the time send() is invoked and IllegalArgumentException is thrown. **Parameters:** - `subject`: subject of the mail to send. **Returns:** this Mail object. --- ### setTo **Signature:** `setTo(to : List) : Mail` **Description:** Sets the to address List where the email is sent. If there are already to addresses, they are overwritten. **Parameters:** - `to`: list of Strings representing RFC822 compliant email addresses. List replaces any previously set List of addresses. Throws an exception if the given List is null. **Returns:** this Mail object --- ### validateAddress **Signature:** `static validateAddress(address : String) : boolean` **Description:** Validates the address that is sent as parameter. This validation includes: The format must match RFC822 The address must be 7-bit ASCII The top-level domain must be IANA-registered Sample domains such as example.com are not allowed **Parameters:** - `address`: Email address to be validated **Returns:** true if valid, false otherwise --- ``` -------------------------------------------------------------------------------- /docs/dw_order/Invoice.md: -------------------------------------------------------------------------------- ```markdown ## Package: dw.order # Class Invoice ## Inheritance Hierarchy - Object - dw.object.Extensible - dw.order.AbstractItemCtnr - dw.order.Invoice ## Description The Invoice can be a debit or credit invoice, and is created from custom scripts using one of the methods ShippingOrder.createInvoice(String), Appeasement.createInvoice(String), ReturnCase.createInvoice(String) or Return.createInvoice(String). Order post-processing APIs (gillian) are now inactive by default and will throw an exception if accessed. Activation needs preliminary approval by Product Management. Please contact support in this case. Existing customers using these APIs are not affected by this change and can use the APIs until further notice. ## Constants ### ORDERBY_CREATION_DATE **Type:** Object Sorting by creation date. Use with method getPaymentTransactions() as an argument to method FilteringCollection.sort(Object). ### ORDERBY_ITEMID **Type:** Object Sorting by item id. Use with method getItems() as an argument to method FilteringCollection.sort(Object). ### ORDERBY_ITEMPOSITION **Type:** Object Sorting by the position of the related oder item. Use with method getItems() as an argument to method FilteringCollection.sort(Object). ### ORDERBY_REVERSE **Type:** Object Reverse orders. Use as an argument to method FilteringCollection.sort(Object). ### ORDERBY_UNSORTED **Type:** Object Unsorted , as it is. Use with method getItems() as an argument to method FilteringCollection.sort(Object). ### QUALIFIER_CAPTURE **Type:** Object Selects the capture transactions. Use with method getPaymentTransactions() as an argument to method FilteringCollection.select(Object). ### QUALIFIER_PRODUCTITEMS **Type:** Object Selects the product items. Use with method getItems() as an argument to method FilteringCollection.select(Object). ### QUALIFIER_REFUND **Type:** Object Selects the refund transactions. Use with method getPaymentTransactions() as an argument to method FilteringCollection.select(Object). ### QUALIFIER_SERVICEITEMS **Type:** Object Selects for the service items. Use with method getItems() as an argument to method FilteringCollection.select(Object). ### STATUS_FAILED **Type:** String = "FAILED" Constant for Invoice Status Failed. The invoice handling failed. ### STATUS_MANUAL **Type:** String = "MANUAL" Constant for Invoice Status Manual. The invoice is not paid but will not be handled automatically. A manual invoice handling (capture or refund) is necessary. ### STATUS_NOT_PAID **Type:** String = "NOT_PAID" Constant for Invoice Status Not Paid. The invoice is not paid and will be handled automatically. ### STATUS_PAID **Type:** String = "PAID" Constant for Invoice Status Paid. The invoice was successfully paid. ### TYPE_APPEASEMENT **Type:** String = "APPEASEMENT" Constant for Invoice Type Appeasement. The invoice was created for an appeasement. The invoice amount needs to be refunded. ### TYPE_RETURN **Type:** String = "RETURN" Constant for Invoice Type Return. The invoice was created for a return. The invoice amount needs to be refunded. ### TYPE_RETURN_CASE **Type:** String = "RETURN_CASE" Constant for Invoice Type Return Case. The invoice was created for a return case. The invoice amount needs to be refunded. ### TYPE_SHIPPING **Type:** String = "SHIPPING" Constant for Invoice Type Shipping. The invoice was created for a shipping order. The invoice amount needs to be captured. ## Properties ### capturedAmount **Type:** Money (Read Only) The sum of the captured amounts. The captured amounts are calculated on the fly. Associate a payment capture for a OrderPaymentInstrument with an Invoice using addCaptureTransaction(OrderPaymentInstrument, Money). ### invoiceNumber **Type:** String (Read Only) The invoice number. ### items **Type:** FilteringCollection (Read Only) Access the collection of InvoiceItems. This FilteringCollection can be sorted / filtered using: FilteringCollection.sort(Object) with ORDERBY_ITEMID FilteringCollection.sort(Object) with ORDERBY_ITEMPOSITION FilteringCollection.sort(Object) with ORDERBY_UNSORTED FilteringCollection.select(Object) with QUALIFIER_PRODUCTITEMS FilteringCollection.select(Object) with QUALIFIER_SERVICEITEMS ### paymentTransactions **Type:** FilteringCollection (Read Only) The payment transactions belonging to this Invoice. This FilteringCollection can be sorted / filtered using: FilteringCollection.sort(Object) with ORDERBY_CREATION_DATE FilteringCollection.sort(Object) with ORDERBY_UNSORTED FilteringCollection.select(Object) with QUALIFIER_CAPTURE FilteringCollection.select(Object) with QUALIFIER_REFUND ### refundedAmount **Type:** Money (Read Only) The sum of the refunded amounts. The refunded amounts are calculated on the fly. Associate a payment capture for a OrderPaymentInstrument with an Invoice using addRefundTransaction(OrderPaymentInstrument, Money). ### status **Type:** EnumValue The invoice status. The possible values are STATUS_NOT_PAID, STATUS_MANUAL, STATUS_PAID, STATUS_FAILED. ### type **Type:** EnumValue (Read Only) The invoice type. The possible values are TYPE_SHIPPING, TYPE_RETURN, TYPE_RETURN_CASE, TYPE_APPEASEMENT. ## Constructor Summary ## Method Summary ### account **Signature:** `account() : boolean` The invoice will be accounted. ### addCaptureTransaction **Signature:** `addCaptureTransaction(instrument : OrderPaymentInstrument, capturedAmount : Money) : PaymentTransaction` Calling this method registers an amount captured for a given order payment instrument. ### addRefundTransaction **Signature:** `addRefundTransaction(instrument : OrderPaymentInstrument, refundedAmount : Money) : PaymentTransaction` Calling this method registers an amount refunded for a given order payment instrument. ### getCapturedAmount **Signature:** `getCapturedAmount() : Money` Returns the sum of the captured amounts. ### getInvoiceNumber **Signature:** `getInvoiceNumber() : String` Returns the invoice number. ### getItems **Signature:** `getItems() : FilteringCollection` Access the collection of InvoiceItems. ### getPaymentTransactions **Signature:** `getPaymentTransactions() : FilteringCollection` Returns the payment transactions belonging to this Invoice. ### getRefundedAmount **Signature:** `getRefundedAmount() : Money` Returns the sum of the refunded amounts. ### getStatus **Signature:** `getStatus() : EnumValue` Returns the invoice status. The possible values are STATUS_NOT_PAID, STATUS_MANUAL, STATUS_PAID, STATUS_FAILED. ### getType **Signature:** `getType() : EnumValue` Returns the invoice type. The possible values are TYPE_SHIPPING, TYPE_RETURN, TYPE_RETURN_CASE, TYPE_APPEASEMENT. ### setStatus **Signature:** `setStatus(status : String) : void` Sets the invoice status. The possible values are STATUS_NOT_PAID, STATUS_MANUAL, STATUS_PAID, STATUS_FAILED. ## Method Detail ## Method Details ### account **Signature:** `account() : boolean` **Description:** The invoice will be accounted. It will be captured in case of a shipping invoice and it will be refunded in case of an appeasement, return case or return invoice. The accounting will be handled in the payment hooks PaymentHooks.capture(Invoice) or PaymentHooks.refund(Invoice). The implementing script could add payment transactions to the invoice. The accompanying business logic will set the status to PAID or FAILED. The accounting will fail when the invoice state is different to STATUS_NOT_PAID or STATUS_FAILED. The method implements its own transaction handling. The method must not be called inside a transaction. **Returns:** true when the accounting was successful, otherwise false. --- ### addCaptureTransaction **Signature:** `addCaptureTransaction(instrument : OrderPaymentInstrument, capturedAmount : Money) : PaymentTransaction` **Description:** Calling this method registers an amount captured for a given order payment instrument. The authorization for the capture is associated with the payment transaction belonging to the instrument. Calling this method allows the Invoice, the OrderPaymentInstrument and the Order to return their captured amount as a sum calculated on the fly. The method may be called multiple times for the same instrument (multiple capture for one authorization) or for different instruments (invoice settlement using multiple payments). **Parameters:** - `instrument`: the order payment instrument - `capturedAmount`: amount to register as captured **Returns:** the created capture transaction --- ### addRefundTransaction **Signature:** `addRefundTransaction(instrument : OrderPaymentInstrument, refundedAmount : Money) : PaymentTransaction` **Description:** Calling this method registers an amount refunded for a given order payment instrument. Calling this method allows the Invoice, the OrderPaymentInstrument and the Order to return their refunded amount as a sum calculated on the fly. The method may be called multiple times for the same instrument (multiple refunds of one payment) or for different instruments (invoice settlement using multiple payments). **Parameters:** - `instrument`: the order payment instrument - `refundedAmount`: amount to register as refunded **Returns:** the created refund transaction --- ### getCapturedAmount **Signature:** `getCapturedAmount() : Money` **Description:** Returns the sum of the captured amounts. The captured amounts are calculated on the fly. Associate a payment capture for a OrderPaymentInstrument with an Invoice using addCaptureTransaction(OrderPaymentInstrument, Money). **Returns:** sum of captured amounts --- ### getInvoiceNumber **Signature:** `getInvoiceNumber() : String` **Description:** Returns the invoice number. **Returns:** the invoice number --- ### getItems **Signature:** `getItems() : FilteringCollection` **Description:** Access the collection of InvoiceItems. This FilteringCollection can be sorted / filtered using: FilteringCollection.sort(Object) with ORDERBY_ITEMID FilteringCollection.sort(Object) with ORDERBY_ITEMPOSITION FilteringCollection.sort(Object) with ORDERBY_UNSORTED FilteringCollection.select(Object) with QUALIFIER_PRODUCTITEMS FilteringCollection.select(Object) with QUALIFIER_SERVICEITEMS **Returns:** the invoice items --- ### getPaymentTransactions **Signature:** `getPaymentTransactions() : FilteringCollection` **Description:** Returns the payment transactions belonging to this Invoice. This FilteringCollection can be sorted / filtered using: FilteringCollection.sort(Object) with ORDERBY_CREATION_DATE FilteringCollection.sort(Object) with ORDERBY_UNSORTED FilteringCollection.select(Object) with QUALIFIER_CAPTURE FilteringCollection.select(Object) with QUALIFIER_REFUND **Returns:** the payment transactions. **See Also:** PaymentTransaction --- ### getRefundedAmount **Signature:** `getRefundedAmount() : Money` **Description:** Returns the sum of the refunded amounts. The refunded amounts are calculated on the fly. Associate a payment capture for a OrderPaymentInstrument with an Invoice using addRefundTransaction(OrderPaymentInstrument, Money). **Returns:** sum of refunded amounts --- ### getStatus **Signature:** `getStatus() : EnumValue` **Description:** Returns the invoice status. The possible values are STATUS_NOT_PAID, STATUS_MANUAL, STATUS_PAID, STATUS_FAILED. **Returns:** the invoice status --- ### getType **Signature:** `getType() : EnumValue` **Description:** Returns the invoice type. The possible values are TYPE_SHIPPING, TYPE_RETURN, TYPE_RETURN_CASE, TYPE_APPEASEMENT. **Returns:** the invoice type --- ### setStatus **Signature:** `setStatus(status : String) : void` **Description:** Sets the invoice status. The possible values are STATUS_NOT_PAID, STATUS_MANUAL, STATUS_PAID, STATUS_FAILED. **Parameters:** - `status`: the invoice status to set --- ``` -------------------------------------------------------------------------------- /src/clients/logs/log-processor.ts: -------------------------------------------------------------------------------- ```typescript /** * Log parsing, entry processing, and data manipulation */ import { parseLogEntries, extractUniqueErrors, normalizeFilePath, extractTimestampFromLogEntry } from '../../utils/utils.js'; import { Logger } from '../../utils/logger.js'; import { LOG_CONSTANTS } from './log-constants.js'; import type { LogEntry, LogLevel, LogFileMetadata, ProcessedLogEntry, JobLogInfo } from './log-types.js'; export class LogProcessor { private logger: Logger; constructor(logger: Logger) { this.logger = logger; } /** * Process log files and extract entries with priority ordering */ async processLogFiles( files: LogFileMetadata[], level: LogLevel, fileContents: Map<string, string>, ): Promise<LogEntry[]> { const sortedFiles = this.sortFilesByPriority(files); const allLogEntries: LogEntry[] = []; for (let i = 0; i < sortedFiles.length; i++) { const file = sortedFiles[i]; const content = fileContents.get(file.filename); if (!content) { this.logger.warn(`No content found for file: ${file.filename}`); continue; } this.logger.debug(`Processing file: ${file.filename} (priority: ${i})`); try { const logEntries = parseLogEntries(content, level.toUpperCase()); // Add entries with extracted timestamps for chronological sorting logEntries.forEach((entry, entryIndex) => { const timestamp = extractTimestampFromLogEntry(entry); allLogEntries.push({ entry: `[${normalizeFilePath(file.filename)}] ${entry}`, filename: normalizeFilePath(file.filename), order: i * LOG_CONSTANTS.FILE_ORDER_MULTIPLIER + entryIndex, // Keep for fallback sorting timestamp: timestamp ?? undefined, // Convert null to undefined }); }); } catch (error) { this.logger.error(`Error processing file ${file.filename}:`, error); // Continue processing other files even if one fails } } return allLogEntries; } /** * Sort files by modification date (newest first) for processing priority */ private sortFilesByPriority(files: LogFileMetadata[]): LogFileMetadata[] { return files .sort((a, b) => new Date(b.lastmod).getTime() - new Date(a.lastmod).getTime()) .map(file => ({ ...file, filename: file.filename })); } /** * Sort and limit log entries by chronological order (actual timestamps) */ sortAndLimitEntries(entries: LogEntry[], limit: number): LogEntry[] { return entries .sort((a, b) => { // Primary sort: by timestamp (newest first) if (a.timestamp && b.timestamp) { return b.timestamp.getTime() - a.timestamp.getTime(); } // Fallback for entries without timestamps: use file order (newest files first) if (a.timestamp && !b.timestamp) { return -1; } if (!a.timestamp && b.timestamp) { return 1; } return a.order - b.order; // Original order-based sorting as fallback }) .slice(0, limit); // Take the first N entries (most recent chronologically) } /** * Extract formatted log entries from sorted entries */ extractFormattedEntries(sortedEntries: LogEntry[]): string[] { return sortedEntries.map(item => item.entry); } /** * Process search results from file contents */ processSearchResults( files: LogFileMetadata[], fileContents: Map<string, string>, pattern: string, limit: number, ): string[] { const matchingEntries: string[] = []; for (const file of files) { const content = fileContents.get(file.filename); if (!content) { continue; } const lines = content.split('\n'); for (const line of lines) { if (line.toLowerCase().includes(pattern.toLowerCase()) && matchingEntries.length < limit) { matchingEntries.push(`[${normalizeFilePath(file.filename)}] ${line.trim()}`); } } } return matchingEntries; } /** * Count log levels in content */ countLogLevels(content: string): { errorCount: number; warningCount: number; infoCount: number; debugCount: number; } { const lines = content.split('\n'); const counts = { errorCount: 0, warningCount: 0, infoCount: 0, debugCount: 0, }; for (const line of lines) { if (line.includes(' ERROR ')) { counts.errorCount++; } if (line.includes(' WARN ')) { counts.warningCount++; } if (line.includes(' INFO ')) { counts.infoCount++; } if (line.includes(' DEBUG ')) { counts.debugCount++; } } return counts; } /** * Extract key issues from error content */ extractKeyIssues(content: string): string[] { const errors = parseLogEntries(content, 'ERROR'); return extractUniqueErrors(errors); } /** * Parse individual log entry for structured data */ parseLogEntry(entry: string): ProcessedLogEntry { // Basic parsing - can be enhanced based on log format const timestampMatch = entry.match(/\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2}/); const levelMatch = entry.match(/\s(ERROR|WARN|INFO|DEBUG)\s/); return { content: entry, timestamp: timestampMatch ? timestampMatch[0] : undefined, level: levelMatch ? levelMatch[1].toLowerCase() : undefined, source: this.extractSourceFromEntry(entry), }; } /** * Extract source information from log entry */ private extractSourceFromEntry(entry: string): string | undefined { // Look for common source patterns like [ClassName] or package.ClassName const sourceMatch = entry.match(/\[([^\]]+)\]/) ?? entry.match(/([a-zA-Z]+\.[a-zA-Z]+)/); return sourceMatch ? sourceMatch[1] : undefined; } /** * Group entries by source/category */ groupEntriesBySource(entries: ProcessedLogEntry[]): Map<string, ProcessedLogEntry[]> { const groups = new Map<string, ProcessedLogEntry[]>(); for (const entry of entries) { const source = entry.source ?? 'unknown'; if (!groups.has(source)) { groups.set(source, []); } groups.get(source)!.push(entry); } return groups; } /** * Filter entries by time range */ filterEntriesByTimeRange( entries: ProcessedLogEntry[], startTime?: Date, endTime?: Date, ): ProcessedLogEntry[] { return entries.filter(entry => { if (!entry.timestamp) { return true; // Include entries without timestamps } const entryTime = new Date(entry.timestamp); if (startTime && entryTime < startTime) { return false; } if (endTime && entryTime > endTime) { return false; } return true; }); } /** * Process job log files - handles all log levels in one file */ async processJobLogFiles( jobLogs: JobLogInfo[], level: LogLevel | 'all', fileContents: Map<string, string>, ): Promise<LogEntry[]> { const allLogEntries: LogEntry[] = []; for (let i = 0; i < jobLogs.length; i++) { const jobLog = jobLogs[i]; const content = fileContents.get(jobLog.logFile); if (!content) { this.logger.warn(`No content found for job log file: ${jobLog.logFile}`); continue; } this.logger.debug(`Processing job log file: ${jobLog.logFile} (job: ${jobLog.jobName})`); try { // For job logs, we need to parse entries based on the level or all levels const logEntries = level === 'all' ? this.parseAllLogLevelsFromContent(content) : parseLogEntries(content, level.toUpperCase()); // Add entries with job context and priority logEntries.forEach((entry, entryIndex) => { allLogEntries.push({ entry: `[${jobLog.jobName}] ${entry}`, filename: `Job: ${jobLog.jobName} (${jobLog.jobId})`, order: i * LOG_CONSTANTS.FILE_ORDER_MULTIPLIER + entryIndex, }); }); } catch (error) { this.logger.error(`Error processing job log file ${jobLog.logFile}:`, error); } } return allLogEntries; } /** * Parse all log levels from job log content */ private parseAllLogLevelsFromContent(content: string): string[] { const lines = content.split('\n'); const logEntries: string[] = []; for (const line of lines) { if (line.trim() && this.isLogEntry(line)) { logEntries.push(line.trim()); } } return logEntries; } /** * Check if a line is a log entry (contains timestamp and level) */ private isLogEntry(line: string): boolean { // Look for timestamp pattern and log level in the line const timestampPattern = /\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2}/; const levelPattern = /\s(ERROR|WARN|INFO|DEBUG)\s/; return timestampPattern.test(line) && levelPattern.test(line); } /** * Filter job log entries by specific log level */ filterJobLogEntriesByLevel(entries: string[], level: LogLevel): string[] { const levelUpper = level.toUpperCase(); return entries.filter(entry => entry.includes(` ${levelUpper} `)); } /** * Extract job execution summary from job log content */ extractJobExecutionSummary(content: string): { startTime?: string; endTime?: string; status?: string; duration?: string; errorCount: number; warningCount: number; steps: string[]; } { const lines = content.split('\n'); const summary = { startTime: undefined as string | undefined, endTime: undefined as string | undefined, status: undefined as string | undefined, duration: undefined as string | undefined, errorCount: 0, warningCount: 0, steps: [] as string[], }; const stepPattern = /Step\s+\d+:/i; for (const line of lines) { // Extract start time (first timestamp) if (!summary.startTime) { const timestampMatch = line.match(/(\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2})/); if (timestampMatch) { summary.startTime = timestampMatch[1]; } } // Extract end time (last timestamp with completion indicators) if (line.includes('completed') || line.includes('finished') || line.includes('ended')) { const timestampMatch = line.match(/(\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2})/); if (timestampMatch) { summary.endTime = timestampMatch[1]; } } // Extract status if (line.includes('Job completed') || line.includes('Job finished')) { summary.status = line.includes('successfully') ? 'SUCCESS' : 'COMPLETED'; } else if (line.includes('Job failed') || line.includes('ERROR')) { summary.status = 'FAILED'; } // Count errors and warnings if (line.includes(' ERROR ')) { summary.errorCount++; } if (line.includes(' WARN ')) { summary.warningCount++; } // Extract step information if (stepPattern.test(line)) { const stepInfo = line.trim(); if (!summary.steps.includes(stepInfo)) { summary.steps.push(stepInfo); } } } // Calculate duration if we have start and end times if (summary.startTime && summary.endTime) { const start = new Date(summary.startTime); const end = new Date(summary.endTime); const durationMs = end.getTime() - start.getTime(); summary.duration = this.formatDuration(durationMs); } return summary; } /** * Format duration in milliseconds to human readable string */ private formatDuration(ms: number): string { const seconds = Math.floor(ms / 1000); const minutes = Math.floor(seconds / 60); const hours = Math.floor(minutes / 60); if (hours > 0) { return `${hours}h ${minutes % 60}m ${seconds % 60}s`; } else if (minutes > 0) { return `${minutes}m ${seconds % 60}s`; } else { return `${seconds}s`; } } } ``` -------------------------------------------------------------------------------- /docs/dw_order/OrderAddress.md: -------------------------------------------------------------------------------- ```markdown ## Package: dw.order # Class OrderAddress ## Inheritance Hierarchy - Object - dw.object.PersistentObject - dw.object.ExtensibleObject - dw.order.OrderAddress ## Description The Address class represents a customer's address. Note: this class allows access to sensitive personal and private information. Pay attention to appropriate legal and regulatory requirements. ## Properties ### address1 **Type:** String The customer's first address. ### address2 **Type:** String The customer's second address. ### city **Type:** String The Customer's City. ### companyName **Type:** String The Customer's company name. ### countryCode **Type:** EnumValue The customer's country code. ### firstName **Type:** String The Customer's first name. ### fullName **Type:** String (Read Only) A concatenation of the Customer's first, middle, and last names and it' suffix. ### jobTitle **Type:** String The customer's job title. ### lastName **Type:** String The customer's last name. ### phone **Type:** String The customer's phone number. ### postalCode **Type:** String The customer's postal code. ### postBox **Type:** String The customer's post box. ### salutation **Type:** String The customer's salutation. ### secondName **Type:** String The customer's second name. ### stateCode **Type:** String The customer's state. ### suffix **Type:** String The customer's suffix. ### suite **Type:** String The customer's suite. ### title **Type:** String The customer's title. ## Constructor Summary ## Method Summary ### getAddress1 **Signature:** `getAddress1() : String` Returns the customer's first address. ### getAddress2 **Signature:** `getAddress2() : String` Returns the customer's second address. ### getCity **Signature:** `getCity() : String` Returns the Customer's City. ### getCompanyName **Signature:** `getCompanyName() : String` Returns the Customer's company name. ### getCountryCode **Signature:** `getCountryCode() : EnumValue` Returns the customer's country code. ### getFirstName **Signature:** `getFirstName() : String` Returns the Customer's first name. ### getFullName **Signature:** `getFullName() : String` Returns a concatenation of the Customer's first, middle, and last names and it' suffix. ### getJobTitle **Signature:** `getJobTitle() : String` Returns the customer's job title. ### getLastName **Signature:** `getLastName() : String` Returns the customer's last name. ### getPhone **Signature:** `getPhone() : String` Returns the customer's phone number. ### getPostalCode **Signature:** `getPostalCode() : String` Returns the customer's postal code. ### getPostBox **Signature:** `getPostBox() : String` Returns the customer's post box. ### getSalutation **Signature:** `getSalutation() : String` Returns the customer's salutation. ### getSecondName **Signature:** `getSecondName() : String` Returns the customer's second name. ### getStateCode **Signature:** `getStateCode() : String` Returns the customer's state. ### getSuffix **Signature:** `getSuffix() : String` Returns the customer's suffix. ### getSuite **Signature:** `getSuite() : String` Returns the customer's suite. ### getTitle **Signature:** `getTitle() : String` Returns the customer's title. ### isEquivalentAddress **Signature:** `isEquivalentAddress(address : Object) : boolean` Returns true if the specified address is equivalent to this address. ### setAddress1 **Signature:** `setAddress1(value : String) : void` Sets the customer's first address. ### setAddress2 **Signature:** `setAddress2(value : String) : void` Sets the customer's second address. ### setCity **Signature:** `setCity(city : String) : void` Sets the Customer's City. ### setCompanyName **Signature:** `setCompanyName(companyName : String) : void` Sets the Customer's company name. ### setCountryCode **Signature:** `setCountryCode(countryCode : String) : void` Sets the Customer's country code. ### setFirstName **Signature:** `setFirstName(firstName : String) : void` Sets the Customer's first name. ### setJobTitle **Signature:** `setJobTitle(jobTitle : String) : void` Sets the customer's job title. ### setLastName **Signature:** `setLastName(lastName : String) : void` Sets the customer's last name. ### setPhone **Signature:** `setPhone(phoneNumber : String) : void` Sets the customer's phone number. ### setPostalCode **Signature:** `setPostalCode(postalCode : String) : void` Sets the customer's postal code. ### setPostBox **Signature:** `setPostBox(postBox : String) : void` Sets the customer's post box. ### setSaluation **Signature:** `setSaluation(value : String) : void` Sets the customer's salutation. ### setSalutation **Signature:** `setSalutation(value : String) : void` Sets the customer's salutation. ### setSecondName **Signature:** `setSecondName(secondName : String) : void` Sets the customer's second name. ### setStateCode **Signature:** `setStateCode(state : String) : void` Sets the customer's state. ### setSuffix **Signature:** `setSuffix(suffix : String) : void` Sets the customer's suffix. ### setSuite **Signature:** `setSuite(value : String) : void` Sets the customer's suite. ### setTitle **Signature:** `setTitle(title : String) : void` Sets the customer's title. ## Method Detail ## Method Details ### getAddress1 **Signature:** `getAddress1() : String` **Description:** Returns the customer's first address. **Returns:** the first address value. --- ### getAddress2 **Signature:** `getAddress2() : String` **Description:** Returns the customer's second address. **Returns:** the second address value. --- ### getCity **Signature:** `getCity() : String` **Description:** Returns the Customer's City. **Returns:** the Customer's city. --- ### getCompanyName **Signature:** `getCompanyName() : String` **Description:** Returns the Customer's company name. **Returns:** the company name. --- ### getCountryCode **Signature:** `getCountryCode() : EnumValue` **Description:** Returns the customer's country code. **Returns:** the country code. --- ### getFirstName **Signature:** `getFirstName() : String` **Description:** Returns the Customer's first name. **Returns:** the Customer first name. --- ### getFullName **Signature:** `getFullName() : String` **Description:** Returns a concatenation of the Customer's first, middle, and last names and it' suffix. **Returns:** a concatenation of the Customer's first, middle, and last names and it' suffix. --- ### getJobTitle **Signature:** `getJobTitle() : String` **Description:** Returns the customer's job title. **Returns:** the job title. --- ### getLastName **Signature:** `getLastName() : String` **Description:** Returns the customer's last name. **Returns:** the last name. --- ### getPhone **Signature:** `getPhone() : String` **Description:** Returns the customer's phone number. **Returns:** the phone number. --- ### getPostalCode **Signature:** `getPostalCode() : String` **Description:** Returns the customer's postal code. **Returns:** the postal code. --- ### getPostBox **Signature:** `getPostBox() : String` **Description:** Returns the customer's post box. **Returns:** the postBox. --- ### getSalutation **Signature:** `getSalutation() : String` **Description:** Returns the customer's salutation. **Returns:** the customer's salutation. --- ### getSecondName **Signature:** `getSecondName() : String` **Description:** Returns the customer's second name. **Returns:** the second name. --- ### getStateCode **Signature:** `getStateCode() : String` **Description:** Returns the customer's state. **Returns:** the state. --- ### getSuffix **Signature:** `getSuffix() : String` **Description:** Returns the customer's suffix. **Returns:** the suffix. --- ### getSuite **Signature:** `getSuite() : String` **Description:** Returns the customer's suite. **Returns:** the customer's suite. --- ### getTitle **Signature:** `getTitle() : String` **Description:** Returns the customer's title. **Returns:** the title. --- ### isEquivalentAddress **Signature:** `isEquivalentAddress(address : Object) : boolean` **Description:** Returns true if the specified address is equivalent to this address. An equivalent address is an address whose core attributes contain the same values. The core attributes are: address1 address2 city companyName countryCode firstName lastName postalCode postBox stateCode **Parameters:** - `address`: the address to test. **Returns:** true if the specified address is equivalent to this address, false otherwise. --- ### setAddress1 **Signature:** `setAddress1(value : String) : void` **Description:** Sets the customer's first address. **Parameters:** - `value`: The value to set. --- ### setAddress2 **Signature:** `setAddress2(value : String) : void` **Description:** Sets the customer's second address. **Parameters:** - `value`: The value to set. --- ### setCity **Signature:** `setCity(city : String) : void` **Description:** Sets the Customer's City. **Parameters:** - `city`: the Customer's city to set. --- ### setCompanyName **Signature:** `setCompanyName(companyName : String) : void` **Description:** Sets the Customer's company name. **Parameters:** - `companyName`: the name of the company. --- ### setCountryCode **Signature:** `setCountryCode(countryCode : String) : void` **Description:** Sets the Customer's country code. **Parameters:** - `countryCode`: the country code. --- ### setFirstName **Signature:** `setFirstName(firstName : String) : void` **Description:** Sets the Customer's first name. **Parameters:** - `firstName`: the customer's first name to set. --- ### setJobTitle **Signature:** `setJobTitle(jobTitle : String) : void` **Description:** Sets the customer's job title. **Parameters:** - `jobTitle`: The job title to set. --- ### setLastName **Signature:** `setLastName(lastName : String) : void` **Description:** Sets the customer's last name. **Parameters:** - `lastName`: The last name to set. --- ### setPhone **Signature:** `setPhone(phoneNumber : String) : void` **Description:** Sets the customer's phone number. The length is restricted to 256 characters. **Parameters:** - `phoneNumber`: The phone number to set. --- ### setPostalCode **Signature:** `setPostalCode(postalCode : String) : void` **Description:** Sets the customer's postal code. **Parameters:** - `postalCode`: The postal code to set. --- ### setPostBox **Signature:** `setPostBox(postBox : String) : void` **Description:** Sets the customer's post box. **Parameters:** - `postBox`: The post box to set. --- ### setSaluation **Signature:** `setSaluation(value : String) : void` **Description:** Sets the customer's salutation. **Deprecated:** Use setSalutation(String) **Parameters:** - `value`: the customer's salutation. --- ### setSalutation **Signature:** `setSalutation(value : String) : void` **Description:** Sets the customer's salutation. **Parameters:** - `value`: the customer's salutation. --- ### setSecondName **Signature:** `setSecondName(secondName : String) : void` **Description:** Sets the customer's second name. **Parameters:** - `secondName`: The second name to set. --- ### setStateCode **Signature:** `setStateCode(state : String) : void` **Description:** Sets the customer's state. **Parameters:** - `state`: The state to set. --- ### setSuffix **Signature:** `setSuffix(suffix : String) : void` **Description:** Sets the customer's suffix. **Parameters:** - `suffix`: The suffix to set. --- ### setSuite **Signature:** `setSuite(value : String) : void` **Description:** Sets the customer's suite. The length is restricted to 256 characters. **Parameters:** - `value`: the customer's suite. --- ### setTitle **Signature:** `setTitle(title : String) : void` **Description:** Sets the customer's title. **Parameters:** - `title`: The title to set. --- ``` -------------------------------------------------------------------------------- /tests/mcp/yaml/get-best-practice-guide.docs-only.test.mcp.yml: -------------------------------------------------------------------------------- ```yaml description: "Test get_best_practice_guide tool in docs-only mode" tests: # Test successful guide retrieval with cartridge_creation guide - it: "should return cartridge creation guide with complete structure" request: jsonrpc: "2.0" id: "cartridge-guide-1" method: "tools/call" params: name: "get_best_practice_guide" arguments: guideName: "cartridge_creation" expect: response: jsonrpc: "2.0" id: "cartridge-guide-1" result: content: - type: "text" text: "match:contains:Instructions for Creating a Salesforce B2C Commerce" isError: false stderr: "toBeEmpty" # Test that the response contains proper JSON structure - it: "should return valid JSON with title, description, sections, and content" request: jsonrpc: "2.0" id: "cartridge-structure-1" method: "tools/call" params: name: "get_best_practice_guide" arguments: guideName: "cartridge_creation" expect: response: jsonrpc: "2.0" id: "cartridge-structure-1" result: content: - type: "text" text: "match:regex:\\{[\\s\\S]*\"title\"[\\s\\S]*\"description\"[\\s\\S]*\"sections\"[\\s\\S]*\"content\"[\\s\\S]*\\}" isError: false stderr: "toBeEmpty" # Test security guide retrieval - it: "should return security best practices guide" request: jsonrpc: "2.0" id: "security-guide-1" method: "tools/call" params: name: "get_best_practice_guide" arguments: guideName: "security" expect: response: jsonrpc: "2.0" id: "security-guide-1" result: content: - type: "text" text: "match:contains:Secure Coding Best Practices" isError: false stderr: "toBeEmpty" # Test performance guide - it: "should return performance optimization guide" request: jsonrpc: "2.0" id: "performance-guide-1" method: "tools/call" params: name: "get_best_practice_guide" arguments: guideName: "performance" expect: response: jsonrpc: "2.0" id: "performance-guide-1" result: content: - type: "text" text: "match:contains:performance" isError: false stderr: "toBeEmpty" # Test SFRA controllers guide - it: "should return SFRA controllers guide" request: jsonrpc: "2.0" id: "sfra-controllers-1" method: "tools/call" params: name: "get_best_practice_guide" arguments: guideName: "sfra_controllers" expect: response: jsonrpc: "2.0" id: "sfra-controllers-1" result: content: - type: "text" text: "match:contains:SFRA" isError: false stderr: "toBeEmpty" # Test SFRA models guide - it: "should return SFRA models guide" request: jsonrpc: "2.0" id: "sfra-models-1" method: "tools/call" params: name: "get_best_practice_guide" arguments: guideName: "sfra_models" expect: response: jsonrpc: "2.0" id: "sfra-models-1" result: content: - type: "text" text: "match:contains:SFRA" isError: false stderr: "toBeEmpty" - it: "should return SFRA client-side JavaScript guide" request: jsonrpc: "2.0" id: "sfra-client-js-1" method: "tools/call" params: name: "get_best_practice_guide" arguments: guideName: "sfra_client_side_js" expect: response: jsonrpc: "2.0" id: "sfra-client-js-1" result: content: - type: "text" text: "match:contains:Client-Side JavaScript" isError: false stderr: "toBeEmpty" - it: "should return SFRA SCSS guide" request: jsonrpc: "2.0" id: "sfra-scss-1" method: "tools/call" params: name: "get_best_practice_guide" arguments: guideName: "sfra_scss" expect: response: jsonrpc: "2.0" id: "sfra-scss-1" result: content: - type: "text" text: "match:contains:SFRA SCSS" isError: false stderr: "toBeEmpty" # Test OCAPI hooks guide - it: "should return OCAPI hooks guide" request: jsonrpc: "2.0" id: "ocapi-hooks-1" method: "tools/call" params: name: "get_best_practice_guide" arguments: guideName: "ocapi_hooks" expect: response: jsonrpc: "2.0" id: "ocapi-hooks-1" result: content: - type: "text" text: "match:contains:OCAPI" isError: false stderr: "toBeEmpty" # Test SCAPI hooks guide - it: "should return SCAPI hooks guide" request: jsonrpc: "2.0" id: "scapi-hooks-1" method: "tools/call" params: name: "get_best_practice_guide" arguments: guideName: "scapi_hooks" expect: response: jsonrpc: "2.0" id: "scapi-hooks-1" result: content: - type: "text" text: "match:contains:SCAPI" isError: false stderr: "toBeEmpty" # Test SCAPI custom endpoint guide - it: "should return SCAPI custom endpoint guide" request: jsonrpc: "2.0" id: "scapi-endpoint-1" method: "tools/call" params: name: "get_best_practice_guide" arguments: guideName: "scapi_custom_endpoint" expect: response: jsonrpc: "2.0" id: "scapi-endpoint-1" result: content: - type: "text" text: "match:contains:SCAPI" isError: false stderr: "toBeEmpty" # Test ISML templates guide - it: "should return ISML templates guide" request: jsonrpc: "2.0" id: "isml-templates-1" method: "tools/call" params: name: "get_best_practice_guide" arguments: guideName: "isml_templates" expect: response: jsonrpc: "2.0" id: "isml-templates-1" result: content: - type: "text" text: "match:contains:ISML" isError: false stderr: "toBeEmpty" # Test job framework guide - it: "should return job framework guide" request: jsonrpc: "2.0" id: "job-framework-1" method: "tools/call" params: name: "get_best_practice_guide" arguments: guideName: "job_framework" expect: response: jsonrpc: "2.0" id: "job-framework-1" result: content: - type: "text" text: "match:contains:job" isError: false stderr: "toBeEmpty" # Test LocalServiceRegistry guide - it: "should return LocalServiceRegistry guide" request: jsonrpc: "2.0" id: "localservice-1" method: "tools/call" params: name: "get_best_practice_guide" arguments: guideName: "localserviceregistry" expect: response: jsonrpc: "2.0" id: "localservice-1" result: content: - type: "text" text: "match:contains:LocalServiceRegistry" isError: false stderr: "toBeEmpty" # Test response time performance - it: "should respond within reasonable time for guide retrieval" request: jsonrpc: "2.0" id: "perf-guide-1" method: "tools/call" params: name: "get_best_practice_guide" arguments: guideName: "cartridge_creation" expect: response: jsonrpc: "2.0" id: "perf-guide-1" result: content: - type: "text" text: "match:type:string" isError: false performance: maxResponseTime: "2000ms" stderr: "toBeEmpty" # Test invalid guide name handling - it: "should handle invalid guide name gracefully" request: jsonrpc: "2.0" id: "invalid-guide-1" method: "tools/call" params: name: "get_best_practice_guide" arguments: guideName: "nonexistent_guide" expect: response: jsonrpc: "2.0" id: "invalid-guide-1" result: content: - type: "text" text: "null" isError: false stderr: "toBeEmpty" # Test empty guide name handling - it: "should handle empty guide name" request: jsonrpc: "2.0" id: "empty-guide-1" method: "tools/call" params: name: "get_best_practice_guide" arguments: guideName: "" expect: response: jsonrpc: "2.0" id: "empty-guide-1" result: content: - type: "text" text: "Error: guideName must be a non-empty string" isError: true stderr: "toBeEmpty" # Test that guide contains essential structural elements - it: "should contain essential sections in cartridge creation guide" request: jsonrpc: "2.0" id: "structure-test-1" method: "tools/call" params: name: "get_best_practice_guide" arguments: guideName: "cartridge_creation" expect: response: jsonrpc: "2.0" id: "structure-test-1" result: content: - type: "text" text: "match:contains:Core Principles" isError: false stderr: "toBeEmpty" # Test security guide contains security-specific content - it: "should contain security-specific content in security guide" request: jsonrpc: "2.0" id: "security-content-1" method: "tools/call" params: name: "get_best_practice_guide" arguments: guideName: "security" expect: response: jsonrpc: "2.0" id: "security-content-1" result: content: - type: "text" text: "match:regex:[\\s\\S]*(CSRF|XSS|authentication|authorization)[\\s\\S]*" isError: false stderr: "toBeEmpty" # Test that guide content is substantial (not just placeholder) - it: "should return substantial content for cartridge creation guide" request: jsonrpc: "2.0" id: "content-length-1" method: "tools/call" params: name: "get_best_practice_guide" arguments: guideName: "cartridge_creation" expect: response: jsonrpc: "2.0" id: "content-length-1" result: content: - type: "text" text: "match:regex:.{1000,}" # At least 1000 characters isError: false stderr: "toBeEmpty" # Test that guide contains code examples for practical guides - it: "should contain code examples in cartridge creation guide" request: jsonrpc: "2.0" id: "code-examples-1" method: "tools/call" params: name: "get_best_practice_guide" arguments: guideName: "cartridge_creation" expect: response: jsonrpc: "2.0" id: "code-examples-1" result: content: - type: "text" text: "match:regex:[\\s\\S]*(```|javascript|module\\.exports)[\\s\\S]*" isError: false stderr: "toBeEmpty" # Test missing required parameter handling - it: "should handle missing guideName parameter" request: jsonrpc: "2.0" id: "missing-param-1" method: "tools/call" params: name: "get_best_practice_guide" arguments: {} expect: response: jsonrpc: "2.0" id: "missing-param-1" result: content: - type: "text" text: "Error: guideName must be a non-empty string" isError: true stderr: "toBeEmpty" ``` -------------------------------------------------------------------------------- /tests/mcp/yaml/get-best-practice-guide.full-mode.test.mcp.yml: -------------------------------------------------------------------------------- ```yaml description: "Test get_best_practice_guide tool in full-mode mode" tests: # Test successful guide retrieval with cartridge_creation guide - it: "should return cartridge creation guide with complete structure" request: jsonrpc: "2.0" id: "cartridge-guide-1" method: "tools/call" params: name: "get_best_practice_guide" arguments: guideName: "cartridge_creation" expect: response: jsonrpc: "2.0" id: "cartridge-guide-1" result: content: - type: "text" text: "match:contains:Instructions for Creating a Salesforce B2C Commerce" isError: false stderr: "toBeEmpty" # Test that the response contains proper JSON structure - it: "should return valid JSON with title, description, sections, and content" request: jsonrpc: "2.0" id: "cartridge-structure-1" method: "tools/call" params: name: "get_best_practice_guide" arguments: guideName: "cartridge_creation" expect: response: jsonrpc: "2.0" id: "cartridge-structure-1" result: content: - type: "text" text: "match:regex:\\{[\\s\\S]*\"title\"[\\s\\S]*\"description\"[\\s\\S]*\"sections\"[\\s\\S]*\"content\"[\\s\\S]*\\}" isError: false stderr: "toBeEmpty" # Test security guide retrieval - it: "should return security best practices guide" request: jsonrpc: "2.0" id: "security-guide-1" method: "tools/call" params: name: "get_best_practice_guide" arguments: guideName: "security" expect: response: jsonrpc: "2.0" id: "security-guide-1" result: content: - type: "text" text: "match:contains:Secure Coding Best Practices" isError: false stderr: "toBeEmpty" # Test performance guide - it: "should return performance optimization guide" request: jsonrpc: "2.0" id: "performance-guide-1" method: "tools/call" params: name: "get_best_practice_guide" arguments: guideName: "performance" expect: response: jsonrpc: "2.0" id: "performance-guide-1" result: content: - type: "text" text: "match:contains:performance" isError: false stderr: "toBeEmpty" # Test SFRA controllers guide - it: "should return SFRA controllers guide" request: jsonrpc: "2.0" id: "sfra-controllers-1" method: "tools/call" params: name: "get_best_practice_guide" arguments: guideName: "sfra_controllers" expect: response: jsonrpc: "2.0" id: "sfra-controllers-1" result: content: - type: "text" text: "match:contains:SFRA" isError: false stderr: "toBeEmpty" # Test SFRA models guide - it: "should return SFRA models guide" request: jsonrpc: "2.0" id: "sfra-models-1" method: "tools/call" params: name: "get_best_practice_guide" arguments: guideName: "sfra_models" expect: response: jsonrpc: "2.0" id: "sfra-models-1" result: content: - type: "text" text: "match:contains:SFRA" isError: false stderr: "toBeEmpty" - it: "should return SFRA client-side JavaScript guide" request: jsonrpc: "2.0" id: "sfra-client-js-1" method: "tools/call" params: name: "get_best_practice_guide" arguments: guideName: "sfra_client_side_js" expect: response: jsonrpc: "2.0" id: "sfra-client-js-1" result: content: - type: "text" text: "match:contains:Client-Side JavaScript" isError: false stderr: "toBeEmpty" - it: "should return SFRA SCSS guide" request: jsonrpc: "2.0" id: "sfra-scss-1" method: "tools/call" params: name: "get_best_practice_guide" arguments: guideName: "sfra_scss" expect: response: jsonrpc: "2.0" id: "sfra-scss-1" result: content: - type: "text" text: "match:contains:SFRA SCSS" isError: false stderr: "toBeEmpty" # Test OCAPI hooks guide - it: "should return OCAPI hooks guide" request: jsonrpc: "2.0" id: "ocapi-hooks-1" method: "tools/call" params: name: "get_best_practice_guide" arguments: guideName: "ocapi_hooks" expect: response: jsonrpc: "2.0" id: "ocapi-hooks-1" result: content: - type: "text" text: "match:contains:OCAPI" isError: false stderr: "toBeEmpty" # Test SCAPI hooks guide - it: "should return SCAPI hooks guide" request: jsonrpc: "2.0" id: "scapi-hooks-1" method: "tools/call" params: name: "get_best_practice_guide" arguments: guideName: "scapi_hooks" expect: response: jsonrpc: "2.0" id: "scapi-hooks-1" result: content: - type: "text" text: "match:contains:SCAPI" isError: false stderr: "toBeEmpty" # Test SCAPI custom endpoint guide - it: "should return SCAPI custom endpoint guide" request: jsonrpc: "2.0" id: "scapi-endpoint-1" method: "tools/call" params: name: "get_best_practice_guide" arguments: guideName: "scapi_custom_endpoint" expect: response: jsonrpc: "2.0" id: "scapi-endpoint-1" result: content: - type: "text" text: "match:contains:SCAPI" isError: false stderr: "toBeEmpty" # Test ISML templates guide - it: "should return ISML templates guide" request: jsonrpc: "2.0" id: "isml-templates-1" method: "tools/call" params: name: "get_best_practice_guide" arguments: guideName: "isml_templates" expect: response: jsonrpc: "2.0" id: "isml-templates-1" result: content: - type: "text" text: "match:contains:ISML" isError: false stderr: "toBeEmpty" # Test job framework guide - it: "should return job framework guide" request: jsonrpc: "2.0" id: "job-framework-1" method: "tools/call" params: name: "get_best_practice_guide" arguments: guideName: "job_framework" expect: response: jsonrpc: "2.0" id: "job-framework-1" result: content: - type: "text" text: "match:contains:job" isError: false stderr: "toBeEmpty" # Test LocalServiceRegistry guide - it: "should return LocalServiceRegistry guide" request: jsonrpc: "2.0" id: "localservice-1" method: "tools/call" params: name: "get_best_practice_guide" arguments: guideName: "localserviceregistry" expect: response: jsonrpc: "2.0" id: "localservice-1" result: content: - type: "text" text: "match:contains:LocalServiceRegistry" isError: false stderr: "toBeEmpty" # Test response time performance - it: "should respond within reasonable time for guide retrieval" request: jsonrpc: "2.0" id: "perf-guide-1" method: "tools/call" params: name: "get_best_practice_guide" arguments: guideName: "cartridge_creation" expect: response: jsonrpc: "2.0" id: "perf-guide-1" result: content: - type: "text" text: "match:type:string" isError: false performance: maxResponseTime: "2000ms" stderr: "toBeEmpty" # Test invalid guide name handling - it: "should handle invalid guide name gracefully" request: jsonrpc: "2.0" id: "invalid-guide-1" method: "tools/call" params: name: "get_best_practice_guide" arguments: guideName: "nonexistent_guide" expect: response: jsonrpc: "2.0" id: "invalid-guide-1" result: content: - type: "text" text: "null" isError: false stderr: "toBeEmpty" # Test empty guide name handling - it: "should handle empty guide name" request: jsonrpc: "2.0" id: "empty-guide-1" method: "tools/call" params: name: "get_best_practice_guide" arguments: guideName: "" expect: response: jsonrpc: "2.0" id: "empty-guide-1" result: content: - type: "text" text: "Error: guideName must be a non-empty string" isError: true stderr: "toBeEmpty" # Test that guide contains essential structural elements - it: "should contain essential sections in cartridge creation guide" request: jsonrpc: "2.0" id: "structure-test-1" method: "tools/call" params: name: "get_best_practice_guide" arguments: guideName: "cartridge_creation" expect: response: jsonrpc: "2.0" id: "structure-test-1" result: content: - type: "text" text: "match:contains:Core Principles" isError: false stderr: "toBeEmpty" # Test security guide contains security-specific content - it: "should contain security-specific content in security guide" request: jsonrpc: "2.0" id: "security-content-1" method: "tools/call" params: name: "get_best_practice_guide" arguments: guideName: "security" expect: response: jsonrpc: "2.0" id: "security-content-1" result: content: - type: "text" text: "match:regex:[\\s\\S]*(CSRF|XSS|authentication|authorization)[\\s\\S]*" isError: false stderr: "toBeEmpty" # Test that guide content is substantial (not just placeholder) - it: "should return substantial content for cartridge creation guide" request: jsonrpc: "2.0" id: "content-length-1" method: "tools/call" params: name: "get_best_practice_guide" arguments: guideName: "cartridge_creation" expect: response: jsonrpc: "2.0" id: "content-length-1" result: content: - type: "text" text: "match:regex:.{1000,}" # At least 1000 characters isError: false stderr: "toBeEmpty" # Test that guide contains code examples for practical guides - it: "should contain code examples in cartridge creation guide" request: jsonrpc: "2.0" id: "code-examples-1" method: "tools/call" params: name: "get_best_practice_guide" arguments: guideName: "cartridge_creation" expect: response: jsonrpc: "2.0" id: "code-examples-1" result: content: - type: "text" text: "match:regex:[\\s\\S]*(```|javascript|module\\.exports)[\\s\\S]*" isError: false stderr: "toBeEmpty" # Test missing required parameter handling - it: "should handle missing guideName parameter" request: jsonrpc: "2.0" id: "missing-param-1" method: "tools/call" params: name: "get_best_practice_guide" arguments: {} expect: response: jsonrpc: "2.0" id: "missing-param-1" result: content: - type: "text" text: "Error: guideName must be a non-empty string" isError: true stderr: "toBeEmpty" ``` -------------------------------------------------------------------------------- /tests/validator.test.ts: -------------------------------------------------------------------------------- ```typescript /** * Tests for Validator utility * Tests input validation functionality */ import { Validator, ValidationError } from '../src/utils/validator.js'; describe('Validator', () => { describe('ValidationError', () => { it('should create validation error with message', () => { const error = new ValidationError('Test error message'); expect(error).toBeInstanceOf(Error); expect(error.name).toBe('ValidationError'); expect(error.message).toBe('Test error message'); }); }); describe('validateRequired', () => { it('should pass when all required fields are present', () => { const params = { field1: 'value1', field2: 'value2', field3: 123, }; expect(() => { Validator.validateRequired(params, ['field1', 'field2']); }).not.toThrow(); }); it('should throw error when required field is missing', () => { const params = { field1: 'value1', }; expect(() => { Validator.validateRequired(params, ['field1', 'field2']); }).toThrow(ValidationError); expect(() => { Validator.validateRequired(params, ['field1', 'field2']); }).toThrow('Required fields are missing or empty: field2'); }); it('should throw error when required field is empty string', () => { const params = { field1: 'value1', field2: '', }; expect(() => { Validator.validateRequired(params, ['field1', 'field2']); }).toThrow('Required fields are missing or empty: field2'); }); it('should throw error when required field is whitespace only', () => { const params = { field1: 'value1', field2: ' ', }; expect(() => { Validator.validateRequired(params, ['field1', 'field2']); }).toThrow('Required fields are missing or empty: field2'); }); it('should throw error for multiple missing fields', () => { const params = { field1: 'value1', }; expect(() => { Validator.validateRequired(params, ['field2', 'field3', 'field4']); }).toThrow('Required fields are missing or empty: field2, field3, field4'); }); it('should handle non-string values correctly', () => { const params = { number: 0, boolean: false, object: {}, array: [], }; expect(() => { Validator.validateRequired(params, ['number', 'boolean', 'object', 'array']); }).not.toThrow(); }); }); describe('validateInstanceType', () => { it('should accept valid instance types', () => { expect(Validator.validateInstanceType('staging')).toBe('staging'); expect(Validator.validateInstanceType('development')).toBe('development'); expect(Validator.validateInstanceType('sandbox')).toBe('sandbox'); expect(Validator.validateInstanceType('production')).toBe('production'); }); it('should throw error for invalid instance type', () => { expect(() => { Validator.validateInstanceType('invalid'); }).toThrow(ValidationError); expect(() => { Validator.validateInstanceType('invalid'); }).toThrow('Invalid instance type \'invalid\'. Must be one of: staging, development, sandbox, production'); }); it('should throw error for empty string', () => { expect(() => { Validator.validateInstanceType(''); }).toThrow('Invalid instance type \'\'. Must be one of: staging, development, sandbox, production'); }); it('should throw error for case-sensitive mismatch', () => { expect(() => { Validator.validateInstanceType('STAGING'); }).toThrow('Invalid instance type \'STAGING\'. Must be one of: staging, development, sandbox, production'); }); }); describe('validateNotEmpty', () => { it('should pass for non-empty string', () => { expect(() => { Validator.validateNotEmpty('valid value', 'testField'); }).not.toThrow(); }); it('should throw error for empty string', () => { expect(() => { Validator.validateNotEmpty('', 'testField'); }).toThrow(ValidationError); expect(() => { Validator.validateNotEmpty('', 'testField'); }).toThrow('testField cannot be empty'); }); it('should throw error for whitespace-only string', () => { expect(() => { Validator.validateNotEmpty(' ', 'testField'); }).toThrow('testField cannot be empty'); }); }); describe('validatePositiveNumber', () => { it('should pass for positive numbers', () => { expect(() => { Validator.validatePositiveNumber(1, 'testField'); Validator.validatePositiveNumber(100, 'testField'); Validator.validatePositiveNumber(0.5, 'testField'); }).not.toThrow(); }); it('should pass for zero', () => { expect(() => { Validator.validatePositiveNumber(0, 'testField'); }).not.toThrow(); }); it('should throw error for negative numbers', () => { expect(() => { Validator.validatePositiveNumber(-1, 'testField'); }).toThrow(ValidationError); expect(() => { Validator.validatePositiveNumber(-1, 'testField'); }).toThrow('testField must be a positive number'); }); }); describe('validateObjectType', () => { it('should pass for valid object types', () => { expect(() => { Validator.validateObjectType('Product'); Validator.validateObjectType('Customer'); Validator.validateObjectType('SitePreferences'); Validator.validateObjectType('Custom_Object'); Validator.validateObjectType('MyObject123'); }).not.toThrow(); }); it('should throw error for empty object type', () => { expect(() => { Validator.validateObjectType(''); }).toThrow('objectType cannot be empty'); }); it('should throw error for object type starting with number', () => { expect(() => { Validator.validateObjectType('123Object'); }).toThrow('Invalid object type \'123Object\'. Must start with a letter and contain only letters, numbers, and underscores.'); }); it('should throw error for object type with special characters', () => { expect(() => { Validator.validateObjectType('Product-Type'); }).toThrow('Invalid object type \'Product-Type\'. Must start with a letter and contain only letters, numbers, and underscores.'); }); it('should throw error for object type with spaces', () => { expect(() => { Validator.validateObjectType('Product Type'); }).toThrow('Invalid object type \'Product Type\'. Must start with a letter and contain only letters, numbers, and underscores.'); }); }); describe('validateSearchRequest', () => { it('should pass for valid search request with text_query', () => { const searchRequest = { query: { text_query: { fields: ['id', 'display_name'], search_phrase: 'test', }, }, }; expect(() => { Validator.validateSearchRequest(searchRequest); }).not.toThrow(); }); it('should pass for valid search request with term_query', () => { const searchRequest = { query: { term_query: { fields: ['value_type'], operator: 'is', values: ['string'], }, }, }; expect(() => { Validator.validateSearchRequest(searchRequest); }).not.toThrow(); }); it('should pass for valid search request with match_all_query', () => { const searchRequest = { query: { match_all_query: {}, }, }; expect(() => { Validator.validateSearchRequest(searchRequest); }).not.toThrow(); }); it('should pass for search request with sorts', () => { const searchRequest = { query: { match_all_query: {}, }, sorts: [ { field: 'id', sort_order: 'asc' }, { field: 'display_name' }, ], }; expect(() => { Validator.validateSearchRequest(searchRequest); }).not.toThrow(); }); it('should pass for search request with pagination', () => { const searchRequest = { query: { match_all_query: {}, }, start: 0, count: 25, }; expect(() => { Validator.validateSearchRequest(searchRequest); }).not.toThrow(); }); it('should throw error for non-object search request', () => { expect(() => { Validator.validateSearchRequest('invalid'); }).toThrow('Search request must be a valid object'); }); it('should throw error for null search request', () => { expect(() => { Validator.validateSearchRequest(null); }).toThrow('Search request must be a valid object'); }); it('should throw error for search request with no valid query types', () => { const searchRequest = { query: { invalid_query: {}, }, }; expect(() => { Validator.validateSearchRequest(searchRequest); }).toThrow('Search query must contain at least one of: text_query, term_query, filtered_query, bool_query, match_all_query'); }); it('should throw error for text_query with empty fields', () => { const searchRequest = { query: { text_query: { fields: [], search_phrase: 'test', }, }, }; expect(() => { Validator.validateSearchRequest(searchRequest); }).toThrow('text_query.fields must be a non-empty array'); }); it('should throw error for text_query with missing search_phrase', () => { const searchRequest = { query: { text_query: { fields: ['id'], }, }, }; expect(() => { Validator.validateSearchRequest(searchRequest); }).toThrow('text_query.search_phrase must be a non-empty string'); }); it('should throw error for term_query with invalid structure', () => { const searchRequest = { query: { term_query: { fields: [], operator: 'is', values: ['test'], }, }, }; expect(() => { Validator.validateSearchRequest(searchRequest); }).toThrow('term_query.fields must be a non-empty array'); }); it('should throw error for invalid sorts structure', () => { const searchRequest = { query: { match_all_query: {}, }, sorts: 'invalid', }; expect(() => { Validator.validateSearchRequest(searchRequest); }).toThrow('sorts must be an array'); }); it('should throw error for sort with missing field', () => { const searchRequest = { query: { match_all_query: {}, }, sorts: [ { sort_order: 'asc' }, ], }; expect(() => { Validator.validateSearchRequest(searchRequest); }).toThrow('sorts[0].field must be a non-empty string'); }); it('should throw error for sort with invalid sort_order', () => { const searchRequest = { query: { match_all_query: {}, }, sorts: [ { field: 'id', sort_order: 'invalid' }, ], }; expect(() => { Validator.validateSearchRequest(searchRequest); }).toThrow('sorts[0].sort_order must be either \'asc\' or \'desc\''); }); it('should throw error for negative start value', () => { const searchRequest = { query: { match_all_query: {}, }, start: -1, }; expect(() => { Validator.validateSearchRequest(searchRequest); }).toThrow('start must be a positive number'); }); it('should throw error for negative count value', () => { const searchRequest = { query: { match_all_query: {}, }, count: -5, }; expect(() => { Validator.validateSearchRequest(searchRequest); }).toThrow('count must be a positive number'); }); }); }); ``` -------------------------------------------------------------------------------- /docs/dw_web/HttpParameter.md: -------------------------------------------------------------------------------- ```markdown ## Package: dw.web # Class HttpParameter ## Inheritance Hierarchy - Object - dw.web.HttpParameter ## Description Represents an HTTP parameter. ## Properties ### booleanValue **Type:** boolean (Read Only) The value of the current HttpParameter attribute as a boolean. If there is more than one value defined, only the first one is returned. For an undefined attribute it returns null. ### dateValue **Type:** Date (Read Only) The value of the current HttpParameter attribute as a date. If there is more than one value defined, only the first one is returned. For an undefined attribute and if attribute is not a date it return null. ### doubleValue **Type:** Number (Read Only) The value of the current HttpParameter attribute as a number. If there is more than one value defined, only the first one is returned. For an undefined attribute it returns 0.0. ### empty **Type:** boolean (Read Only) Identifies if there is a value for the http parameter attribute and whether the value is empty. A value is treated as empty if it's not blank. ### intValue **Type:** Number (Read Only) The value of the current HttpParameter attribute as int. If there is more than one value defined, only the first one is returned. For an undefined attribute it returns null. ### rawValue **Type:** String (Read Only) The raw value for this HttpParameter instance. The raw value is the not trimmed String value of this HTTP parameter. If there is more than one value defined, only the first one is returned. For an undefined attribute the method returns a null. ### rawValues **Type:** Collection (Read Only) A Collection of all raw values for this HTTP parameter. The raw value is the not trimmed String value of this HTTP parameter. ### stringValue **Type:** String (Read Only) The value of the current HttpParameter attribute. If there is more than one value defined, only the first one is returned. For an undefined attribute the method returns a null. ### stringValues **Type:** Collection (Read Only) A Collection of all defined values for this HTTP parameter. ### submitted **Type:** boolean (Read Only) Identifies if the parameter was submitted. This is equivalent to the check, whether the parameter has a value. ### value **Type:** String (Read Only) The value of the current HttpParameter attribute. If there is more than one value defined, only the first one is returned. For an undefined attribute the method returns null. ### values **Type:** Collection (Read Only) A Collection of all defined values for this current HTTP parameter. ## Constructor Summary ## Method Summary ### containsStringValue **Signature:** `containsStringValue(value : String) : boolean` Identifies if the given value is part of the actual values. ### getBooleanValue **Signature:** `getBooleanValue() : boolean` Returns the value of the current HttpParameter attribute as a boolean. ### getBooleanValue **Signature:** `getBooleanValue(defaultValue : boolean) : boolean` Returns the value of the current HttpParameter attribute as a boolean. ### getDateValue **Signature:** `getDateValue() : Date` Returns the value of the current HttpParameter attribute as a date. ### getDateValue **Signature:** `getDateValue(defaultValue : Date) : Date` Returns the value of the current HttpParameter attribute as a date. ### getDoubleValue **Signature:** `getDoubleValue() : Number` Returns the value of the current HttpParameter attribute as a number. ### getDoubleValue **Signature:** `getDoubleValue(defaultValue : Number) : Number` Returns the value of the current HttpParameter attribute as a number. ### getIntValue **Signature:** `getIntValue() : Number` Returns the value of the current HttpParameter attribute as int. ### getIntValue **Signature:** `getIntValue(defaultValue : Number) : Number` Returns the value of the current HttpParameter attribute as an integer. ### getRawValue **Signature:** `getRawValue() : String` Returns the raw value for this HttpParameter instance. ### getRawValues **Signature:** `getRawValues() : Collection` Returns a Collection of all raw values for this HTTP parameter. ### getStringValue **Signature:** `getStringValue() : String` Returns the value of the current HttpParameter attribute. ### getStringValue **Signature:** `getStringValue(defaultValue : String) : String` Returns the value of the current HttpParameter attribute. ### getStringValues **Signature:** `getStringValues() : Collection` Returns a Collection of all defined values for this HTTP parameter. ### getValue **Signature:** `getValue() : String` Returns the value of the current HttpParameter attribute. ### getValues **Signature:** `getValues() : Collection` Returns a Collection of all defined values for this current HTTP parameter. ### isChecked **Signature:** `isChecked(value : String) : boolean` Identifies if the given String is an actual value of this http parameter. ### isEmpty **Signature:** `isEmpty() : boolean` Identifies if there is a value for the http parameter attribute and whether the value is empty. ### isSubmitted **Signature:** `isSubmitted() : boolean` Identifies if the parameter was submitted. ### toString **Signature:** `toString() : String` Returns the value of the current HttpParameter attribute. ## Method Detail ## Method Details ### containsStringValue **Signature:** `containsStringValue(value : String) : boolean` **Description:** Identifies if the given value is part of the actual values. **Parameters:** - `value`: the value to check. **Returns:** true if the value is among the actual values, false otherwise. --- ### getBooleanValue **Signature:** `getBooleanValue() : boolean` **Description:** Returns the value of the current HttpParameter attribute as a boolean. If there is more than one value defined, only the first one is returned. For an undefined attribute it returns null. **Returns:** the actual value as a boolean or null of no value is available. --- ### getBooleanValue **Signature:** `getBooleanValue(defaultValue : boolean) : boolean` **Description:** Returns the value of the current HttpParameter attribute as a boolean. If there is more than one value defined, only the first one is returned. For an undefined attribute it returns the given default value. **Parameters:** - `defaultValue`: the default value to use. **Returns:** the value of the parameter or the default value if empty. --- ### getDateValue **Signature:** `getDateValue() : Date` **Description:** Returns the value of the current HttpParameter attribute as a date. If there is more than one value defined, only the first one is returned. For an undefined attribute and if attribute is not a date it return null. **Returns:** the actual value as date or null if empty. --- ### getDateValue **Signature:** `getDateValue(defaultValue : Date) : Date` **Description:** Returns the value of the current HttpParameter attribute as a date. If there is more than one value defined, only the first one is returned. For an undefined attribute it returns the given default value and if the attributes is not a date it returns null. **Parameters:** - `defaultValue`: the default value to use. **Returns:** the data value of the attribute or the default value if empty --- ### getDoubleValue **Signature:** `getDoubleValue() : Number` **Description:** Returns the value of the current HttpParameter attribute as a number. If there is more than one value defined, only the first one is returned. For an undefined attribute it returns 0.0. **Returns:** the actual value as double or null if the parameter has no value. --- ### getDoubleValue **Signature:** `getDoubleValue(defaultValue : Number) : Number` **Description:** Returns the value of the current HttpParameter attribute as a number. If there is more than one value defined, only the first one is returned. For an undefined attribute it returns the given default value. **Parameters:** - `defaultValue`: the default value to use. **Returns:** the actual value as double or the default value if empty. --- ### getIntValue **Signature:** `getIntValue() : Number` **Description:** Returns the value of the current HttpParameter attribute as int. If there is more than one value defined, only the first one is returned. For an undefined attribute it returns null. **Returns:** the actual value as an integer or null of no value is available. --- ### getIntValue **Signature:** `getIntValue(defaultValue : Number) : Number` **Description:** Returns the value of the current HttpParameter attribute as an integer. If there is more than one value defined, only the first one is returned. For an undefined attribute it returns the given default value. **Parameters:** - `defaultValue`: the default value to use. **Returns:** the value of the parameter or the default value if empty. --- ### getRawValue **Signature:** `getRawValue() : String` **Description:** Returns the raw value for this HttpParameter instance. The raw value is the not trimmed String value of this HTTP parameter. If there is more than one value defined, only the first one is returned. For an undefined attribute the method returns a null. **Returns:** the actual value or null. **See Also:** getStringValue() --- ### getRawValues **Signature:** `getRawValues() : Collection` **Description:** Returns a Collection of all raw values for this HTTP parameter. The raw value is the not trimmed String value of this HTTP parameter. **Returns:** the raw values as a Collection of String, might be empty **See Also:** getStringValues() --- ### getStringValue **Signature:** `getStringValue() : String` **Description:** Returns the value of the current HttpParameter attribute. If there is more than one value defined, only the first one is returned. For an undefined attribute the method returns a null. **Returns:** the actual value or null. --- ### getStringValue **Signature:** `getStringValue(defaultValue : String) : String` **Description:** Returns the value of the current HttpParameter attribute. If there is more than one value defined, only the first one is returned. For an undefined attribute the method returns the given default value. **Parameters:** - `defaultValue`: the default value to use. **Returns:** the actual value or the default value. --- ### getStringValues **Signature:** `getStringValues() : Collection` **Description:** Returns a Collection of all defined values for this HTTP parameter. **Returns:** the actual values as Collection. --- ### getValue **Signature:** `getValue() : String` **Description:** Returns the value of the current HttpParameter attribute. If there is more than one value defined, only the first one is returned. For an undefined attribute the method returns null. **Returns:** the actual value or null. --- ### getValues **Signature:** `getValues() : Collection` **Description:** Returns a Collection of all defined values for this current HTTP parameter. **Returns:** the actual values as Collection. **See Also:** getStringValues() --- ### isChecked **Signature:** `isChecked(value : String) : boolean` **Description:** Identifies if the given String is an actual value of this http parameter. **Parameters:** - `value`: the value to check. **Returns:** true if the value is among the actual values, false otherwise. --- ### isEmpty **Signature:** `isEmpty() : boolean` **Description:** Identifies if there is a value for the http parameter attribute and whether the value is empty. A value is treated as empty if it's not blank. **Returns:** true if a value is empty, false otherwise. --- ### isSubmitted **Signature:** `isSubmitted() : boolean` **Description:** Identifies if the parameter was submitted. This is equivalent to the check, whether the parameter has a value. **Returns:** true if a value is there, false otherwise. --- ### toString **Signature:** `toString() : String` **Description:** Returns the value of the current HttpParameter attribute. If there is more than one value defined, only the first one is returned. For an undefined attribute the method returns an empty string. **Returns:** the actual value or an empty String. --- ``` -------------------------------------------------------------------------------- /tests/servers/sfcc-mock-server/src/routes/ocapi/site-preferences-handler.js: -------------------------------------------------------------------------------- ```javascript /** * Site Preferences Handler * * Handles site preferences search operations for OCAPI endpoints. */ const express = require('express'); class SitePreferencesHandler { constructor(config, dataLoader) { this.config = config; this.ocapiConfig = config.getOcapiConfig(); this.dataLoader = dataLoader; this.router = express.Router(); this.setupRoutes(); } setupRoutes() { // Site Preferences Search - proper SFCC route pattern this.router.post(`/s/-/dw/data/${this.ocapiConfig.version}/site_preferences/preference_groups/:groupId/:instanceType/preference_search`, this.handleSearchSitePreferences.bind(this) ); } /** * Handle site preferences search */ async handleSearchSitePreferences(req, res) { const { groupId, instanceType } = req.params; const searchRequest = req.body; try { // Validate input parameters const validationError = this.validateSearchRequest(searchRequest, groupId, instanceType); if (validationError) { return res.status(validationError.status).json(validationError.body); } // Try to load specific site preferences let mockData = this.dataLoader.loadOcapiData(`site-preferences-${groupId.toLowerCase()}.json`); // Check if group exists (simulate 404 for unknown groups that aren't in our known list) const knownGroups = ['ccv', 'fastforward', 'system', 'storefront', 'sfra', 'integration']; if (!mockData && !knownGroups.includes(groupId.toLowerCase())) { return res.status(404).json({ "_v": "23.2", "fault": { "arguments": {"preferenceGroupId": groupId}, "type": "CustomPreferenceGroupNotFoundException", "message": `No preference group with ID '${groupId}' could be found.` } }); } if (!mockData) { // Create fallback data with proper SFCC format (matching real API) mockData = { "_v": "23.2", "_type": "preference_value_search_result", "count": 0, "hits": [], "query": searchRequest.query || {"match_all_query": {"_type": "match_all_query"}}, "select": searchRequest.select || "(**)", "start": 0, "total": 0 }; } // Apply search and pagination let results = mockData.hits || []; // Apply search filtering results = this.applySearchFiltering(results, searchRequest.query); // Apply pagination const start = searchRequest.start || 0; const count = searchRequest.count || 200; const paginatedResults = results.slice(start, start + count); // Build response with proper SFCC format const response = { "_v": mockData._v || "23.2", "_type": "preference_value_search_result", "count": paginatedResults.length, "hits": paginatedResults, "query": this.enhanceQueryWithTypes(searchRequest.query || {"match_all_query": {"_type": "match_all_query"}}), "select": searchRequest.select || "(**)", "start": start, "total": results.length }; res.json(response); } catch (error) { // Handle unexpected errors res.status(500).json({ "_v": "23.2", "fault": { "type": "InternalServerError", "message": "An internal server error occurred while processing your request." } }); } } /** * Validate search request parameters */ validateSearchRequest(searchRequest, groupId, instanceType) { // Validate pagination parameters if (searchRequest.start && searchRequest.start < 0) { return { status: 400, body: { "_v": "23.2", "fault": { "arguments": {"path": "$.start", "document": "search_request"}, "type": "PropertyConstraintViolationException", "message": "An error occurred while decoding the request. There's a value constraint violation of property '$.start' in document 'search_request'." } } }; } if (searchRequest.count && (searchRequest.count < 0 || searchRequest.count > 200)) { return { status: 400, body: { "_v": "23.2", "fault": { "arguments": {"path": "$.count", "document": "search_request"}, "type": "PropertyConstraintViolationException", "message": "An error occurred while decoding the request. There's a value constraint violation of property '$.count' in document 'search_request'." } } }; } // Validate query structure if (searchRequest.query && !this.isValidQueryStructure(searchRequest.query)) { return { status: 400, body: { "_v": "23.2", "fault": { "type": "InvalidQueryException", "message": "Search query must contain at least one of: text_query, term_query, filtered_query, bool_query, match_all_query" } } }; } // Validate text query parameters if (searchRequest.query?.text_query) { const textQuery = searchRequest.query.text_query; if (!textQuery.search_phrase || textQuery.search_phrase.trim() === '') { return { status: 400, body: { "_v": "23.2", "fault": { "type": "ValidationException", "message": "text_query.search_phrase must be a non-empty string" } } }; } } return null; // No validation errors } /** * Check if query structure is valid */ isValidQueryStructure(query) { const validQueryTypes = ['text_query', 'term_query', 'filtered_query', 'bool_query', 'match_all_query']; return validQueryTypes.some(type => query.hasOwnProperty(type)); } /** * Apply search filtering based on query */ applySearchFiltering(results, query) { if (!query) return results; if (query.text_query) { return this.applyTextQuery(results, query.text_query); } if (query.bool_query) { return this.applyBoolQuery(results, query.bool_query); } if (query.term_query) { return this.applyTermQuery(results, query.term_query); } if (query.match_all_query) { return results; // Match all returns everything } return results; } /** * Apply text query filtering */ applyTextQuery(results, textQuery) { const searchPhrase = textQuery.search_phrase?.toLowerCase(); const searchFields = textQuery.fields || ['id', 'display_name']; if (!searchPhrase) return results; return results.filter(item => { return searchFields.some(field => { const fieldValue = field === 'display_name' ? item.display_name?.default || item.attribute_definition?.display_name?.default : item[field]; return fieldValue?.toLowerCase().includes(searchPhrase); }); }); } /** * Apply boolean query filtering (simplified implementation) */ applyBoolQuery(results, boolQuery) { let filteredResults = results; // Apply must conditions (AND) if (boolQuery.must && boolQuery.must.length > 0) { for (const condition of boolQuery.must) { filteredResults = this.applySearchFiltering(filteredResults, condition); } } // Apply must_not conditions (exclude) if (boolQuery.must_not && boolQuery.must_not.length > 0) { for (const condition of boolQuery.must_not) { const excludeResults = this.applySearchFiltering(results, condition); const excludeIds = new Set(excludeResults.map(item => item.id)); filteredResults = filteredResults.filter(item => !excludeIds.has(item.id)); } } // Apply should conditions (OR) - for now, just return if any match if (boolQuery.should && boolQuery.should.length > 0) { const shouldResults = []; for (const condition of boolQuery.should) { const conditionResults = this.applySearchFiltering(results, condition); shouldResults.push(...conditionResults); } // Remove duplicates and combine with must results const shouldIds = new Set(shouldResults.map(item => item.id)); if (boolQuery.must && boolQuery.must.length > 0) { // Intersect with must results filteredResults = filteredResults.filter(item => shouldIds.has(item.id)); } else { // Use should results if no must conditions filteredResults = shouldResults.filter((item, index, self) => self.findIndex(i => i.id === item.id) === index ); } } return filteredResults; } /** * Apply term query filtering */ applyTermQuery(results, termQuery) { const { fields, operator, values } = termQuery; return results.filter(item => { return fields.some(field => { const fieldValue = item[field] || item.attribute_definition?.[field]; switch (operator) { case 'is': return values.includes(fieldValue); case 'one_of': return values.some(value => fieldValue === value); case 'contains': return values.some(value => fieldValue?.includes(value)); default: return false; } }); }); } /** * Enhance query object with proper _type fields for response */ enhanceQueryWithTypes(query) { const enhanced = { ...query }; if (enhanced.text_query) { enhanced.text_query._type = 'text_query'; } if (enhanced.bool_query) { enhanced.bool_query._type = 'bool_query'; if (enhanced.bool_query.must) { enhanced.bool_query.must = enhanced.bool_query.must.map(q => this.enhanceQueryWithTypes(q)); } if (enhanced.bool_query.must_not) { enhanced.bool_query.must_not = enhanced.bool_query.must_not.map(q => this.enhanceQueryWithTypes(q)); } if (enhanced.bool_query.should) { enhanced.bool_query.should = enhanced.bool_query.should.map(q => this.enhanceQueryWithTypes(q)); } } if (enhanced.term_query) { enhanced.term_query._type = 'term_query'; } if (enhanced.match_all_query) { enhanced.match_all_query._type = 'match_all_query'; } return enhanced; } /** * Get the configured router */ getRouter() { return this.router; } } module.exports = SitePreferencesHandler; ``` -------------------------------------------------------------------------------- /tests/site-preferences-client.test.ts: -------------------------------------------------------------------------------- ```typescript /** * Tests for OCAPISitePreferencesClient * Tests site preferences operations */ import { OCAPISitePreferencesClient } from '../src/clients/ocapi/site-preferences-client.js'; import { OCAPIConfig } from '../src/types/types.js'; import { QueryBuilder } from '../src/utils/query-builder.js'; import { Validator } from '../src/utils/validator.js'; // Mock dependencies jest.mock('../src/clients/base/ocapi-auth-client.js'); jest.mock('../src/utils/query-builder.js'); jest.mock('../src/utils/validator.js'); describe('OCAPISitePreferencesClient', () => { let client: OCAPISitePreferencesClient; let mockValidateRequired: jest.MockedFunction<typeof Validator.validateRequired>; let mockValidateInstanceType: jest.MockedFunction<typeof Validator.validateInstanceType>; let mockValidateSearchRequest: jest.MockedFunction<typeof Validator.validateSearchRequest>; let mockQueryBuilderFromObject: jest.MockedFunction<typeof QueryBuilder.fromObject>; const mockConfig: OCAPIConfig = { hostname: 'test-instance.demandware.net', clientId: 'test-client-id', clientSecret: 'test-client-secret', version: 'v21_3', }; beforeEach(() => { jest.clearAllMocks(); // Mock Validator methods mockValidateRequired = Validator.validateRequired as jest.MockedFunction<typeof Validator.validateRequired>; mockValidateInstanceType = Validator.validateInstanceType as jest.MockedFunction< typeof Validator.validateInstanceType >; mockValidateSearchRequest = Validator.validateSearchRequest as jest.MockedFunction< typeof Validator.validateSearchRequest >; // Reset mock implementations to default behavior mockValidateRequired.mockImplementation(() => {}); mockValidateInstanceType.mockImplementation(() => 'sandbox'); // Return a valid instance type mockValidateSearchRequest.mockImplementation(() => {}); // Mock QueryBuilder mockQueryBuilderFromObject = QueryBuilder.fromObject as jest.MockedFunction<typeof QueryBuilder.fromObject>; client = new OCAPISitePreferencesClient(mockConfig); // Mock the inherited methods by adding them as properties - avoid protected access (client as any).post = jest.fn().mockResolvedValue({ data: 'mocked' }); }); describe('constructor', () => { it('should initialize with correct base URL', () => { expect(client).toBeInstanceOf(OCAPISitePreferencesClient); }); it('should use default version when not provided', () => { const configWithoutVersion = { hostname: 'test.demandware.net', clientId: 'client-id', clientSecret: 'client-secret', }; const clientWithDefaults = new OCAPISitePreferencesClient(configWithoutVersion); expect(clientWithDefaults).toBeInstanceOf(OCAPISitePreferencesClient); }); }); describe('searchSitePreferences', () => { const groupId = 'SiteGeneral'; const instanceType = 'sandbox'; const searchRequest = { query: { match_all_query: {} }, }; beforeEach(() => { mockValidateInstanceType.mockReturnValue('sandbox'); }); it('should validate all required parameters', async () => { await client.searchSitePreferences(groupId, instanceType, searchRequest); expect(Validator.validateRequired).toHaveBeenCalledWith( { groupId, instanceType }, ['groupId', 'instanceType'], ); expect(Validator.validateInstanceType).toHaveBeenCalledWith(instanceType); expect(Validator.validateSearchRequest).toHaveBeenCalledWith(searchRequest); }); it('should make POST request to site preferences search endpoint', async () => { await client.searchSitePreferences(groupId, instanceType, searchRequest); expect((client as any).post).toHaveBeenCalledWith( '/site_preferences/preference_groups/SiteGeneral/sandbox/preference_search', searchRequest, ); }); it('should encode group ID in URL', async () => { const encodedGroupId = 'Site General Settings'; await client.searchSitePreferences(encodedGroupId, instanceType, searchRequest); expect((client as any).post).toHaveBeenCalledWith( '/site_preferences/preference_groups/Site%20General%20Settings/sandbox/preference_search', searchRequest, ); }); it('should handle different instance types', async () => { const testCases = [ { type: 'staging', expected: 'staging' }, { type: 'development', expected: 'development' }, { type: 'production', expected: 'production' }, ]; for (const testCase of testCases) { mockValidateInstanceType.mockReturnValue(testCase.expected as any); await client.searchSitePreferences(groupId, testCase.type, searchRequest); expect((client as any).post).toHaveBeenCalledWith( `/site_preferences/preference_groups/${groupId}/${testCase.expected}/preference_search`, searchRequest, ); } }); it('should include options in query string when provided', async () => { const options = { maskPasswords: true, expand: 'value', }; mockQueryBuilderFromObject.mockReturnValue('maskPasswords=true&expand=value'); await client.searchSitePreferences(groupId, instanceType, searchRequest, options); expect(QueryBuilder.fromObject).toHaveBeenCalledWith(options); expect((client as any).post).toHaveBeenCalledWith( '/site_preferences/preference_groups/SiteGeneral/sandbox/preference_search?maskPasswords=true&expand=value', searchRequest, ); }); it('should not include query string when options are empty', async () => { const options = {}; mockQueryBuilderFromObject.mockReturnValue(''); await client.searchSitePreferences(groupId, instanceType, searchRequest, options); expect((client as any).post).toHaveBeenCalledWith( '/site_preferences/preference_groups/SiteGeneral/sandbox/preference_search', searchRequest, ); }); it('should handle complex search request', async () => { const complexSearchRequest = { query: { text_query: { fields: ['id', 'display_name', 'description'], search_phrase: 'email', }, }, sorts: [ { field: 'display_name', sort_order: 'asc' as const }, { field: 'id' }, ], start: 0, count: 25, select: '(**)', }; await client.searchSitePreferences(groupId, instanceType, complexSearchRequest); expect(Validator.validateSearchRequest).toHaveBeenCalledWith(complexSearchRequest); expect((client as any).post).toHaveBeenCalledWith( '/site_preferences/preference_groups/SiteGeneral/sandbox/preference_search', complexSearchRequest, ); }); it('should handle term query for value types', async () => { const termSearchRequest = { query: { term_query: { fields: ['value_type'], operator: 'one_of', values: ['string', 'boolean', 'int'], }, }, }; await client.searchSitePreferences(groupId, instanceType, termSearchRequest); expect((client as any).post).toHaveBeenCalledWith( '/site_preferences/preference_groups/SiteGeneral/sandbox/preference_search', termSearchRequest, ); }); it('should handle boolean query combinations', async () => { const boolSearchRequest = { query: { bool_query: { must: [ { text_query: { fields: ['display_name'], search_phrase: 'payment', }, }, ], must_not: [ { term_query: { fields: ['value_type'], operator: 'is', values: ['password'], }, }, ], }, }, }; await client.searchSitePreferences(groupId, instanceType, boolSearchRequest); expect((client as any).post).toHaveBeenCalledWith( '/site_preferences/preference_groups/SiteGeneral/sandbox/preference_search', boolSearchRequest, ); }); }); describe('error handling', () => { it('should propagate validation errors for required fields', async () => { const validationError = new Error('Required field missing'); mockValidateRequired.mockImplementation(() => { throw validationError; }); await expect( client.searchSitePreferences('groupId', 'sandbox', { query: {} }), ).rejects.toThrow(validationError); }); it('should propagate instance type validation errors', async () => { const instanceTypeError = new Error('Invalid instance type'); mockValidateInstanceType.mockImplementation(() => { throw instanceTypeError; }); await expect( client.searchSitePreferences('groupId', 'invalid', { query: {} }), ).rejects.toThrow(instanceTypeError); }); it('should propagate search request validation errors', async () => { const searchValidationError = new Error('Invalid search request'); mockValidateSearchRequest.mockImplementation(() => { throw searchValidationError; }); await expect( client.searchSitePreferences('groupId', 'sandbox', { query: {} }), ).rejects.toThrow(searchValidationError); }); it('should propagate HTTP errors from base client', async () => { const httpError = new Error('HTTP request failed'); (client as any).post = jest.fn().mockRejectedValue(httpError); await expect( client.searchSitePreferences('groupId', 'sandbox', { query: { match_all_query: {} } }), ).rejects.toThrow(httpError); }); }); describe('integration scenarios', () => { it('should handle complete site preferences search workflow', async () => { const groupId = 'CustomPreferences'; const instanceType = 'development'; const searchRequest = { query: { bool_query: { must: [ { text_query: { fields: ['id', 'display_name'], search_phrase: 'api', }, }, { term_query: { fields: ['value_type'], operator: 'one_of', values: ['string', 'text'], }, }, ], }, }, sorts: [ { field: 'display_name', sort_order: 'asc' as const }, ], start: 0, count: 50, }; const options = { maskPasswords: false, expand: 'value', }; mockValidateInstanceType.mockReturnValue('development'); mockQueryBuilderFromObject.mockReturnValue('maskPasswords=false&expand=value'); await client.searchSitePreferences(groupId, instanceType, searchRequest, options); // Verify all validations were called expect(Validator.validateRequired).toHaveBeenCalledWith( { groupId, instanceType }, ['groupId', 'instanceType'], ); expect(Validator.validateInstanceType).toHaveBeenCalledWith(instanceType); expect(Validator.validateSearchRequest).toHaveBeenCalledWith(searchRequest); // Verify query string building expect(QueryBuilder.fromObject).toHaveBeenCalledWith(options); // Verify the final API call expect((client as any).post).toHaveBeenCalledWith( '/site_preferences/preference_groups/CustomPreferences/development/preference_search?maskPasswords=false&expand=value', searchRequest, ); }); it('should handle minimal search request', async () => { const minimalRequest = { query: { match_all_query: {} }, }; mockValidateInstanceType.mockReturnValue('sandbox'); await client.searchSitePreferences('Basic', 'sandbox', minimalRequest); expect((client as any).post).toHaveBeenCalledWith( '/site_preferences/preference_groups/Basic/sandbox/preference_search', minimalRequest, ); }); }); }); ``` -------------------------------------------------------------------------------- /docs/dw_util/List.md: -------------------------------------------------------------------------------- ```markdown ## Package: dw.util # Class List ## Inheritance Hierarchy - Object - dw.util.Collection - dw.util.List ## Description An ordered collection of objects. The user of a List has precise control over where in the list each element is inserted. The user can access elements by their integer index (position in the list), and search for elements in the list. Lists are zero based similar to arrays. Unlike sets, lists allow duplicate elements. ## Properties ## Constructor Summary ## Method Summary ### addAt **Signature:** `addAt(index : Number, value : Object) : void` Adds the specified object into the list at the specified index. ### concat **Signature:** `concat(values : Object...) : List` Creates and returns a new List that is the result of concatenating this list with each of the specified values. ### fill **Signature:** `fill(obj : Object) : void` Replaces all of the elements in the list with the given object. ### get **Signature:** `get(index : Number) : Object` Returns the object at the specified index. ### indexOf **Signature:** `indexOf(value : Object) : Number` Returns the index of the first occurrence of the specified element in this list, or -1 if this list does not contain the element. ### join **Signature:** `join() : String` Converts all elements of the list to a string by calling the toString() method and then concatenates them together, with a comma between elements. ### join **Signature:** `join(separator : String) : String` Converts all elements of the list to a string by calling the toString() method and then concatenates them together, with the separator string between elements. ### lastIndexOf **Signature:** `lastIndexOf(value : Object) : Number` Returns the index of the last occurrence of the specified element in this list, or -1 if this list does not contain the element. ### pop **Signature:** `pop() : Object` Removes and returns the last element from the list. ### push **Signature:** `push(values : Object...) : Number` Appends the specified values to the end of the list in order. ### removeAt **Signature:** `removeAt(index : Number) : Object` Removes the object at the specified index. ### replaceAll **Signature:** `replaceAll(oldValue : Object, newValue : Object) : boolean` Replaces all occurrences of oldValue with newValue. ### reverse **Signature:** `reverse() : void` Reverses the order of the elements in the list. ### rotate **Signature:** `rotate(distance : Number) : void` Rotates the elements in the list by the specified distance. ### set **Signature:** `set(index : Number, value : Object) : Object` Replaces the object at the specified index in this list with the specified object. ### shift **Signature:** `shift() : Object` Removes and returns the first element of the list. ### shuffle **Signature:** `shuffle() : void` Randomly permutes the elements in the list. ### size **Signature:** `size() : Number` Returns the size of this list. ### slice **Signature:** `slice(from : Number) : List` Returns a slice, or sublist, of this list. ### slice **Signature:** `slice(from : Number, to : Number) : List` Returns a slice, or sublist, of this list. ### sort **Signature:** `sort() : void` Sorts the elements of the list based on their natural order. ### sort **Signature:** `sort(comparator : Object) : void` Sorts the elements of a list. ### subList **Signature:** `subList(from : Number, to : Number) : List` Returns a list containing the elements in this list identified by the specified arguments. ### swap **Signature:** `swap(i : Number, j : Number) : void` Swaps the elements at the specified positions in the list. ### unshift **Signature:** `unshift(values : Object...) : Number` Inserts values at the beginning of the list. ## Method Detail ## Method Details ### addAt **Signature:** `addAt(index : Number, value : Object) : void` **Description:** Adds the specified object into the list at the specified index. **Parameters:** - `index`: the index to use. - `value`: the object to insert. --- ### concat **Signature:** `concat(values : Object...) : List` **Description:** Creates and returns a new List that is the result of concatenating this list with each of the specified values. This list itself is unmodified. If any of the specified values is itself an array or a Collection, then the elements of that Collection or array are appended to the new list rather than the object itself. **Parameters:** - `values`: one or more objects to concatenate. **Returns:** a new List that is the result of concatenating this list with each of the specified values. --- ### fill **Signature:** `fill(obj : Object) : void` **Description:** Replaces all of the elements in the list with the given object. **Parameters:** - `obj`: the object to use during replacement. --- ### get **Signature:** `get(index : Number) : Object` **Description:** Returns the object at the specified index. **Parameters:** - `index`: the index to use. **Returns:** the object at the specified index. --- ### indexOf **Signature:** `indexOf(value : Object) : Number` **Description:** Returns the index of the first occurrence of the specified element in this list, or -1 if this list does not contain the element. **Parameters:** - `value`: the element to use. **Returns:** the index of the specified object or -1 if the passed object is not found in the list. --- ### join **Signature:** `join() : String` **Description:** Converts all elements of the list to a string by calling the toString() method and then concatenates them together, with a comma between elements. **Returns:** The string that results from converting each element of the list to a string and then concatenating them together, with a comma between elements. --- ### join **Signature:** `join(separator : String) : String` **Description:** Converts all elements of the list to a string by calling the toString() method and then concatenates them together, with the separator string between elements. If null is passed, then the comma character is used as a separator. **Parameters:** - `separator`: The separator string. May be null in which case the comma character is used. **Returns:** The string that results from converting each element of the list to a string and then concatenating them together, with the separator string between elements. --- ### lastIndexOf **Signature:** `lastIndexOf(value : Object) : Number` **Description:** Returns the index of the last occurrence of the specified element in this list, or -1 if this list does not contain the element. **Parameters:** - `value`: the element to use. **Returns:** the last index of the specified object or -1 if the passed object is not found in the list. --- ### pop **Signature:** `pop() : Object` **Description:** Removes and returns the last element from the list. **Returns:** The last element of the list or null if the list is already empty. --- ### push **Signature:** `push(values : Object...) : Number` **Description:** Appends the specified values to the end of the list in order. **Parameters:** - `values`: One or more values to be appended to the end of the list. **Returns:** The new length of the list, after the specified values are appended to it. --- ### removeAt **Signature:** `removeAt(index : Number) : Object` **Description:** Removes the object at the specified index. **Parameters:** - `index`: the index to use. **Returns:** the object that was removed. --- ### replaceAll **Signature:** `replaceAll(oldValue : Object, newValue : Object) : boolean` **Description:** Replaces all occurrences of oldValue with newValue. **Parameters:** - `oldValue`: the old object. - `newValue`: the new object. **Returns:** true if one or more elements were replaced, false otherwise. --- ### reverse **Signature:** `reverse() : void` **Description:** Reverses the order of the elements in the list. --- ### rotate **Signature:** `rotate(distance : Number) : void` **Description:** Rotates the elements in the list by the specified distance. **Parameters:** - `distance`: the distance to use. --- ### set **Signature:** `set(index : Number, value : Object) : Object` **Description:** Replaces the object at the specified index in this list with the specified object. **Parameters:** - `index`: the index to use. - `value`: the object to use when replacing the existing object. **Returns:** the replaced object. --- ### shift **Signature:** `shift() : Object` **Description:** Removes and returns the first element of the list. If the list is already empty, this method simply returns null. **Returns:** The former first element of the list, or null is list is already empty. --- ### shuffle **Signature:** `shuffle() : void` **Description:** Randomly permutes the elements in the list. --- ### size **Signature:** `size() : Number` **Description:** Returns the size of this list. **Returns:** the size of this list. --- ### slice **Signature:** `slice(from : Number) : List` **Description:** Returns a slice, or sublist, of this list. The returned list contains the element specified by from and all subsequent elements up to the end of this list. **Parameters:** - `from`: The index at which the slice is to begin. If negative, this argument specifies a position measured from the end of this list. That, -1 indicates the last element, -2 indicates the next from the last element, and so on. **Returns:** A new List that contains the elements of this list from the element specified by from up to the end of this list. --- ### slice **Signature:** `slice(from : Number, to : Number) : List` **Description:** Returns a slice, or sublist, of this list. The returned list contains the element specified by from and all subsequent elements up to, but not including, the element specified by to. **Parameters:** - `from`: The index at which the slice is to begin. If negative, this argument specifies a position measured from the end of this list. That, -1 indicates the last element, -2 indicates the next from the last element, and so on. - `to`: The index immediately after the end of the slice. If this argument is negative, it specifies an element measured from the end of this list. **Returns:** A new List that contains the elements of this list from the element specified by from up to, but not including, the element specified by to. --- ### sort **Signature:** `sort() : void` **Description:** Sorts the elements of the list based on their natural order. This sort is guaranteed to be stable: equal elements will not be reordered as a result of the sort. --- ### sort **Signature:** `sort(comparator : Object) : void` **Description:** Sorts the elements of a list. The order of the elements is determined with a comparator (see PropertyComparator) or with the help of the given function. The function must take two parameters and return a value <0 if the first parameter is smaller than the second, a value of 0 if both are equal and a value if >0 if the first one is greater than the second parameter. This sort is guaranteed to be stable: equal elements will not be reordered as a result of the sort. **Parameters:** - `comparator`: an instance of a PropertyComparator or a comparison function --- ### subList **Signature:** `subList(from : Number, to : Number) : List` **Description:** Returns a list containing the elements in this list identified by the specified arguments. **Parameters:** - `from`: the beginning index of the elements to move to the new list. - `to`: the ending index of the elements to move to the new list. **Returns:** the new list containing the elements. --- ### swap **Signature:** `swap(i : Number, j : Number) : void` **Description:** Swaps the elements at the specified positions in the list. **Parameters:** - `i`: the first element to swap. - `j`: the second element to swap. --- ### unshift **Signature:** `unshift(values : Object...) : Number` **Description:** Inserts values at the beginning of the list. The first argument becomes the new element 0; the second argument becomes element 1; and so on. **Parameters:** - `values`: The values to insert into the list. **Returns:** The new length of the lest. --- ``` -------------------------------------------------------------------------------- /tests/mcp/node/get-system-object-definitions.docs-only.programmatic.test.js: -------------------------------------------------------------------------------- ```javascript /** * MCP Aegis - Programmatic Tests for get_system_object_definitions Tool (Docs-Only Mode) * * Tests that system object tools are NOT available in docs-only mode. * This tool requires SFCC credentials and should not be available without them. * * Quick Test Commands: * node --test tests/mcp/node/get-system-object-definitions.docs-only.programmatic.test.js * npm test -- --grep "get_system_object_definitions.*Docs-Only" */ import { test, describe, before, after, beforeEach } from 'node:test'; import { strict as assert } from 'node:assert'; import { connect } from 'mcp-aegis'; describe('get_system_object_definitions Tool - Docs-Only Mode Programmatic Tests', () => { let client; before(async () => { client = await connect('./aegis.config.docs-only.json'); }); after(async () => { if (client?.connected) { await client.disconnect(); } }); beforeEach(() => { // CRITICAL: Clear all buffers to prevent leaking into next tests client.clearAllBuffers(); }); // ================================================================================== // TOOL UNAVAILABILITY TESTS // ================================================================================== describe('Tool Unavailability in Docs-Only Mode', () => { test('should NOT list get_system_object_definitions tool in docs-only mode', async () => { const tools = await client.listTools(); assert.ok(Array.isArray(tools), 'Tools should be an array'); const toolNames = tools.map(tool => tool.name); assert.ok(!toolNames.includes('get_system_object_definitions'), 'Should NOT include get_system_object_definitions tool in docs-only mode'); }); test('should NOT list any system object tools in docs-only mode', async () => { const tools = await client.listTools(); const toolNames = tools.map(tool => tool.name); const systemObjectTools = [ 'get_system_object_definitions', 'get_system_object_definition', 'search_system_object_attribute_definitions', 'search_site_preferences', 'search_system_object_attribute_groups', 'search_custom_object_attribute_definitions' ]; systemObjectTools.forEach(toolName => { assert.ok(!toolNames.includes(toolName), `Should NOT include ${toolName} tool in docs-only mode`); }); }); test('should have expected number of tools in docs-only mode', async () => { const tools = await client.listTools(); // Should have documentation, SFRA, best practices, and cartridge tools // but NOT system object, log, or code version tools assert.ok(tools.length >= 10, 'Should have at least 10 tools available'); assert.ok(tools.length <= 20, 'Should not have too many tools (likely around 15)'); }); }); // ================================================================================== // TOOL CALL BEHAVIOR - SHOULD RETURN ERROR // ================================================================================== describe('Tool Call Behavior - Configuration Error', () => { test('should return configuration error when calling unlisted tool', async () => { const result = await client.callTool('get_system_object_definitions', {}); assert.equal(result.isError, true, 'Should return error result'); assert.ok(result.content, 'Should have content'); assert.ok(Array.isArray(result.content), 'Content should be array'); assert.equal(result.content[0].type, 'text', 'Content should be text type'); const errorText = result.content[0].text; assert.ok(errorText.includes('OCAPI client not configured') || errorText.includes('not configured') || errorText.includes('credentials'), 'Error should mention configuration/credentials issue'); }); test('should return proper error result structure for unlisted tool', async () => { const result = await client.callTool('get_system_object_definitions', {}); assert.equal(result.isError, true, 'Should be error result'); assert.ok(Array.isArray(result.content), 'Content should be array'); assert.ok(result.content.length > 0, 'Should have error content'); assert.equal(result.content[0].type, 'text', 'Error content should be text'); }); test('should fail fast when calling unlisted tool with parameters', async () => { const startTime = Date.now(); const result = await client.callTool('get_system_object_definitions', { start: 0, count: 10, select: '(**)' }); const duration = Date.now() - startTime; assert.equal(result.isError, true, 'Should return error'); assert.ok(duration < 1000, 'Should fail quickly (under 1 second)'); const errorText = result.content[0].text; assert.ok(errorText.includes('OCAPI client not configured') || errorText.includes('not configured') || errorText.includes('credentials'), 'Error should mention configuration issue'); }); test('should handle invalid parameters gracefully even in error mode', async () => { const result = await client.callTool('get_system_object_definitions', { invalidParam: 'test', anotherInvalid: 123 }); assert.equal(result.isError, true, 'Should return error'); const errorText = result.content[0].text; // Should mention configuration, not parameter validation assert.ok(errorText.includes('OCAPI client not configured') || errorText.includes('not configured') || errorText.includes('credentials'), 'Should prioritize configuration error over parameter validation'); }); }); // ================================================================================== // OTHER SYSTEM OBJECT TOOLS VERIFICATION // ================================================================================== describe('Other System Object Tools Unavailability', () => { test('should NOT have get_system_object_definition tool', async () => { const tools = await client.listTools(); const toolNames = tools.map(tool => tool.name); assert.ok(!toolNames.includes('get_system_object_definition'), 'Should NOT include get_system_object_definition tool'); // Verify calling it also returns error const result = await client.callTool('get_system_object_definition', { objectType: 'Product' }); assert.equal(result.isError, true, 'Should return configuration error'); }); test('should NOT have search_system_object_attribute_definitions tool', async () => { const tools = await client.listTools(); const toolNames = tools.map(tool => tool.name); assert.ok(!toolNames.includes('search_system_object_attribute_definitions'), 'Should NOT include search_system_object_attribute_definitions tool'); // Verify calling it also returns error const result = await client.callTool('search_system_object_attribute_definitions', { objectType: 'Product', searchRequest: { query: { match_all_query: {} } } }); assert.equal(result.isError, true, 'Should return configuration error'); }); test('should NOT have site preferences tools', async () => { const tools = await client.listTools(); const toolNames = tools.map(tool => tool.name); assert.ok(!toolNames.includes('search_site_preferences'), 'Should NOT include search_site_preferences tool'); // Verify calling it also returns error const result = await client.callTool('search_site_preferences', { groupId: 'SitePreferences', instanceType: 'sandbox', searchRequest: { query: { match_all_query: {} } } }); assert.equal(result.isError, true, 'Should return configuration error'); }); }); // ================================================================================== // CONSISTENCY TESTS // ================================================================================== describe('Consistency Tests', () => { test('should consistently exclude system object tools across multiple calls', async () => { const tools1 = await client.listTools(); const tools2 = await client.listTools(); const toolNames1 = tools1.map(tool => tool.name); const toolNames2 = tools2.map(tool => tool.name); assert.ok(!toolNames1.includes('get_system_object_definitions'), 'First call should exclude system object tools'); assert.ok(!toolNames2.includes('get_system_object_definitions'), 'Second call should exclude system object tools'); }); test('should maintain consistent tool exclusion on second call', async () => { const tools = await client.listTools(); const toolNames = tools.map(tool => tool.name); assert.ok(!toolNames.includes('get_system_object_definitions'), 'Should consistently exclude get_system_object_definitions'); }); test('should consistently return configuration error across multiple attempts', async () => { const result1 = await client.callTool('get_system_object_definitions', {}); const result2 = await client.callTool('get_system_object_definitions', {}); assert.equal(result1.isError, true, 'First call should return error'); assert.equal(result2.isError, true, 'Second call should return error'); const error1 = result1.content[0].text; const error2 = result2.content[0].text; assert.ok(error1.includes('OCAPI client not configured') || error1.includes('not configured'), 'First error should mention configuration'); assert.ok(error2.includes('OCAPI client not configured') || error2.includes('not configured'), 'Second error should mention configuration'); }); test('should have consistent tool count in docs-only mode', async () => { const tools1 = await client.listTools(); const tools2 = await client.listTools(); assert.equal(tools1.length, tools2.length, 'Tool count should be consistent between calls'); // Should have around 15 tools in docs-only mode assert.ok(tools1.length >= 10, 'Should have reasonable number of tools'); assert.ok(tools1.length <= 20, 'Should not have excessive tools'); }); }); // ================================================================================== // MODE IDENTIFICATION TESTS - FOCUSED ON SYSTEM OBJECT TOOLS // ================================================================================== describe('System Object Tools Mode Identification', () => { test('should clearly identify system object tools unavailability in docs-only mode', async () => { const tools = await client.listTools(); const toolNames = tools.map(tool => tool.name); const hasSystemObjectTools = toolNames.includes('get_system_object_definitions'); const hasOtherSystemObjectTools = toolNames.includes('search_site_preferences'); assert.ok(!hasSystemObjectTools, 'Should NOT have get_system_object_definitions tool'); assert.ok(!hasOtherSystemObjectTools, 'Should NOT have other system object tools'); }); test('should exclude all system object tools in docs-only mode', async () => { const tools = await client.listTools(); const toolNames = tools.map(tool => tool.name); // System object tools that should NOT be available in docs-only mode const systemObjectTools = [ 'get_system_object_definitions', 'get_system_object_definition', 'search_system_object_attribute_definitions', 'search_site_preferences', 'search_system_object_attribute_groups', 'search_custom_object_attribute_definitions' ]; systemObjectTools.forEach(toolName => { assert.ok(!toolNames.includes(toolName), `Docs-only mode should NOT include system object tool: ${toolName}`); }); }); }); }); ``` -------------------------------------------------------------------------------- /docs/TopLevel/global.md: -------------------------------------------------------------------------------- ```markdown ## Package: TopLevel # Class global ## Inheritance Hierarchy - Object - global ## Description The global object is a pre-defined object that serves as a placeholder for the global properties and functions of JavaScript. All other predefined objects, functions, and properties are accessible through the global object. ## Constants ### PIPELET_ERROR **Type:** Number represents an error during pipelet execution ### PIPELET_NEXT **Type:** Number represents the next pipelet to fire ## Properties ## Constructor Summary ## Method Summary ### decodeURI **Signature:** `static decodeURI(uri : String) : String` Unescapes characters in a URI component. ### decodeURIComponent **Signature:** `static decodeURIComponent(uriComponent : String) : String` Unescapes characters in a URI component. ### empty **Signature:** `static empty(obj : Object) : boolean` The method tests, whether the given object is empty. ### encodeURI **Signature:** `static encodeURI(uri : String) : String` Escapes characters in a URI. ### encodeURIComponent **Signature:** `static encodeURIComponent(uriComponent : String) : String` Escapes characters in a URI component. ### escape **Signature:** `static escape(s : String) : String` Encodes a String. ### eval **Signature:** `static eval(code : String) : Object` Execute JavaScript code from a String. ### importClass **Signature:** `static importClass(classPath : Object) : void` Import the specified class and make it available at the top level. ### importPackage **Signature:** `static importPackage(packagePath : Object) : void` Import all the classes in the specified package available at the top level. ### importScript **Signature:** `static importScript(scriptPath : String) : void` Imports all functions from the specified script. ### isFinite **Signature:** `static isFinite(number : Number) : boolean` Returns true if the specified Number is finite. ### isNaN **Signature:** `static isNaN(object : Object) : boolean` Test the specified value to determine if it is not a Number. ### isXMLName **Signature:** `static isXMLName(name : String) : boolean` Determines whether the specified string is a valid name for an XML element or attribute. ### parseFloat **Signature:** `static parseFloat(s : String) : Number` Parses a String into an float Number. ### parseInt **Signature:** `static parseInt(s : String, radix : Number) : Number` Parses a String into an integer Number using the specified radix. ### parseInt **Signature:** `static parseInt(s : String) : Number` Parses a String into an integer Number. This function is a short form for the call to parseInt(String, Number) with automatic determination of the radix. ### parseInt **Signature:** `static parseInt(s : String) : Number` Parses a String into an integer Number. ### require **Signature:** `static require(path : String) : Module` The require() function supports loading of modules in JavaScript. ### trace **Signature:** `static trace(msg : String, params : Object...) : void` Formats and prints the message using the specified params and returns the formatted message. ### unescape **Signature:** `static unescape(string : String) : String` Decode an escaped String. ## Method Detail ## Method Details ### decodeURI **Signature:** `static decodeURI(uri : String) : String` **Description:** Unescapes characters in a URI component. **Parameters:** - `uri`: a string that contains an encoded URI or other text to be decoded. **Returns:** A copy of uri with any hexadecimal escape sequences replaced with the characters they represent --- ### decodeURIComponent **Signature:** `static decodeURIComponent(uriComponent : String) : String` **Description:** Unescapes characters in a URI component. **Parameters:** - `uriComponent`: a string that contains an encoded URI component or other text to be decoded. **Returns:** A copy of uriComponent with any hexadecimal escape sequences replaced with the characters they represent --- ### empty **Signature:** `static empty(obj : Object) : boolean` **Description:** The method tests, whether the given object is empty. The interpretation of empty is the following. - null is always empty - undefined is always empty - a string with zero length is empty - an array with no elements is empty - a collection with no elements is empty **Parameters:** - `obj`: the object to be thested **Returns:** true if the object is interpreted as being empty --- ### encodeURI **Signature:** `static encodeURI(uri : String) : String` **Description:** Escapes characters in a URI. **Parameters:** - `uri`: a String that contains the URI or other text to be encoded. **Returns:** a copy of uri with certain characters replaced by hexadecimal escape sequences. --- ### encodeURIComponent **Signature:** `static encodeURIComponent(uriComponent : String) : String` **Description:** Escapes characters in a URI component. **Parameters:** - `uriComponent`: a String that contains a portion of a URI or other text to be encoded. **Returns:** a copy of uriComponent with certain characters replaced by hexadecimal escape sequences. --- ### escape **Signature:** `static escape(s : String) : String` **Description:** Encodes a String. **Parameters:** - `s`: the String to be encoded. **Returns:** a copy of s where characters have been replace by hexadecimal escape sequences. --- ### eval **Signature:** `static eval(code : String) : Object` **Description:** Execute JavaScript code from a String. **Deprecated:** The eval() function is deprecated, because it's potential security risk for server side code injection. **Parameters:** - `code`: a String that contains the JavaScript expression to be evaluated or the statements to be executed. **Returns:** the value of the executed call or null. --- ### importClass **Signature:** `static importClass(classPath : Object) : void` **Description:** Import the specified class and make it available at the top level. It's equivalent in effect to the Java import declaration. **Parameters:** - `classPath`: the fully qualified class path. --- ### importPackage **Signature:** `static importPackage(packagePath : Object) : void` **Description:** Import all the classes in the specified package available at the top level. It's equivalent in effect to the Java import declaration. **Parameters:** - `packagePath`: the fully qualified package path. --- ### importScript **Signature:** `static importScript(scriptPath : String) : void` **Description:** Imports all functions from the specified script. Variables are not imported from the script and must be accessed through helper functions. The script path has the following syntax: [cartridgename:]scriptname, where cartridgename identifies a cartridge where the script file is located. If cartridgename is omitted the script file is loaded from the same cartridge in which the importing component is located. Examples: importScript( 'example.ds' ) imports the script file example.ds from the same cartridge importScript( 'abc:example.ds' ) imports the script file example.ds from the cartridge 'abc' **Parameters:** - `scriptPath`: the path to the script. --- ### isFinite **Signature:** `static isFinite(number : Number) : boolean` **Description:** Returns true if the specified Number is finite. **Parameters:** - `number`: the Number to test. **Returns:** true if the specified Number is finite, false otherwise. --- ### isNaN **Signature:** `static isNaN(object : Object) : boolean` **Description:** Test the specified value to determine if it is not a Number. **Parameters:** - `object`: the Object to be tested as a number **Returns:** True if the object is not a number --- ### isXMLName **Signature:** `static isXMLName(name : String) : boolean` **Description:** Determines whether the specified string is a valid name for an XML element or attribute. **Parameters:** - `name`: the String specified **Returns:** True if the string is a valid name --- ### parseFloat **Signature:** `static parseFloat(s : String) : Number` **Description:** Parses a String into an float Number. **Parameters:** - `s`: the String to parse. **Returns:** Returns the float as a Number. --- ### parseInt **Signature:** `static parseInt(s : String, radix : Number) : Number` **Description:** Parses a String into an integer Number using the specified radix. **Parameters:** - `s`: the String to parse. - `radix`: the radix to use. **Returns:** Returns the integer as a Number. --- ### parseInt **Signature:** `static parseInt(s : String) : Number` **Description:** Parses a String into an integer Number. This function is a short form for the call to parseInt(String, Number) with automatic determination of the radix. If the string starts with "0x" or "0X" then the radix is 16. If the string starts with "0" the the radix is 8. In all other cases the radix is 10. **API Versioned:** No longer available as of version 16.1. **Parameters:** - `s`: the String to parse. **Returns:** Returns the integer as a Number. --- ### parseInt **Signature:** `static parseInt(s : String) : Number` **Description:** Parses a String into an integer Number. This function is a short form for the call to parseInt(String, Number) with automatic determination of the radix. If the string starts with "0x" or "0X" then the radix is 16. In all other cases the radix is 10. **API Versioned:** From version 16.1. ECMAScript 5 compliance: removed support for octal numbers. **Parameters:** - `s`: the String to parse. **Returns:** Returns the integer as a Number. --- ### require **Signature:** `static require(path : String) : Module` **Description:** The require() function supports loading of modules in JavaScript. The function works similar to the require() function in CommonJS. The general module loading works the same way, but the exact path lookup is slightly different and better fits into Demandware concepts. Here are the details for the lookup: If the module name starts with "./" or "../" then load it relative to the current module. The module can be a file or a directory. A file extension is acknowledged, but not required. If it's a directory a 'package.json' or a 'main' file is expected. If the 'package.json' does not contain a main entry, then default to main file in the directory. Access to parent files can't go beyond the cartridges directory. Access to other cartridges is explicitly allowed. If the module name starts with "~/" it's a path relative to the current cartridge. If the module name starts with "*/" try to find the module in all cartridges that are assigned to the current site. A module with the name "dw" or which starts with "dw/" references Demandware built-in functions and classes. For example var u = require( 'dw/util' ); loads the classes in the util package, which can be then used like var h = new u.HashMap(); A module, which doesn't start with "./" or "../" is resolved as top level module. The module name is used to find a folder in the top cartridge directory, typically a cartridge itself, but it can also be a simple folder. If nothing is found, the module name is used to look into a special folder called "modules" in the top cartridge directory. That folder can be used by a developer to manage different modules. For example a developer could drop a module like "less.js" just into that folder. If the require function is used to reference a file then an optional file extension is used to determine the content of the file. Currently supported are the extensions ordered by priority: js - JavaScript file ds - Demandware Script file json - JSON file **Parameters:** - `path`: the path to the JavaScript module. **Returns:** an object with the exported functions and properties. --- ### trace **Signature:** `static trace(msg : String, params : Object...) : void` **Description:** Formats and prints the message using the specified params and returns the formatted message. The format message is a Java MessageFormat expression. Printing happens in the script log output. **Parameters:** - `msg`: the message to format. - `params`: one, or multiple parameters that are used to format the message. --- ### unescape **Signature:** `static unescape(string : String) : String` **Description:** Decode an escaped String. **Parameters:** - `string`: the String to decode. **Returns:** a copy of the String where hexadecimal character sequences are replace by Unicode characters. --- ``` -------------------------------------------------------------------------------- /docs/dw_system/Site.md: -------------------------------------------------------------------------------- ```markdown ## Package: dw.system # Class Site ## Inheritance Hierarchy - Object - dw.system.Site ## Description This class represents a site in Commerce Cloud Digital and provides access to several site-level configuration values which are managed from within the Business Manager. It is only possible to get a reference to the current site as determined by the current request. The static method getCurrent() returns a reference to the current site. ## Constants ### SITE_STATUS_MAINTENANCE **Type:** Number = 3 Constant that represents the Site under maintenance/offline ### SITE_STATUS_ONLINE **Type:** Number = 1 Constant that represents the Site is Online ### SITE_STATUS_PROTECTED **Type:** Number = 5 Constant that represents the Site is in preview mode or online/password (protected) ## Properties ### allowedCurrencies **Type:** List (Read Only) The allowed currencies of the current site as a collection of currency codes. ### allowedLocales **Type:** List (Read Only) The allowed locales of the current site as a collection of locale ID's. ### allSites **Type:** List (Read Only) All sites. ### calendar **Type:** Calendar (Read Only) A new Calendar object in the time zone of the current site. ### currencyCode **Type:** String (Read Only) The default currency code for the current site. ### current **Type:** Site (Read Only) The current site. ### defaultCurrency **Type:** String (Read Only) The default currency code for the current site. ### defaultLocale **Type:** String (Read Only) Return default locale for the site. ### einsteinSiteID **Type:** String (Read Only) The Einstein site Id. Typically this is a concatenation of the realm, underscore character and the site id. It can be overwritten by support users to help with realm moves to continue using the Einstein data from the old realm. Used when making calls to the Einstein APIs. ### httpHostName **Type:** String (Read Only) The configured HTTP host name. If no host name is configured the method returns the instance hostname. ### httpsHostName **Type:** String (Read Only) The configured HTTPS host name. If no host name is configured the method returns the HTTP host name or the instance hostname, if that is not configured as well. ### ID **Type:** String (Read Only) The ID of the site. ### name **Type:** String (Read Only) A descriptive name for the site. ### OMSEnabled **Type:** boolean (Read Only) Whether oms is active in the current site. This depends on a general property which states whether oms is active for the server, and a site-dependent preference whether oms is available for the current site. ### pageMetaTags **Type:** Array (Read Only) All page meta tags, defined for this instance for which content can be generated. The meta tag content is generated based on the home page meta tag context and rules. The rules are obtained from the current repository domain. ### preferences **Type:** SitePreferences (Read Only) This method returns a container of all site preferences of this site. ### status **Type:** Number (Read Only) The status of this site. Possible values are SITE_STATUS_ONLINE, SITE_STATUS_MAINTENANCE, SITE_STATUS_PROTECTED ### timezone **Type:** String (Read Only) The code for the time zone in which the storefront is running. ### timezoneOffset **Type:** Number (Read Only) Returns time zone offset in which the storefront is running. ## Constructor Summary ## Method Summary ### getAllowedCurrencies **Signature:** `getAllowedCurrencies() : List` Returns the allowed currencies of the current site as a collection of currency codes. ### getAllowedLocales **Signature:** `getAllowedLocales() : List` Returns the allowed locales of the current site as a collection of locale ID's. ### getAllSites **Signature:** `static getAllSites() : List` Returns all sites. ### getCalendar **Signature:** `static getCalendar() : Calendar` Returns a new Calendar object in the time zone of the current site. ### getCurrencyCode **Signature:** `getCurrencyCode() : String` Returns the default currency code for the current site. ### getCurrent **Signature:** `static getCurrent() : Site` Returns the current site. ### getCustomPreferenceValue **Signature:** `getCustomPreferenceValue(name : String) : Object` Returns a custom preference value. ### getDefaultCurrency **Signature:** `getDefaultCurrency() : String` Returns the default currency code for the current site. ### getDefaultLocale **Signature:** `getDefaultLocale() : String` Return default locale for the site. ### getEinsteinSiteID **Signature:** `getEinsteinSiteID() : String` Returns the Einstein site Id. ### getHttpHostName **Signature:** `getHttpHostName() : String` Returns the configured HTTP host name. ### getHttpsHostName **Signature:** `getHttpsHostName() : String` Returns the configured HTTPS host name. ### getID **Signature:** `getID() : String` Returns the ID of the site. ### getName **Signature:** `getName() : String` Returns a descriptive name for the site. ### getPageMetaTag **Signature:** `getPageMetaTag(id : String) : PageMetaTag` Returns the page meta tag for the specified id. ### getPageMetaTags **Signature:** `getPageMetaTags() : Array` Returns all page meta tags, defined for this instance for which content can be generated. ### getPreferences **Signature:** `getPreferences() : SitePreferences` This method returns a container of all site preferences of this site. ### getStatus **Signature:** `getStatus() : Number` Returns the status of this site. ### getTimezone **Signature:** `getTimezone() : String` Returns the code for the time zone in which the storefront is running. ### getTimezoneOffset **Signature:** `getTimezoneOffset() : Number` Returns time zone offset in which the storefront is running. ### isOMSEnabled **Signature:** `isOMSEnabled() : boolean` Whether oms is active in the current site. ### setCustomPreferenceValue **Signature:** `setCustomPreferenceValue(name : String, value : Object) : void` The method sets a value for a custom preference. ## Method Detail ## Method Details ### getAllowedCurrencies **Signature:** `getAllowedCurrencies() : List` **Description:** Returns the allowed currencies of the current site as a collection of currency codes. **Returns:** Collection of allowed site currencies --- ### getAllowedLocales **Signature:** `getAllowedLocales() : List` **Description:** Returns the allowed locales of the current site as a collection of locale ID's. **Returns:** Collection if allowed site locales --- ### getAllSites **Signature:** `static getAllSites() : List` **Description:** Returns all sites. **Returns:** all sites for the current instance --- ### getCalendar **Signature:** `static getCalendar() : Calendar` **Description:** Returns a new Calendar object in the time zone of the current site. **Returns:** the Calendar object in the time zone of the current site. --- ### getCurrencyCode **Signature:** `getCurrencyCode() : String` **Description:** Returns the default currency code for the current site. **Deprecated:** Use getDefaultCurrency() method instead, **Returns:** the default currency code for the current site. --- ### getCurrent **Signature:** `static getCurrent() : Site` **Description:** Returns the current site. **Returns:** the current site. --- ### getCustomPreferenceValue **Signature:** `getCustomPreferenceValue(name : String) : Object` **Description:** Returns a custom preference value. If the preference does not exist the method returns null. This method is simply a shortcut method for accessing the value for a custom attribute defined on the SitePreferences object. // Method #1 var mySitePrefValue1 : String = dw.system.Site.getCurrent(). getCustomPreferenceValue("mySitePref"); // Method #2 var sitePrefs : SitePreferences = dw.system.Site.getCurrent().getPreferences(); var mySitePrefValue2 : String = sitePrefs.getCustom()["mySitePref"]; **Parameters:** - `name`: preference name. **Returns:** the preference value, or null if there is no preference with the given name. --- ### getDefaultCurrency **Signature:** `getDefaultCurrency() : String` **Description:** Returns the default currency code for the current site. **Returns:** the default currency code for the current site. --- ### getDefaultLocale **Signature:** `getDefaultLocale() : String` **Description:** Return default locale for the site. **Returns:** default locale for the site. --- ### getEinsteinSiteID **Signature:** `getEinsteinSiteID() : String` **Description:** Returns the Einstein site Id. Typically this is a concatenation of the realm, underscore character and the site id. It can be overwritten by support users to help with realm moves to continue using the Einstein data from the old realm. Used when making calls to the Einstein APIs. **Returns:** the Einstein site Id --- ### getHttpHostName **Signature:** `getHttpHostName() : String` **Description:** Returns the configured HTTP host name. If no host name is configured the method returns the instance hostname. **Returns:** the configured HTTP host name or if it is not set the instance hostname. --- ### getHttpsHostName **Signature:** `getHttpsHostName() : String` **Description:** Returns the configured HTTPS host name. If no host name is configured the method returns the HTTP host name or the instance hostname, if that is not configured as well. **Returns:** the configured HTTPS host name or HTTP host name or the instance hostname. --- ### getID **Signature:** `getID() : String` **Description:** Returns the ID of the site. **Returns:** the ID of the site. --- ### getName **Signature:** `getName() : String` **Description:** Returns a descriptive name for the site. **Returns:** a descriptive name for the site. --- ### getPageMetaTag **Signature:** `getPageMetaTag(id : String) : PageMetaTag` **Description:** Returns the page meta tag for the specified id. The meta tag content is generated based on the home page meta tag context and rule. The rule is obtained from the current repository domain. Null will be returned if the meta tag is undefined on the current instance, or if no rule can be found for the current context, or if the rule resolves to an empty string. **Parameters:** - `id`: the ID to get the page meta tag for **Returns:** page meta tag containing content generated based on rules --- ### getPageMetaTags **Signature:** `getPageMetaTags() : Array` **Description:** Returns all page meta tags, defined for this instance for which content can be generated. The meta tag content is generated based on the home page meta tag context and rules. The rules are obtained from the current repository domain. **Returns:** page meta tags defined for this instance, containing content generated based on rules --- ### getPreferences **Signature:** `getPreferences() : SitePreferences` **Description:** This method returns a container of all site preferences of this site. **Returns:** a preferences object containing all system and custom site preferences of this site --- ### getStatus **Signature:** `getStatus() : Number` **Description:** Returns the status of this site. Possible values are SITE_STATUS_ONLINE, SITE_STATUS_MAINTENANCE, SITE_STATUS_PROTECTED **Returns:** Status of the this site. --- ### getTimezone **Signature:** `getTimezone() : String` **Description:** Returns the code for the time zone in which the storefront is running. **Returns:** time zone code in which the storefront is running. --- ### getTimezoneOffset **Signature:** `getTimezoneOffset() : Number` **Description:** Returns time zone offset in which the storefront is running. **Returns:** time zone offset in which the storefront is running. --- ### isOMSEnabled **Signature:** `isOMSEnabled() : boolean` **Description:** Whether oms is active in the current site. This depends on a general property which states whether oms is active for the server, and a site-dependent preference whether oms is available for the current site. **Deprecated:** This item is deprecated. **Returns:** whether oms is active in the site --- ### setCustomPreferenceValue **Signature:** `setCustomPreferenceValue(name : String, value : Object) : void` **Description:** The method sets a value for a custom preference. The type of the value must match with the declared type of the preference definition. **Parameters:** - `name`: name of the preference - `value`: new value for the preference --- ```