#
tokens: 48129/50000 17/825 files (page 14/61)
lines: on (toggle) GitHub
raw markdown copy reset
This is page 14 of 61. Use http://codebase.md/taurgis/sfcc-dev-mcp?lines=true&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

--------------------------------------------------------------------------------
/tests/servers/sfcc-mock-server/src/routes/ocapi/code-versions-handler.js:
--------------------------------------------------------------------------------

```javascript
  1 | /**
  2 |  * Code Versions Handler
  3 |  * 
  4 |  * Handles code version listing and activation operations for OCAPI endpoints.
  5 |  */
  6 | 
  7 | const express = require('express');
  8 | 
  9 | class CodeVersionsHandler {
 10 |     constructor(config, dataLoader) {
 11 |         this.config = config;
 12 |         this.ocapiConfig = config.getOcapiConfig();
 13 |         this.dataLoader = dataLoader;
 14 |         this.router = express.Router();
 15 |         this.setupRoutes();
 16 |     }
 17 | 
 18 |     setupRoutes() {
 19 |         // Code Versions API
 20 |         this.router.get(`/s/-/dw/data/${this.ocapiConfig.version}/code_versions`, 
 21 |             this.handleGetCodeVersions.bind(this)
 22 |         );
 23 |         
 24 |         this.router.patch(`/s/-/dw/data/${this.ocapiConfig.version}/code_versions/:versionId`, 
 25 |             this.handleActivateCodeVersion.bind(this)
 26 |         );
 27 |     }
 28 | 
 29 |     /**
 30 |      * Handle get code versions
 31 |      */
 32 |     async handleGetCodeVersions(req, res) {
 33 |         let mockData = this.dataLoader.loadOcapiData('code-versions.json');
 34 |         
 35 |         if (!mockData) {
 36 |             // Create fallback data with proper SFCC format
 37 |             mockData = {
 38 |                 "_v": "23.2",
 39 |                 "_type": "code_version_result",
 40 |                 "count": 1,
 41 |                 "data": [
 42 |                     {
 43 |                         "_type": "code_version",
 44 |                         "id": "SFRA_FALLBACK_VERSION",
 45 |                         "active": true,
 46 |                         "activation_time": new Date().toISOString(),
 47 |                         "last_modification_time": new Date().toISOString(),
 48 |                         "rollback": false,
 49 |                         "compatibility_mode": "22.7",
 50 |                         "cartridges": [
 51 |                             "app_storefront_base",
 52 |                             "bm_app_storefront_base",
 53 |                             "modules"
 54 |                         ],
 55 |                         "web_dav_url": "https://development-na01-sandbox.dx.commercecloud.salesforce.com/on/demandware.servlet/webdav/Sites/Cartridges/SFRA_FALLBACK_VERSION"
 56 |                     }
 57 |                 ],
 58 |                 "total": 1
 59 |             };
 60 |         }
 61 | 
 62 |         res.json(mockData);
 63 |     }
 64 | 
 65 |     /**
 66 |      * Handle activate code version
 67 |      */
 68 |     async handleActivateCodeVersion(req, res) {
 69 |         const { versionId } = req.params;
 70 |         
 71 |         // Load current mock data to find the version being activated
 72 |         let mockData = this.dataLoader.loadOcapiData('code-versions.json');
 73 |         
 74 |         if (!mockData) {
 75 |             return res.status(404).json({
 76 |                 "_v": "23.2",
 77 |                 "_type": "fault",
 78 |                 "fault": {
 79 |                     "type": "InvalidParameterException",
 80 |                     "message": `Code version '${versionId}' not found`
 81 |                 }
 82 |             });
 83 |         }
 84 | 
 85 |         // Find the code version being activated
 86 |         const versionToActivate = mockData.data.find(cv => cv.id === versionId);
 87 |         if (!versionToActivate) {
 88 |             return res.status(404).json({
 89 |                 "_v": "23.2",
 90 |                 "_type": "fault",
 91 |                 "fault": {
 92 |                     "type": "InvalidParameterException",
 93 |                     "message": `Code version '${versionId}' not found`
 94 |                 }
 95 |             });
 96 |         }
 97 | 
 98 |         if (versionToActivate.active) {
 99 |             // For the reset version, return the current version data instead of an error
100 |             // This allows tests to "activate" it reliably regardless of current state
101 |             if (versionId === 'reset_version') {
102 |                 const activationTime = versionToActivate.activation_time || new Date().toISOString();
103 |                 const activatedVersion = {
104 |                     "_v": "23.2",
105 |                     "_type": "code_version",
106 |                     "_resource_state": this.generateResourceState(),
107 |                     "activation_time": activationTime,
108 |                     "active": true,
109 |                     "cartridges": versionToActivate.cartridges || [],
110 |                     "compatibility_mode": versionToActivate.compatibility_mode || "22.7",
111 |                     "id": versionId,
112 |                     "last_modification_time": versionToActivate.last_modification_time || activationTime,
113 |                     "rollback": false,
114 |                     "web_dav_url": versionToActivate.web_dav_url || `https://development-na01-sandbox.dx.commercecloud.salesforce.com/on/demandware.servlet/webdav/Sites/Cartridges/${versionId}`
115 |                 };
116 |                 return res.json(activatedVersion);
117 |             }
118 |             
119 |             return res.status(400).json({
120 |                 "_v": "23.2",
121 |                 "_type": "fault",
122 |                 "fault": {
123 |                     "type": "InvalidParameterException",
124 |                     "message": `Code version '${versionId}' is already active`
125 |                 }
126 |             });
127 |         }
128 | 
129 |         // Create response matching real SFCC API behavior
130 |         const activationTime = new Date().toISOString();
131 |         const activatedVersion = {
132 |             "_v": "23.2",
133 |             "_type": "code_version",
134 |             "_resource_state": this.generateResourceState(),
135 |             "activation_time": activationTime,
136 |             "active": true,
137 |             "cartridges": versionToActivate.cartridges || [],
138 |             "compatibility_mode": versionToActivate.compatibility_mode || "22.7",
139 |             "id": versionId,
140 |             "last_modification_time": versionToActivate.last_modification_time || activationTime,
141 |             "rollback": false, // Real API sets this to false when activating
142 |             "web_dav_url": versionToActivate.web_dav_url || `https://development-na01-sandbox.dx.commercecloud.salesforce.com/on/demandware.servlet/webdav/Sites/Cartridges/${versionId}`
143 |         };
144 | 
145 |         // Update the mock data state (deactivate others, activate target)
146 |         mockData.data.forEach(cv => {
147 |             if (cv.id === versionId) {
148 |                 cv.active = true;
149 |                 cv.activation_time = activationTime;
150 |                 cv.rollback = false;
151 |             } else if (cv.active) {
152 |                 cv.active = false;
153 |                 delete cv.activation_time; // Remove activation_time from deactivated versions
154 |             }
155 |         });
156 | 
157 |         // Save updated state back to file (in a real scenario)
158 |         // For now, just return the response
159 | 
160 |         res.json(activatedVersion);
161 |     }
162 | 
163 |     /**
164 |      * Generate a mock resource state hash
165 |      */
166 |     generateResourceState() {
167 |         // Generate a 64-character hex string similar to SFCC's resource state
168 |         const chars = '0123456789abcdef';
169 |         let result = '';
170 |         for (let i = 0; i < 64; i++) {
171 |             result += chars[Math.floor(Math.random() * chars.length)];
172 |         }
173 |         return result;
174 |     }
175 | 
176 |     /**
177 |      * Get the configured router
178 |      */
179 |     getRouter() {
180 |         return this.router;
181 |     }
182 | }
183 | 
184 | module.exports = CodeVersionsHandler;
```

--------------------------------------------------------------------------------
/docs/sfra/product-bundle.md:
--------------------------------------------------------------------------------

```markdown
  1 | # SFRA Product Bundle Model
  2 | 
  3 | ## Overview
  4 | 
  5 | The Product Bundle model represents bundled products in SFRA applications, where multiple products are sold together as a single unit. It provides comprehensive bundle information including individual bundled products, pricing, and bundle-specific functionality.
  6 | 
  7 | ## Module Function
  8 | 
  9 | ```javascript
 10 | module.exports = function bundleProduct(product, apiProduct, options, factory)
 11 | ```
 12 | 
 13 | Decorates a product object with bundle-specific information using various decorators.
 14 | 
 15 | ### Parameters
 16 | 
 17 | - `product` (Object) - Product Model to be decorated
 18 | - `apiProduct` (dw.catalog.Product) - Product information returned by the script API
 19 | - `options` (Object) - Options object containing:
 20 |   - `productType` (string) - Product type information
 21 |   - `variationModel` (dw.catalog.ProductVariationModel) - Variation model returned by the API
 22 |   - `options` (Object) - Options provided on the query string
 23 |   - `optionModel` (dw.catalog.ProductOptionModel) - Options model returned by the API
 24 |   - `promotions` (dw.util.Collection) - Active promotions for the product
 25 |   - `quantity` (number) - Current selected quantity
 26 |   - `variables` (Object) - Variables passed in on the query string
 27 | - `factory` (Object) - Reference to product factory for creating bundled products
 28 | 
 29 | ### Returns
 30 | 
 31 | Object - Decorated product model with bundle-specific information
 32 | 
 33 | ## Applied Decorators
 34 | 
 35 | The product bundle model applies the following decorators in sequence:
 36 | 
 37 | ### Standard Product Decorators
 38 | - **base** - Fundamental product information: `uuid`, `id`, `productName`, `productType`, `brand`
 39 | - **price** - Bundle pricing: `price` and `renderedPrice` with promotions
 40 | - **images** - Product images: `images` with large and small sizes
 41 | - **quantity** - Quantity constraints: `selectedQuantity`, `minOrderQuantity`, `maxOrderQuantity`
 42 | - **description** - Product descriptions: `longDescription` and `shortDescription` markup
 43 | - **ratings** - Product rating: `rating` value calculated from product ID
 44 | - **promotions** - Active promotions: `promotions` array with promotion details
 45 | - **attributes** - Product attributes: `attributes` array with grouped attribute data
 46 | - **availability** - Availability status: `availability` object with messages and stock status
 47 | - **options** - Product options: `options` array with option configurations
 48 | - **quantitySelector** - Quantity selection: `quantities` array with step quantity options
 49 | 
 50 | ### Bundle-Specific Decorators
 51 | - **sizeChart** (conditional) - Size chart: `sizeChartId` if category has custom sizeChartID
 52 | - **currentUrl** - Product URL: `selectedProductUrl` with variation and option parameters
 53 | - **bundledProducts** - Bundle contents: `bundledProducts` array with individual product models
 54 | - **bundleReadyToOrder** - Bundle readiness: `readyToOrder` boolean validation for entire bundle
 55 | - **raw** - Raw API data: `raw` property (non-enumerable) with original API product
 56 | - **pageMetaData** - SEO metadata: `pageTitle`, `pageDescription`, `pageKeywords`, `pageMetaTags`
 57 | - **template** - Template info: `template` property for rendering
 58 | 
 59 | ## Bundle-Specific Features
 60 | 
 61 | ### Bundled Products Information
 62 | The `bundledProducts` decorator adds:
 63 | - List of individual products in the bundle
 64 | - Quantities of each bundled product
 65 | - Individual product pricing and availability
 66 | - Product configuration options for each item
 67 | 
 68 | ### Bundle Readiness Validation
 69 | The `bundleReadyToOrder` decorator provides:
 70 | - Overall bundle availability status
 71 | - Validation that all required bundled products are available
 72 | - Bundle-specific ordering constraints
 73 | 
 74 | ### Bundle Pricing
 75 | Bundle pricing includes:
 76 | - Combined pricing of all bundled products
 77 | - Bundle-level discounts and promotions
 78 | - Individual product price contributions
 79 | - Savings compared to individual purchases
 80 | 
 81 | ## Usage Example
 82 | 
 83 | ```javascript
 84 | var bundleProductDecorator = require('*/cartridge/models/product/productBundle');
 85 | var productFactory = require('*/cartridge/scripts/factories/product');
 86 | 
 87 | // Prepare options for bundle
 88 | var options = {
 89 |     productType: 'bundle',
 90 |     variationModel: variationModel,
 91 |     optionModel: optionModel,
 92 |     promotions: activePromotions,
 93 |     quantity: 1,
 94 |     variables: req.querystring,
 95 |     options: req.httpParameterMap
 96 | };
 97 | 
 98 | // Create and decorate bundle product
 99 | var product = {};
100 | var bundleProduct = bundleProductDecorator(product, apiProduct, options, productFactory);
101 | 
102 | // Access bundle-specific information
103 | console.log(bundleProduct.bundledProducts.length);
104 | console.log(bundleProduct.price.sales.formatted);
105 | console.log(bundleProduct.readyToOrder);
106 | 
107 | // Check individual bundled products
108 | bundleProduct.bundledProducts.forEach(function(bundledProduct) {
109 |     console.log(bundledProduct.productName + ' x ' + bundledProduct.quantity);
110 | });
111 | ```
112 | 
113 | ## Bundle Structure
114 | 
115 | After decoration, the bundle product contains:
116 | 
117 | ### Standard Product Properties
118 | - **uuid** - Product UUID
119 | - **id** - Product ID  
120 | - **productName** - Product name
121 | - **productType** - Product type
122 | - **brand** - Product brand
123 | - **price** - Comprehensive pricing with bundle discounts
124 | - **renderedPrice** - HTML-rendered price for display
125 | - **images** - Product images (large and small sizes)
126 | - **selectedQuantity** - Currently selected quantity
127 | - **minOrderQuantity** - Minimum order quantity
128 | - **maxOrderQuantity** - Maximum order quantity
129 | - **longDescription** - Product long description markup
130 | - **shortDescription** - Product short description markup
131 | - **rating** - Product rating value
132 | - **promotions** - Active promotion information
133 | - **attributes** - Product attribute groups and values
134 | - **availability** - Availability status and messages
135 | - **options** - Product option configurations
136 | - **quantities** - Available quantity selection options
137 | - **selectedProductUrl** - Current product URL with parameters
138 | 
139 | ### Bundle-Specific Properties
140 | - **bundledProducts** - Array of individual product models in the bundle
141 | - **readyToOrder** - Boolean indicating if the entire bundle can be ordered
142 | - **sizeChartId** - Size chart identifier (if applicable)
143 | - **pageTitle** - SEO page title
144 | - **pageDescription** - SEO page description  
145 | - **pageKeywords** - SEO page keywords
146 | - **pageMetaTags** - SEO meta tags array
147 | - **template** - Template identifier for rendering
148 | 
149 | ## Notes
150 | 
151 | - Handles complex bundle pricing calculations
152 | - Validates availability for all bundled products
153 | - Supports bundle-specific promotions and discounts
154 | - Maintains individual product information within the bundle
155 | - Provides comprehensive bundle readiness validation
156 | - Includes size chart support if any bundled products have size charts
157 | - Optimized for bundle product detail pages
158 | 
159 | ## Related Models
160 | 
161 | - **Product Factory** - Creates individual bundled product models
162 | - **Full Product Model** - Similar comprehensive decoration approach
163 | - **Product Set Model** - Alternative product grouping model
164 | - **Product Decorators** - Individual decoration functions
165 | 
```

--------------------------------------------------------------------------------
/tests/servers/sfcc-mock-server-manager.ts:
--------------------------------------------------------------------------------

```typescript
  1 | import { spawn, ChildProcess } from 'child_process';
  2 | import path from 'path';
  3 | 
  4 | /**
  5 |  * Manager for the unified SFCC Mock Server for testing purposes
  6 |  * 
  7 |  * This class provides utilities to start, stop, and interact with the unified
  8 |  * SFCC mock server that combines WebDAV and OCAPI functionality.
  9 |  */
 10 | export class SFCCMockServerManager {
 11 |   private serverProcess: ChildProcess | null = null;
 12 |   private readonly config: SFCCMockServerConfig;
 13 |   private readonly serverPath: string;
 14 |   private startupPromise: Promise<void> | null = null;
 15 | 
 16 |   constructor(config: Partial<SFCCMockServerConfig> = {}) {
 17 |     this.config = {
 18 |       port: 3000,
 19 |       host: 'localhost',
 20 |       dev: false,
 21 |       autoSetup: true,
 22 |       timeout: 10000,
 23 |       webdav: true,
 24 |       ocapi: true,
 25 |       cors: true,
 26 |       ...config,
 27 |     };
 28 | 
 29 |     this.serverPath = path.join(__dirname, 'sfcc-mock-server');
 30 |   }
 31 | 
 32 |   /**
 33 |    * Check if the SFCC mock server is available for testing
 34 |    */
 35 |   async isServerAvailable(): Promise<boolean> {
 36 |     try {
 37 |       const fs = await import('fs');
 38 |       const serverJs = path.join(this.serverPath, 'server.js');
 39 |       const packageJson = path.join(this.serverPath, 'package.json');
 40 |       
 41 |       return fs.existsSync(serverJs) && fs.existsSync(packageJson);
 42 |     } catch {
 43 |       return false;
 44 |     }
 45 |   }
 46 | 
 47 |   /**
 48 |    * Start the SFCC mock server
 49 |    */
 50 |   async start(): Promise<void> {
 51 |     if (this.startupPromise) {
 52 |       return this.startupPromise;
 53 |     }
 54 | 
 55 |     this.startupPromise = this._startServer();
 56 |     return this.startupPromise;
 57 |   }
 58 | 
 59 |   private async _startServer(): Promise<void> {
 60 |     if (this.serverProcess) {
 61 |       throw new Error('Server is already running');
 62 |     }
 63 | 
 64 |     const isAvailable = await this.isServerAvailable();
 65 |     if (!isAvailable) {
 66 |       throw new Error('SFCC mock server is not available. Run setup first.');
 67 |     }
 68 | 
 69 |     // Setup logs if auto-setup is enabled
 70 |     if (this.config.autoSetup) {
 71 |       await this._runSetup();
 72 |     }
 73 | 
 74 |     const args = this._buildServerArgs();
 75 |     
 76 |     return new Promise((resolve, reject) => {
 77 |       const timeout = setTimeout(() => {
 78 |         this.stop();
 79 |         reject(new Error(`Server failed to start within ${this.config.timeout}ms`));
 80 |       }, this.config.timeout);
 81 | 
 82 |       this.serverProcess = spawn('node', ['server.js', ...args], {
 83 |         cwd: this.serverPath,
 84 |         stdio: this.config.dev ? 'inherit' : 'pipe',
 85 |       });
 86 | 
 87 |       this.serverProcess.on('error', (error) => {
 88 |         clearTimeout(timeout);
 89 |         reject(error);
 90 |       });
 91 | 
 92 |       this.serverProcess.on('exit', (code, signal) => {
 93 |         if (code !== null && code !== 0) {
 94 |           clearTimeout(timeout);
 95 |           reject(new Error(`Server exited with code ${code}`));
 96 |         }
 97 |       });
 98 | 
 99 |       // Wait a bit for the server to start up
100 |       setTimeout(async () => {
101 |         try {
102 |           // Test if server is responding using the health endpoint
103 |           const response = await fetch(`${this.getServerUrl()}/health`);
104 |           if (response.ok) {
105 |             clearTimeout(timeout);
106 |             resolve();
107 |           } else {
108 |             clearTimeout(timeout);
109 |             reject(new Error(`Server health check failed with status ${response.status}`));
110 |           }
111 |         } catch (error) {
112 |           clearTimeout(timeout);
113 |           reject(new Error(`Server health check failed: ${error}`));
114 |         }
115 |       }, 2000); // Give server 2 seconds to start
116 |     });
117 |   }
118 | 
119 |   private async _runSetup(): Promise<void> {
120 |     return new Promise((resolve, reject) => {
121 |       const setupProcess = spawn('npm', ['run', 'setup:logs'], {
122 |         cwd: this.serverPath,
123 |         stdio: 'pipe',
124 |       });
125 | 
126 |       setupProcess.on('error', reject);
127 |       setupProcess.on('exit', (code) => {
128 |         if (code === 0) {
129 |           resolve();
130 |         } else {
131 |           reject(new Error(`Setup failed with code ${code}`));
132 |         }
133 |       });
134 |     });
135 |   }
136 | 
137 |   private _buildServerArgs(): string[] {
138 |     const args: string[] = [];
139 | 
140 |     args.push('--port', this.config.port.toString());
141 |     args.push('--host', this.config.host);
142 | 
143 |     if (this.config.dev) {
144 |       args.push('--dev');
145 |     }
146 | 
147 |     if (!this.config.webdav) {
148 |       args.push('--no-webdav');
149 |     }
150 | 
151 |     if (!this.config.ocapi) {
152 |       args.push('--no-ocapi');
153 |     }
154 | 
155 |     if (!this.config.cors) {
156 |       args.push('--no-cors');
157 |     }
158 | 
159 |     return args;
160 |   }
161 | 
162 |   /**
163 |    * Stop the SFCC mock server
164 |    */
165 |   async stop(): Promise<void> {
166 |     return new Promise((resolve) => {
167 |       if (!this.serverProcess) {
168 |         resolve();
169 |         return;
170 |       }
171 | 
172 |       const process = this.serverProcess;
173 |       this.serverProcess = null;
174 |       this.startupPromise = null;
175 | 
176 |       const timeout = setTimeout(() => {
177 |         process.kill('SIGKILL');
178 |         resolve();
179 |       }, 5000);
180 | 
181 |       process.on('exit', () => {
182 |         clearTimeout(timeout);
183 |         resolve();
184 |       });
185 | 
186 |       process.kill('SIGTERM');
187 |     });
188 |   }
189 | 
190 |   /**
191 |    * Check if the server is currently running
192 |    */
193 |   isRunning(): boolean {
194 |     return this.serverProcess !== null && this.serverProcess.exitCode === null;
195 |   }
196 | 
197 |   /**
198 |    * Get the base server URL
199 |    */
200 |   getServerUrl(): string {
201 |     return `http://${this.config.host}:${this.config.port}`;
202 |   }
203 | 
204 |   /**
205 |    * Get the WebDAV logs URL (SFCC path)
206 |    */
207 |   getWebDAVLogsUrl(): string {
208 |     return `${this.getServerUrl()}/on/demandware.servlet/webdav/Sites/Logs/`;
209 |   }
210 | 
211 |   /**
212 |    * Get the direct logs URL
213 |    */
214 |   getDirectLogsUrl(): string {
215 |     return `${this.getServerUrl()}/Logs/`;
216 |   }
217 | 
218 |   /**
219 |    * Get the OCAPI base URL
220 |    */
221 |   getOCAPIUrl(): string {
222 |     return `${this.getServerUrl()}/s/-/dw/data/v23_2`;
223 |   }
224 | 
225 |   /**
226 |    * Get the OCAPI OAuth URL
227 |    */
228 |   getOAuthUrl(): string {
229 |     return `${this.getServerUrl()}/dw/oauth2/access_token`;
230 |   }
231 | }
232 | 
233 | /**
234 |  * Configuration interface for the SFCC mock server manager
235 |  */
236 | export interface SFCCMockServerConfig {
237 |   port: number;
238 |   host: string;
239 |   dev: boolean;
240 |   autoSetup: boolean;
241 |   timeout: number;
242 |   webdav: boolean;
243 |   ocapi: boolean;
244 |   cors: boolean;
245 | }
246 | 
247 | /**
248 |  * Utility function to run a test with the SFCC mock server
249 |  * 
250 |  * @param testFn Function to run with server URLs
251 |  * @param config Optional server configuration
252 |  * @returns Promise resolving to the test function result
253 |  */
254 | export async function withSFCCMockServer<T>(
255 |   testFn: (serverUrl: string, webdavLogsUrl: string, directLogsUrl: string, ocapiUrl: string, oauthUrl: string) => Promise<T>,
256 |   config: Partial<SFCCMockServerConfig> = {}
257 | ): Promise<T> {
258 |   const manager = new SFCCMockServerManager({
259 |     port: 3004, // Use different port for utility function
260 |     ...config,
261 |   });
262 | 
263 |   if (!await manager.isServerAvailable()) {
264 |     throw new Error('SFCC mock server is not available');
265 |   }
266 | 
267 |   try {
268 |     await manager.start();
269 | 
270 |     return await testFn(
271 |       manager.getServerUrl(),
272 |       manager.getWebDAVLogsUrl(),
273 |       manager.getDirectLogsUrl(),
274 |       manager.getOCAPIUrl(),
275 |       manager.getOAuthUrl()
276 |     );
277 |   } finally {
278 |     await manager.stop();
279 |   }
280 | }
```

--------------------------------------------------------------------------------
/docs/dw_rpc/Stub.md:
--------------------------------------------------------------------------------

```markdown
  1 | ## Package: dw.rpc
  2 | 
  3 | # Class Stub
  4 | 
  5 | ## Inheritance Hierarchy
  6 | 
  7 | - Object
  8 |   - dw.rpc.Stub
  9 | 
 10 | ## Description
 11 | 
 12 | This is the base class for all service stubs accessible through a WebReference object. The Stub provides access to the WSDL operations. Demandware recommends a low timeout to ensure responsiveness of the site and to avoid thread exhaustion. Use the Services module in Business Manager to set timeout values, not the methods for this class. The Services module provides better analytics and timeout management. The default timeout, if not set, is 15 minutes when the web service is used in a job, and 2 minutes otherwise. If the timeout of the calling script is lower, the script timeout is used. // get WebReference var webref : WebReference = webreferences.myWSDLname; // get service stub var stub : Stub = webref.defaultService;
 13 | 
 14 | ## Constants
 15 | 
 16 | ### CONNECTION_TIMEOUT
 17 | 
 18 | **Type:** String
 19 | 
 20 | This property allows the user to set the web service connection timeout value in milliseconds. By default, the web service connection timeout is 5000 milliseconds (5 seconds). The minimum allowed value is 100 milliseconds and the maximum allowed value is 15000 milliseconds (15 seconds). Demandware recommends setting timeout values in Business Manager Services module as it provides better analytics and timeout management.
 21 | 
 22 | ### ENDPOINT_ADDRESS_PROPERTY
 23 | 
 24 | **Type:** String
 25 | 
 26 | Standard property: target service endpoint address. The URI scheme for the endpoint address specification must correspond to the protocol/transport binding for this stub class.
 27 | 
 28 | ### PASSWORD_PROPERTY
 29 | 
 30 | **Type:** String
 31 | 
 32 | Standard property: password for authentication.
 33 | 
 34 | ### SESSION_MAINTAIN_PROPERTY
 35 | 
 36 | **Type:** String
 37 | 
 38 | Standard property: this boolean property is used by a service client to indicate whether or not it wants to participate in a session with a service endpoint. If this property is set to true, the service client indicates that it wants the session to be maintained. If set to false, the session is not maintained. The default value for this property is false.
 39 | 
 40 | ### USERNAME_PROPERTY
 41 | 
 42 | **Type:** String
 43 | 
 44 | Standard property: user name for authentication.
 45 | 
 46 | ## Properties
 47 | 
 48 | ### password
 49 | 
 50 | **Type:** String
 51 | 
 52 | The password.
 53 | 
 54 | ### timeout
 55 | 
 56 | **Type:** Number
 57 | 
 58 | The current read timeout value in milliseconds for this Stub.
 59 | 
 60 | ### username
 61 | 
 62 | **Type:** String
 63 | 
 64 | The user name.
 65 |  
 66 |  Note: this method handles sensitive security-related data.
 67 |  Pay special attention to PCI DSS v3. requirements 2, 4, and 12.
 68 | 
 69 | ## Constructor Summary
 70 | 
 71 | Stub()
 72 | 
 73 | ## Method Summary
 74 | 
 75 | ### _getProperty
 76 | 
 77 | **Signature:** `_getProperty(name : String) : Object`
 78 | 
 79 | Gets the value of a specific configuration property.
 80 | 
 81 | ### _setProperty
 82 | 
 83 | **Signature:** `_setProperty(name : String, value : Object) : void`
 84 | 
 85 | Sets the name and value of a configuration property for this Stub instance.
 86 | 
 87 | ### getPassword
 88 | 
 89 | **Signature:** `getPassword() : String`
 90 | 
 91 | Returns the password.
 92 | 
 93 | ### getTimeout
 94 | 
 95 | **Signature:** `getTimeout() : Number`
 96 | 
 97 | Returns the current read timeout value in milliseconds for this Stub.
 98 | 
 99 | ### getUsername
