#
tokens: 47055/50000 6/825 files (page 36/61)
lines: on (toggle) GitHub
raw markdown copy reset
This is page 36 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

--------------------------------------------------------------------------------
/docs/dw_catalog/VariationGroup.md:
--------------------------------------------------------------------------------

```markdown
  1 | ## Package: dw.catalog
  2 | 
  3 | # Class VariationGroup
  4 | 
  5 | ## Inheritance Hierarchy
  6 | 
  7 | - Object
  8 |   - dw.object.PersistentObject
  9 |   - dw.object.ExtensibleObject
 10 |     - dw.catalog.Product
 11 |       - dw.catalog.VariationGroup
 12 | 
 13 | ## Description
 14 | 
 15 | Class representing a group of variants within a master product who share a common value for one or more variation attribute values. Variation groups are used to simplify merchandising of products. From a more technical perspective, variation groups are defined by two things: A relation to a master product. A set of variation attributes which have fixed values. A variant of the related master product is considered in the group if and only if it matches on the fixed variation attribute values. Similar to a Variant, a VariationGroup does a fallback to the master product for all attributes (name, description, etc) and relations (recommendations, etc).
 16 | 
 17 | ## Properties
 18 | 
 19 | ### allProductLinks
 20 | 
 21 | **Type:** Collection (Read Only)
 22 | 
 23 | All product links of the product variation group. 
 24 | 
 25 |  If the variation group does not define any product links, but the master product
 26 |  does, the product links of the master are returned.
 27 | 
 28 | ### brand
 29 | 
 30 | **Type:** String (Read Only)
 31 | 
 32 | The brand of the product variation group. 
 33 | 
 34 |  If the variation group does not define an own value for 'brand', the value of
 35 |  the master product is returned.
 36 | 
 37 | ### classificationCategory
 38 | 
 39 | **Type:** Category (Read Only)
 40 | 
 41 | The classification category of the product variation group. 
 42 | 
 43 |  Please note that the classification category is always inherited
 44 |  from the master and cannot be overridden by the variation group.
 45 | 
 46 | ### custom
 47 | 
 48 | **Type:** CustomAttributes (Read Only)
 49 | 
 50 | The custom attributes of the variation group. 
 51 | 
 52 |  Custom attributes are inherited from the master product and can
 53 |  be overridden by the variation group.
 54 | 
 55 | ### EAN
 56 | 
 57 | **Type:** String (Read Only)
 58 | 
 59 | The EAN of the product variation group. 
 60 | 
 61 |  If the variation group does not define an own value for 'EAN', the value of
 62 |  the master product is returned.
 63 | 
 64 | ### image
 65 | 
 66 | **Type:** MediaFile (Read Only)
 67 | 
 68 | The image of the product variation group. 
 69 | 
 70 |  If the variation group does not define an own value for 'image', the value of
 71 |  the master product is returned.
 72 | 
 73 | ### longDescription
 74 | 
 75 | **Type:** MarkupText (Read Only)
 76 | 
 77 | The long description of the product variation group. 
 78 | 
 79 |  If the variation group does not define an own value for 'longDescription', the value of
 80 |  the master product is returned.
 81 | 
 82 | ### manufacturerName
 83 | 
 84 | **Type:** String (Read Only)
 85 | 
 86 | The manufacturer name of the product variation group. 
 87 | 
 88 |  If the variation group does not define an own value for 'manufacturerName', the value of
 89 |  the master product is returned.
 90 | 
 91 | ### manufacturerSKU
 92 | 
 93 | **Type:** String (Read Only)
 94 | 
 95 | The manufacturer sku of the product variation group. 
 96 | 
 97 |  If the variation group does not define an own value for 'manufacturerSKU', the value of
 98 |  the master product is returned.
 99 | 
100 | ### masterProduct
101 | 
102 | **Type:** Product (Read Only)
103 | 
104 | The ProductMaster for this mastered product.
105 | 
106 | ### name
107 | 
108 | **Type:** String (Read Only)
109 | 
110 | The name of the product variation group. 
111 | 
112 |  If the variation group does not define an own value for 'name', the value of
113 |  the master product is returned.
114 | 
115 | ### onlineFrom
116 | 
117 | **Type:** Date (Read Only)
118 | 
119 | The onlineFrom date of the product variation group. 
120 | 
121 |  If the variation group does not define an own value for 'onlineFrom', the value of
122 |  the master product is returned.
123 | 
124 | ### onlineTo
125 | 
126 | **Type:** Date (Read Only)
127 | 
128 | The onlineTo date of the product variation group. 
129 | 
130 |  If the variation group does not define an own value for 'onlineTo', the value of
131 |  the master product is returned.
132 | 
133 | ### optionProduct
134 | 
135 | **Type:** boolean (Read Only)
136 | 
137 | Returns 'true' if the variation group has any options, otherwise 'false'.
138 |  Method also returns 'true' if the variation group has not any options,
139 |  but the related master product has options.
140 | 
141 | ### pageDescription
142 | 
143 | **Type:** String (Read Only)
144 | 
145 | The pageDescription of the product variation group. 
146 | 
147 |  If the variation group does not define an own value for 'pageDescription', the value of
148 |  the master product is returned.
149 | 
150 | ### pageKeywords
151 | 
152 | **Type:** String (Read Only)
153 | 
154 | The pageKeywords of the product variation group. 
155 | 
156 |  If the variation group does not define an own value for 'pageKeywords', the value of
157 |  the master product is returned.
158 | 
159 | ### pageTitle
160 | 
161 | **Type:** String (Read Only)
162 | 
163 | The pageTitle of the product variation group. 
164 | 
165 |  If the variation group does not define an own value for 'pageTitle', the value of
166 |  the master product is returned.
167 | 
168 | ### pageURL
169 | 
170 | **Type:** String (Read Only)
171 | 
172 | The pageURL of the product variation group. 
173 | 
174 |  If the variation group does not define an own value for 'pageURL', the value of
175 |  the master product is returned.
176 | 
177 | ### productLinks
178 | 
179 | **Type:** Collection (Read Only)
180 | 
181 | All product links of the product variation group for which the target
182 |  product is assigned to the current site catalog. 
183 | 
184 |  If the variation group does not define any product links, but the master product
185 |  does, the product links of the master are returned.
186 | 
187 | ### shortDescription
188 | 
189 | **Type:** MarkupText (Read Only)
190 | 
191 | The short description of the product variation group. 
192 | 
193 |  If the variation group does not define an own value for 'shortDescription', the value of
194 |  the master product is returned.
195 | 
196 | ### taxClassID
197 | 
198 | **Type:** String (Read Only)
199 | 
200 | The tax class id of the product variation group. 
201 | 
202 |  If the variation group does not define an own value for 'taxClassID', the value of
203 |  the master product is returned.
204 | 
205 | ### template
206 | 
207 | **Type:** String (Read Only)
208 | 
209 | The rendering template name of the product variation group. 
210 | 
211 |  If the variation group does not define an own value for 'template', the value of
212 |  the master product is returned.
213 | 
214 | ### thumbnail
215 | 
216 | **Type:** MediaFile (Read Only)
217 | 
218 | The thumbnail image of the product variation group. 
219 | 
220 |  If the variation group does not define an own value for 'thumbnailImage', the value of
221 |  the master product is returned.
222 | 
223 | ### unit
224 | 
225 | **Type:** String (Read Only)
226 | 
227 | The sales unit of the product variation group as defined by the
228 |  master product. 
229 | 
230 |  If the variation group does not define an own value for 'unit', the value of
231 |  the master product is returned.
232 | 
233 | ### unitQuantity
234 | 
235 | **Type:** Quantity (Read Only)
236 | 
237 | The unitQuantity of the product variation group as defined by the
238 |  master product. 
239 | 
240 |  If the variation group does not define an own value for 'unitQuantity', the value of
241 |  the master product is returned.
242 | 
243 | ### UPC
244 | 
245 | **Type:** String (Read Only)
246 | 
247 | The UPC of the product variation group. 
248 | 
249 |  If the variation group does not define an own value for 'UPC', the value of
250 |  the master product is returned.
251 | 
252 | ## Constructor Summary
253 | 
254 | ## Method Summary
255 | 
256 | ### getAllProductLinks
257 | 
258 | **Signature:** `getAllProductLinks() : Collection`
259 | 
260 | Returns all product links of the product variation group.
261 | 
262 | ### getAllProductLinks
263 | 
264 | **Signature:** `getAllProductLinks(type : Number) : Collection`
265 | 
266 | Returns all product links of the specified type of the product variation group.
267 | 
268 | ### getBrand
269 | 
270 | **Signature:** `getBrand() : String`
271 | 
272 | Returns the brand of the product variation group.
273 | 
274 | ### getClassificationCategory
275 | 
276 | **Signature:** `getClassificationCategory() : Category`
277 | 
278 | Returns the classification category of the product variation group.
279 | 
280 | ### getCustom
281 | 
282 | **Signature:** `getCustom() : CustomAttributes`
283 | 
284 | Returns the custom attributes of the variation group.
285 | 
286 | ### getEAN
287 | 
288 | **Signature:** `getEAN() : String`
289 | 
290 | Returns the EAN of the product variation group.
291 | 
292 | ### getImage
293 | 
294 | **Signature:** `getImage() : MediaFile`
295 | 
296 | Returns the image of the product variation group.
297 | 
298 | ### getLongDescription
299 | 
300 | **Signature:** `getLongDescription() : MarkupText`
301 | 
302 | Returns the long description of the product variation group.
303 | 
304 | ### getManufacturerName
305 | 
306 | **Signature:** `getManufacturerName() : String`
307 | 
308 | Returns the manufacturer name of the product variation group.
309 | 
310 | ### getManufacturerSKU
311 | 
312 | **Signature:** `getManufacturerSKU() : String`
313 | 
314 | Returns the manufacturer sku of the product variation group.
315 | 
316 | ### getMasterProduct
317 | 
318 | **Signature:** `getMasterProduct() : Product`
319 | 
320 | Returns the ProductMaster for this mastered product.
321 | 
322 | ### getName
323 | 
324 | **Signature:** `getName() : String`
325 | 
326 | Returns the name of the product variation group.
327 | 
328 | ### getOnlineFrom
329 | 
330 | **Signature:** `getOnlineFrom() : Date`
331 | 
332 | Returns the onlineFrom date of the product variation group.
333 | 
334 | ### getOnlineTo
335 | 
336 | **Signature:** `getOnlineTo() : Date`
337 | 
338 | Returns the onlineTo date of the product variation group.
339 | 
340 | ### getPageDescription
341 | 
342 | **Signature:** `getPageDescription() : String`
343 | 
344 | Returns the pageDescription of the product variation group.
345 | 
346 | ### getPageKeywords
347 | 
348 | **Signature:** `getPageKeywords() : String`
349 | 
350 | Returns the pageKeywords of the product variation group.
351 | 
352 | ### getPageTitle
353 | 
354 | **Signature:** `getPageTitle() : String`
355 | 
356 | Returns the pageTitle of the product variation group.
357 | 
358 | ### getPageURL
359 | 
360 | **Signature:** `getPageURL() : String`
361 | 
362 | Returns the pageURL of the product variation group.
363 | 
364 | ### getProductLinks
365 | 
366 | **Signature:** `getProductLinks() : Collection`
367 | 
368 | Returns all product links of the product variation group for which the target product is assigned to the current site catalog.
369 | 
370 | ### getProductLinks
371 | 
372 | **Signature:** `getProductLinks(type : Number) : Collection`
373 | 
374 | Returns all product links of the specified type of the product variation group for which the target product is assigned to the current site catalog.
375 | 
376 | ### getRecommendations
377 | 
378 | **Signature:** `getRecommendations(type : Number) : Collection`
379 | 
380 | Retrieve the sorted collection of recommendations of the specified type for this product variation group.
381 | 
382 | ### getShortDescription
383 | 
384 | **Signature:** `getShortDescription() : MarkupText`
385 | 
386 | Returns the short description of the product variation group.
387 | 
388 | ### getTaxClassID
389 | 
390 | **Signature:** `getTaxClassID() : String`
391 | 
392 | Returns the tax class id of the product variation group.
393 | 
394 | ### getTemplate
395 | 
396 | **Signature:** `getTemplate() : String`
397 | 
398 | Returns the rendering template name of the product variation group.
399 | 
400 | ### getThumbnail
401 | 
402 | **Signature:** `getThumbnail() : MediaFile`
403 | 
404 | Returns the thumbnail image of the product variation group.
405 | 
406 | ### getUnit
407 | 
408 | **Signature:** `getUnit() : String`
409 | 
410 | Returns the sales unit of the product variation group as defined by the master product.
411 | 
412 | ### getUnitQuantity
413 | 
414 | **Signature:** `getUnitQuantity() : Quantity`
415 | 
416 | Returns the unitQuantity of the product variation group as defined by the master product.
417 | 
418 | ### getUPC
419 | 
420 | **Signature:** `getUPC() : String`
421 | 
422 | Returns the UPC of the product variation group.
423 | 
424 | ### isOptionProduct
425 | 
426 | **Signature:** `isOptionProduct() : boolean`
427 | 
428 | Returns 'true' if the variation group has any options, otherwise 'false'.
429 | 
430 | ## Method Detail
431 | 
432 | ## Method Details
433 | 
434 | ### getAllProductLinks
435 | 
436 | **Signature:** `getAllProductLinks() : Collection`
437 | 
438 | **Description:** Returns all product links of the product variation group. If the variation group does not define any product links, but the master product does, the product links of the master are returned.
439 | 
440 | **Returns:**
441 | 
442 | All product links of the variation group or master
443 | 
444 | ---
445 | 
446 | ### getAllProductLinks
447 | 
448 | **Signature:** `getAllProductLinks(type : Number) : Collection`
449 | 
450 | **Description:** Returns all product links of the specified type of the product variation group. If the variation group does not define any product links, but the master product does, the product links of the master are returned.
451 | 
452 | **Parameters:**
453 | 
454 | - `type`: Type of the product link
455 | 
456 | **Returns:**
457 | 
458 | Product links of specified type of the variation group or master
459 | 
460 | ---
461 | 
462 | ### getBrand
463 | 
464 | **Signature:** `getBrand() : String`
465 | 
466 | **Description:** Returns the brand of the product variation group. If the variation group does not define an own value for 'brand', the value of the master product is returned.
467 | 
468 | **Returns:**
469 | 
470 | The brand of the variation group or master
471 | 
472 | ---
473 | 
474 | ### getClassificationCategory
475 | 
476 | **Signature:** `getClassificationCategory() : Category`
477 | 
478 | **Description:** Returns the classification category of the product variation group. Please note that the classification category is always inherited from the master and cannot be overridden by the variation group.
479 | 
480 | **Returns:**
481 | 
482 | The classification category as defined for the master product of the variation group
483 | 
484 | ---
485 | 
486 | ### getCustom
487 | 
488 | **Signature:** `getCustom() : CustomAttributes`
489 | 
490 | **Description:** Returns the custom attributes of the variation group. Custom attributes are inherited from the master product and can be overridden by the variation group.
491 | 
492 | **Returns:**
493 | 
494 | the custom attributes of the variation group.
495 | 
496 | ---
497 | 
498 | ### getEAN
499 | 
500 | **Signature:** `getEAN() : String`
501 | 
502 | **Description:** Returns the EAN of the product variation group. If the variation group does not define an own value for 'EAN', the value of the master product is returned.
503 | 
504 | **Returns:**
505 | 
506 | The EAN of the variation group or master
507 | 
508 | ---
509 | 
510 | ### getImage
511 | 
512 | **Signature:** `getImage() : MediaFile`
513 | 
514 | **Description:** Returns the image of the product variation group. If the variation group does not define an own value for 'image', the value of the master product is returned.
515 | 
516 | **Returns:**
517 | 
518 | The image of the variation group or master
519 | 
520 | ---
521 | 
522 | ### getLongDescription
523 | 
524 | **Signature:** `getLongDescription() : MarkupText`
525 | 
526 | **Description:** Returns the long description of the product variation group. If the variation group does not define an own value for 'longDescription', the value of the master product is returned.
527 | 
528 | **Returns:**
529 | 
530 | The long description name of the variation group or master
531 | 
532 | ---
533 | 
534 | ### getManufacturerName
535 | 
536 | **Signature:** `getManufacturerName() : String`
537 | 
538 | **Description:** Returns the manufacturer name of the product variation group. If the variation group does not define an own value for 'manufacturerName', the value of the master product is returned.
539 | 
540 | **Returns:**
541 | 
542 | The manufacturer name of the variation group or master
543 | 
544 | ---
545 | 
546 | ### getManufacturerSKU
547 | 
548 | **Signature:** `getManufacturerSKU() : String`
549 | 
550 | **Description:** Returns the manufacturer sku of the product variation group. If the variation group does not define an own value for 'manufacturerSKU', the value of the master product is returned.
551 | 
552 | **Returns:**
553 | 
554 | The manufacturer sku of the variation group or master
555 | 
556 | ---
557 | 
558 | ### getMasterProduct
559 | 
560 | **Signature:** `getMasterProduct() : Product`
561 | 
562 | **Description:** Returns the ProductMaster for this mastered product.
563 | 
564 | **Returns:**
565 | 
566 | the ProductMaster of this mastered product
567 | 
568 | ---
569 | 
570 | ### getName
571 | 
572 | **Signature:** `getName() : String`
573 | 
574 | **Description:** Returns the name of the product variation group. If the variation group does not define an own value for 'name', the value of the master product is returned.
575 | 
576 | **Returns:**
577 | 
578 | The name of the variation group or master
579 | 
580 | ---
581 | 
582 | ### getOnlineFrom
583 | 
584 | **Signature:** `getOnlineFrom() : Date`
585 | 
586 | **Description:** Returns the onlineFrom date of the product variation group. If the variation group does not define an own value for 'onlineFrom', the value of the master product is returned.
587 | 
588 | **Returns:**
589 | 
590 | The onlineFrom date of the variation group or master
591 | 
592 | ---
593 | 
594 | ### getOnlineTo
595 | 
596 | **Signature:** `getOnlineTo() : Date`
597 | 
598 | **Description:** Returns the onlineTo date of the product variation group. If the variation group does not define an own value for 'onlineTo', the value of the master product is returned.
599 | 
600 | **Returns:**
601 | 
602 | The onlineTo date of the variation group or master
603 | 
604 | ---
605 | 
606 | ### getPageDescription
607 | 
608 | **Signature:** `getPageDescription() : String`
609 | 
610 | **Description:** Returns the pageDescription of the product variation group. If the variation group does not define an own value for 'pageDescription', the value of the master product is returned.
611 | 
612 | **Returns:**
613 | 
614 | The pageDescription of the variation group or master
615 | 
616 | ---
617 | 
618 | ### getPageKeywords
619 | 
620 | **Signature:** `getPageKeywords() : String`
621 | 
622 | **Description:** Returns the pageKeywords of the product variation group. If the variation group does not define an own value for 'pageKeywords', the value of the master product is returned.
623 | 
624 | **Returns:**
625 | 
626 | The pageKeywords of the variation group or master
627 | 
628 | ---
629 | 
630 | ### getPageTitle
631 | 
632 | **Signature:** `getPageTitle() : String`
633 | 
634 | **Description:** Returns the pageTitle of the product variation group. If the variation group does not define an own value for 'pageTitle', the value of the master product is returned.
635 | 
636 | **Returns:**
637 | 
638 | The pageTitle of the variation group or master
639 | 
640 | ---
641 | 
642 | ### getPageURL
643 | 
644 | **Signature:** `getPageURL() : String`
645 | 
646 | **Description:** Returns the pageURL of the product variation group. If the variation group does not define an own value for 'pageURL', the value of the master product is returned.
647 | 
648 | **Returns:**
649 | 
650 | The pageURL of the variation group or master
651 | 
652 | ---
653 | 
654 | ### getProductLinks
655 | 
656 | **Signature:** `getProductLinks() : Collection`
657 | 
658 | **Description:** Returns all product links of the product variation group for which the target product is assigned to the current site catalog. If the variation group does not define any product links, but the master product does, the product links of the master are returned.
659 | 
660 | **Returns:**
661 | 
662 | Product links of the variation group or master
663 | 
664 | ---
665 | 
666 | ### getProductLinks
667 | 
668 | **Signature:** `getProductLinks(type : Number) : Collection`
669 | 
670 | **Description:** Returns all product links of the specified type of the product variation group for which the target product is assigned to the current site catalog. If the variation group does not define any product links of the specified type, but the master product does, the product links of the master are returned.
671 | 
672 | **Parameters:**
673 | 
674 | - `type`: Type of the product link
675 | 
676 | **Returns:**
677 | 
678 | Product links of specified type of the variation group or master
679 | 
680 | ---
681 | 
682 | ### getRecommendations
683 | 
684 | **Signature:** `getRecommendations(type : Number) : Collection`
685 | 
686 | **Description:** Retrieve the sorted collection of recommendations of the specified type for this product variation group. The types (cross-sell, up-sell, etc) are enumerated in the dw.catalog.Recommendation class. Only recommendations which are stored in the current site catalog are returned. Furthermore, a recommendation is only returned if the target of the recommendation is assigned to the current site catalog. If the variation group does not define any recommendations, but the master product does, the recommendations of the master are returned.
687 | 
688 | **Parameters:**
689 | 
690 | - `type`: the recommendation type
691 | 
692 | **Returns:**
693 | 
694 | the sorted collection, never null but possibly empty.
695 | 
696 | ---
697 | 
698 | ### getShortDescription
699 | 
700 | **Signature:** `getShortDescription() : MarkupText`
701 | 
702 | **Description:** Returns the short description of the product variation group. If the variation group does not define an own value for 'shortDescription', the value of the master product is returned.
703 | 
704 | **Returns:**
705 | 
706 | The short description name of the variation group or master
707 | 
708 | ---
709 | 
710 | ### getTaxClassID
711 | 
712 | **Signature:** `getTaxClassID() : String`
713 | 
714 | **Description:** Returns the tax class id of the product variation group. If the variation group does not define an own value for 'taxClassID', the value of the master product is returned.
715 | 
716 | **Returns:**
717 | 
718 | The tax class id of the variation group or master
719 | 
720 | ---
721 | 
722 | ### getTemplate
723 | 
724 | **Signature:** `getTemplate() : String`
725 | 
726 | **Description:** Returns the rendering template name of the product variation group. If the variation group does not define an own value for 'template', the value of the master product is returned.
727 | 
728 | **Returns:**
729 | 
730 | The rendering template name of the variation group or master
731 | 
732 | ---
733 | 
734 | ### getThumbnail
735 | 
736 | **Signature:** `getThumbnail() : MediaFile`
737 | 
738 | **Description:** Returns the thumbnail image of the product variation group. If the variation group does not define an own value for 'thumbnailImage', the value of the master product is returned.
739 | 
740 | **Returns:**
741 | 
742 | The thumbnail image of the variation group or master
743 | 
744 | ---
745 | 
746 | ### getUnit
747 | 
748 | **Signature:** `getUnit() : String`
749 | 
750 | **Description:** Returns the sales unit of the product variation group as defined by the master product. If the variation group does not define an own value for 'unit', the value of the master product is returned.
751 | 
752 | **Returns:**
753 | 
754 | The sales unit of the variation group or master
755 | 
756 | ---
757 | 
758 | ### getUnitQuantity
759 | 
760 | **Signature:** `getUnitQuantity() : Quantity`
761 | 
762 | **Description:** Returns the unitQuantity of the product variation group as defined by the master product. If the variation group does not define an own value for 'unitQuantity', the value of the master product is returned.
763 | 
764 | **Returns:**
765 | 
766 | The unitQuantity of the variation group or master
767 | 
768 | ---
769 | 
770 | ### getUPC
771 | 
772 | **Signature:** `getUPC() : String`
773 | 
774 | **Description:** Returns the UPC of the product variation group. If the variation group does not define an own value for 'UPC', the value of the master product is returned.
775 | 
776 | **Returns:**
777 | 
778 | The UPC of the variation group or master
779 | 
780 | ---
781 | 
782 | ### isOptionProduct
783 | 
784 | **Signature:** `isOptionProduct() : boolean`
785 | 
786 | **Description:** Returns 'true' if the variation group has any options, otherwise 'false'. Method also returns 'true' if the variation group has not any options, but the related master product has options.
787 | 
788 | **Returns:**
789 | 
790 | true if the variation group has any options, false otherwise.
791 | 
792 | ---
```