100 | 
101 | **Signature:** `getUsername() : String`
102 | 
103 | Returns the user name.
104 | 
105 | ### setHeader
106 | 
107 | **Signature:** `setHeader(namespace : String, name : String, value : Object) : void`
108 | 
109 | Sets an additional SOAP header value for the next operation.
110 | 
111 | ### setPassword
112 | 
113 | **Signature:** `setPassword(password : String) : void`
114 | 
115 | Sets the password.
116 | 
117 | ### setTimeout
118 | 
119 | **Signature:** `setTimeout(timeout : Number) : void`
120 | 
121 | Sets the timeout in milliseconds for the next call through this Stub.
122 | 
123 | ### setUsername
124 | 
125 | **Signature:** `setUsername(username : String) : void`
126 | 
127 | Sets the user name.
128 | 
129 | ## Constructor Detail
130 | 
131 | ## Method Detail
132 | 
133 | ## Method Details
134 | 
135 | ### _getProperty
136 | 
137 | **Signature:** `_getProperty(name : String) : Object`
138 | 
139 | **Description:** Gets the value of a specific configuration property.
140 | 
141 | **Deprecated:**
142 | 
143 | use webreferences2 instead
144 | 
145 | **Parameters:**
146 | 
147 | - `name`: Name of the property whose value is to be retrieved
148 | 
149 | **Returns:**
150 | 
151 | Value of the configuration property
152 | 
153 | ---
154 | 
155 | ### _setProperty
156 | 
157 | **Signature:** `_setProperty(name : String, value : Object) : void`
158 | 
159 | **Description:** Sets the name and value of a configuration property for this Stub instance. If the Stub instance contains a value for the same property, the old value is replaced. Note: the _setProperty method may not perform a validity check on a configured property value. An example is the standard property for the target service endpoint address, which is not checked for validity in the _setProperty method. In this case, stub configuration errors are detected at the remote method invocation.
160 | 
161 | **Deprecated:**
162 | 
163 | use webreferences2 instead
164 | 
165 | **Parameters:**
166 | 
167 | - `name`: Name of the configuration property
168 | - `value`: Value of the property
169 | 
170 | ---
171 | 
172 | ### getPassword
173 | 
174 | **Signature:** `getPassword() : String`
175 | 
176 | **Description:** Returns the password.
177 | 
178 | **Deprecated:**
179 | 
180 | use webreferences2 instead
181 | 
182 | **Returns:**
183 | 
184 | the password. Note: this method handles sensitive security-related data. Pay special attention to PCI DSS v3. requirements 2, 4, and 12.
185 | 
186 | ---
187 | 
188 | ### getTimeout
189 | 
190 | **Signature:** `getTimeout() : Number`
191 | 
192 | **Description:** Returns the current read timeout value in milliseconds for this Stub.
193 | 
194 | **Deprecated:**
195 | 
196 | use webreferences2 instead
197 | 
198 | **Returns:**
199 | 
200 | the current timeout value for this Stub.
201 | 
202 | ---
203 | 
204 | ### getUsername
205 | 
206 | **Signature:** `getUsername() : String`
207 | 
208 | **Description:** Returns the user name. Note: this method handles sensitive security-related data. Pay special attention to PCI DSS v3. requirements 2, 4, and 12.
209 | 
210 | **Deprecated:**
211 | 
212 | use webreferences2 instead
213 | 
214 | **Returns:**
215 | 
216 | the user name.
217 | 
218 | ---
219 | 
220 | ### setHeader
221 | 
222 | **Signature:** `setHeader(namespace : String, name : String, value : Object) : void`
223 | 
224 | **Description:** Sets an additional SOAP header value for the next operation.
225 | 
226 | **Deprecated:**
227 | 
228 | use webreferences2 instead
229 | 
230 | **Parameters:**
231 | 
232 | - `namespace`: the namespace to use.
233 | - `name`: the name of the header item.
234 | - `value`: the value for the header item.
235 | 
236 | ---
237 | 
238 | ### setPassword
239 | 
240 | **Signature:** `setPassword(password : String) : void`
241 | 
242 | **Description:** Sets the password.
243 | 
244 | **Deprecated:**
245 | 
246 | use webreferences2 instead
247 | 
248 | **Parameters:**
249 | 
250 | - `password`: the password to set.
251 | 
252 | ---
253 | 
254 | ### setTimeout
255 | 
256 | **Signature:** `setTimeout(timeout : Number) : void`
257 | 
258 | **Description:** Sets the timeout in milliseconds for the next call through this Stub. This timeout value controls "read timeout" (how long, after connecting, it will wait without any data being read). To control "connection timeout" you use the _setProperty(String, Object) method where the name parameter is CONNECTION_TIMEOUT.
259 | 
260 | **Deprecated:**
261 | 
262 | use webreferences2 instead
263 | 
264 | **Parameters:**
265 | 
266 | - `timeout`: the timeout for the next call through this stub.
267 | 
268 | **See Also:**
269 | 
270 | _setProperty(String, Object)
271 | CONNECTION_TIMEOUT
272 | 
273 | ---
274 | 
275 | ### setUsername
276 | 
277 | **Signature:** `setUsername(username : String) : void`
278 | 
279 | **Description:** Sets the user name.
280 | 
281 | **Deprecated:**
282 | 
283 | use webreferences2 instead
284 | 
285 | **Parameters:**
286 | 
287 | - `username`: the user name to set.
288 | 
289 | ---
```

--------------------------------------------------------------------------------
/tests/servers/sfcc-mock-server/mock-data/ocapi/site-preferences-sfra.json:
--------------------------------------------------------------------------------

```json
  1 | {
  2 |   "_v": "23.2",
  3 |   "_type": "preference_value_search_result",
  4 |   "count": 4,
  5 |   "hits": [
  6 |     {
  7 |       "_type": "preference_value",
  8 |       "attribute_definition": {
  9 |         "_type": "object_attribute_definition",
 10 |         "_resource_state": "sfra1-resource-state",
 11 |         "creation_date": "2024-01-01T00:00:00.000Z",
 12 |         "description": {
 13 |           "default": "Enable SFRA debug mode for development"
 14 |         },
 15 |         "display_name": {
 16 |           "default": "SFRA Debug Mode"
 17 |         },
 18 |         "effective_id": "c_sfraDebugMode",
 19 |         "externally_defined": false,
 20 |         "externally_managed": false,
 21 |         "id": "sfraDebugMode",
 22 |         "key": false,
 23 |         "last_modified": "2024-01-01T00:00:00.000Z",
 24 |         "link": "https://localhost:3000/s/-/dw/data/v23_2/system_object_definitions/SitePreferences/attribute_definitions/sfraDebugMode",
 25 |         "localizable": false,
 26 |         "mandatory": false,
 27 |         "multi_value_type": false,
 28 |         "order_required": false,
 29 |         "queryable": false,
 30 |         "read_only": false,
 31 |         "requires_encoding": false,
 32 |         "searchable": false,
 33 |         "set_value_type": false,
 34 |         "site_specific": false,
 35 |         "system": false,
 36 |         "value_type": "boolean",
 37 |         "visible": true
 38 |       },
 39 |       "description": {
 40 |         "default": "Enable SFRA debug mode for development"
 41 |       },
 42 |       "display_name": {
 43 |         "default": "SFRA Debug Mode"
 44 |       },
 45 |       "id": "sfraDebugMode",
 46 |       "site_values": {
 47 |         "RefArch": false,
 48 |         "RefArchGlobal": false,
 49 |         "pxl_1": true,
 50 |         "pxl_2": false,
 51 |         "pxl_3": null,
 52 |         "pxl_4": null,
 53 |         "pxl_5": null,
 54 |         "pxl_6": null
 55 |       },
 56 |       "value_type": "boolean"
 57 |     },
 58 |     {
 59 |       "_type": "preference_value",
 60 |       "attribute_definition": {
 61 |         "_type": "object_attribute_definition",
 62 |         "_resource_state": "sfra2-resource-state",
 63 |         "creation_date": "2024-01-01T00:00:00.000Z",
 64 |         "description": {
 65 |           "default": "Custom middleware configurations for SFRA"
 66 |         },
 67 |         "display_name": {
 68 |           "default": "SFRA Middleware Config"
 69 |         },
 70 |         "effective_id": "c_sfraMiddlewareConfig",
 71 |         "externally_defined": false,
 72 |         "externally_managed": false,
 73 |         "field_height": 8,
 74 |         "id": "sfraMiddlewareConfig",
 75 |         "key": false,
 76 |         "last_modified": "2024-01-01T00:00:00.000Z",
 77 |         "link": "https://localhost:3000/s/-/dw/data/v23_2/system_object_definitions/SitePreferences/attribute_definitions/sfraMiddlewareConfig",
 78 |         "localizable": false,
 79 |         "mandatory": false,
 80 |         "multi_value_type": false,
 81 |         "order_required": false,
 82 |         "queryable": false,
 83 |         "read_only": false,
 84 |         "requires_encoding": false,
 85 |         "searchable": false,
 86 |         "set_value_type": false,
 87 |         "site_specific": true,
 88 |         "system": false,
 89 |         "value_type": "text",
 90 |         "visible": true
 91 |       },
 92 |       "description": {
 93 |         "default": "Custom middleware configurations for SFRA"
 94 |       },
 95 |       "display_name": {
 96 |         "default": "SFRA Middleware Config"
 97 |       },
 98 |       "id": "sfraMiddlewareConfig",
 99 |       "site_values": {
100 |         "RefArch": "{\"cache\": true, \"csrf\": true, \"compression\": false}",
101 |         "RefArchGlobal": "{\"cache\": true, \"csrf\": true, \"compression\": true, \"logging\": \"debug\"}",
102 |         "pxl_1": "",
103 |         "pxl_2": "{\"cache\": false, \"csrf\": false}",
104 |         "pxl_3": null,
105 |         "pxl_4": null,
106 |         "pxl_5": null,
107 |         "pxl_6": null
108 |       },
109 |       "value_type": "text"
110 |     },
111 |     {
112 |       "_type": "preference_value",
113 |       "attribute_definition": {
114 |         "_type": "object_attribute_definition",
115 |         "_resource_state": "sfra3-resource-state",
116 |         "creation_date": "2024-01-01T00:00:00.000Z",
117 |         "description": {
118 |           "default": "Maximum SFRA cache timeout in seconds"
119 |         },
120 |         "display_name": {
121 |           "default": "SFRA Cache Timeout"
122 |         },
123 |         "effective_id": "c_sfraCacheTimeout",
124 |         "externally_defined": false,
125 |         "externally_managed": false,
126 |         "id": "sfraCacheTimeout",
127 |         "key": false,
128 |         "last_modified": "2024-01-01T00:00:00.000Z",
129 |         "link": "https://localhost:3000/s/-/dw/data/v23_2/system_object_definitions/SitePreferences/attribute_definitions/sfraCacheTimeout",
130 |         "localizable": false,
131 |         "mandatory": false,
132 |         "multi_value_type": false,
133 |         "order_required": false,
134 |         "queryable": false,
135 |         "read_only": false,
136 |         "requires_encoding": false,
137 |         "searchable": false,
138 |         "set_value_type": false,
139 |         "site_specific": true,
140 |         "system": false,
141 |         "value_type": "int",
142 |         "visible": true
143 |       },
144 |       "description": {
145 |         "default": "Maximum SFRA cache timeout in seconds"
146 |       },
147 |       "display_name": {
148 |         "default": "SFRA Cache Timeout"
149 |       },
150 |       "id": "sfraCacheTimeout",
151 |       "site_values": {
152 |         "RefArch": 3600,
153 |         "RefArchGlobal": 7200,
154 |         "pxl_1": 0,
155 |         "pxl_2": 1800,
156 |         "pxl_3": null,
157 |         "pxl_4": null,
158 |         "pxl_5": null,
159 |         "pxl_6": null
160 |       },
161 |       "value_type": "int"
162 |     },
163 |     {
164 |       "_type": "preference_value",
165 |       "attribute_definition": {
166 |         "_type": "object_attribute_definition",
167 |         "_resource_state": "sfra4-resource-state",
168 |         "creation_date": "2024-01-01T00:00:00.000Z",
169 |         "description": {
170 |           "default": "Configuration with null values to test edge cases"
171 |         },
172 |         "display_name": {
173 |           "default": "Edge Case Config"
174 |         },
175 |         "effective_id": "c_edgeCaseConfig",
176 |         "externally_defined": false,
177 |         "externally_managed": false,
178 |         "id": "edgeCaseConfig",
179 |         "key": false,
180 |         "last_modified": "2024-01-01T00:00:00.000Z",
181 |         "link": "https://localhost:3000/s/-/dw/data/v23_2/system_object_definitions/SitePreferences/attribute_definitions/edgeCaseConfig",
182 |         "localizable": false,
183 |         "mandatory": false,
184 |         "multi_value_type": false,
185 |         "order_required": false,
186 |         "queryable": false,
187 |         "read_only": false,
188 |         "requires_encoding": false,
189 |         "searchable": false,
190 |         "set_value_type": false,
191 |         "site_specific": true,
192 |         "system": false,
193 |         "value_type": "text",
194 |         "visible": false
195 |       },
196 |       "description": {
197 |         "default": "Configuration with null values to test edge cases"
198 |       },
199 |       "display_name": {
200 |         "default": "Edge Case Config"
201 |       },
202 |       "id": "edgeCaseConfig",
203 |       "site_values": {
204 |         "RefArch": null,
205 |         "RefArchGlobal": null,
206 |         "pxl_1": null,
207 |         "pxl_2": null,
208 |         "pxl_3": null,
209 |         "pxl_4": null,
210 |         "pxl_5": null,
211 |         "pxl_6": null
212 |       },
213 |       "value_type": "text"
214 |     }
215 |   ],
216 |   "query": {
217 |     "match_all_query": {
218 |       "_type": "match_all_query"
219 |     }
220 |   },
221 |   "select": "(**)",
222 |   "start": 0,
223 |   "total": 4
224 | }
```

--------------------------------------------------------------------------------
/src/core/server.ts:
--------------------------------------------------------------------------------

```typescript
  1 | /**
  2 |  * MCP Server for SFCC Development
  3 |  *
  4 |  * This module implements the Model Context Protocol (MCP) server for accessing
  5 |  * Salesforce B2C Commerce Cloud development features. It provides a standardized interface
  6 |  * for AI assistants to interact with SFCC development tools and data.
  7 |  */
  8 | 
  9 | import { Server } from '@modelcontextprotocol/sdk/server/index.js';
 10 | import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
 11 | import {
 12 |   CallToolRequestSchema,
 13 |   ListToolsRequestSchema,
 14 | } from '@modelcontextprotocol/sdk/types.js';
 15 | import { SFCCConfig } from '../types/types.js';
 16 | import { Logger } from '../utils/logger.js';
 17 | import { ConfigurationFactory } from '../config/configuration-factory.js';
 18 | import {
 19 |   SFCC_DOCUMENTATION_TOOLS,
 20 |   BEST_PRACTICES_TOOLS,
 21 |   SFRA_DOCUMENTATION_TOOLS,
 22 |   LOG_TOOLS,
 23 |   JOB_LOG_TOOLS,
 24 |   SYSTEM_OBJECT_TOOLS,
 25 |   CARTRIDGE_GENERATION_TOOLS,
 26 |   CODE_VERSION_TOOLS,
 27 | } from './tool-definitions.js';
 28 | 
 29 | // Modular tool handlers
 30 | import { BaseToolHandler, HandlerContext } from './handlers/base-handler.js';
 31 | import { LogToolHandler } from './handlers/log-handler.js';
 32 | import { JobLogToolHandler } from './handlers/job-log-handler.js';
 33 | import { DocsToolHandler } from './handlers/docs-handler.js';
 34 | import { BestPracticesToolHandler } from './handlers/best-practices-handler.js';
 35 | import { SFRAToolHandler } from './handlers/sfra-handler.js';
 36 | import { SystemObjectToolHandler } from './handlers/system-object-handler.js';
 37 | import { CodeVersionToolHandler } from './handlers/code-version-handler.js';
 38 | import { CartridgeToolHandler } from './handlers/cartridge-handler.js';
 39 | /**
 40 |  * MCP Server implementation for SFCC development assistance
 41 |  *
 42 |  * This class sets up the MCP server, defines available tools, and handles
 43 |  * requests from MCP clients (like AI assistants) to interact with SFCC development features.
 44 |  */
 45 | export class SFCCDevServer {
 46 |   private server!: Server;
 47 |   private logger: Logger;
 48 |   private config: SFCCConfig;
 49 |   private capabilities: ReturnType<typeof ConfigurationFactory.getCapabilities>;
 50 |   private handlers: BaseToolHandler[] = [];
 51 | 
 52 |   /**
 53 |    * Initialize the SFCC Development MCP Server
 54 |    *
 55 |    * @param config - SFCC configuration for connecting to the logging system
 56 |    */
 57 |   constructor(config: SFCCConfig) {
 58 |     this.logger = Logger.getChildLogger('Server');
 59 |     this.config = config;
 60 |     this.logMethodEntry('constructor', { hostname: config.hostname });
 61 |     this.capabilities = ConfigurationFactory.getCapabilities(config);
 62 |     this.initializeServer();
 63 |     this.registerHandlers();
 64 |     this.setupToolHandlers();
 65 | 
 66 |     this.logMethodExit('constructor');
 67 |   }
 68 | 
 69 |   private initializeServer(): void {
 70 |     this.server = new Server(
 71 |       {
 72 |         name: 'SFCC Development MCP Server',
 73 |         version: '1.0.14', // synced with package.json
 74 |       },
 75 |       {
 76 |         capabilities: {
 77 |           tools: {},
 78 |         },
 79 |       },
 80 |     );
 81 |   }
 82 | 
 83 |   private logMethodEntry(methodName: string, params?: any): void {
 84 |     this.logger.methodEntry(methodName, params);
 85 |   }
 86 | 
 87 |   private logMethodExit(methodName: string, result?: any): void {
 88 |     this.logger.methodExit(methodName, result);
 89 |   }
 90 | 
 91 |   // Register modular handlers (each encapsulates its own responsibility)
 92 |   private registerHandlers(): void {
 93 |     const context: HandlerContext = {
 94 |       logger: this.logger,
 95 |       config: this.config,
 96 |       capabilities: this.capabilities,
 97 |     };
 98 |     this.handlers = [
 99 |       new LogToolHandler(context, 'Log'),
100 |       new JobLogToolHandler(context, 'JobLog'),
101 |       new DocsToolHandler(context, 'Docs'),
102 |       new BestPracticesToolHandler(context, 'BestPractices'),
103 |       new SFRAToolHandler(context, 'SFRA'),
104 |       new SystemObjectToolHandler(context, 'SystemObjects'),
105 |       new CodeVersionToolHandler(context, 'CodeVersions'),
106 |       new CartridgeToolHandler(context, 'Cartridge'),
107 |     ];
108 |   }
109 | 
110 |   /**
111 |    * Set up MCP tool handlers for SFCC operations
112 |    */
113 |   private setupToolHandlers(): void {
114 |     this.server.setRequestHandler(ListToolsRequestSchema, async () => {
115 |       const tools = [];
116 | 
117 |       // Always available tools
118 |       tools.push(...SFCC_DOCUMENTATION_TOOLS);
119 |       tools.push(...BEST_PRACTICES_TOOLS);
120 |       tools.push(...SFRA_DOCUMENTATION_TOOLS);
121 |       tools.push(...CARTRIDGE_GENERATION_TOOLS);
122 | 
123 |       // Conditional tools based on available capabilities
124 |       if (this.capabilities.canAccessLogs) {
125 |         tools.push(...LOG_TOOLS);
126 |         tools.push(...JOB_LOG_TOOLS);
127 |       }
128 | 
129 |       if (this.capabilities.canAccessOCAPI) {
130 |         tools.push(...SYSTEM_OBJECT_TOOLS);
131 |         tools.push(...CODE_VERSION_TOOLS);
132 |       }
133 | 
134 |       return { tools };
135 |     });
136 | 
137 |     this.server.setRequestHandler(CallToolRequestSchema, async (request): Promise<any> => {
138 |       const { name, arguments: args } = request.params;
139 |       const startTime = Date.now();
140 | 
141 |       this.logger.methodEntry(`handleToolRequest:${name}`, args);
142 | 
143 |       try {
144 |         const handler = this.handlers.find((h) => h.canHandle(name));
145 |         if (!handler) {
146 |           this.logger.error(`Unknown tool requested: ${name}`);
147 |           throw new Error(`Unknown tool: ${name}`);
148 |         }
149 |         const result = await handler.handle(name, args ?? {}, startTime);
150 | 
151 |         // Log the full response in debug mode
152 |         this.logger.debug(`Full response for ${name}:`, {
153 |           contentType: result.content?.[0]?.type,
154 |           contentLength: result.content?.[0]?.text?.length ?? 0,
155 |           responsePreview: result.content?.[0]?.text?.substring(0, 200) + (result.content?.[0]?.text?.length > 200 ? '...' : ''),
156 |           fullResponse: result.content?.[0]?.text,
157 |         });
158 | 
159 |         return result as any;
160 |       } catch (error) {
161 |         this.logger.error(`Error handling tool "${name}":`, error);
162 |         this.logger.timing(`${name}_error`, startTime);
163 |         const errorResult = {
164 |           content: [
165 |             {
166 |               type: 'text',
167 |               text: `Error: ${error instanceof Error ? error.message : String(error)}`,
168 |             },
169 |           ],
170 |           isError: true,
171 |         };
172 | 
173 |         // Log error response in debug mode
174 |         this.logger.debug(`Error response for ${name}:`, errorResult);
175 | 
176 |         return errorResult as any;
177 |       } finally {
178 |         this.logger.methodExit(`handleToolRequest:${name}`);
179 |       }
180 |     });
181 |   }
182 | 
183 |   /**
184 |    * Start the MCP server
185 |    */
186 |   async run(): Promise<void> {
187 |     const transport = new StdioServerTransport();
188 | 
189 |     // Set up graceful shutdown
190 |     process.on('SIGINT', () => this.shutdown());
191 |     process.on('SIGTERM', () => this.shutdown());
192 | 
193 |     await this.server.connect(transport);
194 |     this.logger.log('SFCC Development MCP server running on stdio');
195 |   }
196 | 
197 |   /**
198 |    * Gracefully shutdown the server and dispose of resources
199 |    */
200 |   private async shutdown(): Promise<void> {
201 |     this.logger.log('Shutting down SFCC Development MCP server...');
202 | 
203 |     // Dispose of all handlers
204 |     await Promise.all(this.handlers.map(handler => handler.dispose()));
205 | 
206 |     this.logger.log('SFCC Development MCP server shutdown complete');
207 |     process.exit(0);
208 |   }
209 | }
210 | 
```

--------------------------------------------------------------------------------
/tests/servers/sfcc-mock-server/src/routes/ocapi/ocapi-error-utils.js:
--------------------------------------------------------------------------------

```javascript
  1 | /**
  2 |  * OCAPI Error Utilities
  3 |  * 
  4 |  * Utilities for generating SFCC-compliant error responses that match
  5 |  * the real OCAPI Data API error format and behavior.
  6 |  */
  7 | 
  8 | class OCAPIErrorUtils {
  9 |     /**
 10 |      * Create a standard SFCC fault response
 11 |      */
 12 |     static createFaultResponse(type, message, args = {}, statusCode = 400, version = "23.2") {
 13 |         return {
 14 |             response: {
 15 |                 "_v": version,
 16 |                 "fault": {
 17 |                     "arguments": args,
 18 |                     "type": type,
 19 |                     "message": message
 20 |                 }
 21 |             },
 22 |             statusCode: statusCode
 23 |         };
 24 |     }
 25 | 
 26 |     /**
 27 |      * Create ObjectTypeNotFoundException (404)
 28 |      */
 29 |     static createObjectTypeNotFound(objectType) {
 30 |         return this.createFaultResponse(
 31 |             "ObjectTypeNotFoundException",
 32 |             `No object type with ID '${objectType}' could be found.`,
 33 |             { objectType },
 34 |             404
 35 |         );
 36 |     }
 37 | 
 38 |     /**
 39 |      * Create PropertyConstraintViolationException (400)
 40 |      */
 41 |     static createPropertyConstraintViolation(path, document = "search_request") {
 42 |         return this.createFaultResponse(
 43 |             "PropertyConstraintViolationException",
 44 |             `An error occurred while decoding the request. There's a value constraint violation of property '${path}' in document '${document}'.`,
 45 |             { path, document },
 46 |             400
 47 |         );
 48 |     }
 49 | 
 50 |     /**
 51 |      * Create EnumConstraintViolationException (400)
 52 |      */
 53 |     static createEnumConstraintViolation(enumValue, document = "search_request") {
 54 |         return this.createFaultResponse(
 55 |             "EnumConstraintViolationException",
 56 |             `An error occurred while decoding the request. There's an unknown enum value '${enumValue}' in document '${document}'.`,
 57 |             { document, enumValue },
 58 |             400
 59 |         );
 60 |     }
 61 | 
 62 |     /**
 63 |      * Create InvalidRequestException (400)
 64 |      */
 65 |     static createInvalidRequest(message, field = null) {
 66 |         const args = field ? { field } : {};
 67 |         return this.createFaultResponse(
 68 |             "InvalidRequestException",
 69 |             message,
 70 |             args,
 71 |             400
 72 |         );
 73 |     }
 74 | 
 75 |     /**
 76 |      * Create AuthenticationFailedException (401)
 77 |      */
 78 |     static createAuthenticationFailed() {
 79 |         return this.createFaultResponse(
 80 |             "AuthenticationFailedException",
 81 |             "Authentication failed. Please check your credentials.",
 82 |             {},
 83 |             401
 84 |         );
 85 |     }
 86 | 
 87 |     /**
 88 |      * Create InsufficientPermissionsException (403)
 89 |      */
 90 |     static createInsufficientPermissions(permission = "access") {
 91 |         return this.createFaultResponse(
 92 |             "InsufficientPermissionsException",
 93 |             `You are not allowed to ${permission} the requested resource.`,
 94 |             { permission },
 95 |             403
 96 |         );
 97 |     }
 98 | 
 99 |     /**
100 |      * Create InternalServerException (500)
101 |      */
102 |     static createInternalServerError(details = "An unexpected error occurred.") {
103 |         return this.createFaultResponse(
104 |             "InternalServerException",
105 |             details,
106 |             {},
107 |             500
108 |         );
109 |     }
110 | 
111 |     /**
112 |      * Validate object type against known system objects
113 |      */
114 |     static validateObjectType(objectType) {
115 |         const validObjectTypes = [
116 |             'Product', 'Customer', 'Order', 'Category', 'Site', 'SitePreferences',
117 |             'CustomerGroup', 'CustomerAddress', 'Profile', 'Basket', 'OrderPaymentInstrument',
118 |             'ProductOption', 'ProductVariationAttribute', 'PriceBook', 'Campaign',
119 |             'Promotion', 'Content', 'ContentSlot', 'Folder', 'Library'
120 |         ];
121 | 
122 |         if (!validObjectTypes.includes(objectType)) {
123 |             return this.createObjectTypeNotFound(objectType);
124 |         }
125 |         return null;
126 |     }
127 | 
128 |     /**
129 |      * Validate search request structure
130 |      */
131 |     static validateSearchRequest(searchRequest) {
132 |         // Check if searchRequest exists
133 |         if (!searchRequest || typeof searchRequest !== 'object') {
134 |             return this.createPropertyConstraintViolation("$", "search_request");
135 |         }
136 | 
137 |         // Check if query exists
138 |         if (!searchRequest.query) {
139 |             return this.createPropertyConstraintViolation("$.query", "search_request");
140 |         }
141 | 
142 |         // Validate query type
143 |         const validQueryTypes = ['text_query', 'term_query', 'filtered_query', 'bool_query', 'match_all_query'];
144 |         const hasValidQuery = validQueryTypes.some(type => searchRequest.query[type]);
145 |         
146 |         if (!hasValidQuery) {
147 |             return this.createInvalidRequest(
148 |                 "Search query must contain at least one of: text_query, term_query, filtered_query, bool_query, match_all_query"
149 |             );
150 |         }
151 | 
152 |         return null;
153 |     }
154 | 
155 |     /**
156 |      * Validate pagination parameters
157 |      */
158 |     static validatePagination(start, count) {
159 |         // Validate start parameter
160 |         if (start !== undefined && start !== null) {
161 |             if (typeof start !== 'number' || start < 0) {
162 |                 return this.createInvalidRequest("start must be a positive number");
163 |             }
164 |         }
165 | 
166 |         // Validate count parameter
167 |         if (count !== undefined && count !== null) {
168 |             if (typeof count !== 'number' || count < 0) {
169 |                 return this.createPropertyConstraintViolation("$.count", "search_request");
170 |             }
171 |             if (count > 200) {
172 |                 return this.createPropertyConstraintViolation("$.count", "search_request");
173 |             }
174 |         }
175 | 
176 |         return null;
177 |     }
178 | 
179 |     /**
180 |      * Validate text_query structure
181 |      */
182 |     static validateTextQuery(textQuery) {
183 |         if (!textQuery.fields || !Array.isArray(textQuery.fields) || textQuery.fields.length === 0) {
184 |             return this.createPropertyConstraintViolation("$.query.text_query.fields", "search_request");
185 |         }
186 |         
187 |         if (!textQuery.search_phrase || typeof textQuery.search_phrase !== 'string') {
188 |             return this.createPropertyConstraintViolation("$.query.text_query.search_phrase", "search_request");
189 |         }
190 | 
191 |         return null;
192 |     }
193 | 
194 |     /**
195 |      * Validate term_query structure  
196 |      */
197 |     static validateTermQuery(termQuery) {
198 |         if (!termQuery.fields || !Array.isArray(termQuery.fields) || termQuery.fields.length === 0) {
199 |             return this.createPropertyConstraintViolation("$.query.term_query.fields", "search_request");
200 |         }
201 |         
202 |         if (!termQuery.operator || typeof termQuery.operator !== 'string') {
203 |             return this.createPropertyConstraintViolation("$.query.term_query.operator", "search_request");
204 |         }
205 | 
206 |         if (!termQuery.values || !Array.isArray(termQuery.values)) {
207 |             return this.createPropertyConstraintViolation("$.query.term_query.values", "search_request");
208 |         }
209 | 
210 |         return null;
211 |     }
212 | 
213 |     /**
214 |      * Send error response
215 |      */
216 |     static sendErrorResponse(res, errorInfo) {
217 |         res.status(errorInfo.statusCode).json(errorInfo.response);
218 |     }
219 | }
220 | 
221 | module.exports = OCAPIErrorUtils;
```

--------------------------------------------------------------------------------
/tests/mcp/yaml/get-log-file-contents.full-mode.test.mcp.yml:
--------------------------------------------------------------------------------

```yaml
  1 | ---
  2 | description: "Test get_log_file_contents tool in full mode - optimized for YAML/aegis testing"
  3 | tests:
  4 |   # === Basic Functionality ===
  5 |   - it: "should get log file contents with proper structure"
  6 |     request:
  7 |       jsonrpc: "2.0"
  8 |       id: "get-contents-basic"
  9 |       method: "tools/call"
 10 |       params:
 11 |         name: "get_log_file_contents"
 12 |         arguments:
 13 |           filename: "jobs/ImportCatalog/Job-ImportCatalog-0987654321.log"
 14 |     expect:
 15 |       response:
 16 |         jsonrpc: "2.0"
 17 |         id: "get-contents-basic"
 18 |         result:
 19 |           content: "match:arrayLength:1"
 20 |           isError: false
 21 |       stderr: "toBeEmpty"
 22 |     performance:
 23 |       maxResponseTime: "1500ms"
 24 | 
 25 |   - it: "should include essential metadata in response"
 26 |     request:
 27 |       jsonrpc: "2.0"
 28 |       id: "get-contents-metadata"
 29 |       method: "tools/call"
 30 |       params:
 31 |         name: "get_log_file_contents"
 32 |         arguments:
 33 |           filename: "jobs/ImportCatalog/Job-ImportCatalog-0987654321.log"
 34 |     expect:
 35 |       response:
 36 |         jsonrpc: "2.0"
 37 |         id: "get-contents-metadata"
 38 |         result:
 39 |           content:
 40 |             match:arrayElements:
 41 |               type: "text"
 42 |               text: "match:contains:Log File Contents:"
 43 |           isError: false
 44 |       stderr: "toBeEmpty"
 45 |     performance:
 46 |       maxResponseTime: "1500ms"
 47 | 
 48 |   - it: "should include timestamps in SFCC format"
 49 |     request:
 50 |       jsonrpc: "2.0"
 51 |       id: "get-contents-timestamps"
 52 |       method: "tools/call"
 53 |       params:
 54 |         name: "get_log_file_contents"
 55 |         arguments:
 56 |           filename: "jobs/ImportCatalog/Job-ImportCatalog-0987654321.log"
 57 |     expect:
 58 |       response:
 59 |         jsonrpc: "2.0"
 60 |         id: "get-contents-timestamps"
 61 |         result:
 62 |           content:
 63 |             match:arrayElements:
 64 |               match:partial:
 65 |                 text: "match:regex:\\[\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}\\.\\d{3} GMT\\]"
 66 |           isError: false
 67 |       stderr: "toBeEmpty"
 68 |     performance:
 69 |       maxResponseTime: "1500ms"
 70 | 
 71 |   # === Parameter Validation ===
 72 |   - it: "should work with maxBytes parameter"
 73 |     request:
 74 |       jsonrpc: "2.0"
 75 |       id: "get-contents-maxbytes"
 76 |       method: "tools/call"
 77 |       params:
 78 |         name: "get_log_file_contents"
 79 |         arguments:
 80 |           filename: "jobs/ImportCatalog/Job-ImportCatalog-0987654321.log"
 81 |           maxBytes: 500
 82 |     expect:
 83 |       response:
 84 |         jsonrpc: "2.0"
 85 |         id: "get-contents-maxbytes"
 86 |         result:
 87 |           content:
 88 |             match:arrayElements:
 89 |               type: "text"
 90 |               text: "match:contains:Content size:"
 91 |           isError: false
 92 |       stderr: "toBeEmpty"
 93 |     performance:
 94 |       maxResponseTime: "1000ms"
 95 | 
 96 |   - it: "should work with tailOnly parameter"
 97 |     request:
 98 |       jsonrpc: "2.0"
 99 |       id: "get-contents-tailonly"
100 |       method: "tools/call"
101 |       params:
102 |         name: "get_log_file_contents"
103 |         arguments:
104 |           filename: "jobs/ImportCatalog/Job-ImportCatalog-0987654321.log"
105 |           tailOnly: true
106 |           maxBytes: 200
107 |     expect:
108 |       response:
109 |         jsonrpc: "2.0"
110 |         id: "get-contents-tailonly"
111 |         result:
112 |           content:
113 |             match:arrayElements:
114 |               match:partial:
115 |                 text: "match:contains:tail read"
116 |           isError: false
117 |       stderr: "toBeEmpty"
118 |     performance:
119 |       maxResponseTime: "1000ms"
120 | 
121 |   # === Error Handling ===
122 |   - it: "should handle non-existent file gracefully"
123 |     request:
124 |       jsonrpc: "2.0"
125 |       id: "get-contents-notfound"
126 |       method: "tools/call"
127 |       params:
128 |         name: "get_log_file_contents"
129 |         arguments:
130 |           filename: "nonexistent-file.log"
131 |     expect:
132 |       response:
133 |         jsonrpc: "2.0"
134 |         id: "get-contents-notfound"
135 |         result:
136 |           content:
137 |             match:arrayElements:
138 |               match:partial:
139 |                 text: "match:contains:Failed to get_log_file_contents"
140 |           isError: false
141 |       stderr: "toBeEmpty"
142 |     performance:
143 |       maxResponseTime: "1500ms"
144 | 
145 |   - it: "should handle missing filename parameter"
146 |     request:
147 |       jsonrpc: "2.0"
148 |       id: "get-contents-missing-filename"
149 |       method: "tools/call"
150 |       params:
151 |         name: "get_log_file_contents"
152 |         arguments: {}
153 |     expect:
154 |       response:
155 |         jsonrpc: "2.0"
156 |         id: "get-contents-missing-filename"
157 |         result:
158 |           content:
159 |             match:arrayElements:
160 |               match:partial:
161 |                 text: "match:contains:filename must be a non-empty string"
162 |           isError: true
163 |       stderr: "toBeEmpty"
164 |     performance:
165 |       maxResponseTime: "800ms"
166 | 
167 |   - it: "should handle empty filename parameter"
168 |     request:
169 |       jsonrpc: "2.0"
170 |       id: "get-contents-empty-filename"
171 |       method: "tools/call"
172 |       params:
173 |         name: "get_log_file_contents"
174 |         arguments:
175 |           filename: ""
176 |     expect:
177 |       response:
178 |         jsonrpc: "2.0"
179 |         id: "get-contents-empty-filename"
180 |         result:
181 |           content:
182 |             match:arrayElements:
183 |               match:partial:
184 |                 text: "match:contains:filename must be a non-empty string"
185 |           isError: true
186 |       stderr: "toBeEmpty"
187 |     performance:
188 |       maxResponseTime: "800ms"
189 | 
190 |   - it: "should handle invalid maxBytes parameter"
191 |     request:
192 |       jsonrpc: "2.0"
193 |       id: "get-contents-invalid-maxbytes"
194 |       method: "tools/call"
195 |       params:
196 |         name: "get_log_file_contents"
197 |         arguments:
198 |           filename: "jobs/ImportCatalog/Job-ImportCatalog-0987654321.log"
199 |           maxBytes: 0
200 |     expect:
201 |       response:
202 |         jsonrpc: "2.0"
203 |         id: "get-contents-invalid-maxbytes"
204 |         result:
205 |           content:
206 |             match:arrayElements:
207 |               match:partial:
208 |                 text: "match:contains:Invalid maxBytes"
209 |           isError: true
210 |       stderr: "toBeEmpty"
211 |     performance:
212 |       maxResponseTime: "800ms"
213 | 
214 |   # === Content Structure Validation ===
215 |   - it: "should return exactly one content element"
216 |     request:
217 |       jsonrpc: "2.0"
218 |       id: "get-contents-single-element"
219 |       method: "tools/call"
220 |       params:
221 |         name: "get_log_file_contents"
222 |         arguments:
223 |           filename: "jobs/ImportCatalog/Job-ImportCatalog-0987654321.log"
224 |     expect:
225 |       response:
226 |         jsonrpc: "2.0"
227 |         id: "get-contents-single-element"
228 |         result:
229 |           content: "match:arrayLength:1"
230 |           isError: "match:type:boolean"
231 |       stderr: "toBeEmpty"
232 |     performance:
233 |       maxResponseTime: "1500ms"
234 | 
235 |   - it: "should return proper content types"
236 |     request:
237 |       jsonrpc: "2.0"
238 |       id: "get-contents-types"
239 |       method: "tools/call"
240 |       params:
241 |         name: "get_log_file_contents"
242 |         arguments:
243 |           filename: "jobs/ImportCatalog/Job-ImportCatalog-0987654321.log"
244 |     expect:
245 |       response:
246 |         jsonrpc: "2.0"
247 |         id: "get-contents-types"
248 |         result:
249 |           content:
250 |             match:arrayElements:
251 |               type: "text"
252 |               text: "match:type:string"
253 |           isError: "match:type:boolean"
254 |       stderr: "toBeEmpty"
255 |     performance:
256 |       maxResponseTime: "1500ms"
257 | 
```

--------------------------------------------------------------------------------
/src/clients/docs/documentation-scanner.ts:
--------------------------------------------------------------------------------

```typescript
  1 | /**
  2 |  * Documentation Scanner
  3 |  *
  4 |  * Responsible for scanning the documentation directory structure and
  5 |  * discovering SFCC class documentation files with security validation.
  6 |  *
  7 |  * Single Responsibility: File system operations and documentation discovery
  8 |  */
  9 | 
 10 | import fs from 'fs/promises';
 11 | import path from 'path';
 12 | import { Logger } from '../../utils/logger.js';
 13 | 
 14 | export interface SFCCClassInfo {
 15 |   className: string;
 16 |   packageName: string;
 17 |   filePath: string;
 18 |   content: string;
 19 | }
 20 | 
 21 | export class DocumentationScanner {
 22 |   private logger: Logger;
 23 | 
 24 |   constructor() {
 25 |     this.logger = Logger.getChildLogger('DocumentationScanner');
 26 |   }
 27 | 
 28 |   /**
 29 |    * Check if a directory name represents an SFCC-specific directory
 30 |    * SFCC directories include dw_ prefixed namespaces and TopLevel
 31 |    * Excludes best-practices and sfra directories
 32 |    */
 33 |   private isSFCCDirectory(directoryName: string): boolean {
 34 |     // Include dw_ prefixed directories (SFCC namespaces)
 35 |     if (directoryName.startsWith('dw_')) {
 36 |       return true;
 37 |     }
 38 | 
 39 |     // Include TopLevel directory (contains core JavaScript classes)
 40 |     if (directoryName === 'TopLevel') {
 41 |       return true;
 42 |     }
 43 | 
 44 |     // Exclude best-practices directory (handled by best practices tools)
 45 |     if (directoryName === 'best-practices') {
 46 |       return false;
 47 |     }
 48 | 
 49 |     // Exclude sfra directory (handled by SFRA tools)
 50 |     if (directoryName === 'sfra') {
 51 |       return false;
 52 |     }
 53 | 
 54 |     // Exclude any other non-SFCC directories
 55 |     return false;
 56 |   }
 57 | 
 58 |   /**
 59 |    * Validate file name for security concerns
 60 |    */
 61 |   private validateFileName(fileName: string): boolean {
 62 |     // Enhanced security validation - validate file name before path operations
 63 |     if (!fileName || typeof fileName !== 'string') {
 64 |       this.logger.warn(`Warning: Invalid file name type: ${fileName}`);
 65 |       return false;
 66 |     }
 67 | 
 68 |     // Prevent null bytes and dangerous characters in the file name itself
 69 |     if (fileName.includes('\0') || fileName.includes('\x00')) {
 70 |       this.logger.warn(`Warning: File name contains null bytes: ${fileName}`);
 71 |       return false;
 72 |     }
 73 | 
 74 |     // Prevent path traversal sequences in the file name
 75 |     if (fileName.includes('..') || fileName.includes('/') || fileName.includes('\\')) {
 76 |       this.logger.warn(`Warning: File name contains path traversal sequences: ${fileName}`);
 77 |       return false;
 78 |     }
 79 | 
 80 |     // Only allow alphanumeric characters, underscores, hyphens, and dots for file names
 81 |     if (!/^[a-zA-Z0-9_.-]+$/.test(fileName)) {
 82 |       this.logger.warn(`Warning: File name contains invalid characters: ${fileName}`);
 83 |       return false;
 84 |     }
 85 | 
 86 |     return true;
 87 |   }
 88 | 
 89 |   /**
 90 |    * Validate file path for security concerns
 91 |    */
 92 |   private validateFilePath(filePath: string, packagePath: string, docsPath: string): boolean {
 93 |     // Additional security validation - ensure the resolved path is within the package directory
 94 |     const resolvedPath = path.resolve(filePath);
 95 |     const resolvedPackagePath = path.resolve(packagePath);
 96 |     const resolvedDocsPath = path.resolve(docsPath);
 97 | 
 98 |     // Ensure the file is within the package directory and docs directory
 99 |     if (!resolvedPath.startsWith(resolvedPackagePath) || !resolvedPath.startsWith(resolvedDocsPath)) {
100 |       this.logger.warn(`Warning: File path outside allowed directory: ${filePath}`);
101 |       return false;
102 |     }
103 | 
104 |     // Ensure the file still ends with .md after path resolution
105 |     if (!resolvedPath.toLowerCase().endsWith('.md')) {
106 |       this.logger.warn(`Warning: File does not reference a markdown file: ${filePath}`);
107 |       return false;
108 |     }
109 | 
110 |     return true;
111 |   }
112 | 
113 |   /**
114 |    * Validate file content for security concerns
115 |    */
116 |   private validateFileContent(content: string, fileName: string): boolean {
117 |     // Basic content validation
118 |     if (!content.trim()) {
119 |       this.logger.warn(`Warning: Empty documentation file: ${fileName}`);
120 |       return false;
121 |     }
122 | 
123 |     // Check for binary content
124 |     if (content.includes('\0')) {
125 |       this.logger.warn(`Warning: Binary content detected in: ${fileName}`);
126 |       return false;
127 |     }
128 | 
129 |     return true;
130 |   }
131 | 
132 |   /**
133 |    * Read and validate a single documentation file
134 |    */
135 |   private async readDocumentationFile(
136 |     fileName: string,
137 |     packagePath: string,
138 |     packageName: string,
139 |     docsPath: string,
140 |   ): Promise<SFCCClassInfo | null> {
141 |     if (!this.validateFileName(fileName)) {
142 |       return null;
143 |     }
144 | 
145 |     const className = fileName.replace('.md', '');
146 |     const filePath = path.join(packagePath, fileName);
147 | 
148 |     if (!this.validateFilePath(filePath, packagePath, docsPath)) {
149 |       return null;
150 |     }
151 | 
152 |     try {
153 |       const resolvedPath = path.resolve(filePath);
154 |       const content = await fs.readFile(resolvedPath, 'utf-8');
155 | 
156 |       if (!this.validateFileContent(content, fileName)) {
157 |         return null;
158 |       }
159 | 
160 |       return {
161 |         className,
162 |         packageName,
163 |         filePath,
164 |         content,
165 |       };
166 |     } catch (fileError) {
167 |       this.logger.warn(`Warning: Could not read file ${fileName}: ${fileError}`);
168 |       return null;
169 |     }
170 |   }
171 | 
172 |   /**
173 |    * Scan a single package directory for documentation files
174 |    */
175 |   private async scanPackageDirectory(
176 |     packageName: string,
177 |     packagePath: string,
178 |     docsPath: string,
179 |   ): Promise<SFCCClassInfo[]> {
180 |     const classInfos: SFCCClassInfo[] = [];
181 | 
182 |     try {
183 |       const files = await fs.readdir(packagePath);
184 | 
185 |       for (const file of files) {
186 |         // Validate file name type and basic content before processing
187 |         if (!file || typeof file !== 'string') {
188 |           this.logger.warn(`Warning: Invalid file name type: ${file}`);
189 |           continue;
190 |         }
191 | 
192 |         if (file.endsWith('.md')) {
193 |           const classInfo = await this.readDocumentationFile(file, packagePath, packageName, docsPath);
194 |           if (classInfo) {
195 |             classInfos.push(classInfo);
196 |           }
197 |         }
198 |       }
199 |     } catch (error) {
200 |       this.logger.warn(`Warning: Could not read package ${packageName}: ${error}`);
201 |     }
202 | 
203 |     return classInfos;
204 |   }
205 | 
206 |   /**
207 |    * Scan the docs directory and index all SFCC classes
208 |    * Only scans SFCC-specific directories, excluding best-practices and sfra
209 |    */
210 |   async scanDocumentation(docsPath: string): Promise<Map<string, SFCCClassInfo>> {
211 |     const classCache = new Map<string, SFCCClassInfo>();
212 |     const packages = await fs.readdir(docsPath, { withFileTypes: true });
213 | 
214 |     for (const packageDir of packages) {
215 |       if (!packageDir.isDirectory()) {
216 |         continue;
217 |       }
218 | 
219 |       const packageName = packageDir.name;
220 | 
221 |       // Only scan SFCC-specific directories (dw_ prefixed and TopLevel)
222 |       // Exclude best-practices and sfra directories which are handled by other tools
223 |       if (!this.isSFCCDirectory(packageName)) {
224 |         continue;
225 |       }
226 | 
227 |       const packagePath = path.join(docsPath, packageName);
228 |       const classInfos = await this.scanPackageDirectory(packageName, packagePath, docsPath);
229 | 
230 |       // Add to cache with normalized keys
231 |       for (const classInfo of classInfos) {
232 |         const cacheKey = `${packageName}.${classInfo.className}`;
233 |         classCache.set(cacheKey, classInfo);
234 |       }
235 |     }
236 | 
237 |     return classCache;
238 |   }
239 | }
240 | 
```

--------------------------------------------------------------------------------
/docs/dw_catalog/SearchRefinements.md:
--------------------------------------------------------------------------------

```markdown
  1 | ## Package: dw.catalog
  2 | 
  3 | # Class SearchRefinements
  4 | 
  5 | ## Inheritance Hierarchy
  6 | 
  7 | - Object
  8 |   - dw.catalog.SearchRefinements
  9 | 
 10 | ## Description
 11 | 
 12 | Common search refinements base class.
 13 | 
 14 | ## Constants
 15 | 
 16 | ### ASCENDING
 17 | 
 18 | **Type:** Number = 0
 19 | 
 20 | Flag for an ascending sort.
 21 | 
 22 | ### DESCENDING
 23 | 
 24 | **Type:** Number = 1
 25 | 
 26 | Flag for a descending sort.
 27 | 
 28 | ### SORT_VALUE_COUNT
 29 | 
 30 | **Type:** Number = 1
 31 | 
 32 | Flag for sorting on value count.
 33 | 
 34 | ### SORT_VALUE_NAME
 35 | 
 36 | **Type:** Number = 0
 37 | 
 38 | Flag for sorting on value name.
 39 | 
 40 | ## Properties
 41 | 
 42 | ### allRefinementDefinitions
 43 | 
 44 | **Type:** Collection (Read Only)
 45 | 
 46 | A sorted list of refinement definitions that are appropriate for
 47 |  the deepest common category (or deepest common folder) of the search
 48 |  result. The method concatenates the sorted refinement definitions per
 49 |  category starting at the root category until reaching the deepest common
 50 |  category.
 51 | 
 52 |  The method does not filter out refinement definitions that do
 53 |  not provide values for the current search result and can therefore also
 54 |  be used on empty search results.
 55 | 
 56 | ### refinementDefinitions
 57 | 
 58 | **Type:** Collection (Read Only)
 59 | 
 60 | A sorted list of refinement definitions that are appropriate for
 61 |  the deepest common category (or deepest common folder) of the search
 62 |  result. The method concatenates the sorted refinement definitions per category
 63 |  starting at the root category until reaching the deepest common category.
 64 | 
 65 |  The method also filters out refinement definitions that do not provide
 66 |  any values for the current search result.
 67 | 
 68 | ## Constructor Summary
 69 | 
 70 | ## Method Summary
 71 | 
 72 | ### getAllRefinementDefinitions
 73 | 
 74 | **Signature:** `getAllRefinementDefinitions() : Collection`
 75 | 
 76 | Returns a sorted list of refinement definitions that are appropriate for the deepest common category (or deepest common folder) of the search result.
 77 | 
 78 | ### getAllRefinementValues
 79 | 
 80 | **Signature:** `getAllRefinementValues(attributeName : String) : Collection`
 81 | 
 82 | Returns a sorted collection of refinement values for the given refinement attribute.
 83 | 
 84 | ### getAllRefinementValues
 85 | 
 86 | **Signature:** `getAllRefinementValues(attributeName : String, sortMode : Number, sortDirection : Number) : Collection`
 87 | 
 88 | Returns a sorted collection of refinement values for the given refinement attribute.
 89 | 
 90 | ### getRefinementDefinitions
 91 | 
 92 | **Signature:** `getRefinementDefinitions() : Collection`
 93 | 
 94 | Returns a sorted list of refinement definitions that are appropriate for the deepest common category (or deepest common folder) of the search result.
 95 | 
 96 | ### getRefinementValues
 97 | 
 98 | **Signature:** `getRefinementValues(attributeName : String, sortMode : Number, sortDirection : Number) : Collection`
 99 | 