--------------------------------------------------------------------------------
/tests/mcp/yaml/search-sfcc-methods.full-mode.test.mcp.yml:
--------------------------------------------------------------------------------

```yaml
  1 | # ==================================================================================
  2 | # SFCC MCP Server - search_sfcc_methods Tool YAML Tests
  3 | # Comprehensive testing for SFCC method search functionality
  4 | # Tests both successful responses and error handling scenarios
  5 | # 
  6 | # Quick Test Commands:
  7 | # aegis "tests/mcp/yaml/search-sfcc-methods.full-mode.test.mcp.yml" --config "aegis.config.with-dw.json" --verbose
  8 | # aegis "tests/mcp/yaml/search-sfcc-methods.full-mode.test.mcp.yml" --config "aegis.config.with-dw.json" --debug --timing
  9 | # aegis query search_sfcc_methods '{"methodName": "get"}' --config "aegis.config.with-dw.json"
 10 | # aegis query search_sfcc_methods '{"methodName": "create"}' --config "aegis.config.with-dw.json"
 11 | # ==================================================================================
 12 | description: "SFCC MCP Server search_sfcc_methods tool - comprehensive validation"
 13 | 
 14 | # ==================================================================================
 15 | # BASIC TOOL STRUCTURE VALIDATION
 16 | # ==================================================================================
 17 | tests:
 18 |   - it: "should list search_sfcc_methods tool in available tools"
 19 |     request:
 20 |       jsonrpc: "2.0"
 21 |       id: "tool-available"
 22 |       method: "tools/list"
 23 |       params: {}
 24 |     expect:
 25 |       response:
 26 |         jsonrpc: "2.0"
 27 |         id: "tool-available"
 28 |         result:
 29 |           match:extractField: "tools.*.name"
 30 |           value: "match:arrayContains:search_sfcc_methods"
 31 |       stderr: "toBeEmpty"
 32 | 
 33 |   - it: "should have search_sfcc_methods in tools list with proper structure"
 34 |     request:
 35 |       jsonrpc: "2.0"
 36 |       id: "tool-metadata"
 37 |       method: "tools/list"
 38 |       params: {}
 39 |     expect:
 40 |       response:
 41 |         jsonrpc: "2.0"
 42 |         id: "tool-metadata"
 43 |         result:
 44 |           tools: "match:arrayContains:name:search_sfcc_methods"
 45 |       stderr: "toBeEmpty"
 46 | 
 47 |   - it: "should have tool with meaningful description"
 48 |     request:
 49 |       jsonrpc: "2.0"
 50 |       id: "tool-description-quality"
 51 |       method: "tools/list"
 52 |       params: {}
 53 |     expect:
 54 |       response:
 55 |         jsonrpc: "2.0"
 56 |         id: "tool-description-quality"
 57 |         result:
 58 |           tools:
 59 |             match:arrayContains:name:search_sfcc_methods
 60 |       stderr: "toBeEmpty"
 61 | 
 62 |   - it: "should have proper input schema for methodName parameter"
 63 |     request:
 64 |       jsonrpc: "2.0"
 65 |       id: "tool-schema-validation"
 66 |       method: "tools/list"
 67 |       params: {}
 68 |     expect:
 69 |       response:
 70 |         jsonrpc: "2.0"
 71 |         id: "tool-schema-validation"
 72 |         result:
 73 |           match:extractField: "tools.*.name"
 74 |           value: "match:arrayContains:search_sfcc_methods"
 75 |       stderr: "toBeEmpty"
 76 | 
 77 | # ==================================================================================
 78 | # SUCCESSFUL METHOD SEARCH OPERATIONS
 79 | # ==================================================================================
 80 | 
 81 |   - it: "should successfully search for 'get' methods returning valid JSON array"
 82 |     request:
 83 |       jsonrpc: "2.0"
 84 |       id: "search-get-methods"
 85 |       method: "tools/call"
 86 |       params:
 87 |         name: "search_sfcc_methods"
 88 |         arguments:
 89 |           methodName: "get"
 90 |     expect:
 91 |       response:
 92 |         jsonrpc: "2.0"
 93 |         id: "search-get-methods"
 94 |         result:
 95 |           content:
 96 |             - type: "text"
 97 |               text: "match:regex:\\[[\\s\\S]*\\]"  # Valid JSON array structure
 98 |           isError: false
 99 |       stderr: "toBeEmpty"
100 | 
101 |   - it: "should find multiple get methods with proper structure"
102 |     request:
103 |       jsonrpc: "2.0"
104 |       id: "search-get-structure"
105 |       method: "tools/call"
106 |       params:
107 |         name: "search_sfcc_methods"
108 |         arguments:
109 |           methodName: "get"
110 |     expect:
111 |       response:
112 |         jsonrpc: "2.0"
113 |         id: "search-get-structure"
114 |         result:
115 |           content:
116 |             - type: "text"
117 |               text: "match:contains:className"  # Should contain className field
118 |           isError: false
119 |       stderr: "toBeEmpty"
120 | 
121 |   - it: "should find get methods with method objects containing name and signature"
122 |     request:
123 |       jsonrpc: "2.0"
124 |       id: "search-get-method-details"
125 |       method: "tools/call"
126 |       params:
127 |         name: "search_sfcc_methods"
128 |         arguments:
129 |           methodName: "get"
130 |     expect:
131 |       response:
132 |         jsonrpc: "2.0"
133 |         id: "search-get-method-details"
134 |         result:
135 |           content:
136 |             - type: "text"
137 |               text: "match:contains:signature"  # Should contain signature information
138 |           isError: false
139 |       stderr: "toBeEmpty"
140 | 
141 |   - it: "should successfully search for 'create' methods"
142 |     request:
143 |       jsonrpc: "2.0"
144 |       id: "search-create-methods"
145 |       method: "tools/call"
146 |       params:
147 |         name: "search_sfcc_methods"
148 |         arguments:
149 |           methodName: "create"
150 |     expect:
151 |       response:
152 |         jsonrpc: "2.0"
153 |         id: "search-create-methods"
154 |         result:
155 |           content:
156 |             - type: "text"
157 |               text: "match:regex:\\[[\\s\\S]*\\]"  # Valid JSON array
158 |           isError: false
159 |       stderr: "toBeEmpty"
160 | 
161 |   - it: "should find create methods containing relevant class information"
162 |     request:
163 |       jsonrpc: "2.0"
164 |       id: "search-create-content"
165 |       method: "tools/call"
166 |       params:
167 |         name: "search_sfcc_methods"
168 |         arguments:
169 |           methodName: "create"
170 |     expect:
171 |       response:
172 |         jsonrpc: "2.0"
173 |         id: "search-create-content"
174 |         result:
175 |           content:
176 |             - type: "text"
177 |               text: "match:contains:dw_"  # Should contain SFCC class references
178 |           isError: false
179 |       stderr: "toBeEmpty"
180 | 
181 |   - it: "should successfully search for 'toString' method"
182 |     request:
183 |       jsonrpc: "2.0"
184 |       id: "search-tostring-method"
185 |       method: "tools/call"
186 |       params:
187 |         name: "search_sfcc_methods"
188 |         arguments:
189 |           methodName: "toString"
190 |     expect:
191 |       response:
192 |         jsonrpc: "2.0"
193 |         id: "search-tostring-method"
194 |         result:
195 |           content:
196 |             - type: "text"
197 |               text: "match:regex:\\[[\\s\\S]*\\]"  # Valid JSON array
198 |           isError: false
199 |       stderr: "toBeEmpty"
200 | 
201 |   - it: "should successfully search for 'getValue' method"
202 |     request:
203 |       jsonrpc: "2.0"
204 |       id: "search-getvalue-method"
205 |       method: "tools/call"
206 |       params:
207 |         name: "search_sfcc_methods"
208 |         arguments:
209 |           methodName: "getValue"
210 |     expect:
211 |       response:
212 |         jsonrpc: "2.0"
213 |         id: "search-getvalue-method"
214 |         result:
215 |           content:
216 |             - type: "text"
217 |               text: "match:contains:getValue"  # Should contain the searched method name
218 |           isError: false
219 |       stderr: "toBeEmpty"
220 | 
221 |   - it: "should handle case-sensitive method search"
222 |     request:
223 |       jsonrpc: "2.0"
224 |       id: "search-case-sensitive"
225 |       method: "tools/call"
226 |       params:
227 |         name: "search_sfcc_methods"
228 |         arguments:
229 |           methodName: "GET"  # Uppercase should be different from 'get'
230 |     expect:
231 |       response:
232 |         jsonrpc: "2.0"
233 |         id: "search-case-sensitive"
234 |         result:
235 |           content:
236 |             - type: "text"
237 |               text: "match:regex:\\[[\\s\\S]*\\]"  # Should still return valid array (might be empty)
238 |           isError: false
239 |       stderr: "toBeEmpty"
240 | 
241 | # ==================================================================================
242 | # EMPTY RESULT VALIDATION
243 | # ==================================================================================
244 | 
245 |   - it: "should return empty array for non-existent method names"
246 |     request:
247 |       jsonrpc: "2.0"
248 |       id: "search-nonexistent-method"
249 |       method: "tools/call"
250 |       params:
251 |         name: "search_sfcc_methods"
252 |         arguments:
253 |           methodName: "zzznothingfound"
254 |     expect:
255 |       response:
256 |         jsonrpc: "2.0"
257 |         id: "search-nonexistent-method"
258 |         result:
259 |           content:
260 |             - type: "text"
261 |               text: "match:regex:^\\[\\s*\\]$"  # Empty JSON array
262 |           isError: false
263 |       stderr: "toBeEmpty"
264 | 
265 |   - it: "should return empty array for very specific method name"
266 |     request:
267 |       jsonrpc: "2.0"
268 |       id: "search-specific-nonexistent"
269 |       method: "tools/call"
270 |       params:
271 |         name: "search_sfcc_methods"
272 |         arguments:
273 |           methodName: "verySpecificMethodThatDoesNotExist123"
274 |     expect:
275 |       response:
276 |         jsonrpc: "2.0"
277 |         id: "search-specific-nonexistent"
278 |         result:
279 |           content:
280 |             - type: "text"
281 |               text: "[]"  # Exact empty array
282 |           isError: false
283 |       stderr: "toBeEmpty"
284 | 
285 |   - it: "should return empty array for special characters in method name"
286 |     request:
287 |       jsonrpc: "2.0"
288 |       id: "search-special-chars"
289 |       method: "tools/call"
290 |       params:
291 |         name: "search_sfcc_methods"
292 |         arguments:
293 |           methodName: "method@#$%"
294 |     expect:
295 |       response:
296 |         jsonrpc: "2.0"
297 |         id: "search-special-chars"
298 |         result:
299 |           content:
300 |             - type: "text"
301 |               text: "match:regex:^\\[\\s*\\]$"  # Empty array for invalid method names
302 |           isError: false
303 |       stderr: "toBeEmpty"
304 | 
305 | # ==================================================================================
306 | # ERROR HANDLING VALIDATION
307 | # ==================================================================================
308 | 
309 |   - it: "should return error for empty method name"
310 |     request:
311 |       jsonrpc: "2.0"
312 |       id: "error-empty-method"
313 |       method: "tools/call"
314 |       params:
315 |         name: "search_sfcc_methods"
316 |         arguments:
317 |           methodName: ""
318 |     expect:
319 |       response:
320 |         jsonrpc: "2.0"
321 |         id: "error-empty-method"
322 |         result:
323 |           content:
324 |             - type: "text"
325 |               text: "match:contains:Error"
326 |           isError: true
327 |       stderr: "toBeEmpty"
328 | 
329 |   - it: "should return specific error message for empty method name"
330 |     request:
331 |       jsonrpc: "2.0"
332 |       id: "error-empty-message"
333 |       method: "tools/call"
334 |       params:
335 |         name: "search_sfcc_methods"
336 |         arguments:
337 |           methodName: ""
338 |     expect:
339 |       response:
340 |         jsonrpc: "2.0"
341 |         id: "error-empty-message"
342 |         result:
343 |           content:
344 |             - type: "text"
345 |               text: "match:contains:non-empty string"
346 |           isError: true
347 |       stderr: "toBeEmpty"
348 | 
349 |   - it: "should return error for missing methodName parameter"
350 |     request:
351 |       jsonrpc: "2.0"
352 |       id: "error-missing-param"
353 |       method: "tools/call"
354 |       params:
355 |         name: "search_sfcc_methods"
356 |         arguments: {}
357 |     expect:
358 |       response:
359 |         jsonrpc: "2.0"
360 |         id: "error-missing-param"
361 |         result:
362 |           content:
363 |             - type: "text"
364 |               text: "match:contains:Error"
365 |           isError: true
366 |       stderr: "toBeEmpty"
367 | 
368 |   - it: "should return error for whitespace-only method name"
369 |     request:
370 |       jsonrpc: "2.0"
371 |       id: "error-whitespace-method"
372 |       method: "tools/call"
373 |       params:
374 |         name: "search_sfcc_methods"
375 |         arguments:
376 |           methodName: "   "
377 |     expect:
378 |       response:
379 |         jsonrpc: "2.0"
380 |         id: "error-whitespace-method"
381 |         result:
382 |           content:
383 |             - type: "text"
384 |               text: "match:contains:Error"
385 |           isError: true
386 |       stderr: "toBeEmpty"
387 | 
388 |   - it: "should return error for null method name"
389 |     request:
390 |       jsonrpc: "2.0"
391 |       id: "error-null-method"
392 |       method: "tools/call"
393 |       params:
394 |         name: "search_sfcc_methods"
395 |         arguments:
396 |           methodName: null
397 |     expect:
398 |       response:
399 |         jsonrpc: "2.0"
400 |         id: "error-null-method"
401 |         result:
402 |           content:
403 |             - type: "text"
404 |               text: "match:contains:Error"
405 |           isError: true
406 |       stderr: "toBeEmpty"
407 | 
408 |   - it: "should return error for non-string method name (number)"
409 |     request:
410 |       jsonrpc: "2.0"
411 |       id: "error-number-method"
412 |       method: "tools/call"
413 |       params:
414 |         name: "search_sfcc_methods"
415 |         arguments:
416 |           methodName: 123
417 |     expect:
418 |       response:
419 |         jsonrpc: "2.0"
420 |         id: "error-number-method"
421 |         result:
422 |           content:
423 |             - type: "text"
424 |               text: "match:contains:Error"
425 |           isError: true
426 |       stderr: "toBeEmpty"
427 | 
428 |   - it: "should return error for non-string method name (boolean)"
429 |     request:
430 |       jsonrpc: "2.0"
431 |       id: "error-boolean-method"
432 |       method: "tools/call"
433 |       params:
434 |         name: "search_sfcc_methods"
435 |         arguments:
436 |           methodName: true
437 |     expect:
438 |       response:
439 |         jsonrpc: "2.0"
440 |         id: "error-boolean-method"
441 |         result:
442 |           content:
443 |             - type: "text"
444 |               text: "match:contains:Error"
445 |           isError: true
446 |       stderr: "toBeEmpty"
447 | 
448 | # ==================================================================================
449 | # PERFORMANCE AND RESPONSE TIME VALIDATION
450 | # ==================================================================================
451 | 
452 |   - it: "should complete method search within reasonable time (large result set)"
453 |     request:
454 |       jsonrpc: "2.0"
455 |       id: "perf-large-search"
456 |       method: "tools/call"
457 |       params:
458 |         name: "search_sfcc_methods"
459 |         arguments:
460 |           methodName: "get"  # Common method name with many results
461 |     expect:
462 |       response:
463 |         jsonrpc: "2.0"
464 |         id: "perf-large-search"
465 |         result:
466 |           content:
467 |             - type: "text"
468 |               text: "match:regex:\\[[\\s\\S]*\\]"
469 |           isError: false
470 |       performance:
471 |         maxResponseTime: "3000ms"  # Allow more time for comprehensive search
472 |       stderr: "toBeEmpty"
473 | 
474 |   - it: "should complete method search quickly for empty results"
475 |     request:
476 |       jsonrpc: "2.0"
477 |       id: "perf-empty-search"
478 |       method: "tools/call"
479 |       params:
480 |         name: "search_sfcc_methods"
481 |         arguments:
482 |           methodName: "zzznothingfound"
483 |     expect:
484 |       response:
485 |         jsonrpc: "2.0"
486 |         id: "perf-empty-search"
487 |         result:
488 |           content:
489 |             - type: "text"
490 |               text: "[]"  # Exact empty array
491 |           isError: false
492 |       performance:
493 |         maxResponseTime: "1000ms"  # Empty searches should be faster
494 |       stderr: "toBeEmpty"
495 | 
496 |   - it: "should handle error cases quickly"
497 |     request:
498 |       jsonrpc: "2.0"
499 |       id: "perf-error-handling"
500 |       method: "tools/call"
501 |       params:
502 |         name: "search_sfcc_methods"
503 |         arguments:
504 |           methodName: ""
505 |     expect:
506 |       response:
507 |         jsonrpc: "2.0"
508 |         id: "perf-error-handling"
509 |         result:
510 |           content:
511 |             - type: "text"
512 |               text: "match:contains:Error"
513 |           isError: true
514 |       performance:
515 |         maxResponseTime: "500ms"  # Error validation should be very fast
516 |       stderr: "toBeEmpty"
517 | 
518 | # ==================================================================================
519 | # EDGE CASE VALIDATION
520 | # ==================================================================================
521 | 
522 |   - it: "should handle single character method search"
523 |     request:
524 |       jsonrpc: "2.0"
525 |       id: "edge-single-char"
526 |       method: "tools/call"
527 |       params:
528 |         name: "search_sfcc_methods"
529 |         arguments:
530 |           methodName: "a"
531 |     expect:
532 |       response:
533 |         jsonrpc: "2.0"
534 |         id: "edge-single-char"
535 |         result:
536 |           content:
537 |             - type: "text"
538 |               text: "match:regex:\\[[\\s\\S]*\\]"  # Valid JSON array
539 |           isError: false
540 |       stderr: "toBeEmpty"
541 | 
542 |   - it: "should handle very long method name search"
543 |     request:
544 |       jsonrpc: "2.0"
545 |       id: "edge-long-method"
546 |       method: "tools/call"
547 |       params:
548 |         name: "search_sfcc_methods"
549 |         arguments:
550 |           methodName: "thisIsAVeryLongMethodNameThatProbablyDoesNotExistInTheSystem"
551 |     expect:
552 |       response:
553 |         jsonrpc: "2.0"
554 |         id: "edge-long-method"
555 |         result:
556 |           content:
557 |             - type: "text"
558 |               text: "match:regex:^\\[\\s*\\]$"  # Likely empty array for very long names
559 |           isError: false
560 |       stderr: "toBeEmpty"
561 | 
562 |   - it: "should handle method names with numbers"
563 |     request:
564 |       jsonrpc: "2.0"
565 |       id: "edge-method-with-numbers"
566 |       method: "tools/call"
567 |       params:
568 |         name: "search_sfcc_methods"
569 |         arguments:
570 |           methodName: "method123"
571 |     expect:
572 |       response:
573 |         jsonrpc: "2.0"
574 |         id: "edge-method-with-numbers"
575 |         result:
576 |           content:
577 |             - type: "text"
578 |               text: "match:regex:\\[[\\s\\S]*\\]"  # Valid response
579 |           isError: false
580 |       stderr: "toBeEmpty"
581 | 
582 |   - it: "should handle method names with underscores"
583 |     request:
584 |       jsonrpc: "2.0"
585 |       id: "edge-method-underscore"
586 |       method: "tools/call"
587 |       params:
588 |         name: "search_sfcc_methods"
589 |         arguments:
590 |           methodName: "method_name"
591 |     expect:
592 |       response:
593 |         jsonrpc: "2.0"
594 |         id: "edge-method-underscore"
595 |         result:
596 |           content:
597 |             - type: "text"
598 |               text: "match:regex:\\[[\\s\\S]*\\]"  # Valid response
599 |           isError: false
600 |       stderr: "toBeEmpty"
601 | 
602 | # ==================================================================================
603 | # CONTENT STRUCTURE VALIDATION
604 | # ==================================================================================
605 | 
606 |   - it: "should return methods with complete information structure (if results exist)"
607 |     request:
608 |       jsonrpc: "2.0"
609 |       id: "content-structure-complete"
610 |       method: "tools/call"
611 |       params:
612 |         name: "search_sfcc_methods"
613 |         arguments:
614 |           methodName: "get"  # Method likely to have results
615 |     expect:
616 |       response:
617 |         jsonrpc: "2.0"
618 |         id: "content-structure-complete"
619 |         result:
620 |           content:
621 |             - type: "text"
622 |               text: "match:contains:description"  # Should include method descriptions
623 |           isError: false
624 |       stderr: "toBeEmpty"
625 | 
626 |   - it: "should include both className and method information"
627 |     request:
628 |       jsonrpc: "2.0"
629 |       id: "content-both-class-method"
630 |       method: "tools/call"
631 |       params:
632 |         name: "search_sfcc_methods"
633 |         arguments:
634 |           methodName: "create"
635 |     expect:
636 |       response:
637 |         jsonrpc: "2.0"
638 |         id: "content-both-class-method"
639 |         result:
640 |           content:
641 |             - type: "text"
642 |               text: "match:regex:[\\s\\S]*className[\\s\\S]*method[\\s\\S]*"  # Contains both className and method
643 |           isError: false
644 |       stderr: "toBeEmpty"
645 | 
646 |   - it: "should maintain consistent response format across different searches"
647 |     request:
648 |       jsonrpc: "2.0"
649 |       id: "content-consistent-format"
650 |       method: "tools/call"
651 |       params:
652 |         name: "search_sfcc_methods"
653 |         arguments:
654 |           methodName: "getValue"
655 |     expect:
656 |       response:
657 |         jsonrpc: "2.0"
658 |         id: "content-consistent-format"
659 |         result:
660 |           content:
661 |             - type: "text"
662 |               text: "match:type:string"  # Always returns string content
663 |           isError: false
664 |       stderr: "toBeEmpty"
665 | 
666 | # ==================================================================================
667 | # INTEGRATION VALIDATION
668 | # ==================================================================================
669 | 
670 |   - it: "should be available in full-mode mode"
671 |     request:
672 |       jsonrpc: "2.0"
673 |       id: "integration-full-mode"
674 |       method: "tools/list"
675 |       params: {}
676 |     expect:
677 |       response:
678 |         jsonrpc: "2.0"
679 |         id: "integration-full-mode"
680 |         result:
681 |           match:extractField: "tools.*.name"
682 |           value: "match:arrayContains:search_sfcc_methods"
683 |       stderr: "toBeEmpty"
684 | 
685 |   - it: "should work with SFCC namespace prefixes in results"
686 |     request:
687 |       jsonrpc: "2.0"
688 |       id: "integration-namespace-prefix"
689 |       method: "tools/call"
690 |       params:
691 |         name: "search_sfcc_methods"
692 |         arguments:
693 |           methodName: "get"
694 |     expect:
695 |       response:
696 |         jsonrpc: "2.0"
697 |         id: "integration-namespace-prefix"
698 |         result:
699 |           content:
700 |             - type: "text"
701 |               text: "match:regex:[\\s\\S]*dw_[a-z]+\\.[A-Z][\\s\\S]*"  # Contains SFCC class patterns like dw_catalog.Product
702 |           isError: false
703 |       stderr: "toBeEmpty"
704 | 
705 |   - it: "should return methods from multiple SFCC namespaces"
706 |     request:
707 |       jsonrpc: "2.0"
708 |       id: "integration-multiple-namespaces"
709 |       method: "tools/call"
710 |       params:
711 |         name: "search_sfcc_methods"
712 |         arguments:
713 |           methodName: "toString"  # Common method across many classes
714 |     expect:
715 |       response:
716 |         jsonrpc: "2.0"
717 |         id: "integration-multiple-namespaces"
718 |         result:
719 |           content:
720 |             - type: "text"
721 |               text: "match:regex:[\\s\\S]*dw_[a-z]+[\\s\\S]*"  # Should find methods in various dw_ namespaces
722 |           isError: false
723 |       stderr: "toBeEmpty"
724 | 
```