100 | Returns a collection of refinement values for the given refinement attribute, sorting mode and sorting direction.
101 | 
102 | ## Method Detail
103 | 
104 | ## Method Details
105 | 
106 | ### getAllRefinementDefinitions
107 | 
108 | **Signature:** `getAllRefinementDefinitions() : Collection`
109 | 
110 | **Description:** Returns a sorted list of refinement definitions that are appropriate for the deepest common category (or deepest common folder) of the search result. The method concatenates the sorted refinement definitions per category starting at the root category until reaching the deepest common category. The method does not filter out refinement definitions that do not provide values for the current search result and can therefore also be used on empty search results.
111 | 
112 | **Returns:**
113 | 
114 | A sorted list of refinement definitions appropriate for the search result (based on its deepest common category)
115 | 
116 | ---
117 | 
118 | ### getAllRefinementValues
119 | 
120 | **Signature:** `getAllRefinementValues(attributeName : String) : Collection`
121 | 
122 | **Description:** Returns a sorted collection of refinement values for the given refinement attribute. The returned collection includes all refinement values for which the hit count is greater than 0 within the search result when the passed attribute is excluded from filtering the search hits but all other refinement filters are still applied. This method is useful for rendering broadening options for attributes that the search is currently refined by. This method does NOT return refinement values independent of the search result. For product search refinements, this method may return slightly different results based on the "value set" property of the refinement definition. See ProductSearchRefinements.getAllRefinementValues(ProductSearchRefinementDefinition) for details.
123 | 
124 | **Parameters:**
125 | 
126 | - `attributeName`: The name of the attribute to return refinement values for.
127 | 
128 | **Returns:**
129 | 
130 | The collection of SearchRefinementValue instances, sorted according to the settings of the refinement definition, or null if there is no refinement definition for the passed attribute name.
131 | 
132 | ---
133 | 
134 | ### getAllRefinementValues
135 | 
136 | **Signature:** `getAllRefinementValues(attributeName : String, sortMode : Number, sortDirection : Number) : Collection`
137 | 
138 | **Description:** Returns a sorted collection of refinement values for the given refinement attribute. In general, the returned collection includes all refinement values for which hit count is greater than 0 within the search result assuming that: The passed refinement attribute is NOT used to filter the search hits. All other refinements are still applied. This is useful for rendering broadening options for the refinement definitions that the search is already refined by. It is important to note that this method does NOT return refinement values independent of the search result. For product search refinements, this method may return slightly different results based on the "value set" of the refinement definition. See ProductSearchRefinements.getAllRefinementValues(ProductSearchRefinementDefinition) for details.
139 | 
140 | **Parameters:**
141 | 
142 | - `attributeName`: The name of the attribute to return refinement values for.
143 | - `sortMode`: The sort mode to use to control how the collection is sorted.
144 | - `sortDirection`: The sort direction to use.
145 | 
146 | **Returns:**
147 | 
148 | The collection of SearchRefinementValue instances, sorted according to the passed parameters.
149 | 
150 | ---
151 | 
152 | ### getRefinementDefinitions
153 | 
154 | **Signature:** `getRefinementDefinitions() : Collection`
155 | 
156 | **Description:** Returns a sorted list of refinement definitions that are appropriate for the deepest common category (or deepest common folder) of the search result. The method concatenates the sorted refinement definitions per category starting at the root category until reaching the deepest common category. The method also filters out refinement definitions that do not provide any values for the current search result.
157 | 
158 | **Returns:**
159 | 
160 | A sorted list of refinement definitions appropriate for the search result (based on its deepest common category)
161 | 
162 | ---
163 | 
164 | ### getRefinementValues
165 | 
166 | **Signature:** `getRefinementValues(attributeName : String, sortMode : Number, sortDirection : Number) : Collection`
167 | 
168 | **Description:** Returns a collection of refinement values for the given refinement attribute, sorting mode and sorting direction.
169 | 
170 | **Parameters:**
171 | 
172 | - `attributeName`: The attribute name to use when collection refinement values.
173 | - `sortMode`: The sort mode to use to control how the collection is sorted.
174 | - `sortDirection`: The sort direction to use.
175 | 
176 | **Returns:**
177 | 
178 | The collection of refinement values.
179 | 
180 | ---
```

--------------------------------------------------------------------------------
/docs/dw_campaign/Campaign.md:
--------------------------------------------------------------------------------

```markdown
  1 | ## Package: dw.campaign
  2 | 
  3 | # Class Campaign
  4 | 
  5 | ## Inheritance Hierarchy
  6 | 
  7 | - Object
  8 |   - dw.object.PersistentObject
  9 |   - dw.object.ExtensibleObject
 10 |     - dw.campaign.Campaign
 11 | 
 12 | ## Description
 13 | 
 14 | A Campaign is a set of experiences (or site configurations) which may be deployed as a single unit for a given time frame. The system currently supports 3 types of experience that may be assigned to a campaign: Promotions Slot Configurations Sorting Rules This list may be extended in the future. A campaign can have a start and end date or be open-ended. It may also have "qualifiers" which determine which customers the campaign applies to. The currently supported qualifiers are: Customer groups (where "Everyone" is a possible customer group) Source codes Coupons A campaign can have list of stores or store groups where it can be applicable to.
 15 | 
 16 | ## Properties
 17 | 
 18 | ### active
 19 | 
 20 | **Type:** boolean (Read Only)
 21 | 
 22 | Returns 'true' if the campaign is currently active, otherwise
 23 |  'false'. 
 24 |  A campaign is active if it is enabled and scheduled for now.
 25 | 
 26 | ### applicableInStore
 27 | 
 28 | **Type:** boolean (Read Only)
 29 | 
 30 | Returns true if campaign is applicable to store, otherwise false.
 31 | 
 32 | ### applicableOnline
 33 | 
 34 | **Type:** boolean (Read Only)
 35 | 
 36 | Returns true if campaign is applicable to online site, otherwise false.
 37 | 
 38 | ### coupons
 39 | 
 40 | **Type:** Collection (Read Only)
 41 | 
 42 | The coupons assigned to the campaign.
 43 | 
 44 | ### customerGroups
 45 | 
 46 | **Type:** Collection (Read Only)
 47 | 
 48 | The customer groups assigned to the campaign.
 49 | 
 50 | ### description
 51 | 
 52 | **Type:** String (Read Only)
 53 | 
 54 | The internal description of the campaign.
 55 | 
 56 | ### enabled
 57 | 
 58 | **Type:** boolean (Read Only)
 59 | 
 60 | Returns true if campaign is enabled, otherwise false.
 61 | 
 62 | ### endDate
 63 | 
 64 | **Type:** Date (Read Only)
 65 | 
 66 | The end date of the campaign. If no end date is defined for the
 67 |  campaign, null is returned. A campaign w/o end date will run forever.
 68 | 
 69 | ### ID
 70 | 
 71 | **Type:** String (Read Only)
 72 | 
 73 | The unique campaign ID.
 74 | 
 75 | ### promotions
 76 | 
 77 | **Type:** Collection (Read Only)
 78 | 
 79 | Returns promotions defined in this campaign in no particular order.
 80 | 
 81 | ### sourceCodeGroups
 82 | 
 83 | **Type:** Collection (Read Only)
 84 | 
 85 | The source codes assigned to the campaign.
 86 | 
 87 | ### startDate
 88 | 
 89 | **Type:** Date (Read Only)
 90 | 
 91 | The start date of the campaign. If no start date is defined for the
 92 |  campaign, null is returned. A campaign w/o start date is immediately
 93 |  effective.
 94 | 
 95 | ### storeGroups
 96 | 
 97 | **Type:** Collection (Read Only)
 98 | 
 99 | Returns store groups assigned to the campaign.
100 | 
101 | ### stores
102 | 
103 | **Type:** Collection (Read Only)
104 | 
105 | Returns stores assigned to the campaign.
106 | 
107 | ## Constructor Summary
108 | 
109 | ## Method Summary
110 | 
111 | ### getCoupons
112 | 
113 | **Signature:** `getCoupons() : Collection`
114 | 
115 | Returns the coupons assigned to the campaign.
116 | 
117 | ### getCustomerGroups
118 | 
119 | **Signature:** `getCustomerGroups() : Collection`
120 | 
121 | Returns the customer groups assigned to the campaign.
122 | 
123 | ### getDescription
124 | 
125 | **Signature:** `getDescription() : String`
126 | 
127 | Returns the internal description of the campaign.
128 | 
129 | ### getEndDate
130 | 
131 | **Signature:** `getEndDate() : Date`
132 | 
133 | Returns the end date of the campaign.
134 | 
135 | ### getID
136 | 
137 | **Signature:** `getID() : String`
138 | 
139 | Returns the unique campaign ID.
140 | 
141 | ### getPromotions
142 | 
143 | **Signature:** `getPromotions() : Collection`
144 | 
145 | Returns promotions defined in this campaign in no particular order.
146 | 
147 | ### getSourceCodeGroups
148 | 
149 | **Signature:** `getSourceCodeGroups() : Collection`
150 | 
151 | Returns the source codes assigned to the campaign.
152 | 
153 | ### getStartDate
154 | 
155 | **Signature:** `getStartDate() : Date`
156 | 
157 | Returns the start date of the campaign.
158 | 
159 | ### getStoreGroups
160 | 
161 | **Signature:** `getStoreGroups() : Collection`
162 | 
163 | Returns store groups assigned to the campaign.
164 | 
165 | ### getStores
166 | 
167 | **Signature:** `getStores() : Collection`
168 | 
169 | Returns stores assigned to the campaign.
170 | 
171 | ### isActive
172 | 
173 | **Signature:** `isActive() : boolean`
174 | 
175 | Returns 'true' if the campaign is currently active, otherwise 'false'.
176 | 
177 | ### isApplicableInStore
178 | 
179 | **Signature:** `isApplicableInStore() : boolean`
180 | 
181 | Returns true if campaign is applicable to store, otherwise false.
182 | 
183 | ### isApplicableOnline
184 | 
185 | **Signature:** `isApplicableOnline() : boolean`
186 | 
187 | Returns true if campaign is applicable to online site, otherwise false.
188 | 
189 | ### isEnabled
190 | 
191 | **Signature:** `isEnabled() : boolean`
192 | 
193 | Returns true if campaign is enabled, otherwise false.
194 | 
195 | ## Method Detail
196 | 
197 | ## Method Details
198 | 
199 | ### getCoupons
200 | 
201 | **Signature:** `getCoupons() : Collection`
202 | 
203 | **Description:** Returns the coupons assigned to the campaign.
204 | 
205 | **Returns:**
206 | 
207 | All coupons assigned to the campaign.
208 | 
209 | ---
210 | 
211 | ### getCustomerGroups
212 | 
213 | **Signature:** `getCustomerGroups() : Collection`
214 | 
215 | **Description:** Returns the customer groups assigned to the campaign.
216 | 
217 | **Returns:**
218 | 
219 | Customer groups assigned to campaign.
220 | 
221 | ---
222 | 
223 | ### getDescription
224 | 
225 | **Signature:** `getDescription() : String`
226 | 
227 | **Description:** Returns the internal description of the campaign.
228 | 
229 | **Returns:**
230 | 
231 | Internal description of campaign.
232 | 
233 | ---
234 | 
235 | ### getEndDate
236 | 
237 | **Signature:** `getEndDate() : Date`
238 | 
239 | **Description:** Returns the end date of the campaign. If no end date is defined for the campaign, null is returned. A campaign w/o end date will run forever.
240 | 
241 | **Returns:**
242 | 
243 | End date of campaign.
244 | 
245 | ---
246 | 
247 | ### getID
248 | 
249 | **Signature:** `getID() : String`
250 | 
251 | **Description:** Returns the unique campaign ID.
252 | 
253 | **Returns:**
254 | 
255 | ID of the campaign.
256 | 
257 | ---
258 | 
259 | ### getPromotions
260 | 
261 | **Signature:** `getPromotions() : Collection`
262 | 
263 | **Description:** Returns promotions defined in this campaign in no particular order.
264 | 
265 | **Returns:**
266 | 
267 | All promotions defined in campaign.
268 | 
269 | ---
270 | 
271 | ### getSourceCodeGroups
272 | 
273 | **Signature:** `getSourceCodeGroups() : Collection`
274 | 
275 | **Description:** Returns the source codes assigned to the campaign.
276 | 
277 | **Returns:**
278 | 
279 | All source code groups assigned to campaign.
280 | 
281 | ---
282 | 
283 | ### getStartDate
284 | 
285 | **Signature:** `getStartDate() : Date`
286 | 
287 | **Description:** Returns the start date of the campaign. If no start date is defined for the campaign, null is returned. A campaign w/o start date is immediately effective.
288 | 
289 | **Returns:**
290 | 
291 | Start date of campaign.
292 | 
293 | ---
294 | 
295 | ### getStoreGroups
296 | 
297 | **Signature:** `getStoreGroups() : Collection`
298 | 
299 | **Description:** Returns store groups assigned to the campaign.
300 | 
301 | **Returns:**
302 | 
303 | All store groups assigned to the campaign.
304 | 
305 | ---
306 | 
307 | ### getStores
308 | 
309 | **Signature:** `getStores() : Collection`
310 | 
311 | **Description:** Returns stores assigned to the campaign.
312 | 
313 | **Returns:**
314 | 
315 | All stores assigned to the campaign.
316 | 
317 | ---
318 | 
319 | ### isActive
320 | 
321 | **Signature:** `isActive() : boolean`
322 | 
323 | **Description:** Returns 'true' if the campaign is currently active, otherwise 'false'. A campaign is active if it is enabled and scheduled for now.
324 | 
325 | **Returns:**
326 | 
327 | true of campaign is active, otherwise false.
328 | 
329 | ---
330 | 
331 | ### isApplicableInStore
332 | 
333 | **Signature:** `isApplicableInStore() : boolean`
334 | 
335 | **Description:** Returns true if campaign is applicable to store, otherwise false.
336 | 
337 | **Returns:**
338 | 
339 | true if campaign is applicable to store, otherwise false.
340 | 
341 | ---
342 | 
343 | ### isApplicableOnline
344 | 
345 | **Signature:** `isApplicableOnline() : boolean`
346 | 
347 | **Description:** Returns true if campaign is applicable to online site, otherwise false.
348 | 
349 | **Returns:**
350 | 
351 | true if campaign is applicable to online site, otherwise false.
352 | 
353 | ---
354 | 
355 | ### isEnabled
356 | 
357 | **Signature:** `isEnabled() : boolean`
358 | 
359 | **Description:** Returns true if campaign is enabled, otherwise false.
360 | 
361 | **Returns:**
362 | 
363 | true if campaign is enabled, otherwise false.
364 | 
365 | ---
```

--------------------------------------------------------------------------------
/docs/dw_order/ProductShippingLineItem.md:
--------------------------------------------------------------------------------

```markdown
  1 | ## Package: dw.order
  2 | 
  3 | # Class ProductShippingLineItem
  4 | 
  5 | ## Inheritance Hierarchy
  6 | 
  7 | - Object
  8 |   - dw.object.PersistentObject
  9 |   - dw.object.ExtensibleObject
 10 |     - dw.order.LineItem
 11 |       - dw.order.ProductShippingLineItem
 12 | 
 13 | ## Description
 14 | 
 15 | Represents a specific line item in a shipment. A ProductShippingLineItem defines lineitem-specific shipping costs.
 16 | 
 17 | ## Constants
 18 | 
 19 | ### PRODUCT_SHIPPING_ID
 20 | 
 21 | **Type:** String = "PRODUCT_SHIPPING"
 22 | 
 23 | Reserved constant.
 24 | 
 25 | ## Properties
 26 | 
 27 | ### adjustedGrossPrice
 28 | 
 29 | **Type:** Money (Read Only)
 30 | 
 31 | The gross price of the product shipping line item after applying
 32 |  all product-shipping-level adjustments.
 33 | 
 34 | ### adjustedNetPrice
 35 | 
 36 | **Type:** Money (Read Only)
 37 | 
 38 | The net price of the product shipping line item after applying
 39 |  all product-shipping-level adjustments.
 40 | 
 41 | ### adjustedPrice
 42 | 
 43 | **Type:** Money (Read Only)
 44 | 
 45 | The price of the product shipping line item after applying all
 46 |  pproduct-shipping-level adjustments. For net pricing the adjusted net
 47 |  price is returned (see getAdjustedNetPrice()). For gross
 48 |  pricing, the adjusted gross price is returned (see
 49 |  getAdjustedGrossPrice()).
 50 | 
 51 | ### adjustedTax
 52 | 
 53 | **Type:** Money (Read Only)
 54 | 
 55 | The tax of the unit after applying adjustments, in the purchase
 56 |  currency.
 57 | 
 58 | ### priceAdjustments
 59 | 
 60 | **Type:** Collection (Read Only)
 61 | 
 62 | An iterator of price adjustments that have been applied to this
 63 |  product shipping line item.
 64 | 
 65 | ### productLineItem
 66 | 
 67 | **Type:** ProductLineItem (Read Only)
 68 | 
 69 | The parent product line item this shipping line item belongs to.
 70 | 
 71 | ### quantity
 72 | 
 73 | **Type:** Quantity
 74 | 
 75 | The quantity of the shipping cost.
 76 | 
 77 | ### shipment
 78 | 
 79 | **Type:** Shipment (Read Only)
 80 | 
 81 | The shipment this shipping line item belongs to.
 82 | 
 83 | ### surcharge
 84 | 
 85 | **Type:** boolean
 86 | 
 87 | The 'surcharge' flag.
 88 | 
 89 | ## Constructor Summary
 90 | 
 91 | ## Method Summary
 92 | 
 93 | ### getAdjustedGrossPrice
 94 | 
 95 | **Signature:** `getAdjustedGrossPrice() : Money`
 96 | 
 97 | Returns the gross price of the product shipping line item after applying all product-shipping-level adjustments.
 98 | 
 99 | ### getAdjustedNetPrice