--------------------------------------------------------------------------------
/tests/mcp/yaml/search-sfcc-methods.docs-only.test.mcp.yml:
--------------------------------------------------------------------------------

```yaml
  1 | # ==================================================================================
  2 | # SFCC MCP Server - search_sfcc_methods Tool YAML Tests
  3 | # Comprehensive testing for SFCC method search functionality
  4 | # Tests both successful responses and error handling scenarios
  5 | # 
  6 | # Quick Test Commands:
  7 | # aegis "tests/mcp/yaml/search-sfcc-methods.docs-only.test.mcp.yml" --config "aegis.config.docs-only.json" --verbose
  8 | # aegis "tests/mcp/yaml/search-sfcc-methods.docs-only.test.mcp.yml" --config "aegis.config.docs-only.json" --debug --timing
  9 | # aegis query search_sfcc_methods '{"methodName": "get"}' --config "aegis.config.docs-only.json"
 10 | # aegis query search_sfcc_methods '{"methodName": "create"}' --config "aegis.config.docs-only.json"
 11 | # ==================================================================================
 12 | description: "SFCC MCP Server search_sfcc_methods tool - comprehensive validation"
 13 | 
 14 | # ==================================================================================
 15 | # BASIC TOOL STRUCTURE VALIDATION
 16 | # ==================================================================================
 17 | tests:
 18 |   - it: "should list search_sfcc_methods tool in available tools"
 19 |     request:
 20 |       jsonrpc: "2.0"
 21 |       id: "tool-available"
 22 |       method: "tools/list"
 23 |       params: {}
 24 |     expect:
 25 |       response:
 26 |         jsonrpc: "2.0"
 27 |         id: "tool-available"
 28 |         result:
 29 |           match:extractField: "tools.*.name"
 30 |           value: "match:arrayContains:search_sfcc_methods"
 31 |       stderr: "toBeEmpty"
 32 | 
 33 |   - it: "should have search_sfcc_methods in tools list with proper structure"
 34 |     request:
 35 |       jsonrpc: "2.0"
 36 |       id: "tool-metadata"
 37 |       method: "tools/list"
 38 |       params: {}
 39 |     expect:
 40 |       response:
 41 |         jsonrpc: "2.0"
 42 |         id: "tool-metadata"
 43 |         result:
 44 |           tools: "match:arrayContains:name:search_sfcc_methods"
 45 |       stderr: "toBeEmpty"
 46 | 
 47 |   - it: "should have tool with meaningful description"
 48 |     request:
 49 |       jsonrpc: "2.0"
 50 |       id: "tool-description-quality"
 51 |       method: "tools/list"
 52 |       params: {}
 53 |     expect:
 54 |       response:
 55 |         jsonrpc: "2.0"
 56 |         id: "tool-description-quality"
 57 |         result:
 58 |           tools:
 59 |             match:arrayContains:name:search_sfcc_methods
 60 |       stderr: "toBeEmpty"
 61 | 
 62 |   - it: "should have proper input schema for methodName parameter"
 63 |     request:
 64 |       jsonrpc: "2.0"
 65 |       id: "tool-schema-validation"
 66 |       method: "tools/list"
 67 |       params: {}
 68 |     expect:
 69 |       response:
 70 |         jsonrpc: "2.0"
 71 |         id: "tool-schema-validation"
 72 |         result:
 73 |           match:extractField: "tools.*.name"
 74 |           value: "match:arrayContains:search_sfcc_methods"
 75 |       stderr: "toBeEmpty"
 76 | 
 77 | # ==================================================================================
 78 | # SUCCESSFUL METHOD SEARCH OPERATIONS
 79 | # ==================================================================================
 80 | 
 81 |   - it: "should successfully search for 'get' methods returning valid JSON array"
 82 |     request:
 83 |       jsonrpc: "2.0"
 84 |       id: "search-get-methods"
 85 |       method: "tools/call"
 86 |       params:
 87 |         name: "search_sfcc_methods"
 88 |         arguments:
 89 |           methodName: "get"
 90 |     expect:
 91 |       response:
 92 |         jsonrpc: "2.0"
 93 |         id: "search-get-methods"
 94 |         result:
 95 |           content:
 96 |             - type: "text"
 97 |               text: "match:regex:\\[[\\s\\S]*\\]"  # Valid JSON array structure
 98 |           isError: false
 99 |       stderr: "toBeEmpty"
100 | 
101 |   - it: "should find multiple get methods with proper structure"
102 |     request:
103 |       jsonrpc: "2.0"
104 |       id: "search-get-structure"
105 |       method: "tools/call"
106 |       params:
107 |         name: "search_sfcc_methods"
108 |         arguments:
109 |           methodName: "get"
110 |     expect:
111 |       response:
112 |         jsonrpc: "2.0"
113 |         id: "search-get-structure"
114 |         result:
115 |           content:
116 |             - type: "text"
117 |               text: "match:contains:className"  # Should contain className field
118 |           isError: false
119 |       stderr: "toBeEmpty"
120 | 
121 |   - it: "should find get methods with method objects containing name and signature"
122 |     request:
123 |       jsonrpc: "2.0"
124 |       id: "search-get-method-details"
125 |       method: "tools/call"
126 |       params:
127 |         name: "search_sfcc_methods"
128 |         arguments:
129 |           methodName: "get"
130 |     expect:
131 |       response:
132 |         jsonrpc: "2.0"
133 |         id: "search-get-method-details"
134 |         result:
135 |           content:
136 |             - type: "text"
137 |               text: "match:contains:signature"  # Should contain signature information
138 |           isError: false
139 |       stderr: "toBeEmpty"
140 | 
141 |   - it: "should successfully search for 'create' methods"
142 |     request:
143 |       jsonrpc: "2.0"
144 |       id: "search-create-methods"
145 |       method: "tools/call"
146 |       params:
147 |         name: "search_sfcc_methods"
148 |         arguments:
149 |           methodName: "create"
150 |     expect:
151 |       response:
152 |         jsonrpc: "2.0"
153 |         id: "search-create-methods"
154 |         result:
155 |           content:
156 |             - type: "text"
157 |               text: "match:regex:\\[[\\s\\S]*\\]"  # Valid JSON array
158 |           isError: false
159 |       stderr: "toBeEmpty"
160 | 
161 |   - it: "should find create methods containing relevant class information"
162 |     request:
163 |       jsonrpc: "2.0"
164 |       id: "search-create-content"
165 |       method: "tools/call"
166 |       params:
167 |         name: "search_sfcc_methods"
168 |         arguments:
169 |           methodName: "create"
170 |     expect:
171 |       response:
172 |         jsonrpc: "2.0"
173 |         id: "search-create-content"
174 |         result:
175 |           content:
176 |             - type: "text"
177 |               text: "match:contains:dw_"  # Should contain SFCC class references
178 |           isError: false
179 |       stderr: "toBeEmpty"
180 | 
181 |   - it: "should successfully search for 'toString' method"
182 |     request:
183 |       jsonrpc: "2.0"
184 |       id: "search-tostring-method"
185 |       method: "tools/call"
186 |       params:
187 |         name: "search_sfcc_methods"
188 |         arguments:
189 |           methodName: "toString"
190 |     expect:
191 |       response:
192 |         jsonrpc: "2.0"
193 |         id: "search-tostring-method"
194 |         result:
195 |           content:
196 |             - type: "text"
197 |               text: "match:regex:\\[[\\s\\S]*\\]"  # Valid JSON array
198 |           isError: false
199 |       stderr: "toBeEmpty"
200 | 
201 |   - it: "should successfully search for 'getValue' method"
202 |     request:
203 |       jsonrpc: "2.0"
204 |       id: "search-getvalue-method"
205 |       method: "tools/call"
206 |       params:
207 |         name: "search_sfcc_methods"
208 |         arguments:
209 |           methodName: "getValue"
210 |     expect:
211 |       response:
212 |         jsonrpc: "2.0"
213 |         id: "search-getvalue-method"
214 |         result:
215 |           content:
216 |             - type: "text"
217 |               text: "match:contains:getValue"  # Should contain the searched method name
218 |           isError: false
219 |       stderr: "toBeEmpty"
220 | 
221 |   - it: "should handle case-sensitive method search"
222 |     request:
223 |       jsonrpc: "2.0"
224 |       id: "search-case-sensitive"
225 |       method: "tools/call"
226 |       params:
227 |         name: "search_sfcc_methods"
228 |         arguments:
229 |           methodName: "GET"  # Uppercase should be different from 'get'
230 |     expect:
231 |       response:
232 |         jsonrpc: "2.0"
233 |         id: "search-case-sensitive"
234 |         result:
235 |           content:
236 |             - type: "text"
237 |               text: "match:regex:\\[[\\s\\S]*\\]"  # Should still return valid array (might be empty)
238 |           isError: false
239 |       stderr: "toBeEmpty"
240 | 
241 | # ==================================================================================
242 | # EMPTY RESULT VALIDATION
243 | # ==================================================================================
244 | 
245 |   - it: "should return empty array for non-existent method names"
246 |     request:
247 |       jsonrpc: "2.0"
248 |       id: "search-nonexistent-method"
249 |       method: "tools/call"
250 |       params:
251 |         name: "search_sfcc_methods"
252 |         arguments:
253 |           methodName: "zzznothingfound"
254 |     expect:
255 |       response:
256 |         jsonrpc: "2.0"
257 |         id: "search-nonexistent-method"
258 |         result:
259 |           content:
260 |             - type: "text"
261 |               text: "match:regex:^\\[\\s*\\]$"  # Empty JSON array
262 |           isError: false
263 |       stderr: "toBeEmpty"
264 | 
265 |   - it: "should return empty array for very specific method name"
266 |     request:
267 |       jsonrpc: "2.0"
268 |       id: "search-specific-nonexistent"
269 |       method: "tools/call"
270 |       params:
271 |         name: "search_sfcc_methods"
272 |         arguments:
273 |           methodName: "verySpecificMethodThatDoesNotExist123"
274 |     expect:
275 |       response:
276 |         jsonrpc: "2.0"
277 |         id: "search-specific-nonexistent"
278 |         result:
279 |           content:
280 |             - type: "text"
281 |               text: "[]"  # Exact empty array
282 |           isError: false
283 |       stderr: "toBeEmpty"
284 | 
285 |   - it: "should return empty array for special characters in method name"
286 |     request:
287 |       jsonrpc: "2.0"
288 |       id: "search-special-chars"
289 |       method: "tools/call"
290 |       params:
291 |         name: "search_sfcc_methods"
292 |         arguments:
293 |           methodName: "method@#$%"
294 |     expect:
295 |       response:
296 |         jsonrpc: "2.0"
297 |         id: "search-special-chars"
298 |         result:
299 |           content:
300 |             - type: "text"
301 |               text: "match:regex:^\\[\\s*\\]$"  # Empty array for invalid method names
302 |           isError: false
303 |       stderr: "toBeEmpty"
304 | 
305 | # ==================================================================================
306 | # ERROR HANDLING VALIDATION
307 | # ==================================================================================
308 | 
309 |   - it: "should return error for empty method name"
310 |     request:
311 |       jsonrpc: "2.0"
312 |       id: "error-empty-method"
313 |       method: "tools/call"
314 |       params:
315 |         name: "search_sfcc_methods"
316 |         arguments:
317 |           methodName: ""
318 |     expect:
319 |       response:
320 |         jsonrpc: "2.0"
321 |         id: "error-empty-method"
322 |         result:
323 |           content:
324 |             - type: "text"
325 |               text: "match:contains:Error"
326 |           isError: true
327 |       stderr: "toBeEmpty"
328 | 
329 |   - it: "should return specific error message for empty method name"
330 |     request:
331 |       jsonrpc: "2.0"
332 |       id: "error-empty-message"
333 |       method: "tools/call"
334 |       params:
335 |         name: "search_sfcc_methods"
336 |         arguments:
337 |           methodName: ""
338 |     expect:
339 |       response:
340 |         jsonrpc: "2.0"
341 |         id: "error-empty-message"
342 |         result:
343 |           content:
344 |             - type: "text"
345 |               text: "match:contains:non-empty string"
346 |           isError: true
347 |       stderr: "toBeEmpty"
348 | 
349 |   - it: "should return error for missing methodName parameter"
350 |     request:
351 |       jsonrpc: "2.0"
352 |       id: "error-missing-param"
353 |       method: "tools/call"
354 |       params:
355 |         name: "search_sfcc_methods"
356 |         arguments: {}
357 |     expect:
358 |       response:
359 |         jsonrpc: "2.0"
360 |         id: "error-missing-param"
361 |         result:
362 |           content:
363 |             - type: "text"
364 |               text: "match:contains:Error"
365 |           isError: true
366 |       stderr: "toBeEmpty"
367 | 
368 |   - it: "should return error for whitespace-only method name"
369 |     request:
370 |       jsonrpc: "2.0"
371 |       id: "error-whitespace-method"
372 |       method: "tools/call"
373 |       params:
374 |         name: "search_sfcc_methods"
375 |         arguments:
376 |           methodName: "   "
377 |     expect:
378 |       response:
379 |         jsonrpc: "2.0"
380 |         id: "error-whitespace-method"
381 |         result:
382 |           content:
383 |             - type: "text"
384 |               text: "match:contains:Error"
385 |           isError: true
386 |       stderr: "toBeEmpty"
387 | 
388 |   - it: "should return error for null method name"
389 |     request:
390 |       jsonrpc: "2.0"
391 |       id: "error-null-method"
392 |       method: "tools/call"
393 |       params:
394 |         name: "search_sfcc_methods"
395 |         arguments:
396 |           methodName: null
397 |     expect:
398 |       response:
399 |         jsonrpc: "2.0"
400 |         id: "error-null-method"
401 |         result:
402 |           content:
403 |             - type: "text"
404 |               text: "match:contains:Error"
405 |           isError: true
406 |       stderr: "toBeEmpty"
407 | 
408 |   - it: "should return error for non-string method name (number)"
409 |     request:
410 |       jsonrpc: "2.0"
411 |       id: "error-number-method"
412 |       method: "tools/call"
413 |       params:
414 |         name: "search_sfcc_methods"
415 |         arguments:
416 |           methodName: 123
417 |     expect:
418 |       response:
419 |         jsonrpc: "2.0"
420 |         id: "error-number-method"
421 |         result:
422 |           content:
423 |             - type: "text"
424 |               text: "match:contains:Error"
425 |           isError: true
426 |       stderr: "toBeEmpty"
427 | 
428 |   - it: "should return error for non-string method name (boolean)"
429 |     request:
430 |       jsonrpc: "2.0"
431 |       id: "error-boolean-method"
432 |       method: "tools/call"
433 |       params:
434 |         name: "search_sfcc_methods"
435 |         arguments:
436 |           methodName: true
437 |     expect:
438 |       response:
439 |         jsonrpc: "2.0"
440 |         id: "error-boolean-method"
441 |         result:
442 |           content:
443 |             - type: "text"
444 |               text: "match:contains:Error"
445 |           isError: true
446 |       stderr: "toBeEmpty"
447 | 
448 | # ==================================================================================
449 | # PERFORMANCE AND RESPONSE TIME VALIDATION
450 | # ==================================================================================
451 | 
452 |   - it: "should complete method search within reasonable time (large result set)"
453 |     request:
454 |       jsonrpc: "2.0"
455 |       id: "perf-large-search"
456 |       method: "tools/call"
457 |       params:
458 |         name: "search_sfcc_methods"
459 |         arguments:
460 |           methodName: "get"  # Common method name with many results
461 |     expect:
462 |       response:
463 |         jsonrpc: "2.0"
464 |         id: "perf-large-search"
465 |         result:
466 |           content:
467 |             - type: "text"
468 |               text: "match:regex:\\[[\\s\\S]*\\]"
469 |           isError: false
470 |       performance:
471 |         maxResponseTime: "3000ms"  # Allow more time for comprehensive search
472 |       stderr: "toBeEmpty"
473 | 
474 |   - it: "should complete method search quickly for empty results"
475 |     request:
476 |       jsonrpc: "2.0"
477 |       id: "perf-empty-search"
478 |       method: "tools/call"
479 |       params:
480 |         name: "search_sfcc_methods"
481 |         arguments:
482 |           methodName: "zzznothingfound"
483 |     expect:
484 |       response:
485 |         jsonrpc: "2.0"
486 |         id: "perf-empty-search"
487 |         result:
488 |           content:
489 |             - type: "text"
490 |               text: "[]"  # Exact empty array
491 |           isError: false
492 |       performance:
493 |         maxResponseTime: "1000ms"  # Empty searches should be faster
494 |       stderr: "toBeEmpty"
495 | 
496 |   - it: "should handle error cases quickly"
497 |     request:
498 |       jsonrpc: "2.0"
499 |       id: "perf-error-handling"
500 |       method: "tools/call"
501 |       params:
502 |         name: "search_sfcc_methods"
503 |         arguments:
504 |           methodName: ""
505 |     expect:
506 |       response:
507 |         jsonrpc: "2.0"
508 |         id: "perf-error-handling"
509 |         result:
510 |           content:
511 |             - type: "text"
512 |               text: "match:contains:Error"
513 |           isError: true
514 |       performance:
515 |         maxResponseTime: "500ms"  # Error validation should be very fast
516 |       stderr: "toBeEmpty"
517 | 
518 | # ==================================================================================
519 | # EDGE CASE VALIDATION
520 | # ==================================================================================
521 | 
522 |   - it: "should handle single character method search"
523 |     request:
524 |       jsonrpc: "2.0"
525 |       id: "edge-single-char"
526 |       method: "tools/call"
527 |       params:
528 |         name: "search_sfcc_methods"
529 |         arguments:
530 |           methodName: "a"
531 |     expect:
532 |       response:
533 |         jsonrpc: "2.0"
534 |         id: "edge-single-char"
535 |         result:
536 |           content:
537 |             - type: "text"
538 |               text: "match:regex:\\[[\\s\\S]*\\]"  # Valid JSON array
539 |           isError: false
540 |       stderr: "toBeEmpty"
541 | 
542 |   - it: "should handle very long method name search"
543 |     request:
544 |       jsonrpc: "2.0"
545 |       id: "edge-long-method"
546 |       method: "tools/call"
547 |       params:
548 |         name: "search_sfcc_methods"
549 |         arguments:
550 |           methodName: "thisIsAVeryLongMethodNameThatProbablyDoesNotExistInTheSystem"
551 |     expect:
552 |       response:
553 |         jsonrpc: "2.0"
554 |         id: "edge-long-method"
555 |         result:
556 |           content:
557 |             - type: "text"
558 |               text: "match:regex:^\\[\\s*\\]$"  # Likely empty array for very long names
559 |           isError: false
560 |       stderr: "toBeEmpty"
561 | 
562 |   - it: "should handle method names with numbers"
563 |     request:
564 |       jsonrpc: "2.0"
565 |       id: "edge-method-with-numbers"
566 |       method: "tools/call"
567 |       params:
568 |         name: "search_sfcc_methods"
569 |         arguments:
570 |           methodName: "method123"
571 |     expect:
572 |       response:
573 |         jsonrpc: "2.0"
574 |         id: "edge-method-with-numbers"
575 |         result:
576 |           content:
577 |             - type: "text"
578 |               text: "match:regex:\\[[\\s\\S]*\\]"  # Valid response
579 |           isError: false
580 |       stderr: "toBeEmpty"
581 | 
582 |   - it: "should handle method names with underscores"
583 |     request:
584 |       jsonrpc: "2.0"
585 |       id: "edge-method-underscore"
586 |       method: "tools/call"
587 |       params:
588 |         name: "search_sfcc_methods"
589 |         arguments:
590 |           methodName: "method_name"
591 |     expect:
592 |       response:
593 |         jsonrpc: "2.0"
594 |         id: "edge-method-underscore"
595 |         result:
596 |           content:
597 |             - type: "text"
598 |               text: "match:regex:\\[[\\s\\S]*\\]"  # Valid response
599 |           isError: false
600 |       stderr: "toBeEmpty"
601 | 
602 | # ==================================================================================
603 | # CONTENT STRUCTURE VALIDATION
604 | # ==================================================================================
605 | 
606 |   - it: "should return methods with complete information structure (if results exist)"
607 |     request:
608 |       jsonrpc: "2.0"
609 |       id: "content-structure-complete"
610 |       method: "tools/call"
611 |       params:
612 |         name: "search_sfcc_methods"
613 |         arguments:
614 |           methodName: "get"  # Method likely to have results
615 |     expect:
616 |       response:
617 |         jsonrpc: "2.0"
618 |         id: "content-structure-complete"
619 |         result:
620 |           content:
621 |             - type: "text"
622 |               text: "match:contains:description"  # Should include method descriptions
623 |           isError: false
624 |       stderr: "toBeEmpty"
625 | 
626 |   - it: "should include both className and method information"
627 |     request:
628 |       jsonrpc: "2.0"
629 |       id: "content-both-class-method"
630 |       method: "tools/call"
631 |       params:
632 |         name: "search_sfcc_methods"
633 |         arguments:
634 |           methodName: "create"
635 |     expect:
636 |       response:
637 |         jsonrpc: "2.0"
638 |         id: "content-both-class-method"
639 |         result:
640 |           content:
641 |             - type: "text"
642 |               text: "match:regex:[\\s\\S]*className[\\s\\S]*method[\\s\\S]*"  # Contains both className and method
643 |           isError: false
644 |       stderr: "toBeEmpty"
645 | 
646 |   - it: "should maintain consistent response format across different searches"
647 |     request:
648 |       jsonrpc: "2.0"
649 |       id: "content-consistent-format"
650 |       method: "tools/call"
651 |       params:
652 |         name: "search_sfcc_methods"
653 |         arguments:
654 |           methodName: "getValue"
655 |     expect:
656 |       response:
657 |         jsonrpc: "2.0"
658 |         id: "content-consistent-format"
659 |         result:
660 |           content:
661 |             - type: "text"
662 |               text: "match:type:string"  # Always returns string content
663 |           isError: false
664 |       stderr: "toBeEmpty"
665 | 
666 | # ==================================================================================
667 | # INTEGRATION VALIDATION
668 | # ==================================================================================
669 | 
670 |   - it: "should be available in docs-only mode"
671 |     request:
672 |       jsonrpc: "2.0"
673 |       id: "integration-docs-only"
674 |       method: "tools/list"
675 |       params: {}
676 |     expect:
677 |       response:
678 |         jsonrpc: "2.0"
679 |         id: "integration-docs-only"
680 |         result:
681 |           match:extractField: "tools.*.name"
682 |           value: "match:arrayContains:search_sfcc_methods"
683 |       stderr: "toBeEmpty"
684 | 
685 |   - it: "should work with SFCC namespace prefixes in results"
686 |     request:
687 |       jsonrpc: "2.0"
688 |       id: "integration-namespace-prefix"
689 |       method: "tools/call"
690 |       params:
691 |         name: "search_sfcc_methods"
692 |         arguments:
693 |           methodName: "get"
694 |     expect:
695 |       response:
696 |         jsonrpc: "2.0"
697 |         id: "integration-namespace-prefix"
698 |         result:
699 |           content:
700 |             - type: "text"
701 |               text: "match:regex:[\\s\\S]*dw_[a-z]+\\.[A-Z][\\s\\S]*"  # Contains SFCC class patterns like dw_catalog.Product
702 |           isError: false
703 |       stderr: "toBeEmpty"
704 | 
705 |   - it: "should return methods from multiple SFCC namespaces"
706 |     request:
707 |       jsonrpc: "2.0"
708 |       id: "integration-multiple-namespaces"
709 |       method: "tools/call"
710 |       params:
711 |         name: "search_sfcc_methods"
712 |         arguments:
713 |           methodName: "toString"  # Common method across many classes
714 |     expect:
715 |       response:
716 |         jsonrpc: "2.0"
717 |         id: "integration-multiple-namespaces"
718 |         result:
719 |           content:
720 |             - type: "text"
721 |               text: "match:regex:[\\s\\S]*dw_[a-z]+[\\s\\S]*"  # Should find methods in various dw_ namespaces
722 |           isError: false
723 |       stderr: "toBeEmpty"
724 | 
```