100 | 
101 | **Signature:** `getAdjustedNetPrice() : Money`
102 | 
103 | Returns the net price of the product shipping line item after applying all product-shipping-level adjustments.
104 | 
105 | ### getAdjustedPrice
106 | 
107 | **Signature:** `getAdjustedPrice() : Money`
108 | 
109 | Returns the price of the product shipping line item after applying all pproduct-shipping-level adjustments.
110 | 
111 | ### getAdjustedTax
112 | 
113 | **Signature:** `getAdjustedTax() : Money`
114 | 
115 | Returns the tax of the unit after applying adjustments, in the purchase currency.
116 | 
117 | ### getPriceAdjustments
118 | 
119 | **Signature:** `getPriceAdjustments() : Collection`
120 | 
121 | Returns an iterator of price adjustments that have been applied to this product shipping line item.
122 | 
123 | ### getProductLineItem
124 | 
125 | **Signature:** `getProductLineItem() : ProductLineItem`
126 | 
127 | Returns the parent product line item this shipping line item belongs to.
128 | 
129 | ### getQuantity
130 | 
131 | **Signature:** `getQuantity() : Quantity`
132 | 
133 | Returns the quantity of the shipping cost.
134 | 
135 | ### getShipment
136 | 
137 | **Signature:** `getShipment() : Shipment`
138 | 
139 | Returns the shipment this shipping line item belongs to.
140 | 
141 | ### isSurcharge
142 | 
143 | **Signature:** `isSurcharge() : boolean`
144 | 
145 | Returns the 'surcharge' flag.
146 | 
147 | ### setPriceValue
148 | 
149 | **Signature:** `setPriceValue(value : Number) : void`
150 | 
151 | Sets price attributes of the line item based on the purchase currency, taxation policy and line item quantity. The method sets the 'basePrice' attribute of the line item.
152 | 
153 | ### setQuantity
154 | 
155 | **Signature:** `setQuantity(quantity : Quantity) : void`
156 | 
157 | Sets the quantity of the shipping cost.
158 | 
159 | ### setSurcharge
160 | 
161 | **Signature:** `setSurcharge(flag : boolean) : void`
162 | 
163 | Sets the 'surcharge' flag.
164 | 
165 | ## Method Detail
166 | 
167 | ## Method Details
168 | 
169 | ### getAdjustedGrossPrice
170 | 
171 | **Signature:** `getAdjustedGrossPrice() : Money`
172 | 
173 | **Description:** Returns the gross price of the product shipping line item after applying all product-shipping-level adjustments.
174 | 
175 | **Returns:**
176 | 
177 | gross price after applying product-shipping-level adjustments
178 | 
179 | **See Also:**
180 | 
181 | getAdjustedNetPrice()
182 | getAdjustedPrice()
183 | 
184 | ---
185 | 
186 | ### getAdjustedNetPrice
187 | 
188 | **Signature:** `getAdjustedNetPrice() : Money`
189 | 
190 | **Description:** Returns the net price of the product shipping line item after applying all product-shipping-level adjustments.
191 | 
192 | **Returns:**
193 | 
194 | net price after applying product-shipping-level adjustments
195 | 
196 | **See Also:**
197 | 
198 | getAdjustedGrossPrice()
199 | getAdjustedPrice()
200 | 
201 | ---
202 | 
203 | ### getAdjustedPrice
204 | 
205 | **Signature:** `getAdjustedPrice() : Money`
206 | 
207 | **Description:** Returns the price of the product shipping line item after applying all pproduct-shipping-level adjustments. For net pricing the adjusted net price is returned (see getAdjustedNetPrice()). For gross pricing, the adjusted gross price is returned (see getAdjustedGrossPrice()).
208 | 
209 | **Returns:**
210 | 
211 | Adjusted net or gross price
212 | 
213 | **See Also:**
214 | 
215 | getAdjustedGrossPrice()
216 | getAdjustedNetPrice()
217 | 
218 | ---
219 | 
220 | ### getAdjustedTax
221 | 
222 | **Signature:** `getAdjustedTax() : Money`
223 | 
224 | **Description:** Returns the tax of the unit after applying adjustments, in the purchase currency.
225 | 
226 | **Returns:**
227 | 
228 | the tax of the unit after applying adjustments, in the purchase currency.
229 | 
230 | ---
231 | 
232 | ### getPriceAdjustments
233 | 
234 | **Signature:** `getPriceAdjustments() : Collection`
235 | 
236 | **Description:** Returns an iterator of price adjustments that have been applied to this product shipping line item.
237 | 
238 | **Returns:**
239 | 
240 | a collection of price adjustments that have been applied to this product shipping line item.
241 | 
242 | ---
243 | 
244 | ### getProductLineItem
245 | 
246 | **Signature:** `getProductLineItem() : ProductLineItem`
247 | 
248 | **Description:** Returns the parent product line item this shipping line item belongs to.
249 | 
250 | **Returns:**
251 | 
252 | the product line item
253 | 
254 | ---
255 | 
256 | ### getQuantity
257 | 
258 | **Signature:** `getQuantity() : Quantity`
259 | 
260 | **Description:** Returns the quantity of the shipping cost.
261 | 
262 | **Returns:**
263 | 
264 | the shipping quantity
265 | 
266 | ---
267 | 
268 | ### getShipment
269 | 
270 | **Signature:** `getShipment() : Shipment`
271 | 
272 | **Description:** Returns the shipment this shipping line item belongs to.
273 | 
274 | **Returns:**
275 | 
276 | the shipment
277 | 
278 | ---
279 | 
280 | ### isSurcharge
281 | 
282 | **Signature:** `isSurcharge() : boolean`
283 | 
284 | **Description:** Returns the 'surcharge' flag.
285 | 
286 | **Returns:**
287 | 
288 | true if this is a surcharge shipping cost, false if fixed shipping cost
289 | 
290 | ---
291 | 
292 | ### setPriceValue
293 | 
294 | **Signature:** `setPriceValue(value : Number) : void`
295 | 
296 | **Description:** Sets price attributes of the line item based on the purchase currency, taxation policy and line item quantity. The method sets the 'basePrice' attribute of the line item. Additionally, it sets the 'netPrice' attribute of the line item if the current taxation policy is 'net', and the 'grossPrice' attribute, if the current taxation policy is 'gross'. The 'netPrice'/'grossPrice' attributes are set by multiplying the specified price value with the line item quantity. If null is specified as value, the price attributes are reset to Money.NA.
297 | 
298 | **Parameters:**
299 | 
300 | - `value`: Price value or null
301 | 
302 | ---
303 | 
304 | ### setQuantity
305 | 
306 | **Signature:** `setQuantity(quantity : Quantity) : void`
307 | 
308 | **Description:** Sets the quantity of the shipping cost.
309 | 
310 | **Parameters:**
311 | 
312 | - `quantity`: the shipping quantity
313 | 
314 | ---
315 | 
316 | ### setSurcharge
317 | 
318 | **Signature:** `setSurcharge(flag : boolean) : void`
319 | 
320 | **Description:** Sets the 'surcharge' flag.
321 | 
322 | **Parameters:**
323 | 
324 | - `flag`: true if this is a surcharge shipping cost, false if this is a fixed shipping cost.
325 | 
326 | ---
```

--------------------------------------------------------------------------------
/docs/sfra/product-search.md:
--------------------------------------------------------------------------------

```markdown
  1 | # SFRA Product Search Model
  2 | 
  3 | ## Overview
  4 | 
  5 | The Product Search model represents search functionality in SFRA applications, providing comprehensive search results, refinements, sorting options, and pagination for product discovery and catalog browsing.
  6 | 
  7 | ## Constructor
  8 | 
  9 | ```javascript
 10 | function ProductSearch(productSearch, httpParams, sortingRule, sortingOptions, rootCategory)
 11 | ```
 12 | 
 13 | Creates a Product Search model instance with search results and related functionality.
 14 | 
 15 | ### Parameters
 16 | 
 17 | - `productSearch` (dw.catalog.ProductSearchModel) - Product search object from the API
 18 | - `httpParams` (Object) - HTTP query parameters including search terms and refinements
 19 | - `sortingRule` (string) - Current sorting rule being applied
 20 | - `sortingOptions` (dw.util.ArrayList<dw.catalog.SortingOption>) - Options to sort search results
 21 | - `rootCategory` (dw.catalog.Category) - Search result's root category if applicable
 22 | 
 23 | ## Properties
 24 | 
 25 | ### searchKeywords
 26 | **Type:** string
 27 | 
 28 | The search keywords entered by the user.
 29 | 
 30 | ### category
 31 | **Type:** Object | null
 32 | 
 33 | Current category information if this is a category-based search.
 34 | 
 35 | ### productIds
 36 | **Type:** Array<Object>
 37 | 
 38 | Array of product information objects with `productID` and `productSearchHit` properties for search results.
 39 | 
 40 | ### products
 41 | **Type:** Array<Object>
 42 | 
 43 | Array of product tile models for the search results. **Note:** This property is not directly set by the constructor but would be populated by calling code using the `productIds` array.
 44 | 
 45 | ### pageNumber
 46 | **Type:** number
 47 | 
 48 | Current page number for pagination (1-based).
 49 | 
 50 | ### pageSize
 51 | **Type:** number
 52 | 
 53 | Number of products displayed per page (from httpParams.sz or default).
 54 | 
 55 | ### count
 56 | **Type:** number
 57 | 
 58 | Total number of products found matching the search criteria.
 59 | 
 60 | ### isCategorySearch
 61 | **Type:** boolean
 62 | 
 63 | Indicates whether this is a category-based search.
 64 | 
 65 | ### isRefinedCategorySearch
 66 | **Type:** boolean
 67 | 
 68 | Indicates whether this is a refined category search.
 69 | 
 70 | ### resetLink
 71 | **Type:** string
 72 | 
 73 | URL to reset all search refinements (AJAX endpoint).
 74 | 
 75 | ### resetLinkSeo
 76 | **Type:** string
 77 | 
 78 | SEO-friendly URL to reset all search refinements.
 79 | 
 80 | ### refinements
 81 | **Type:** Array<Object> (computed property)
 82 | 
 83 | Array of available search refinements including:
 84 | - `displayName` - Human-readable refinement name
 85 | - `isCategoryRefinement` - Boolean flag for category refinements
 86 | - `isAttributeRefinement` - Boolean flag for attribute refinements
 87 | - `isPriceRefinement` - Boolean flag for price refinements
 88 | - `isPromotionRefinement` - Boolean flag for promotion refinements
 89 | - `values` - Array of refinement value objects
 90 | 
 91 | ### selectedFilters
 92 | **Type:** Array<Object> (computed property)
 93 | 
 94 | Array of currently applied refinements extracted from the refinements.
 95 | 
 96 | ### productSort
 97 | **Type:** ProductSortOptions
 98 | 
 99 | Available sorting options for the search results (ProductSortOptions model instance).
100 | 
101 | ### bannerImageUrl
102 | **Type:** string | null
103 | 
104 | URL for category banner image (null if not available).
105 | 
106 | ### showMoreUrl
107 | **Type:** string
108 | 
109 | URL to load more search results (for infinite scroll or "show more" functionality).
110 | 
111 | ### permalink
112 | **Type:** string
113 | 
114 | Permalink URL for the current search with filters and pagination preserved.
115 | 
116 | ### isSearchSuggestionsAvailable
117 | **Type:** boolean
118 | 
119 | Indicates whether search suggestions are available for the current search.
120 | 
121 | ### suggestionPhrases
122 | **Type:** Array<Object>
123 | 
124 | Array of suggested search phrases with `value` and `url` properties (only available when `isSearchSuggestionsAvailable` is true).
125 | 
126 | ### category
127 | **Type:** Object | null
128 | 
129 | Current category information if this is a category-based search, including:
130 | - `name` - Category display name
131 | - `id` - Category ID
132 | - `pageTitle` - Category page title
133 | - `pageDescription` - Category page description  
134 | - `pageKeywords` - Category page keywords
135 | 
136 | ### pageMetaTags
137 | **Type:** Object
138 | 
139 | Page meta tags for SEO purposes.
140 | 
141 | ## Helper Functions
142 | 
143 | ### getResetLink(search, httpParams, actionEndpoint)
144 | Generates URL to remove all refinements and reset search criteria.
145 | 
146 | **Parameters:**
147 | - `search` (dw.catalog.ProductSearchModel) - Product search object
148 | - `httpParams` (Object) - Query parameters
149 | - `actionEndpoint` (string) - Action endpoint to use
150 | 
151 | **Returns:** string - URL to reset search refinements
152 | 
153 | ### getRefinements(productSearch, refinements, refinementDefinitions)
154 | Retrieves and formats search refinements for display.
155 | 
156 | **Parameters:**
157 | - `productSearch` (dw.catalog.ProductSearchModel) - Product search object
158 | - `refinements` (dw.catalog.ProductSearchRefinements) - Search refinements
159 | - `refinementDefinitions` (ArrayList) - Refinement definitions
160 | 
161 | **Returns:** Array<Object> - Formatted refinement objects
162 | 
163 | ## Usage Example
164 | 
165 | ```javascript
166 | var ProductSearch = require('*/cartridge/models/search/productSearch');
167 | 
168 | // From search controller
169 | var productSearch = new ProductSearch(
170 |     apiProductSearch,
171 |     req.querystring,
172 |     sortingRule,
173 |     sortingOptions,
174 |     rootCategory
175 | );
176 | 
177 | // Access search results
178 | console.log('Found ' + productSearch.count + ' products');
179 | console.log('Search term: ' + productSearch.searchKeywords);
180 | 
181 | // Display product IDs (products would be populated separately)
182 | productSearch.productIds.forEach(function(item) {
183 |     console.log('Product ID: ' + item.productID);
184 | });
185 | 
186 | // Handle refinements
187 | productSearch.refinements.forEach(function(refinement) {
188 |     console.log(refinement.displayName + ':');
189 |     refinement.values.forEach(function(value) {
190 |         console.log('  ' + value.displayValue + ' (' + value.hitCount + ')');
191 |     });
192 | });
193 | 
194 | // Pagination
195 | console.log('Page ' + productSearch.pageNumber + ', showing ' + productSearch.pageSize + ' items');
196 | 
197 | // Check for search suggestions
198 | if (productSearch.isSearchSuggestionsAvailable) {
199 |     productSearch.suggestionPhrases.forEach(function(phrase) {
200 |         console.log('Suggested: ' + phrase.value);
201 |     });
202 | }
203 | ```
204 | 
205 | ## Search Types
206 | 
207 | ### Keyword Search
208 | - Based on search terms entered by users
209 | - Full-text search across product attributes
210 | - Includes search suggestions and spell correction
211 | 
212 | ### Category Search  
213 | - Browse products within specific categories
214 | - Maintains category hierarchy navigation
215 | - Category-specific refinements and sorting
216 | 
217 | ### Refined Search
218 | - Apply filters to narrow results
219 | - Multiple refinement types (price, attributes, categories)
220 | - Combinable refinements with removal options
221 | 
222 | ## Refinement Types
223 | 
224 | The model supports various refinement types:
225 | - **Category Refinements** - Filter by product categories
226 | - **Attribute Refinements** - Filter by product attributes (color, size, brand)
227 | - **Price Refinements** - Filter by price ranges
228 | - **Promotion Refinements** - Filter by promotional offers
229 | 
230 | ## Notes
231 | 
232 | - Provides comprehensive search functionality for SFRA storefronts
233 | - Handles both keyword and category-based searches
234 | - Includes pagination support with configurable page sizes
235 | - Supports multiple refinement types with hit counts
236 | - Integrates with product tile models for consistent display
237 | - Includes sorting options and search result optimization
238 | - Provides URLs for search refinement and reset functionality
239 | 
240 | ## Related Models
241 | 
242 | - **ProductSortOptions** - Used for search result sorting
243 | - **Product Tile Model** - Used for individual product display
244 | - **Categories Model** - Used for category-based searches
245 | - **Refinement Models** - Used for search filtering
246 | 
```

--------------------------------------------------------------------------------
/docs/dw_util/Locale.md:
--------------------------------------------------------------------------------

```markdown
  1 | ## Package: dw.util
  2 | 
  3 | # Class Locale
  4 | 
  5 | ## Inheritance Hierarchy
  6 | 
  7 | - Object
  8 |   - dw.util.Locale
  9 | 
 10 | ## Description
 11 | 
 12 | Represents a Locale supported by the system.
 13 | 
 14 | ## Properties
 15 | 
 16 | ### country
 17 | 
 18 | **Type:** String (Read Only)
 19 | 
 20 | The uppercase ISO 3166 2-letter country/region code for this Locale.
 21 |  If no country has been specified for this Locale, this value is an empty string.
 22 | 
 23 | ### displayCountry
 24 | 
 25 | **Type:** String (Read Only)
 26 | 
 27 | The display name of this Locale's country, in this Locale's language,
 28 |  not in the session locale's language.
 29 |  If no country has been specified for this Locale, this value is an empty string.
 30 | 
 31 | ### displayLanguage
 32 | 
 33 | **Type:** String (Read Only)
 34 | 
 35 | The display name of this Locale's language, in this Locale's language,
 36 |  not in the session locale's language.
 37 |  If no country has been specified for this Locale, this value is an empty string.
 38 | 
 39 | ### displayName
 40 | 
 41 | **Type:** String (Read Only)
 42 | 
 43 | The display name of this Locale, in this Locale's language,
 44 |  not in the session locale's language.
 45 |  If no display name has been specified for this Locale, this value is an empty string.
 46 | 
 47 | ### ID
 48 | 
 49 | **Type:** String (Read Only)
 50 | 
 51 | The String representation of the localeID.
 52 |  
 53 |  Combines the language and the country key, concatenated with "_". 
 54 |  For example: "en_US". This attribute is the primary key of the class.
 55 | 
 56 | ### ISO3Country
 57 | 
 58 | **Type:** String (Read Only)
 59 | 
 60 | The uppercase ISO 3166 3-letter country/region code for this Locale.
 61 |  If no country has been specified for this Locale, this value is an empty string.
 62 | 
 63 | ### ISO3Language
 64 | 
 65 | **Type:** String (Read Only)
 66 | 
 67 | The 3-letter ISO 639 language code for this Locale.
 68 |  If no language has been specified for this Locale, this value is an empty string.
 69 | 
 70 | ### language
 71 | 
 72 | **Type:** String (Read Only)
 73 | 
 74 | The lowercase ISO 639 language code for this Locale.
 75 |  If no language has been specified for this Locale, this value is an empty string.
 76 | 
 77 | ## Constructor Summary
 78 | 
 79 | ## Method Summary
 80 | 
 81 | ### getCountry
 82 | 
 83 | **Signature:** `getCountry() : String`
 84 | 
 85 | Returns the uppercase ISO 3166 2-letter country/region code for this Locale.
 86 | 
 87 | ### getDisplayCountry
 88 | 
 89 | **Signature:** `getDisplayCountry() : String`
 90 | 
 91 | Returns the display name of this Locale's country, in this Locale's language, not in the session locale's language.
 92 | 
 93 | ### getDisplayLanguage
 94 | 
 95 | **Signature:** `getDisplayLanguage() : String`
 96 | 
 97 | Returns the display name of this Locale's language, in this Locale's language, not in the session locale's language.
 98 | 
 99 | ### getDisplayName