--------------------------------------------------------------------------------
/tests/mcp/node/get-sfra-document.programmatic.test.js:
--------------------------------------------------------------------------------

```javascript
  1 | import { test, describe, before, after, beforeEach } from 'node:test';
  2 | import { strict as assert } from 'node:assert';
  3 | import { connect } from 'mcp-aegis';
  4 | 
  5 | describe('get_sfra_document Tool - Programmatic Tests', () => {
  6 |   let client;
  7 | 
  8 |   before(async () => {
  9 |     client = await connect('./aegis.config.docs-only.json');
 10 |   });
 11 | 
 12 |   after(async () => {
 13 |     if (client?.connected) {
 14 |       await client.disconnect();
 15 |     }
 16 |   });
 17 | 
 18 |   beforeEach(() => {
 19 |     client.clearAllBuffers();
 20 |   });
 21 | 
 22 |   describe('Protocol Compliance & Tool Discovery', () => {
 23 |     test('should be registered and accessible', async () => {
 24 |       const tools = await client.listTools();
 25 |       
 26 |       const sfraDocTool = tools.find(tool => tool.name === 'get_sfra_document');
 27 |       assert.ok(sfraDocTool, 'get_sfra_document tool should be available');
 28 |       
 29 |       // Validate tool schema structure
 30 |       assertToolSchema(sfraDocTool);
 31 |       
 32 |       // Validate specific schema requirements
 33 |       const { inputSchema } = sfraDocTool;
 34 |       assert.ok(inputSchema.properties.documentName, 'Should have documentName parameter');
 35 |       assert.equal(inputSchema.properties.documentName.type, 'string');
 36 |       assert.ok(inputSchema.required.includes('documentName'), 'documentName should be required');
 37 |     });
 38 | 
 39 |     test('should have comprehensive tool description', async () => {
 40 |       const tools = await client.listTools();
 41 |       const sfraDocTool = tools.find(tool => tool.name === 'get_sfra_document');
 42 |       
 43 |       const description = sfraDocTool.description.toLowerCase();
 44 |       assert.ok(description.includes('sfra'), 'Description should mention SFRA');
 45 |       assert.ok(description.includes('documentation'), 'Description should mention documentation');
 46 |       assert.ok(description.includes('sfra') || description.includes('class') || description.includes('model'), 
 47 |         'Description should mention SFRA classes or models');
 48 |       assert.ok(description.length > 100, 'Description should be comprehensive');
 49 |     });
 50 |   });
 51 | 
 52 |   describe('Core SFRA Documents - Dynamic Discovery', () => {
 53 |     const coreDocuments = [
 54 |       { name: 'server', expectedContent: ['Class Server', 'middleware', 'routing'] },
 55 |       { name: 'request', expectedContent: ['Class Request', 'HTTP', 'session'] },
 56 |       { name: 'response', expectedContent: ['Class Response', 'render', 'redirect'] },
 57 |       { name: 'querystring', expectedContent: ['QueryString', 'parameters', 'URL'] },
 58 |       { name: 'render', expectedContent: ['render', 'template', 'ISML'] }
 59 |     ];
 60 | 
 61 |     coreDocuments.forEach(({ name, expectedContent }) => {
 62 |       test(`should retrieve ${name} document with rich content`, async () => {
 63 |         const result = await client.callTool('get_sfra_document', { documentName: name });
 64 | 
 65 |         // Basic response validation
 66 |         assertValidMCPResponse(result);
 67 |         assert.equal(result.isError, false, `${name} document should load successfully`);
 68 | 
 69 |         // Parse and validate JSON content
 70 |         const documentData = parseDocumentJSON(result.content[0].text);
 71 |         
 72 |         // Validate document structure
 73 |         assertDocumentStructure(documentData, name);
 74 |         
 75 |         // Validate expected content is present
 76 |         expectedContent.forEach(content => {
 77 |           assert.ok(
 78 |             documentData.content.toLowerCase().includes(content.toLowerCase()),
 79 |             `${name} document should contain "${content}"`
 80 |           );
 81 |         });
 82 |       });
 83 |     });
 84 | 
 85 |     test('should maintain consistent document structure across all core docs', async () => {
 86 |       const results = [];
 87 |       
 88 |       // Process documents sequentially to avoid message stream interference
 89 |       for (let i = 0; i < coreDocuments.length; i++) {
 90 |         const { name } = coreDocuments[i];
 91 |         const result = await client.callTool('get_sfra_document', { documentName: name });
 92 |         const documentData = parseDocumentJSON(result.content[0].text);
 93 |         results.push({ name, documentData });
 94 |       }
 95 | 
 96 |       // Validate all documents have consistent structure
 97 |       results.forEach(({ name, documentData }) => {
 98 |         assert.ok(documentData.title, `${name} should have title`);
 99 |         assert.ok(Array.isArray(documentData.sections), `${name} should have sections array`);
100 |         assert.ok(documentData.content, `${name} should have content`);
101 |         assert.ok(documentData.type, `${name} should have type`);
102 |         assert.ok(documentData.category, `${name} should have category`);
103 |         assert.ok(documentData.filename, `${name} should have filename`);
104 |         assert.ok(documentData.lastModified, `${name} should have lastModified`);
105 |         
106 |         // Validate sections are comprehensive
107 |         assert.ok(documentData.sections.length >= 5, `${name} should have at least 5 sections`);
108 |         
109 |         // Validate content is substantial
110 |         assert.ok(documentData.content.length > 1000, `${name} should have substantial content`);
111 |       });
112 |       assert.ok(results.length > 0, 'Should have processed core documents');
113 |     });
114 |   });
115 | 
116 |   describe('Model Documents - Advanced Validation', () => {
117 |     const modelDocuments = [
118 |       { name: 'product-full', category: 'product', keywords: ['product', 'pricing', 'variation'] },
119 |       { name: 'cart', category: 'order', keywords: ['cart', 'basket', 'items'] },
120 |       { name: 'account', category: 'customer', keywords: ['account', 'customer', 'profile'] },
121 |       { name: 'billing', category: 'order', keywords: ['billing', 'payment', 'address'] },
122 |       { name: 'shipping', category: 'order', keywords: ['shipping', 'delivery', 'address'] }
123 |     ];
124 | 
125 |     test('should retrieve all model documents with correct categorization', async () => {
126 |       const results = [];
127 |       
128 |       // Process documents sequentially to avoid message stream interference
129 |       for (let i = 0; i < modelDocuments.length; i++) {
130 |         const { name, category, keywords } = modelDocuments[i];
131 |         const result = await client.callTool('get_sfra_document', { documentName: name });
132 |         assert.equal(result.isError, false, `${name} should load successfully`);
133 |         
134 |         const documentData = parseDocumentJSON(result.content[0].text);
135 |         
136 |         // Validate keywords are present in content
137 |         const content = documentData.content.toLowerCase();
138 |         const keywordMatches = keywords.filter(keyword => 
139 |           content.includes(keyword.toLowerCase())
140 |         );
141 |         
142 |         assert.ok(keywordMatches.length >= 1, 
143 |           `${name} should contain at least one keyword: ${keywords.join(', ')}`);
144 |         
145 |         results.push({ name, documentData, category, keywordMatches });
146 |       }
147 | 
148 |       // Group by category and validate
149 |       const categoryGroups = results.reduce((groups, { name, category }) => {
150 |         if (!groups[category]) groups[category] = [];
151 |         groups[category].push(name);
152 |         return groups;
153 |       }, {});
154 | 
155 |       // Validate category distribution
156 |       Object.entries(categoryGroups).forEach(([category, docs]) => {
157 |         assert.ok(docs.length > 0, `Category ${category} should have documents`);
158 |       });
159 |     });
160 | 
161 |     test('should handle hyphenated document names correctly', async () => {
162 |       const hyphenatedDocs = modelDocuments
163 |         .filter(({ name }) => name.includes('-'))
164 |         .map(({ name }) => name);
165 | 
166 |       assert.ok(hyphenatedDocs.length > 0, 'Should have hyphenated document names to test');
167 | 
168 |       for (const docName of hyphenatedDocs) {
169 |         const result = await client.callTool('get_sfra_document', { documentName: docName });
170 |         assert.equal(result.isError, false, `Hyphenated document ${docName} should work`);
171 |         
172 |         const documentData = parseDocumentJSON(result.content[0].text);
173 |         // More flexible filename checking - just ensure it's related to the document
174 |         const filenameRelated = documentData.filename.toLowerCase().includes(docName.toLowerCase()) || 
175 |                               documentData.filename.toLowerCase().replace(/-/g, '').includes(docName.toLowerCase().replace(/-/g, '')) ||
176 |                               documentData.title.toLowerCase().includes(docName.toLowerCase().split('-')[0]);
177 |         assert.ok(filenameRelated,
178 |                  `Filename should be related to ${docName}: ${documentData.filename}`);
179 |         
180 |       }
181 |     });
182 |   });
183 | 
184 |   describe('Case Sensitivity & Input Validation', () => {
185 |     const caseTestCases = [
186 |       { input: 'server', expected: true, description: 'lowercase' },
187 |       { input: 'SERVER', expected: true, description: 'uppercase' },
188 |       { input: 'Server', expected: true, description: 'mixed case' },
189 |       { input: 'SeRvEr', expected: true, description: 'random case' },
190 |       { input: 'request', expected: true, description: 'lowercase request' },
191 |       { input: 'REQUEST', expected: true, description: 'uppercase request' }
192 |     ];
193 | 
194 |     test('should handle case variations consistently', async () => {
195 |       const results = [];
196 |       
197 |       // Process case variations sequentially to avoid message stream interference
198 |       for (let i = 0; i < caseTestCases.length; i++) {
199 |         const { input, expected, description } = caseTestCases[i];
200 |         const result = await client.callTool('get_sfra_document', { documentName: input });
201 |         const success = !result.isError;
202 |         
203 |         assert.equal(success, expected, 
204 |           `${description} "${input}" should ${expected ? 'succeed' : 'fail'}`);
205 |         
206 |         if (success) {
207 |           const documentData = parseDocumentJSON(result.content[0].text);
208 |           // Case variations should return the same document
209 |           assert.ok(documentData.title.includes('Server') || documentData.title.includes('Request'),
210 |             'Should return valid SFRA document');
211 |         }
212 |         
213 |         results.push({ input, success, description });
214 |         
215 |       }
216 | 
217 |       // Verify case insensitivity
218 |       const serverVariants = results
219 |         .filter(({ input }) => input.toLowerCase() === 'server')
220 |         .filter(({ success }) => success);
221 | 
222 |       assert.ok(serverVariants.length > 1, 'Multiple case variations should work for server');
223 |       assert.ok(serverVariants.length > 0, 'Should handle case insensitive variations');
224 |     });
225 | 
226 |     test('should validate input parameters thoroughly', async () => {
227 |       const invalidInputs = [
228 |         { args: {}, expectedError: 'documentName', description: 'missing parameter' },
229 |         { args: { documentName: '' }, expectedError: 'non-empty', description: 'empty string' },
230 |         { args: { documentName: null }, expectedError: 'string', description: 'null value' },
231 |         { args: { documentName: 123 }, expectedError: 'string', description: 'numeric value' },
232 |         { args: { documentName: 'invalid/path/name' }, expectedError: 'not found', description: 'invalid path' },
233 |         { args: { documentName: 'definitely-does-not-exist' }, expectedError: 'not found', description: 'nonexistent doc' }
234 |       ];
235 | 
236 |       for (const { args, expectedError, description } of invalidInputs) {
237 |         const result = await client.callTool('get_sfra_document', args);
238 |         
239 |         assert.equal(result.isError, true, `${description} should result in error`);
240 |         assert.ok(result.content[0].text.toLowerCase().includes(expectedError.toLowerCase()),
241 |           `${description} should mention "${expectedError}"`);
242 |         
243 |       }
244 |     });
245 |   });
246 | 
247 | 
248 |   describe('Content Quality & Completeness Analysis', () => {
249 |     test('should provide comprehensive documentation content', async () => {
250 |       const qualityChecks = [
251 |         { doc: 'server', minSections: 10, minContentLength: 5000, requiredSections: ['Method Summary', 'Method Detail', 'Usage Examples'] },
252 |         { doc: 'request', minSections: 8, minContentLength: 4000, requiredSections: ['Properties', 'Constructor Summary', 'Property Details'] },
253 |         { doc: 'response', minSections: 8, minContentLength: 4000, requiredSections: ['Method Summary', 'Properties'] }
254 |       ];
255 | 
256 |       for (const { doc, minSections, minContentLength, requiredSections } of qualityChecks) {
257 |         const result = await client.callTool('get_sfra_document', { documentName: doc });
258 |         const documentData = parseDocumentJSON(result.content[0].text);
259 | 
260 |         // Section count validation
261 |         assert.ok(documentData.sections.length >= minSections,
262 |           `${doc} should have at least ${minSections} sections (has ${documentData.sections.length})`);
263 | 
264 |         // Content length validation
265 |         assert.ok(documentData.content.length >= minContentLength,
266 |           `${doc} should have substantial content (${documentData.content.length} chars, min ${minContentLength})`);
267 | 
268 |         // Required sections validation
269 |         requiredSections.forEach(requiredSection => {
270 |           const hasSection = documentData.sections.some(section => 
271 |             section.toLowerCase().includes(requiredSection.toLowerCase())
272 |           );
273 |           assert.ok(hasSection, `${doc} should have "${requiredSection}" section`);
274 |         });
275 |         
276 |       }
277 |     });
278 | 
279 |     test('should include code examples and usage patterns', async () => {
280 |       const docsWithExamples = ['server', 'request', 'response'];
281 | 
282 |       for (const doc of docsWithExamples) {
283 |         const result = await client.callTool('get_sfra_document', { documentName: doc });
284 |         const documentData = parseDocumentJSON(result.content[0].text);
285 | 
286 |         const content = documentData.content.toLowerCase();
287 |         
288 |         // Check for code examples
289 |         const hasCodeBlocks = content.includes('```') || content.includes('```javascript');
290 |         const hasUsageExamples = content.includes('example') && (
291 |           content.includes('function') || 
292 |           content.includes('var ') || 
293 |           content.includes('new ') ||
294 |           content.includes('server.')
295 |         );
296 | 
297 |         // Check for method signatures and constructor patterns  
298 |         const hasSignatures = content.includes('signature:') || 
299 |           (content.includes('(') && content.includes(')')) ||
300 |           content.includes('constructor') ||
301 |           content.includes('method');
302 | 
303 |         assert.ok(hasCodeBlocks || hasUsageExamples || hasSignatures,
304 |           `${doc} should contain code examples, usage patterns, or method signatures`);
305 | 
306 |         // Additional signature verification
307 |         assert.ok(hasSignatures, `${doc} should contain method signatures or constructors`);
308 | 
309 |         // Note: Validated code examples and signatures for ${doc}
310 |         
311 |       }
312 |     });
313 | 
314 |     test('should maintain cross-reference consistency', async () => {
315 |       const docs = ['server', 'request', 'response'];
316 |       const documentContents = {};
317 | 
318 |       // Load all documents
319 |       for (const doc of docs) {
320 |         const result = await client.callTool('get_sfra_document', { documentName: doc });
321 |         const documentData = parseDocumentJSON(result.content[0].text);
322 |         documentContents[doc] = documentData.content.toLowerCase();
323 |         
324 |       }
325 | 
326 |       // Check cross-references
327 |       const crossRefs = [
328 |         { from: 'server', to: 'request', mention: 'request' },
329 |         { from: 'server', to: 'response', mention: 'response' },
330 |         { from: 'request', to: 'session', mention: 'session' }
331 |       ];
332 | 
333 |       crossRefs.forEach(({ from, to, mention }) => {
334 |         if (documentContents[from] && documentContents[to]) {
335 |           assert.ok(documentContents[from].includes(mention),
336 |             `${from} document should reference ${mention}`);
337 |         }
338 |       });
339 |     });
340 |   });
341 | 
342 |   describe('Error Recovery & Resilience', () => {
343 |     test('should recover gracefully from various error conditions', async () => {
344 |       const errorScenarios = [
345 |         { name: 'nonexistent-doc', expectError: true },
346 |         { name: 'server', expectError: false }, // Should work after error
347 |         { name: '', expectError: true },
348 |         { name: 'request', expectError: false }, // Should work after another error
349 |         { name: 'invalid/path', expectError: true },
350 |         { name: 'response', expectError: false } // Final success
351 |       ];
352 | 
353 |       for (const { name, expectError } of errorScenarios) {
354 |         const result = await client.callTool('get_sfra_document', { documentName: name });
355 |         
356 |         if (expectError) {
357 |           assert.equal(result.isError, true, `${name || 'empty'} should result in error`);
358 |         } else {
359 |           assert.equal(result.isError, false, `${name} should succeed after error`);
360 |           const documentData = parseDocumentJSON(result.content[0].text);
361 |           assert.ok(documentData.title, `${name} should return valid document`);
362 |         }
363 |         
364 |       }
365 |     });
366 | 
367 |     test('should maintain consistent behavior under stress', async () => {
368 |       const stressTests = [
369 |         // Mix of valid and invalid requests
370 |         ...Array(5).fill('server'),
371 |         ...Array(3).fill('nonexistent'),
372 |         ...Array(5).fill('request'),
373 |         ...Array(2).fill(''),
374 |         ...Array(5).fill('response')
375 |       ];
376 | 
377 |       let successCount = 0;
378 |       let errorCount = 0;
379 | 
380 |       for (const docName of stressTests) {
381 |         const result = await client.callTool('get_sfra_document', { documentName: docName });
382 |         
383 |         if (result.isError) {
384 |           errorCount++;
385 |         } else {
386 |           successCount++;
387 |           // Validate successful responses are still valid
388 |           const documentData = parseDocumentJSON(result.content[0].text);
389 |           assert.ok(documentData.title, 'Successful responses should remain valid');
390 |         }
391 |       }
392 |         
393 |       assert.ok(successCount > 0, 'Should have some successful requests');
394 |       assert.ok(errorCount > 0, 'Should have some failed requests');
395 |       assert.ok(successCount > 0, 'Should have successful requests');
396 |       assert.ok(errorCount >= 0, 'Should handle errors gracefully');
397 |     });
398 |   });
399 | 
400 |   describe('Memory & Resource Management', () => {
401 |     test('should handle large document content efficiently', async () => {
402 |       // Test with documents that likely have substantial content
403 |       const largeDocs = ['server', 'product-full', 'cart'];
404 |       const memoryBefore = process.memoryUsage();
405 | 
406 |       for (const doc of largeDocs) {
407 |         const result = await client.callTool('get_sfra_document', { documentName: doc });
408 |         assert.equal(result.isError, false, `${doc} should load successfully`);
409 |         
410 |         const documentData = parseDocumentJSON(result.content[0].text);
411 |         assert.ok(documentData.content.length > 0, `${doc} should have content`);
412 |         
413 |       }
414 | 
415 |       const memoryAfter = process.memoryUsage();
416 |       const memoryIncrease = (memoryAfter.heapUsed - memoryBefore.heapUsed) / 1024 / 1024;
417 |       
418 |       // Memory increase should be reasonable (allowing for some overhead)
419 |       assert.ok(memoryIncrease < 50, 
420 |         `Memory increase should be reasonable: ${memoryIncrease.toFixed(1)}MB`);
421 |     });
422 |   });
423 | });
424 | 
425 | // Helper Classes and Functions
426 | 
427 | 
428 | function assertValidMCPResponse(result) {
429 |   assert.ok(result.content, 'Should have content');
430 |   assert.ok(Array.isArray(result.content), 'Content should be array');
431 |   assert.equal(typeof result.isError, 'boolean', 'isError should be boolean');
432 |   assert.equal(result.content.length, 1, 'Should have exactly one content item');
433 |   assert.equal(result.content[0].type, 'text', 'Content should be text type');
434 | }
435 | 
436 | function assertToolSchema(tool) {
437 |   assert.ok(tool.name, 'Tool should have name');
438 |   assert.ok(tool.description, 'Tool should have description');
439 |   assert.ok(tool.inputSchema, 'Tool should have schema');
440 |   assert.equal(tool.inputSchema.type, 'object', 'Schema should be object type');
441 |   assert.ok(tool.inputSchema.properties, 'Schema should have properties');
442 |   assert.ok(tool.inputSchema.required, 'Schema should have required fields');
443 | }
444 | 
445 | function parseDocumentJSON(textContent) {
446 |   try {
447 |     return JSON.parse(textContent);
448 |   } catch (error) {
449 |     assert.fail(`Document content should be valid JSON: ${error.message}`);
450 |   }
451 | }
452 | 
453 | function assertDocumentStructure(documentData, documentName) {
454 |   assert.ok(documentData.title, `${documentName} should have title`);
455 |   assert.ok(Array.isArray(documentData.sections), `${documentName} should have sections array`);
456 |   assert.ok(documentData.content, `${documentName} should have content`);
457 |   assert.ok(documentData.type, `${documentName} should have type`);
458 |   assert.ok(documentData.category, `${documentName} should have category`);
459 |   assert.ok(documentData.filename, `${documentName} should have filename`);
460 |   assert.ok(documentData.lastModified, `${documentName} should have lastModified`);
461 |   
462 |   // Validate lastModified is a valid date string
463 |   assert.ok(!isNaN(Date.parse(documentData.lastModified)), 
464 |     `${documentName} lastModified should be valid date`);
465 |   
466 |   // Validate filename corresponds to document
467 |   const filenameBase = documentData.filename.toLowerCase().replace(/\.md$/, '');
468 |   const docNameBase = documentName.toLowerCase();
469 |   assert.ok(filenameBase.includes(docNameBase) || docNameBase.includes(filenameBase),
470 |     `${documentName} filename should correspond to document name`);
471 | }
472 | 
```

--------------------------------------------------------------------------------
/docs/dw_net/HTTPClient.md:
--------------------------------------------------------------------------------

```markdown
  1 | ## Package: dw.net
  2 | 
  3 | # Class HTTPClient
  4 | 
  5 | ## Inheritance Hierarchy
  6 | 
  7 | - Object
  8 |   - dw.net.HTTPClient
  9 | 
 10 | ## Description
 11 | 
 12 | The HTTPClient class supports the HTTP methods GET, POST, HEAD, PUT, PATCH, OPTIONS, and DELETE. If a secure connection via HTTPS is established the used server certificate or the signing CAs certificate needs to be imported into the customer key store via Business Manager. Note: when this class is used with sensitive data, be careful in persisting sensitive information. Key selection for mutual TLS: Check if there is an explicit identity requested setIdentity(KeyRef) Else, Check if there is a mapping for hostname in the keystore Deprecated: Select an arbitrary private key from the keystore var httpClient : HTTPClient = new HTTPClient(); var message : String; httpClient.open('GET', 'http://www.myinstance.com/feed.xml'); httpClient.setTimeout(3000); httpClient.send(); if (httpClient.statusCode == 200) { message = httpClient.text; } else { // error handling message="An error occurred with status code "+httpClient.statusCode; }
 13 | 
 14 | ## Constants
 15 | 
 16 | ### DEFAULT_GET_FILE_SIZE
 17 | 
 18 | **Type:** Number = 5242880
 19 | 
 20 | The default size for sendAndReceiveToFile() returning a File is 5MB deprecated in favor of MAX_GET_FILE_SIZE
 21 | 
 22 | ### MAX_GET_FILE_SIZE
 23 | 
 24 | **Type:** Number = 209715200
 25 | 
 26 | The maximum permitted size (in bytes) of an HTTP response when calling operations which write the response to file. (200MB)
 27 | 
 28 | ### MAX_GET_MEM_SIZE
 29 | 
 30 | **Type:** Number = 10485760
 31 | 
 32 | The maximum permitted size (in bytes) of an HTTP response when calling operations which store the response in memory. (10MB)
 33 | 
 34 | ## Properties
 35 | 
 36 | ### allowRedirect
 37 | 
 38 | **Type:** boolean
 39 | 
 40 | Determines whether redirect handling is enabled.
 41 | 
 42 | ### allResponseHeaders
 43 | 
 44 | **Type:** HashMap (Read Only)
 45 | 
 46 | All response headers as a map containing the name and value of the response header.
 47 | 
 48 | ### bytes
 49 | 
 50 | **Type:** Bytes (Read Only)
 51 | 
 52 | The bytes in the message body for HTTP status codes between 200 and 299.
 53 | 
 54 | ### errorBytes
 55 | 
 56 | **Type:** Bytes (Read Only)
 57 | 
 58 | The returned message body as bytes for HTTP status code greater or equal to 400. Error messages are not
 59 |  written to the response file.
 60 | 
 61 | ### errorText
 62 | 
 63 | **Type:** String (Read Only)
 64 | 
 65 | The returned message body as text for HTTP status code greater or equal to 400. Error messages are not
 66 |  written to the response file.
 67 | 
 68 | ### hostNameVerification
 69 | 
 70 | **Type:** boolean
 71 | 
 72 | Determines whether host name verification is enabled.
 73 | 
 74 | ### identity
 75 | 
 76 | **Type:** KeyRef
 77 | 
 78 | Gets the identity used for mutual TLS (mTLS).
 79 | 
 80 | ### responseHeaders
 81 | 
 82 | **Type:** Map (Read Only)
 83 | 
 84 | All response headers as a map in which each entry represents an individual header. The key of the entry
 85 |  holds the header name and the entry value holds a list of all header values.
 86 | 
 87 | ### statusCode
 88 | 
 89 | **Type:** Number (Read Only)
 90 | 
 91 | The status code of the last HTTP operation.
 92 | 
 93 | ### statusMessage
 94 | 
 95 | **Type:** String (Read Only)
 96 | 
 97 | The message text of the last HTTP operation.
 98 | 
 99 | ### text
100 | 
101 | **Type:** String (Read Only)
102 | 
103 | The returned message body as text for HTTP status codes between 200 and 299.
104 | 
105 | ### timeout
106 | 
107 | **Type:** Number
108 | 
109 | The timeout for this client, in milliseconds.
110 | 
111 | ## Constructor Summary
112 | 
113 | HTTPClient()
114 | 
115 | ## Method Summary
116 | 
117 | ### enableCaching
118 | 
119 | **Signature:** `enableCaching(ttl : Number) : void`
120 | 
121 | Calling this method enables caching for GET requests.
122 | 
123 | ### getAllowRedirect
124 | 
125 | **Signature:** `getAllowRedirect() : boolean`
126 | 
127 | Determines whether redirect handling is enabled.
128 | 
129 | ### getAllResponseHeaders
130 | 
131 | **Signature:** `getAllResponseHeaders() : HashMap`
132 | 
133 | Returns all response headers as a map containing the name and value of the response header.
134 | 
135 | ### getBytes
136 | 
137 | **Signature:** `getBytes() : Bytes`
138 | 
139 | Returns the bytes in the message body for HTTP status codes between 200 and 299.
140 | 
141 | ### getErrorBytes
142 | 
143 | **Signature:** `getErrorBytes() : Bytes`
144 | 
145 | Returns the returned message body as bytes for HTTP status code greater or equal to 400.
146 | 
147 | ### getErrorText
148 | 
149 | **Signature:** `getErrorText() : String`
150 | 
151 | Returns the returned message body as text for HTTP status code greater or equal to 400.
152 | 
153 | ### getHostNameVerification
154 | 
155 | **Signature:** `getHostNameVerification() : boolean`
156 | 
157 | Determines whether host name verification is enabled.
158 | 
159 | ### getIdentity
160 | 
161 | **Signature:** `getIdentity() : KeyRef`
162 | 
163 | Gets the identity used for mutual TLS (mTLS).
164 | 
165 | ### getResponseHeader
166 | 
167 | **Signature:** `getResponseHeader(header : String) : String`
168 | 
169 | Returns a specific response header from the last HTTP operation.
170 | 
171 | ### getResponseHeaders
172 | 
173 | **Signature:** `getResponseHeaders(name : String) : List`
174 | 
175 | Returns all the values of a response header from the last HTTP operation as a list of strings.
176 | 
177 | ### getResponseHeaders
178 | 
179 | **Signature:** `getResponseHeaders() : Map`
180 | 
181 | Returns all response headers as a map in which each entry represents an individual header.
182 | 
183 | ### getStatusCode
184 | 
185 | **Signature:** `getStatusCode() : Number`
186 | 
187 | Returns the status code of the last HTTP operation.
188 | 
189 | ### getStatusMessage
190 | 
191 | **Signature:** `getStatusMessage() : String`
192 | 
193 | Returns the message text of the last HTTP operation.
194 | 
195 | ### getText
196 | 
197 | **Signature:** `getText() : String`
198 | 
199 | Returns the returned message body as text for HTTP status codes between 200 and 299.
200 | 
201 | ### getText
202 | 
203 | **Signature:** `getText(encoding : String) : String`
204 | 
205 | Returns the returned message body as text for HTTP status codes between 200 and 299.
206 | 
207 | ### getTimeout
208 | 
209 | **Signature:** `getTimeout() : Number`
210 | 
211 | Returns the timeout for this client, in milliseconds.
212 | 
213 | ### open
214 | 
215 | **Signature:** `open(method : String, url : String) : void`
216 | 
217 | Opens the specified URL using the specified method.
218 | 
219 | ### open
220 | 
221 | **Signature:** `open(method : String, url : String, async : boolean, user : String, password : String) : void`
222 | 
223 | Deprecated method.
224 | 
225 | ### open
226 | 
227 | **Signature:** `open(method : String, url : String, user : String, password : String) : void`
228 | 
229 | Opens the specified URL with the in parameter method specified Http method with given credentials [user, password] using HTTP basic authentication.
230 | 
231 | ### send
232 | 
233 | **Signature:** `send() : void`
234 | 
235 | Sends an HTTP request.
236 | 
237 | ### send
238 | 
239 | **Signature:** `send(text : String) : void`
240 | 
241 | This method performs the actual HTTP communication.
242 | 
243 | ### send
244 | 
245 | **Signature:** `send(text : String, encoding : String) : void`
246 | 
247 | This method performs the actual HTTP communication.
248 | 
249 | ### send
250 | 
251 | **Signature:** `send(file : File) : void`
252 | 
253 | This method performs the actual HTTP communication.
254 | 
255 | ### sendAndReceiveToFile
256 | 
257 | **Signature:** `sendAndReceiveToFile(file : File) : boolean`
258 | 
259 | This method performs the actual HTTP communication.
260 | 
261 | ### sendAndReceiveToFile
262 | 
263 | **Signature:** `sendAndReceiveToFile(text : String, outFile : File) : boolean`
264 | 
265 | This method performs the actual HTTP communication.
266 | 
267 | ### sendAndReceiveToFile
268 | 
269 | **Signature:** `sendAndReceiveToFile(text : String, encoding : String, outFile : File) : boolean`
270 | 
271 | This method performs the actual HTTP communication.
272 | 
273 | ### sendBytes
274 | 
275 | **Signature:** `sendBytes(body : Bytes) : void`
276 | 
277 | This method performs the actual HTTP communication.
278 | 
279 | ### sendBytesAndReceiveToFile
280 | 
281 | **Signature:** `sendBytesAndReceiveToFile(body : Bytes, outFile : File) : boolean`
282 | 
283 | This method performs the actual HTTP communication.
284 | 
285 | ### sendMultiPart
286 | 
287 | **Signature:** `sendMultiPart(parts : HTTPRequestPart...) : boolean`
288 | 
289 | Sends a multipart HTTP request.
290 | 
291 | ### setAllowRedirect
292 | 
293 | **Signature:** `setAllowRedirect(allowRedirect : boolean) : void`
294 | 
295 | Sets whether automatic HTTP redirect handling is enabled.
296 | 
297 | ### setHostNameVerification
298 | 
299 | **Signature:** `setHostNameVerification(enable : boolean) : void`
300 | 
301 | Sets whether certificate host name verification is enabled.
302 | 
303 | ### setIdentity
304 | 
305 | **Signature:** `setIdentity(keyRef : KeyRef) : void`
306 | 
307 | Sets the identity (private key) to use when mutual TLS (mTLS) is configured.
308 | 
309 | ### setRequestHeader
310 | 
311 | **Signature:** `setRequestHeader(key : String, value : String) : void`
312 | 
313 | Sets a request header for the next HTTP operation.
314 | 
315 | ### setTimeout
316 | 
317 | **Signature:** `setTimeout(timeoutMillis : Number) : void`
318 | 
319 | Sets the timeout for connections made with this client to the given number of milliseconds.
320 | 
321 | ## Constructor Detail
322 | 
323 | ## Method Detail
324 | 
325 | ## Method Details
326 | 
327 | ### enableCaching
328 | 
329 | **Signature:** `enableCaching(ttl : Number) : void`
330 | 
331 | **Description:** Calling this method enables caching for GET requests. It basically means that a response is cached, and before making a request the HTTP client looks into the cache to determine whether the response is already available. Only responses with a status code of 2xx, with a content length, with a size less than 50k, and which are not intended to be immediately written to a file are cached. The provided parameter defines the TTL (time to live) for the cached content. A value of 0 disables caching. The URL and the username are used as cache keys. The total size of the cacheable content and the number of cached items is limited and automatically managed by the system. Cache control information send by the remote server is ignored. Caching HTTP responses should be done very carefully. It is important to ensure that the response really depends only on the URL and doesn't contain any remote state information or time information which is independent of the URL. It is also important to verify that the application sends exactly the same URL multiple times.
332 | 
333 | **Parameters:**
334 | 
335 | - `ttl`: the TTL for the cached content in secs
336 | 
337 | ---
338 | 
339 | ### getAllowRedirect
340 | 
341 | **Signature:** `getAllowRedirect() : boolean`
342 | 
343 | **Description:** Determines whether redirect handling is enabled.
344 | 
345 | **Returns:**
346 | 
347 | true if redirect handling is enabled, false otherwise.
348 | 
349 | ---
350 | 
351 | ### getAllResponseHeaders
352 | 
353 | **Signature:** `getAllResponseHeaders() : HashMap`
354 | 
355 | **Description:** Returns all response headers as a map containing the name and value of the response header.
356 | 
357 | **Deprecated:**
358 | 
359 | Use getResponseHeaders() instead.
360 | 
361 | **Returns:**
362 | 
363 | a map containing the names and corresponding values of the response headers.
364 | 
365 | ---
366 | 
367 | ### getBytes
368 | 
369 | **Signature:** `getBytes() : Bytes`
370 | 
371 | **Description:** Returns the bytes in the message body for HTTP status codes between 200 and 299.
372 | 
373 | **Returns:**
374 | 
375 | the returned message body as bytes.
376 | 
377 | ---
378 | 
379 | ### getErrorBytes
380 | 
381 | **Signature:** `getErrorBytes() : Bytes`
382 | 
383 | **Description:** Returns the returned message body as bytes for HTTP status code greater or equal to 400. Error messages are not written to the response file.
384 | 
385 | **Returns:**
386 | 
387 | the returned message body as bytes.
388 | 
389 | ---
390 | 
391 | ### getErrorText
392 | 
393 | **Signature:** `getErrorText() : String`
394 | 
395 | **Description:** Returns the returned message body as text for HTTP status code greater or equal to 400. Error messages are not written to the response file.
396 | 
397 | **Returns:**
398 | 
399 | the returned message body as text.
400 | 
401 | ---
402 | 
403 | ### getHostNameVerification
404 | 
405 | **Signature:** `getHostNameVerification() : boolean`
406 | 
407 | **Description:** Determines whether host name verification is enabled.
408 | 
409 | **Returns:**
410 | 
411 | true if verification is enabled, false otherwise
412 | 
413 | ---
414 | 
415 | ### getIdentity
416 | 
417 | **Signature:** `getIdentity() : KeyRef`
418 | 
419 | **Description:** Gets the identity used for mutual TLS (mTLS).
420 | 
421 | **Returns:**
422 | 
423 | Reference to the private key, or null if not configured
424 | 
425 | ---
426 | 
427 | ### getResponseHeader
428 | 
429 | **Signature:** `getResponseHeader(header : String) : String`
430 | 
431 | **Description:** Returns a specific response header from the last HTTP operation. The method returns null if the specific header was not returned.
432 | 
433 | **Parameters:**
434 | 
435 | - `header`: the name of the response header to locate.
436 | 
437 | **Returns:**
438 | 
439 | the value of the specified header or null if the header cannot be found.
440 | 
441 | ---
442 | 
443 | ### getResponseHeaders
444 | 
445 | **Signature:** `getResponseHeaders(name : String) : List`
446 | 
447 | **Description:** Returns all the values of a response header from the last HTTP operation as a list of strings. This reflects the fact that a specific header, e.g. "Set-Cookie", may be set multiple times. In case there is no such header, the method returns an empty list.
448 | 
449 | **Parameters:**
450 | 
451 | - `name`: The name of the response header to locate.
452 | 
453 | **Returns:**
454 | 
455 | The values of the specified header as a list of strings or an empty list if the header cannot be found.
456 | 
457 | ---
458 | 
459 | ### getResponseHeaders
460 | 
461 | **Signature:** `getResponseHeaders() : Map`
462 | 
463 | **Description:** Returns all response headers as a map in which each entry represents an individual header. The key of the entry holds the header name and the entry value holds a list of all header values.
464 | 
465 | **Returns:**
466 | 
467 | A map containing the names and corresponding values of the response headers.
468 | 
469 | ---
470 | 
471 | ### getStatusCode
472 | 
473 | **Signature:** `getStatusCode() : Number`
474 | 
475 | **Description:** Returns the status code of the last HTTP operation.
476 | 
477 | **Returns:**
478 | 
479 | the status code of the last HTTP operation.
480 | 
481 | ---
482 | 
483 | ### getStatusMessage
484 | 
485 | **Signature:** `getStatusMessage() : String`
486 | 
487 | **Description:** Returns the message text of the last HTTP operation.
488 | 
489 | **Returns:**
490 | 
491 | the message text of the last HTTP operation.
492 | 
493 | ---
494 | 
495 | ### getText
496 | 
497 | **Signature:** `getText() : String`
498 | 
499 | **Description:** Returns the returned message body as text for HTTP status codes between 200 and 299.
500 | 
501 | **Returns:**
502 | 
503 | the returned message body as text.
504 | 
505 | ---
506 | 
507 | ### getText
508 | 
509 | **Signature:** `getText(encoding : String) : String`
510 | 
511 | **Description:** Returns the returned message body as text for HTTP status codes between 200 and 299.
512 | 
513 | **Parameters:**
514 | 
515 | - `encoding`: the character encoding to use.
516 | 
517 | **Returns:**
518 | 
519 | String the encoded String.
520 | 
521 | ---
522 | 
523 | ### getTimeout
524 | 
525 | **Signature:** `getTimeout() : Number`
526 | 
527 | **Description:** Returns the timeout for this client, in milliseconds.
528 | 
529 | **Returns:**
530 | 
531 | the timeout in milliseconds
532 | 
533 | ---
534 | 
535 | ### open
536 | 
537 | **Signature:** `open(method : String, url : String) : void`
538 | 
539 | **Description:** Opens the specified URL using the specified method. The following methods are supported: GET, POST, HEAD, PUT, PATCH, OPTIONS, and DELETE
540 | 
541 | **Parameters:**
542 | 
543 | - `method`: the method to use for opening the URL.
544 | - `url`: the url to open.
545 | 
546 | ---
547 | 
548 | ### open
549 | 
550 | **Signature:** `open(method : String, url : String, async : boolean, user : String, password : String) : void`
551 | 
552 | **Description:** Deprecated method.
553 | 
554 | **Deprecated:**
555 | 
556 | Use open(String, String, String, String) instead.
557 | 
558 | **Parameters:**
559 | 
560 | - `method`: the method to use for opening the URL.
561 | - `url`: the url to open.
562 | - `async`: true if asynchronous.
563 | - `user`: name of the user.
564 | - `password`: password.
565 | 
566 | ---
567 | 
568 | ### open
569 | 
570 | **Signature:** `open(method : String, url : String, user : String, password : String) : void`
571 | 
572 | **Description:** Opens the specified URL with the in parameter method specified Http method with given credentials [user, password] using HTTP basic authentication. The following methods are supported: GET, POST, HEAD, PUT, PATCH, OPTIONS, and DELETE
573 | 
574 | **Parameters:**
575 | 
576 | - `method`: HTTP method
577 | - `url`: the url
578 | - `user`: name of the user
579 | - `password`: password
580 | 
581 | ---
582 | 
583 | ### send
584 | 
585 | **Signature:** `send() : void`
586 | 
587 | **Description:** Sends an HTTP request.
588 | 
589 | ---
590 | 
591 | ### send
592 | 
593 | **Signature:** `send(text : String) : void`
594 | 
595 | **Description:** This method performs the actual HTTP communication. The text is sent as a request body. If the text is null no data will be sent to the HTTP server.
596 | 
597 | **Parameters:**
598 | 
599 | - `text`: text String to be sent as request body.
600 | 
601 | ---
602 | 
603 | ### send
604 | 
605 | **Signature:** `send(text : String, encoding : String) : void`
606 | 
607 | **Description:** This method performs the actual HTTP communication. The text is sent as a request body. If the text is null no data will be sent to the HTTP server.
608 | 
609 | **Parameters:**
610 | 
611 | - `text`: text String to be sent as request body.
612 | - `encoding`: character encoding name.
613 | 
614 | ---
615 | 
616 | ### send
617 | 
618 | **Signature:** `send(file : File) : void`
619 | 
620 | **Description:** This method performs the actual HTTP communication. Sends the file to the HTTP server. The file content is sent as a request body and is sent "as-is" (text or binary).
621 | 
622 | **Parameters:**
623 | 
624 | - `file`: File to be sent.
625 | 
626 | ---
627 | 
628 | ### sendAndReceiveToFile
629 | 
630 | **Signature:** `sendAndReceiveToFile(file : File) : boolean`
631 | 
632 | **Description:** This method performs the actual HTTP communication. If the file is null no data will be sent to the HTTP server. If this method is used with a GET then the file parameter will contain the contents retrieved. When using this method with a PUT/POST then the contents of the file parameter will be sent to the server.
633 | 
634 | **Parameters:**
635 | 
636 | - `file`: local file used to read from or write to, depending on the method used.
637 | 
638 | **Returns:**
639 | 
640 | true if the returned code was a positive status code
641 | 
642 | ---
643 | 
644 | ### sendAndReceiveToFile
645 | 
646 | **Signature:** `sendAndReceiveToFile(text : String, outFile : File) : boolean`
647 | 
648 | **Description:** This method performs the actual HTTP communication. If the text is null no data will be sent to the HTTP server.
649 | 
650 | **Parameters:**
651 | 
652 | - `text`: text String to be sent.
653 | - `outFile`: local file to write to.
654 | 
655 | **Returns:**
656 | 
657 | true if the returned code was a positive status code
658 | 
659 | ---
660 | 
661 | ### sendAndReceiveToFile
662 | 
663 | **Signature:** `sendAndReceiveToFile(text : String, encoding : String, outFile : File) : boolean`
664 | 
665 | **Description:** This method performs the actual HTTP communication. If the text is null no data will be sent to the HTTP server.
666 | 
667 | **Parameters:**
668 | 
669 | - `text`: text String to be sent.
670 | - `encoding`: character encoding name.
671 | - `outFile`: local file to write to.
672 | 
673 | **Returns:**
674 | 
675 | true if the returned code was a positive status code
676 | 
677 | ---
678 | 
679 | ### sendBytes
680 | 
681 | **Signature:** `sendBytes(body : Bytes) : void`
682 | 
683 | **Description:** This method performs the actual HTTP communication. The bytes are sent as a request body. If the bytes are null no data will be sent to the HTTP server.
684 | 
685 | **Parameters:**
686 | 
687 | - `body`: Bytes to be sent as request body.
688 | 
689 | ---
690 | 
691 | ### sendBytesAndReceiveToFile
692 | 
693 | **Signature:** `sendBytesAndReceiveToFile(body : Bytes, outFile : File) : boolean`
694 | 
695 | **Description:** This method performs the actual HTTP communication. If the body is null no data will be sent to the HTTP server.
696 | 
697 | **Parameters:**
698 | 
699 | - `body`: Bytes to be sent.
700 | - `outFile`: local file to write to.
701 | 
702 | **Returns:**
703 | 
704 | true if the returned code was a positive status code
705 | 
706 | **Throws:**
707 | 
708 | - IOException
709 | 
710 | ---
711 | 
712 | ### sendMultiPart
713 | 
714 | **Signature:** `sendMultiPart(parts : HTTPRequestPart...) : boolean`
715 | 
716 | **Description:** Sends a multipart HTTP request. This method should only be called if the connection to the remote URL was opened with a POST or PATCH method. All other methods will result in an exception being thrown. The request is constructed from the passed array of parts.
717 | 
718 | **Parameters:**
719 | 
720 | - `parts`: List of part objects representing either string or file parts.
721 | 
722 | **Returns:**
723 | 
724 | true if the returned code was a positive status code.
725 | 
726 | ---
727 | 
728 | ### setAllowRedirect
729 | 
730 | **Signature:** `setAllowRedirect(allowRedirect : boolean) : void`
731 | 
732 | **Description:** Sets whether automatic HTTP redirect handling is enabled. The default value is true. Set it to false to disable all redirects.
733 | 
734 | **Parameters:**
735 | 
736 | - `allowRedirect`: true or false for enabling or disabling automatic HTTP redirect
737 | 
738 | ---
739 | 
740 | ### setHostNameVerification
741 | 
742 | **Signature:** `setHostNameVerification(enable : boolean) : void`
743 | 
744 | **Description:** Sets whether certificate host name verification is enabled. The default value is true. Set it to false to disable host name verification.
745 | 
746 | **Parameters:**
747 | 
748 | - `enable`: true to enable host name verification or false to disable it.
749 | 
750 | ---
751 | 
752 | ### setIdentity
753 | 
754 | **Signature:** `setIdentity(keyRef : KeyRef) : void`
755 | 
756 | **Description:** Sets the identity (private key) to use when mutual TLS (mTLS) is configured. If this is not set and mTLS is used then the private key will be chosen from the key store based on the host name. If this is set to a reference named "__NONE__" then no private key will be used even if one is requested by the remote server.
757 | 
758 | **Parameters:**
759 | 
760 | - `keyRef`: Reference to the private key
761 | 
762 | ---
763 | 
764 | ### setRequestHeader
765 | 
766 | **Signature:** `setRequestHeader(key : String, value : String) : void`
767 | 
768 | **Description:** Sets a request header for the next HTTP operation.
769 | 
770 | **Parameters:**
771 | 
772 | - `key`: the request header.
773 | - `value`: the request headers' value.
774 | 
775 | ---
776 | 
777 | ### setTimeout
778 | 
779 | **Signature:** `setTimeout(timeoutMillis : Number) : void`
780 | 
781 | **Description:** Sets the timeout for connections made with this client to the given number of milliseconds. If the given timeout is less than or equal to zero, the timeout is set to a maximum value of 2 or 15 minutes, depending on the context. This timeout value controls both the "connection timeout" (how long it takes to connect to the remote host) and the "socket timeout" (how long, after connecting, it will wait without any data being read). Therefore, in the worst case scenario, the total time of inactivity could be twice as long as the specified value. The maximum timeout is 15 minutes when the client is used in a job, and 2 minutes otherwise. The default timeout for a new client is the maximum timeout value. This method can be called at any time, and will affect the next connection made with this client. It is not possible to set the timeout for an open connection. You should always set a reasonable timeout (e.g., a few seconds). Allowing connections to run long can result in thread exhaustion.
782 | 
783 | **Parameters:**
784 | 
785 | - `timeoutMillis`: timeout, in milliseconds, up to a maximum of 2 or 15 minutes, depending on the context.
786 | 
787 | ---
```