100 | 
101 | **Signature:** `getDisplayName() : String`
102 | 
103 | Returns the display name of this Locale, in this Locale's language, not in the session locale's language.
104 | 
105 | ### getID
106 | 
107 | **Signature:** `getID() : String`
108 | 
109 | Returns the String representation of the localeID.
110 | 
111 | ### getISO3Country
112 | 
113 | **Signature:** `getISO3Country() : String`
114 | 
115 | Returns the uppercase ISO 3166 3-letter country/region code for this Locale.
116 | 
117 | ### getISO3Language
118 | 
119 | **Signature:** `getISO3Language() : String`
120 | 
121 | Returns the 3-letter ISO 639 language code for this Locale.
122 | 
123 | ### getLanguage
124 | 
125 | **Signature:** `getLanguage() : String`
126 | 
127 | Returns the lowercase ISO 639 language code for this Locale.
128 | 
129 | ### getLocale
130 | 
131 | **Signature:** `static getLocale(localeId : String) : Locale`
132 | 
133 | Returns a Locale instance for the given localeId, or null if no such Locale could be found.
134 | 
135 | ### toString
136 | 
137 | **Signature:** `toString() : String`
138 | 
139 | Returns the String representation of the localeID.
140 | 
141 | ## Method Detail
142 | 
143 | ## Method Details
144 | 
145 | ### getCountry
146 | 
147 | **Signature:** `getCountry() : String`
148 | 
149 | **Description:** Returns the uppercase ISO 3166 2-letter country/region code for this Locale. If no country has been specified for this Locale, this value is an empty string.
150 | 
151 | **Returns:**
152 | 
153 | the uppercase ISO 3166 2-letter country/region code for this Locale. If no country has been specified for this Locale, this value is an empty string.
154 | 
155 | ---
156 | 
157 | ### getDisplayCountry
158 | 
159 | **Signature:** `getDisplayCountry() : String`
160 | 
161 | **Description:** Returns the display name of this Locale's country, in this Locale's language, not in the session locale's language. If no country has been specified for this Locale, this value is an empty string.
162 | 
163 | **Returns:**
164 | 
165 | the display name of this Locale's country, in this Locale's language. If no country has been specified for this Locale, this value is an empty string.
166 | 
167 | ---
168 | 
169 | ### getDisplayLanguage
170 | 
171 | **Signature:** `getDisplayLanguage() : String`
172 | 
173 | **Description:** Returns the display name of this Locale's language, in this Locale's language, not in the session locale's language. If no country has been specified for this Locale, this value is an empty string.
174 | 
175 | **Returns:**
176 | 
177 | the display name of this Locale's language, in this Locale's language. If no language has been specified for this Locale, this value is an empty string.
178 | 
179 | ---
180 | 
181 | ### getDisplayName
182 | 
183 | **Signature:** `getDisplayName() : String`
184 | 
185 | **Description:** Returns the display name of this Locale, in this Locale's language, not in the session locale's language. If no display name has been specified for this Locale, this value is an empty string.
186 | 
187 | **Returns:**
188 | 
189 | the display name of this Locale, in this Locale's language. If no display name has been specified for this Locale, this value is an empty string.
190 | 
191 | ---
192 | 
193 | ### getID
194 | 
195 | **Signature:** `getID() : String`
196 | 
197 | **Description:** Returns the String representation of the localeID. Combines the language and the country key, concatenated with "_". For example: "en_US". This attribute is the primary key of the class.
198 | 
199 | **Returns:**
200 | 
201 | the String representation of the localeID.
202 | 
203 | ---
204 | 
205 | ### getISO3Country
206 | 
207 | **Signature:** `getISO3Country() : String`
208 | 
209 | **Description:** Returns the uppercase ISO 3166 3-letter country/region code for this Locale. If no country has been specified for this Locale, this value is an empty string.
210 | 
211 | **Returns:**
212 | 
213 | the uppercase ISO 3166 3-letter country/region code for this Locale. If no country has been specified for this Locale, this value is an empty string.
214 | 
215 | ---
216 | 
217 | ### getISO3Language
218 | 
219 | **Signature:** `getISO3Language() : String`
220 | 
221 | **Description:** Returns the 3-letter ISO 639 language code for this Locale. If no language has been specified for this Locale, this value is an empty string.
222 | 
223 | **Returns:**
224 | 
225 | the 3-letter ISO 639 language code for this Locale. If no language has been specified for this Locale, this value is an empty string.
226 | 
227 | ---
228 | 
229 | ### getLanguage
230 | 
231 | **Signature:** `getLanguage() : String`
232 | 
233 | **Description:** Returns the lowercase ISO 639 language code for this Locale. If no language has been specified for this Locale, this value is an empty string.
234 | 
235 | **Returns:**
236 | 
237 | the lowercase ISO 639 language code for this Locale. If no language has been specified for this Locale, this value is an empty string.
238 | 
239 | ---
240 | 
241 | ### getLocale
242 | 
243 | **Signature:** `static getLocale(localeId : String) : Locale`
244 | 
245 | **Description:** Returns a Locale instance for the given localeId, or null if no such Locale could be found.
246 | 
247 | **Parameters:**
248 | 
249 | - `localeId`: the localeID of the desired Locale
250 | 
251 | **Returns:**
252 | 
253 | the Locale instance for the given localeId, or null if no such Locale could be found.
254 | 
255 | ---
256 | 
257 | ### toString
258 | 
259 | **Signature:** `toString() : String`
260 | 
261 | **Description:** Returns the String representation of the localeID. Combines the language and the country key, concatenated with "_". For example: "en_US". This attribute is the primary key of the class.
262 | 
263 | **Returns:**
264 | 
265 | the String representation of the localeID.
266 | 
267 | ---
```

--------------------------------------------------------------------------------
/docs/dw_system/Status.md:
--------------------------------------------------------------------------------

```markdown
  1 | ## Package: dw.system
  2 | 
  3 | # Class Status
  4 | 
  5 | ## Inheritance Hierarchy
  6 | 
  7 | - Object
  8 |   - dw.system.Status
  9 | 
 10 | ## Description
 11 | 
 12 | A Status is used for communicating an API status code back to a client. A status consists of multiple StatusItem. Most often a Status contains only one StatusItem. For convenience, a message with parameters is formatted using standard formatting patterns. If you want to display locale-specific messages in your application, you should use the Status.getCode() as key for a resource bundle.
 13 | 
 14 | ## Properties
 15 | 
 16 | ### code
 17 | 
 18 | **Type:** String (Read Only)
 19 | 
 20 | The status code either of the first ERROR StatusItem or when there
 21 |  is no ERROR StatusITEM, the first StatusItem in the overall list.
 22 | 
 23 |  The status code is the unique identifier for the message and can be used by
 24 |  client programs to check for a specific status and to generate a localized
 25 |  message.
 26 | 
 27 | ### details
 28 | 
 29 | **Type:** Map (Read Only)
 30 | 
 31 | The details either of the first ERROR StatusItem or when there
 32 |  is no ERROR StatusItem, the first StatusItem in the overall list.
 33 | 
 34 | ### error
 35 | 
 36 | **Type:** boolean (Read Only)
 37 | 
 38 | Checks if the status is an ERROR. The Status is an ERROR if one of the
 39 |  contained StatusItems is an ERROR.
 40 | 
 41 | ### items
 42 | 
 43 | **Type:** List (Read Only)
 44 | 
 45 | All status items.
 46 | 
 47 | ### message
 48 | 
 49 | **Type:** String (Read Only)
 50 | 
 51 | The message either of the first ERROR StatusItem or when there
 52 |  is no ERROR StatusItem, the first StatusItem in the overall list.
 53 | 
 54 |  Note: Custom code and client programs must not use this message to identify
 55 |  a specific status. The getCode() must be used for that purpose. The actual
 56 |  message can change from release to release.
 57 | 
 58 | ### parameters
 59 | 
 60 | **Type:** List (Read Only)
 61 | 
 62 | The parameters either of the first ERROR StatusItem or when there
 63 |  is no ERROR StatusItem, the first StatusItem in the overall list.
 64 | 
 65 | ### status
 66 | 
 67 | **Type:** Number (Read Only)
 68 | 
 69 | The overall status. If all StatusItems are OK, the method returns
 70 |  OK. If one StatusItem is an ERROR it returns ERROR.
 71 | 
 72 | ## Constructor Summary
 73 | 
 74 | Status() Creates a Status object with no StatusItems.
 75 | 
 76 | Status(status : Number) Creates a Status with a single StatusItem.
 77 | 
 78 | Status(status : Number, code : String) Creates a Status with a single StatusItem.
 79 | 
 80 | Status(status : Number, code : String, message : String, parameters : Object...) Creates a Status with a single StatusItem.
 81 | 
 82 | ## Method Summary
 83 | 
 84 | ### addDetail
 85 | 
 86 | **Signature:** `addDetail(key : String, value : Object) : void`
 87 | 
 88 | Add detail information for the given key of the first ERROR StatusItem or when there is no ERROR StatusItem, the first StatusItem in the overall list.
 89 | 
 90 | ### addItem
 91 | 
 92 | **Signature:** `addItem(item : StatusItem) : void`
 93 | 
 94 | Adds an additional status item to this status instance.
 95 | 
 96 | ### getCode
 97 | 
 98 | **Signature:** `getCode() : String`
 99 | 
100 | Returns the status code either of the first ERROR StatusItem or when there is no ERROR StatusITEM, the first StatusItem in the overall list.
101 | 
102 | ### getDetail
103 | 
104 | **Signature:** `getDetail(key : String) : Object`
105 | 
106 | Returns the detail value for the given key of the first ERROR StatusItem or when there is no ERROR StatusItem, the first StatusItem in the overall list.
107 | 
108 | ### getDetails
109 | 
110 | **Signature:** `getDetails() : Map`
111 | 
112 | Returns the details either of the first ERROR StatusItem or when there is no ERROR StatusItem, the first StatusItem in the overall list.
113 | 
114 | ### getItems
115 | 
116 | **Signature:** `getItems() : List`
117 | 
118 | Returns all status items.
119 | 
120 | ### getMessage
121 | 
122 | **Signature:** `getMessage() : String`
123 | 
124 | Returns the message either of the first ERROR StatusItem or when there is no ERROR StatusItem, the first StatusItem in the overall list.
125 | 
126 | ### getParameters
127 | 
128 | **Signature:** `getParameters() : List`
129 | 
130 | Returns the parameters either of the first ERROR StatusItem or when there is no ERROR StatusItem, the first StatusItem in the overall list.
131 | 
132 | ### getStatus
133 | 
134 | **Signature:** `getStatus() : Number`
135 | 
136 | Returns the overall status.
137 | 
138 | ### isError
139 | 
140 | **Signature:** `isError() : boolean`
141 | 
142 | Checks if the status is an ERROR.
143 | 
144 | ## Constructor Detail
145 | 
146 | ## Method Detail
147 | 
148 | ## Method Details
149 | 
150 | ### addDetail
151 | 
152 | **Signature:** `addDetail(key : String, value : Object) : void`
153 | 
154 | **Description:** Add detail information for the given key of the first ERROR StatusItem or when there is no ERROR StatusItem, the first StatusItem in the overall list.
155 | 
156 | **Parameters:**
157 | 
158 | - `key`: the key of the first ERROR StatusItem or the first StatusItem in the list.
159 | - `value`: the detail value.
160 | 
161 | ---
162 | 
163 | ### addItem
164 | 
165 | **Signature:** `addItem(item : StatusItem) : void`
166 | 
167 | **Description:** Adds an additional status item to this status instance.
168 | 
169 | **Parameters:**
170 | 
171 | - `item`: the status item to add.
172 | 
173 | ---
174 | 
175 | ### getCode
176 | 
177 | **Signature:** `getCode() : String`
178 | 
179 | **Description:** Returns the status code either of the first ERROR StatusItem or when there is no ERROR StatusITEM, the first StatusItem in the overall list. The status code is the unique identifier for the message and can be used by client programs to check for a specific status and to generate a localized message.
180 | 
181 | **Returns:**
182 | 
183 | the status code
184 | 
185 | ---
186 | 
187 | ### getDetail
188 | 
189 | **Signature:** `getDetail(key : String) : Object`
190 | 
191 | **Description:** Returns the detail value for the given key of the first ERROR StatusItem or when there is no ERROR StatusItem, the first StatusItem in the overall list.
192 | 
193 | **Parameters:**
194 | 
195 | - `key`: the key for the detail to return.
196 | 
197 | **Returns:**
198 | 
199 | the detail value for the given key of the first ERROR StatusItem or when there is no ERROR StatusItem, the first StatusItem in the overall list.
200 | 
201 | ---
202 | 
203 | ### getDetails
204 | 
205 | **Signature:** `getDetails() : Map`
206 | 
207 | **Description:** Returns the details either of the first ERROR StatusItem or when there is no ERROR StatusItem, the first StatusItem in the overall list.
208 | 
209 | **Returns:**
210 | 
211 | the details either of the first ERROR StatusItem or when there is no ERROR StatusItem, the first StatusItem in the overall list.
212 | 
213 | ---
214 | 
215 | ### getItems
216 | 
217 | **Signature:** `getItems() : List`
218 | 
219 | **Description:** Returns all status items.
220 | 
221 | **Returns:**
222 | 
223 | all status items.
224 | 
225 | ---
226 | 
227 | ### getMessage
228 | 
229 | **Signature:** `getMessage() : String`
230 | 
231 | **Description:** Returns the message either of the first ERROR StatusItem or when there is no ERROR StatusItem, the first StatusItem in the overall list. Note: Custom code and client programs must not use this message to identify a specific status. The getCode() must be used for that purpose. The actual message can change from release to release.
232 | 
233 | **Returns:**
234 | 
235 | the message either of the first ERROR StatusItem or when there is no ERROR StatusItem, the first StatusItem in the overall list.
236 | 
237 | ---
238 | 
239 | ### getParameters
240 | 
241 | **Signature:** `getParameters() : List`
242 | 
243 | **Description:** Returns the parameters either of the first ERROR StatusItem or when there is no ERROR StatusItem, the first StatusItem in the overall list.
244 | 
245 | **Returns:**
246 | 
247 | the parameters either of the first ERROR StatusItem or when there is no ERROR StatusItem, the first StatusItem in the overall list.
248 | 
249 | ---
250 | 
251 | ### getStatus
252 | 
253 | **Signature:** `getStatus() : Number`
254 | 
255 | **Description:** Returns the overall status. If all StatusItems are OK, the method returns OK. If one StatusItem is an ERROR it returns ERROR.
256 | 
257 | **Returns:**
258 | 
259 | either OK or ERROR
260 | 
261 | ---
262 | 
263 | ### isError
264 | 
265 | **Signature:** `isError() : boolean`
266 | 
267 | **Description:** Checks if the status is an ERROR. The Status is an ERROR if one of the contained StatusItems is an ERROR.
268 | 
269 | **Returns:**
270 | 
271 | true if status is an ERROR, false otherwise.
272 | 
273 | ---
```

--------------------------------------------------------------------------------
/docs/dw_crypto/Signature.md:
--------------------------------------------------------------------------------

```markdown
  1 | ## Package: dw.crypto
  2 | 
  3 | # Class Signature
  4 | 
  5 | ## Inheritance Hierarchy
  6 | 
  7 | - Object
  8 |   - dw.crypto.Signature
  9 | 
 10 | ## Description
 11 | 
 12 | This class allows access to signature services offered through the Java Cryptography Architecture (JCA). At this time the signature/verification implementation of the methods is based on the default RSA JCE provider of the JDK - sun.security.rsa.SunRsaSign dw.crypto.Signature is an adapter to the security provider implementation and covers several digest algorithms: SHA1withRSA (deprecated) SHA256withRSA SHA384withRSA SHA512withRSA SHA256withRSA/PSS SHA384withRSA/PSS SHA512withRSA/PSS SHA256withECDSA SHA384withECDSA SHA512withECDSA Key size generally ranges between 512 and 65536 bits (the latter of which is unnecessarily large). Default key size for RSA is 1024. SHA384withRSA and SHA512withRSA require a key with length of at least 1024 bits. For ECDSA, the following key sizes are supported: SHA256withECDSA: 256-bit key (NIST P-256) SHA384withECDSA: 384-bit key (NIST P-384) SHA512withECDSA: 521-bit key (NIST P-521) When choosing a key size - beware of the tradeoff between security and processing time: The longer the key, the harder to break it but also it takes more time for the two sides to sign and verify the signature. An exception will be thrown for keys shorter than 2048 bits in this version of the API. Note: this class handles sensitive security-related data. Pay special attention to PCI DSS v3. requirements 2, 4, 12, and other relevant requirements.
 13 | 
 14 | ## Constants
 15 | 
 16 | ### SUPPORTED_DIGEST_ALGORITHMS_AS_ARRAY
 17 | 
 18 | **Type:** String
 19 | 
 20 | Supported digest algorithms exposed as a string array
 21 | 
 22 | ## Properties
 23 | 
 24 | ## Constructor Summary
 25 | 
 26 | Signature()
 27 | 
 28 | ## Method Summary
 29 | 
 30 | ### isDigestAlgorithmSupported
 31 | 
 32 | **Signature:** `isDigestAlgorithmSupported(digestAlgorithm : String) : boolean`
 33 | 
 34 | Checks to see if a digest algorithm is supported
 35 | 
 36 | ### sign
 37 | 
 38 | **Signature:** `sign(contentToSign : String, privateKey : String, digestAlgorithm : String) : String`
 39 | 
 40 | Signs a string and returns a string
 41 | 
 42 | ### sign
 43 | 
 44 | **Signature:** `sign(contentToSign : String, privateKey : KeyRef, digestAlgorithm : String) : String`
 45 | 
 46 | Signs a string and returns a string
 47 | 
 48 | ### signBytes
 49 | 
 50 | **Signature:** `signBytes(contentToSign : Bytes, privateKey : String, digestAlgorithm : String) : Bytes`
 51 | 
 52 | Signs bytes and returns bytes
 53 | 
 54 | ### signBytes
 55 | 
 56 | **Signature:** `signBytes(contentToSign : Bytes, privateKey : KeyRef, digestAlgorithm : String) : Bytes`
 57 | 
 58 | Signs bytes and returns bytes
 59 | 
 60 | ### verifyBytesSignature
 61 | 
 62 | **Signature:** `verifyBytesSignature(signature : Bytes, contentToVerify : Bytes, publicKey : String, digestAlgorithm : String) : boolean`
 63 | 
 64 | Verifies a signature supplied as bytes
 65 | 
 66 | ### verifyBytesSignature
 67 | 
 68 | **Signature:** `verifyBytesSignature(signature : Bytes, contentToVerify : Bytes, certificate : CertificateRef, digestAlgorithm : String) : boolean`
 69 | 
 70 | Verifies a signature supplied as bytes
 71 | 
 72 | ### verifySignature
 73 | 
 74 | **Signature:** `verifySignature(signature : String, contentToVerify : String, publicKey : String, digestAlgorithm : String) : boolean`
 75 | 
 76 | Verifies a signature supplied as string
 77 | 
 78 | ### verifySignature
 79 | 
 80 | **Signature:** `verifySignature(signature : String, contentToVerify : String, certificate : CertificateRef, digestAlgorithm : String) : boolean`
 81 | 
 82 | Verifies a signature supplied as string
 83 | 
 84 | ## Constructor Detail
 85 | 
 86 | ## Method Detail
 87 | 
 88 | ## Method Details
 89 | 
 90 | ### isDigestAlgorithmSupported
 91 | 
 92 | **Signature:** `isDigestAlgorithmSupported(digestAlgorithm : String) : boolean`
 93 | 
 94 | **Description:** Checks to see if a digest algorithm is supported
 95 | 
 96 | **Parameters:**
 97 | 
 98 | - `digestAlgorithm`: the digest algorithm name
 99 | 
100 | **Returns:**
101 | 
102 | a boolean indicating success (true) or failure (false)
103 | 
104 | ---
105 | 
106 | ### sign
107 | 
108 | **Signature:** `sign(contentToSign : String, privateKey : String, digestAlgorithm : String) : String`
109 | 
110 | **Description:** Signs a string and returns a string
111 | 
112 | **Parameters:**
113 | 
114 | - `contentToSign`: base64 encoded content to sign
115 | - `privateKey`: base64 encoded private key
116 | - `digestAlgorithm`: must be one of the currently supported ones
117 | 
118 | **Returns:**
119 | 
120 | the base64 encoded signature
121 | 
122 | ---
123 | 
124 | ### sign
125 | 
126 | **Signature:** `sign(contentToSign : String, privateKey : KeyRef, digestAlgorithm : String) : String`
127 | 
128 | **Description:** Signs a string and returns a string
129 | 
130 | **Parameters:**
131 | 
132 | - `contentToSign`: base64 encoded content to sign
133 | - `privateKey`: a reference to a private key entry in the keystore
134 | - `digestAlgorithm`: must be one of the currently supported ones
135 | 
136 | **Returns:**
137 | 
138 | the base64 encoded signature
139 | 
140 | ---
141 | 
142 | ### signBytes
143 | 
144 | **Signature:** `signBytes(contentToSign : Bytes, privateKey : String, digestAlgorithm : String) : Bytes`
145 | 
146 | **Description:** Signs bytes and returns bytes
147 | 
148 | **Parameters:**
149 | 
150 | - `contentToSign`: transformed with UTF-8 encoding into a byte stream
151 | - `privateKey`: base64 encoded private key
152 | - `digestAlgorithm`: must be one of the currently supported ones
153 | 
154 | **Returns:**
155 | 
156 | signature
157 | 
158 | ---
159 | 
160 | ### signBytes
161 | 
162 | **Signature:** `signBytes(contentToSign : Bytes, privateKey : KeyRef, digestAlgorithm : String) : Bytes`
163 | 
164 | **Description:** Signs bytes and returns bytes
165 | 
166 | **Parameters:**
167 | 
168 | - `contentToSign`: transformed with UTF-8 encoding into a byte stream
169 | - `privateKey`: a reference to a private key entry in the keystore
170 | - `digestAlgorithm`: must be one of the currently supported ones
171 | 
172 | **Returns:**
173 | 
174 | signature
175 | 
176 | ---
177 | 
178 | ### verifyBytesSignature
179 | 
180 | **Signature:** `verifyBytesSignature(signature : Bytes, contentToVerify : Bytes, publicKey : String, digestAlgorithm : String) : boolean`
181 | 
182 | **Description:** Verifies a signature supplied as bytes
183 | 
184 | **Parameters:**
185 | 
186 | - `signature`: signature to check as bytes
187 | - `contentToVerify`: as bytes
188 | - `publicKey`: base64 encoded public key
189 | - `digestAlgorithm`: must be one of the currently supported ones
190 | 
191 | **Returns:**
192 | 
193 | a boolean indicating success (true) or failure (false)
194 | 
195 | ---
196 | 
197 | ### verifyBytesSignature
198 | 
199 | **Signature:** `verifyBytesSignature(signature : Bytes, contentToVerify : Bytes, certificate : CertificateRef, digestAlgorithm : String) : boolean`
200 | 
201 | **Description:** Verifies a signature supplied as bytes
202 | 
203 | **Parameters:**
204 | 
205 | - `signature`: signature to check as bytes
206 | - `contentToVerify`: as bytes
207 | - `certificate`: a reference to a trusted certificate
208 | - `digestAlgorithm`: must be one of the currently supported ones
209 | 
210 | **Returns:**
211 | 
212 | a boolean indicating success (true) or failure (false)
213 | 
214 | ---
215 | 
216 | ### verifySignature
217 | 
218 | **Signature:** `verifySignature(signature : String, contentToVerify : String, publicKey : String, digestAlgorithm : String) : boolean`
219 | 
220 | **Description:** Verifies a signature supplied as string
221 | 
222 | **Parameters:**
223 | 
224 | - `signature`: base64 encoded signature
225 | - `contentToVerify`: base64 encoded content to verify
226 | - `publicKey`: base64 encoded public key
227 | - `digestAlgorithm`: must be one of the currently supported ones
228 | 
229 | **Returns:**
230 | 
231 | a boolean indicating success (true) or failure (false)
232 | 
233 | ---
234 | 
235 | ### verifySignature
236 | 
237 | **Signature:** `verifySignature(signature : String, contentToVerify : String, certificate : CertificateRef, digestAlgorithm : String) : boolean`
238 | 
239 | **Description:** Verifies a signature supplied as string
240 | 
241 | **Parameters:**
242 | 
243 | - `signature`: base64 encoded signature
244 | - `contentToVerify`: base64 encoded content to verify
245 | - `certificate`: a reference to a trusted certificate
246 | - `digestAlgorithm`: must be one of the currently supported ones
247 | 
248 | **Returns:**
249 | 
250 | a boolean indicating success (true) or failure (false)
251 | 
252 | ---
```

--------------------------------------------------------------------------------
/docs/dw_order/GiftCertificateLineItem.md:
--------------------------------------------------------------------------------

```markdown
  1 | ## Package: dw.order
  2 | 
  3 | # Class GiftCertificateLineItem
  4 | 
  5 | ## Inheritance Hierarchy
  6 | 
  7 | - Object
  8 |   - dw.object.PersistentObject
  9 |   - dw.object.ExtensibleObject
 10 |     - dw.order.LineItem
 11 |       - dw.order.GiftCertificateLineItem
 12 | 
 13 | ## Description
 14 | 
 15 | Represents a Gift Certificate line item in the cart. When an order is processed, a Gift Certificate is created based on the information in the Gift Certificate line item.
 16 | 
 17 | ## Properties
 18 | 
 19 | ### giftCertificateID
 20 | 
 21 | **Type:** String
 22 | 
 23 | The ID of the gift certificate that this line item
 24 |  was used to create. If this line item has not been used to create
 25 |  a Gift Certificate, this method returns null.
 26 | 
 27 | ### message
 28 | 
 29 | **Type:** String
 30 | 
 31 | The message to include in the email of the person receiving
 32 |  the gift certificate line item.
 33 | 
 34 | ### productListItem
 35 | 
 36 | **Type:** ProductListItem
 37 | 
 38 | The associated ProductListItem.
 39 | 
 40 | ### recipientEmail
 41 | 
 42 | **Type:** String
 43 | 
 44 | The email address of the person receiving
 45 |  the gift certificate line item.
 46 | 
 47 | ### recipientName
 48 | 
 49 | **Type:** String
 50 | 
 51 | The name of the person receiving the gift certificate line item.
 52 | 
 53 | ### senderName
 54 | 
 55 | **Type:** String
 56 | 
 57 | The name of the person or organization that
 58 |  sent the gift certificate line item or null if undefined.
 59 | 
 60 | ### shipment
 61 | 
 62 | **Type:** Shipment
 63 | 
 64 | The associated Shipment.
 65 | 
 66 | ## Constructor Summary
 67 | 
 68 | ## Method Summary
 69 | 
 70 | ### getGiftCertificateID
 71 | 
 72 | **Signature:** `getGiftCertificateID() : String`
 73 | 
 74 | Returns the ID of the gift certificate that this line item was used to create.
 75 | 
 76 | ### getMessage
 77 | 
 78 | **Signature:** `getMessage() : String`
 79 | 
 80 | Returns the message to include in the email of the person receiving the gift certificate line item.
 81 | 
 82 | ### getProductListItem
 83 | 
 84 | **Signature:** `getProductListItem() : ProductListItem`
 85 | 
 86 | Returns the associated ProductListItem.
 87 | 
 88 | ### getRecipientEmail
 89 | 
 90 | **Signature:** `getRecipientEmail() : String`
 91 | 
 92 | Returns the email address of the person receiving the gift certificate line item.
 93 | 
 94 | ### getRecipientName
 95 | 
 96 | **Signature:** `getRecipientName() : String`
 97 | 
 98 | Returns the name of the person receiving the gift certificate line item.
 99 | 
100 | ### getSenderName
101 | 
102 | **Signature:** `getSenderName() : String`
103 | 
104 | Returns the name of the person or organization that sent the gift certificate line item or null if undefined.
105 | 
106 | ### getShipment
107 | 
108 | **Signature:** `getShipment() : Shipment`
109 | 
110 | Returns the associated Shipment.
111 | 
112 | ### setGiftCertificateID
113 | 
114 | **Signature:** `setGiftCertificateID(id : String) : void`
115 | 
116 | Sets the ID of the gift certificate associated with this line item.
117 | 
118 | ### setMessage
119 | 
120 | **Signature:** `setMessage(message : String) : void`
121 | 
122 | Sets the message to include in the email of the person receiving the gift certificate line item.
123 | 
124 | ### setProductListItem
125 | 
126 | **Signature:** `setProductListItem(productListItem : ProductListItem) : void`
127 | 
128 | Sets the associated ProductListItem.
129 | 
130 | ### setRecipientEmail
131 | 
132 | **Signature:** `setRecipientEmail(recipientEmail : String) : void`
133 | 
134 | Sets the email address of the person receiving the gift certificate line item.
135 | 
136 | ### setRecipientName
137 | 
138 | **Signature:** `setRecipientName(recipient : String) : void`
139 | 
140 | Sets the name of the person receiving the gift certificate line item.
141 | 
142 | ### setSenderName
143 | 
144 | **Signature:** `setSenderName(sender : String) : void`
145 | 
146 | Sets the name of the person or organization that sent the gift certificate line item.
147 | 
148 | ### setShipment
149 | 
150 | **Signature:** `setShipment(shipment : Shipment) : void`
151 | 
152 | Associates the gift certificate line item with the specified shipment.
153 | 
154 | ## Method Detail
155 | 
156 | ## Method Details
157 | 
158 | ### getGiftCertificateID
159 | 
160 | **Signature:** `getGiftCertificateID() : String`
161 | 
162 | **Description:** Returns the ID of the gift certificate that this line item was used to create. If this line item has not been used to create a Gift Certificate, this method returns null.
163 | 
164 | **Returns:**
165 | 
166 | the ID of the gift certificate or null if undefined.
167 | 
168 | ---
169 | 
170 | ### getMessage
171 | 
172 | **Signature:** `getMessage() : String`
173 | 
174 | **Description:** Returns the message to include in the email of the person receiving the gift certificate line item.
175 | 
176 | **Returns:**
177 | 
178 | the message to include in the email of the person receiving the gift certificate line item.
179 | 
180 | ---
181 | 
182 | ### getProductListItem
183 | 
184 | **Signature:** `getProductListItem() : ProductListItem`
185 | 
186 | **Description:** Returns the associated ProductListItem.
187 | 
188 | **Returns:**
189 | 
190 | item or null.
191 | 
192 | ---
193 | 
194 | ### getRecipientEmail
195 | 
196 | **Signature:** `getRecipientEmail() : String`
197 | 
198 | **Description:** Returns the email address of the person receiving the gift certificate line item.
199 | 
200 | **Returns:**
201 | 
202 | the email address of the person receiving the gift certificate line item.
203 | 
204 | ---
205 | 
206 | ### getRecipientName
207 | 
208 | **Signature:** `getRecipientName() : String`
209 | 
210 | **Description:** Returns the name of the person receiving the gift certificate line item.
211 | 
212 | **Returns:**
213 | 
214 | the name of the person receiving the gift certificate line item.
215 | 
216 | ---
217 | 
218 | ### getSenderName
219 | 
220 | **Signature:** `getSenderName() : String`
221 | 
222 | **Description:** Returns the name of the person or organization that sent the gift certificate line item or null if undefined.
223 | 
224 | **Returns:**
225 | 
226 | the name of the person or organization that sent the gift certificate line item or null if undefined.
227 | 
228 | ---
229 | 
230 | ### getShipment
231 | 
232 | **Signature:** `getShipment() : Shipment`
233 | 
234 | **Description:** Returns the associated Shipment.
235 | 
236 | **Returns:**
237 | 
238 | The shipment of the gift certificate line item
239 | 
240 | ---
241 | 
242 | ### setGiftCertificateID
243 | 
244 | **Signature:** `setGiftCertificateID(id : String) : void`
245 | 
246 | **Description:** Sets the ID of the gift certificate associated with this line item.
247 | 
248 | **Parameters:**
249 | 
250 | - `id`: the ID of the gift certificate associated with this line item.
251 | 
252 | ---
253 | 
254 | ### setMessage
255 | 
256 | **Signature:** `setMessage(message : String) : void`
257 | 
258 | **Description:** Sets the message to include in the email of the person receiving the gift certificate line item.
259 | 
260 | **Parameters:**
261 | 
262 | - `message`: the message to include in the email of the person receiving the gift certificate line item.
263 | 
264 | ---
265 | 
266 | ### setProductListItem
267 | 
268 | **Signature:** `setProductListItem(productListItem : ProductListItem) : void`
269 | 
270 | **Description:** Sets the associated ProductListItem. The product list item to be set must be of type gift certificate otherwise an exception is thrown.
271 | 
272 | **Parameters:**
273 | 
274 | - `productListItem`: the product list item to be associated
275 | 
276 | ---
277 | 
278 | ### setRecipientEmail
279 | 
280 | **Signature:** `setRecipientEmail(recipientEmail : String) : void`
281 | 
282 | **Description:** Sets the email address of the person receiving the gift certificate line item.
283 | 
284 | **Parameters:**
285 | 
286 | - `recipientEmail`: the email address of the person receiving the gift certificate line item.
287 | 
288 | ---
289 | 
290 | ### setRecipientName
291 | 
292 | **Signature:** `setRecipientName(recipient : String) : void`
293 | 
294 | **Description:** Sets the name of the person receiving the gift certificate line item.
295 | 
296 | **Parameters:**
297 | 
298 | - `recipient`: the name of the person receiving the gift certificate line item.
299 | 
300 | ---
301 | 
302 | ### setSenderName
303 | 
304 | **Signature:** `setSenderName(sender : String) : void`
305 | 
306 | **Description:** Sets the name of the person or organization that sent the gift certificate line item.
307 | 
308 | **Parameters:**
309 | 
310 | - `sender`: the name of the person or organization that sent the gift certificate line item.
311 | 
312 | ---
313 | 
314 | ### setShipment
315 | 
316 | **Signature:** `setShipment(shipment : Shipment) : void`
317 | 
318 | **Description:** Associates the gift certificate line item with the specified shipment. Gift certificate line item and shipment must belong to the same line item ctnr.
319 | 
320 | **Parameters:**
321 | 
322 | - `shipment`: The new shipment of the gift certificate line item
323 | 
324 | ---
```
Page 14/61FirstPrevNextLast