--------------------------------------------------------------------------------
/docs-site/pages/ConfigurationPage.tsx:
--------------------------------------------------------------------------------

```typescript
  1 | import React from 'react';
  2 | import { NavLink } from 'react-router-dom';
  3 | import SEO from '../components/SEO';
  4 | import BreadcrumbSchema from '../components/BreadcrumbSchema';
  5 | import StructuredData from '../components/StructuredData';
  6 | import { PageSubtitle, H2, H3 } from '../components/Typography';
  7 | import CodeBlock, { InlineCode } from '../components/CodeBlock';
  8 | import ConfigHero from '../components/ConfigHero';
  9 | import ConfigModeTabs from '../components/ConfigModeTabs';
 10 | import ConfigBuilder from '../components/ConfigBuilder';
 11 | import { SITE_DATES } from '../constants';
 12 | import Collapsible from '../components/Collapsible';
 13 | 
 14 | const ConfigurationPage: React.FC = () => {
 15 |   const configurationStructuredData = {
 16 |     "@context": "https://schema.org",
 17 |     "@type": "TechArticle",
 18 |     "headline": "Configuration Guide - SFCC Development MCP Server",
 19 |   "description": "Complete configuration guide for SFCC Development MCP Server. Learn dw.json setup, environment variables, operating modes, authentication, security best practices, and how to enable logs, job logs, system & custom objects, site preferences, and code versions.",
 20 |     "author": {
 21 |       "@type": "Person",
 22 |       "name": "Thomas Theunen"
 23 |     },
 24 |     "publisher": {
 25 |       "@type": "Person",
 26 |       "name": "Thomas Theunen"
 27 |     },
 28 |     "datePublished": SITE_DATES.PUBLISHED,
 29 |     "dateModified": SITE_DATES.MODIFIED,
 30 |     "url": "https://sfcc-mcp-dev.rhino-inquisitor.com/configuration/",
 31 |     "about": [
 32 |       {
 33 |         "@type": "SoftwareApplication",
 34 |         "name": "SFCC Development MCP Server",
 35 |         "applicationCategory": "DeveloperApplication",
 36 |         "operatingSystem": "Node.js",
 37 |         "offers": {
 38 |           "@type": "Offer",
 39 |           "price": "0",
 40 |           "priceCurrency": "USD",
 41 |           "availability": "https://schema.org/InStock"
 42 |         }
 43 |       }
 44 |     ]
 45 |   };
 46 | 
 47 |   return (
 48 |     <div className="max-w-6xl mx-auto px-6 py-8">
 49 |       <SEO 
 50 |         title="Configuration Guide"
 51 |   description="Complete configuration guide for SFCC Development MCP Server. Learn dw.json setup, environment variables, operating modes, authentication, security best practices, and how to enable logs, job logs, system & custom objects, site preferences, and code versions."
 52 |         keywords="SFCC MCP configuration, dw.json setup, SFCC authentication, OCAPI credentials, WebDAV configuration, Commerce Cloud API setup, SFCC development environment"
 53 |         canonical="/configuration/"
 54 |         ogType="article"
 55 |       />
 56 |       <BreadcrumbSchema items={[
 57 |         { name: "Home", url: "/" },
 58 |         { name: "Configuration", url: "/configuration/" }
 59 |       ]} />
 60 |       <StructuredData structuredData={configurationStructuredData} />
 61 |       
 62 |       <ConfigHero />
 63 |       <div className="mb-16 bg-gradient-to-r from-blue-50 via-indigo-50 to-purple-50 rounded-2xl p-8 shadow-xl border border-blue-100">
 64 |           <div className="text-center mb-10">
 65 |             <H2 id="quick-start" className="text-3xl font-bold mb-3">🚀 Quick Start</H2>
 66 |             <p className="text-gray-700 max-w-3xl mx-auto text-lg">Pick a mode, generate <InlineCode>dw.json</InlineCode>, run the server. Minimal friction, fast feedback.</p>
 67 |           </div>
 68 |           <ConfigModeTabs />
 69 |       </div>
 70 |       <div className="mb-20 bg-gradient-to-r from-emerald-50 via-teal-50 to-cyan-50 rounded-2xl p-8 shadow-xl border border-emerald-100">
 71 |           <div className="flex flex-col md:flex-row md:items-center md:justify-between gap-6 mb-6">
 72 |             <div>
 73 |               <H2 id="interactive-config" className="text-2xl font-bold mb-2">🧪 Interactive dw.json Builder</H2>
 74 |               <p className="text-sm text-gray-600 max-w-xl">Start minimal (only <InlineCode>hostname</InlineCode> + <InlineCode>username/password</InlineCode> for runtime & job logs). Add Data API credentials when you need system & custom objects, site preferences or code version tooling.</p>
 75 |             </div>
 76 |             <div className="rounded-lg border border-emerald-200 bg-emerald-50 px-4 py-3 text-xs text-emerald-800 max-w-sm">
 77 |               <p className="font-semibold mb-1">Tips</p>
 78 |               <ul className="list-disc pl-4 space-y-1">
 79 |                 <li>Keep separate <InlineCode>dw.dev.json</InlineCode> / <InlineCode>dw.qa.json</InlineCode></li>
 80 |                 <li>Use env vars to override secrets in CI</li>
 81 |                 <li>Remove unused OAuth fields to stay minimal</li>
 82 |               </ul>
 83 |             </div>
 84 |           </div>
 85 |           <ConfigBuilder />
 86 |       </div>
 87 |       <div className="space-y-20 mb-20">
 88 |         <div className="space-y-16">
 89 |           <section id="data-api" className="scroll-mt-24">
 90 |             <div className="mb-4 space-y-2">
 91 |               <span className="inline-block bg-yellow-100 text-yellow-700 text-[11px] font-semibold px-3 py-1 rounded-full tracking-wide uppercase">Optional – Enables Data API Tools</span>
 92 |               <h2 id="data-api-configuration" className="text-2xl font-bold text-gray-900">🔧 Data API Configuration</h2>
 93 |             </div>
 94 |             <p className="text-gray-600 mb-6 text-sm">Required for system object definitions, custom object attribute searches, site preferences & code version tools. Not required for runtime logs or job log analysis (basic auth only). Skip entirely if you only need docs + log visibility.</p>
 95 |             <div className="space-y-6">
 96 |             <Collapsible id="api-client" title="Step 1: Create API Client (Account Manager)" intent="info" defaultOpen>
 97 |               <ol className="list-decimal list-inside space-y-1">
 98 |                 <li>Login to <strong>Account Manager</strong> (not Business Manager)</li>
 99 |                 <li>Navigate to <strong>API Client</strong> → Add API Client</li>
100 |                 <li>Set name (e.g. <InlineCode>SFCC Dev MCP</InlineCode>) & generate password</li>
101 |                 <li>Select <strong>SFCC</strong> scope and grant required roles</li>
102 |               </ol>
103 |             </Collapsible>
104 |             <Collapsible id="bm-settings" title="Step 2: Business Manager Data API Settings" intent="warn">
105 |               <ol className="list-decimal list-inside space-y-1 mb-4">
106 |                 <li>Business Manager → Administration → Site Development → Open Commerce API Settings</li>
107 |                 <li>Open the <strong>Data API</strong> tab</li>
108 |                 <li>Add client with required resources (below)</li>
109 |               </ol>
110 |               <CodeBlock language="json" code={`{\n  \"_v\": \"23.2\",\n  \"clients\": [{\n    \"client_id\": \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\n    \"resources\": [\n      { \"resource_id\": \"/system_object_definitions\", \"methods\": [\"get\"], \"read_attributes\": \"(**)\", \"write_attributes\": \"(**)\" },\n      { \"resource_id\": \"/system_object_definitions/*\", \"methods\": [\"get\"], \"read_attributes\": \"(**)\", \"write_attributes\": \"(**)\" },\n      { \"resource_id\": \"/system_object_definition_search\", \"methods\": [\"post\"], \"read_attributes\": \"(**)\", \"write_attributes\": \"(**)\" },\n      { \"resource_id\": \"/system_object_definitions/*/attribute_definition_search\", \"methods\": [\"post\"], \"read_attributes\": \"(**)\", \"write_attributes\": \"(**)\" },\n      { \"resource_id\": \"/system_object_definitions/*/attribute_group_search\", \"methods\": [\"post\"], \"read_attributes\": \"(**)\", \"write_attributes\": \"(**)\" },\n      { \"resource_id\": \"/custom_object_definitions/*/attribute_definition_search\", \"methods\": [\"post\"], \"read_attributes\": \"(**)\", \"write_attributes\": \"(**)\" },\n      { \"resource_id\": \"/site_preferences/preference_groups/*/*/preference_search\", \"methods\": [\"post\"], \"read_attributes\": \"(**)\", \"write_attributes\": \"(**)\" },\n      { \"resource_id\": \"/code_versions\", \"methods\": [\"get\"], \"read_attributes\": \"(**)\", \"write_attributes\": \"(**)\" },\n      { \"resource_id\": \"/code_versions/*\", \"methods\": [\"get\", \"patch\"], \"read_attributes\": \"(**)\", \"write_attributes\": \"(**)\" }\n    ]\n  }]\n}\n`} />
111 |               <ul className="text-xs text-green-700 bg-green-50 border border-green-200 rounded-lg p-4 mt-4 space-y-1">
112 |                 <li><strong>Client ID</strong> must match your credentials</li>
113 |                 <li>Allow <InlineCode>get</InlineCode>/<InlineCode>post</InlineCode> for search + retrieval (and <InlineCode>patch</InlineCode> for code version activation)</li>
114 |                 <li><InlineCode>(**)</InlineCode> attributes needed for broad introspection</li>
115 |               </ul>
116 |             </Collapsible>
117 |             <Collapsible id="update-config" title="Step 3: Update dw.json" intent="plain">
118 |               <CodeBlock language="json" code={`{\n  \"hostname\": \"your-instance.sandbox.us01.dx.commercecloud.salesforce.com\",\n  \"username\": \"your-username\",\n  \"password\": \"your-password\",\n  \"client-id\": \"your-ocapi-client-id\",\n  \"client-secret\": \"your-ocapi-client-secret\"\n}`} />
119 |               <p className="text-[11px] text-gray-500 -mt-3">Add <InlineCode>client-id</InlineCode>/<InlineCode>client-secret</InlineCode> only when you need Data API tooling (system & custom objects, site preferences, code versions). Omit for docs + log visibility only.</p>
120 |             </Collapsible>
121 |             <Collapsible id="data-api-troubleshooting" title="Troubleshooting Data API Access" intent="danger">
122 |               <ul className="list-disc pl-5 text-sm space-y-2">
123 |                 <li><strong>403</strong>: Missing scope/role – verify Account Manager roles + BM resource mapping</li>
124 |                 <li><strong>401</strong>: Credential mismatch – regenerate client secret</li>
125 |                 <li><strong>Missing resource</strong>: Pattern mismatch – copy exact resource IDs above</li>
126 |               </ul>
127 |               <CodeBlock language="bash" code={`npx sfcc-dev-mcp --dw-json /Users/username/sfcc-project/dw.json --debug true`} />
128 |             </Collapsible>
129 |             </div>
130 |             <p className="text-[11px] text-gray-500 mt-2">Total surface: 36+ specialized tools spanning documentation, best practices, SFRA, cartridge generation, runtime logs, job logs, system & custom objects, site preferences, and code versions.</p>
131 |           </section>
132 |           <section id="security" className="scroll-mt-24 space-y-6">
133 |             <div className="mb-4 space-y-2">
134 |               <span className="inline-block bg-blue-100 text-blue-700 text-[11px] font-semibold px-3 py-1 rounded-full tracking-wide uppercase">Protect Credentials</span>
135 |               <h2 id="security-basics" className="text-2xl font-bold text-gray-900">🔒 Security Basics</h2>
136 |             </div>
137 |             <div className="grid md:grid-cols-2 gap-6">
138 |               <div className="rounded-xl border border-gray-200 bg-white p-5">
139 |                 <h4 className="font-semibold text-sm mb-3">.gitignore</h4>
140 |                 <CodeBlock language="bash" code={`echo 'dw.json' >> .gitignore\necho '*.dw.json' >> .gitignore`} />
141 |               </div>
142 |               <div className="rounded-xl border border-gray-200 bg-white p-5">
143 |                 <h4 className="font-semibold text-sm mb-3">Environment Overrides</h4>
144 |                 <CodeBlock language="bash" code={`export SFCC_CLIENT_SECRET=\"your-secret\"\nexport SFCC_PASSWORD=\"your-password\"\n\nnpx sfcc-dev-mcp --dw-json /Users/username/sfcc-project/dw.json`} />
145 |               </div>
146 |               <div className="rounded-xl border border-gray-200 bg-white p-5">
147 |                 <h4 className="font-semibold text-sm mb-3">Permissions</h4>
148 |                 <CodeBlock language="bash" code={`chmod 600 dw.json\nls -la dw.json`} />
149 |               </div>
150 |               <div className="rounded-xl border border-gray-200 bg-white p-5">
151 |                 <h4 className="font-semibold text-sm mb-3">Debug Mode</h4>
152 |                 <CodeBlock language="bash" code={`npx sfcc-dev-mcp --dw-json /Users/username/sfcc-project/dw.json --debug true`} />
153 |         </div>
154 |             </div>
155 |           </section>
156 |           <section id="reference" className="scroll-mt-24 space-y-8">
157 |             <div className="mb-4 space-y-2">
158 |               <span className="inline-block bg-purple-100 text-purple-700 text-[11px] font-semibold px-3 py-1 rounded-full tracking-wide uppercase">Reference</span>
159 |               <h2 id="key-reference-tables" className="text-2xl font-bold text-gray-900">📋 Key Reference Tables</h2>
160 |             </div>
161 |             <div>
162 |               <H3 id="field-reference" className="text-lg font-semibold mb-3">Supported dw.json Fields</H3>
163 |               <div className="overflow-x-auto text-sm">
164 |                 <table className="min-w-full bg-white border border-gray-200 rounded-lg">
165 |                   <thead className="bg-gray-50">
166 |                     <tr>
167 |                       <th className="px-3 py-2 text-left font-semibold text-gray-900 border-b">Field</th>
168 |                       <th className="px-3 py-2 text-left font-semibold text-gray-900 border-b">Required For</th>
169 |                       <th className="px-3 py-2 text-left font-semibold text-gray-900 border-b">Notes</th>
170 |                     </tr>
171 |                   </thead>
172 |                   <tbody className="divide-y divide-gray-200">
173 |                     <tr>
174 |                       <td className="px-3 py-2 font-mono text-xs">hostname</td>
175 |                       <td className="px-3 py-2 text-xs">All authenticated tools</td>
176 |                       <td className="px-3 py-2 text-xs">Sandbox domain</td>
177 |                     </tr>
178 |                     <tr>
179 |                       <td className="px-3 py-2 font-mono text-xs">username/password</td>
180 |                       <td className="px-3 py-2 text-xs">Logs & Job Logs (WebDAV)</td>
181 |                       <td className="px-3 py-2 text-xs">WebDAV auth (runtime + job log files)</td>
182 |                     </tr>
183 |                     <tr>
184 |                       <td className="px-3 py-2 font-mono text-xs">client-id/secret</td>
185 |                       <td className="px-3 py-2 text-xs">System & custom objects, site prefs, code versions</td>
186 |                       <td className="px-3 py-2 text-xs">OCAPI Data API + code version management</td>
187 |                     </tr>
188 |                     <tr>
189 |                       <td className="px-3 py-2 font-mono text-xs">code-version</td>
190 |                       <td className="px-3 py-2 text-xs">Code version operations</td>
191 |                       <td className="px-3 py-2 text-xs">Optional</td>
192 |                     </tr>
193 |                     <tr>
194 |                       <td className="px-3 py-2 font-mono text-xs">site-id</td>
195 |                       <td className="px-3 py-2 text-xs">Site-specific actions</td>
196 |                       <td className="px-3 py-2 text-xs">Optional</td>
197 |                     </tr>
198 |                   </tbody>
199 |                 </table>
200 |               </div>
201 |             </div>
202 |             <div>
203 |               <H3 id="tool-availability" className="text-lg font-semibold mb-3">Tool Availability by Mode</H3>
204 |               <div className="overflow-x-auto text-sm">
205 |                 <table className="min-w-full bg-white border border-gray-200 rounded-lg">
206 |                   <thead className="bg-gray-50">
207 |                     <tr>
208 |                       <th className="px-3 py-2 text-left font-semibold text-gray-900 border-b">Category</th>
209 |                       <th className="px-3 py-2 text-left font-semibold text-gray-900 border-b">Docs Only</th>
210 |                       <th className="px-3 py-2 text-left font-semibold text-gray-900 border-b">Full Mode</th>
211 |                     </tr>
212 |                   </thead>
213 |                   <tbody className="divide-y divide-gray-200">
214 |                     <tr>
215 |                       <td className="px-3 py-2 text-xs font-medium">Documentation</td>
216 |                       <td className="px-3 py-2 text-xs">✔</td>
217 |                       <td className="px-3 py-2 text-xs">✔</td>
218 |                     </tr>
219 |                     <tr>
220 |                       <td className="px-3 py-2 text-xs font-medium">Best Practices</td>
221 |                       <td className="px-3 py-2 text-xs">✔</td>
222 |                       <td className="px-3 py-2 text-xs">✔</td>
223 |                     </tr>
224 |                     <tr>
225 |                       <td className="px-3 py-2 text-xs font-medium">SFRA Docs</td>
226 |                       <td className="px-3 py-2 text-xs">✔</td>
227 |                       <td className="px-3 py-2 text-xs">✔</td>
228 |                     </tr>
229 |                     <tr>
230 |                       <td className="px-3 py-2 text-xs font-medium">Cartridge Generation</td>
231 |                       <td className="px-3 py-2 text-xs">✔</td>
232 |                       <td className="px-3 py-2 text-xs">✔</td>
233 |                     </tr>
234 |                     <tr>
235 |                       <td className="px-3 py-2 text-xs font-medium">Log Analysis (runtime)</td>
236 |                       <td className="px-3 py-2 text-xs">—</td>
237 |                       <td className="px-3 py-2 text-xs">✔</td>
238 |                     </tr>
239 |                     <tr>
240 |                       <td className="px-3 py-2 text-xs font-medium">Job Logs</td>
241 |                       <td className="px-3 py-2 text-xs">—</td>
242 |                       <td className="px-3 py-2 text-xs">✔</td>
243 |                     </tr>
244 |                     <tr>
245 |                       <td className="px-3 py-2 text-xs font-medium">System & Custom Objects / Site Prefs</td>
246 |                       <td className="px-3 py-2 text-xs">—</td>
247 |                       <td className="px-3 py-2 text-xs">✔</td>
248 |                     </tr>
249 |                     <tr>
250 |                       <td className="px-3 py-2 text-xs font-medium">Code Versions</td>
251 |                       <td className="px-3 py-2 text-xs">—</td>
252 |                       <td className="px-3 py-2 text-xs">✔</td>
253 |                     </tr>
254 |                   </tbody>
255 |                 </table>
256 |               </div>
257 |             </div>
258 |           </section>
259 |           <section id="troubleshooting" className="scroll-mt-24 space-y-6">
260 |             <div className="mb-4 space-y-2">
261 |               <span className="inline-block bg-red-100 text-red-700 text-[11px] font-semibold px-3 py-1 rounded-full tracking-wide uppercase">Common Issues</span>
262 |               <h2 id="troubleshooting" className="text-2xl font-bold text-gray-900">🐛 Troubleshooting</h2>
263 |             </div>
264 |             <div className="grid md:grid-cols-3 gap-5">
265 |               <div className="bg-white border border-gray-200 rounded-xl p-4">
266 |                 <h4 className="font-semibold text-sm mb-2">Auth Failed</h4>
267 |                 <ul className="text-xs text-gray-600 space-y-1 list-disc pl-4">
268 |                   <li>Verify hostname format</li>
269 |                   <li>Check username/password</li>
270 |                   <li>Match client-id/secret</li>
271 |                   <li>Run with <InlineCode>--debug</InlineCode></li>
272 |                 </ul>
273 |               </div>
274 |               <div className="bg-white border border-gray-200 rounded-xl p-4">
275 |                 <h4 className="font-semibold text-sm mb-2">dw.json Missing</h4>
276 |                 <ul className="text-xs text-gray-600 space-y-1 list-disc pl-4">
277 |                   <li>Add <InlineCode>--dw-json /Users/username/sfcc-project/dw.json</InlineCode></li>
278 |                   <li>Create file in current dir</li>
279 |                   <li>Use env vars instead</li>
280 |                   <li>Check permissions (600)</li>
281 |                 </ul>
282 |               </div>
283 |               <div className="bg-white border border-gray-200 rounded-xl p-4">
284 |                 <h4 className="font-semibold text-sm mb-2">System Object Denied</h4>
285 |                 <ul className="text-xs text-gray-600 space-y-1 list-disc pl-4">
286 |                   <li>Complete Data API config</li>
287 |                   <li>Verify resource IDs</li>
288 |                   <li>Ensure (**) attributes</li>
289 |                   <li>Check client roles</li>
290 |                 </ul>
291 |               </div>
292 |             </div>
293 |           </section>
294 |   </div>
295 |       </div>
296 |       <div className="mb-24">
297 |         <div className="text-center mb-8">
298 |           <h2 id="next-steps" className="text-2xl font-bold text-gray-900 mb-2">🔗 Next Steps</h2>
299 |           <PageSubtitle className="text-base text-gray-600">Pick your next path—feature surface or concrete tool list.</PageSubtitle>
300 |         </div>
301 |         <div className="flex flex-col sm:flex-row gap-4 justify-center">
302 |           <NavLink to="/features/" className="group bg-gradient-to-r from-blue-600 to-purple-600 text-white px-8 py-4 rounded-xl font-semibold text-lg shadow-lg hover:shadow-xl transition-all duration-300 transform hover:-translate-y-1 no-underline hover:no-underline focus:no-underline">
303 |             Features Overview
304 |             <span className="ml-2 group-hover:translate-x-1 inline-block transition-transform">→</span>
305 |           </NavLink>
306 |           <NavLink to="/tools/" className="border-2 border-gray-300 text-gray-700 px-8 py-4 rounded-xl font-semibold text-lg hover:border-blue-500 hover:text-blue-600 transition-all duration-300 no-underline hover:no-underline focus:no-underline">
307 |             Available Tools
308 |           </NavLink>
309 |         </div>
310 |       </div>
311 |     </div>
312 |   );
313 | };
314 | 
315 | export default ConfigurationPage;
316 | 
```
Page 36/61FirstPrevNextLast