#
tokens: 49605/50000 12/825 files (page 19/43)
lines: off (toggle) GitHub
raw markdown copy
This is page 19 of 43. Use http://codebase.md/taurgis/sfcc-dev-mcp?page={x} to view the full context.

# Directory Structure

```
├── .DS_Store
├── .github
│   ├── dependabot.yml
│   ├── instructions
│   │   ├── mcp-node-tests.instructions.md
│   │   └── mcp-yml-tests.instructions.md
│   ├── ISSUE_TEMPLATE
│   │   ├── bug_report.yml
│   │   ├── config.yml
│   │   ├── documentation.yml
│   │   ├── feature_request.yml
│   │   └── question.yml
│   ├── PULL_REQUEST_TEMPLATE
│   │   ├── bug_fix.md
│   │   ├── documentation.md
│   │   └── new_tool.md
│   ├── pull_request_template.md
│   └── workflows
│       ├── ci.yml
│       ├── deploy-pages.yml
│       ├── publish.yml
│       └── update-docs.yml
├── .gitignore
├── .husky
│   └── pre-commit
├── aegis.config.docs-only.json
├── aegis.config.json
├── aegis.config.with-dw.json
├── AGENTS.md
├── ai-instructions
│   ├── claude-desktop
│   │   └── claude_custom_instructions.md
│   ├── cursor
│   │   └── .cursor
│   │       └── rules
│   │           ├── debugging-workflows.mdc
│   │           ├── hooks-development.mdc
│   │           ├── isml-templates.mdc
│   │           ├── job-framework.mdc
│   │           ├── performance-optimization.mdc
│   │           ├── scapi-endpoints.mdc
│   │           ├── security-patterns.mdc
│   │           ├── sfcc-development.mdc
│   │           ├── sfra-controllers.mdc
│   │           ├── sfra-models.mdc
│   │           ├── system-objects.mdc
│   │           └── testing-patterns.mdc
│   └── github-copilot
│       └── copilot-instructions.md
├── CHANGELOG.md
├── CONTRIBUTING.md
├── docs
│   ├── best-practices
│   │   ├── cartridge_creation.md
│   │   ├── isml_templates.md
│   │   ├── job_framework.md
│   │   ├── localserviceregistry.md
│   │   ├── ocapi_hooks.md
│   │   ├── performance.md
│   │   ├── scapi_custom_endpoint.md
│   │   ├── scapi_hooks.md
│   │   ├── security.md
│   │   ├── sfra_client_side_js.md
│   │   ├── sfra_controllers.md
│   │   ├── sfra_models.md
│   │   └── sfra_scss.md
│   ├── dw_campaign
│   │   ├── ABTest.md
│   │   ├── ABTestMgr.md
│   │   ├── ABTestSegment.md
│   │   ├── AmountDiscount.md
│   │   ├── ApproachingDiscount.md
│   │   ├── BonusChoiceDiscount.md
│   │   ├── BonusDiscount.md
│   │   ├── Campaign.md
│   │   ├── CampaignMgr.md
│   │   ├── CampaignStatusCodes.md
│   │   ├── Coupon.md
│   │   ├── CouponMgr.md
│   │   ├── CouponRedemption.md
│   │   ├── CouponStatusCodes.md
│   │   ├── Discount.md
│   │   ├── DiscountPlan.md
│   │   ├── FixedPriceDiscount.md
│   │   ├── FixedPriceShippingDiscount.md
│   │   ├── FreeDiscount.md
│   │   ├── FreeShippingDiscount.md
│   │   ├── PercentageDiscount.md
│   │   ├── PercentageOptionDiscount.md
│   │   ├── PriceBookPriceDiscount.md
│   │   ├── Promotion.md
│   │   ├── PromotionMgr.md
│   │   ├── PromotionPlan.md
│   │   ├── SlotContent.md
│   │   ├── SourceCodeGroup.md
│   │   ├── SourceCodeInfo.md
│   │   ├── SourceCodeStatusCodes.md
│   │   └── TotalFixedPriceDiscount.md
│   ├── dw_catalog
│   │   ├── Catalog.md
│   │   ├── CatalogMgr.md
│   │   ├── Category.md
│   │   ├── CategoryAssignment.md
│   │   ├── CategoryLink.md
│   │   ├── PriceBook.md
│   │   ├── PriceBookMgr.md
│   │   ├── Product.md
│   │   ├── ProductActiveData.md
│   │   ├── ProductAttributeModel.md
│   │   ├── ProductAvailabilityLevels.md
│   │   ├── ProductAvailabilityModel.md
│   │   ├── ProductInventoryList.md
│   │   ├── ProductInventoryMgr.md
│   │   ├── ProductInventoryRecord.md
│   │   ├── ProductLink.md
│   │   ├── ProductMgr.md
│   │   ├── ProductOption.md
│   │   ├── ProductOptionModel.md
│   │   ├── ProductOptionValue.md
│   │   ├── ProductPriceInfo.md
│   │   ├── ProductPriceModel.md
│   │   ├── ProductPriceTable.md
│   │   ├── ProductSearchHit.md
│   │   ├── ProductSearchModel.md
│   │   ├── ProductSearchRefinementDefinition.md
│   │   ├── ProductSearchRefinements.md
│   │   ├── ProductSearchRefinementValue.md
│   │   ├── ProductVariationAttribute.md
│   │   ├── ProductVariationAttributeValue.md
│   │   ├── ProductVariationModel.md
│   │   ├── Recommendation.md
│   │   ├── SearchModel.md
│   │   ├── SearchRefinementDefinition.md
│   │   ├── SearchRefinements.md
│   │   ├── SearchRefinementValue.md
│   │   ├── SortingOption.md
│   │   ├── SortingRule.md
│   │   ├── Store.md
│   │   ├── StoreGroup.md
│   │   ├── StoreInventoryFilter.md
│   │   ├── StoreInventoryFilterValue.md
│   │   ├── StoreMgr.md
│   │   ├── Variant.md
│   │   └── VariationGroup.md
│   ├── dw_content
│   │   ├── Content.md
│   │   ├── ContentMgr.md
│   │   ├── ContentSearchModel.md
│   │   ├── ContentSearchRefinementDefinition.md
│   │   ├── ContentSearchRefinements.md
│   │   ├── ContentSearchRefinementValue.md
│   │   ├── Folder.md
│   │   ├── Library.md
│   │   ├── MarkupText.md
│   │   └── MediaFile.md
│   ├── dw_crypto
│   │   ├── CertificateRef.md
│   │   ├── CertificateUtils.md
│   │   ├── Cipher.md
│   │   ├── Encoding.md
│   │   ├── JWE.md
│   │   ├── JWEHeader.md
│   │   ├── JWS.md
│   │   ├── JWSHeader.md
│   │   ├── KeyRef.md
│   │   ├── Mac.md
│   │   ├── MessageDigest.md
│   │   ├── SecureRandom.md
│   │   ├── Signature.md
│   │   ├── WeakCipher.md
│   │   ├── WeakMac.md
│   │   ├── WeakMessageDigest.md
│   │   ├── WeakSignature.md
│   │   └── X509Certificate.md
│   ├── dw_customer
│   │   ├── AddressBook.md
│   │   ├── AgentUserMgr.md
│   │   ├── AgentUserStatusCodes.md
│   │   ├── AuthenticationStatus.md
│   │   ├── Credentials.md
│   │   ├── Customer.md
│   │   ├── CustomerActiveData.md
│   │   ├── CustomerAddress.md
│   │   ├── CustomerCDPData.md
│   │   ├── CustomerContextMgr.md
│   │   ├── CustomerGroup.md
│   │   ├── CustomerList.md
│   │   ├── CustomerMgr.md
│   │   ├── CustomerPasswordConstraints.md
│   │   ├── CustomerPaymentInstrument.md
│   │   ├── CustomerStatusCodes.md
│   │   ├── EncryptedObject.md
│   │   ├── ExternalProfile.md
│   │   ├── OrderHistory.md
│   │   ├── ProductList.md
│   │   ├── ProductListItem.md
│   │   ├── ProductListItemPurchase.md
│   │   ├── ProductListMgr.md
│   │   ├── ProductListRegistrant.md
│   │   ├── Profile.md
│   │   └── Wallet.md
│   ├── dw_extensions.applepay
│   │   ├── ApplePayHookResult.md
│   │   └── ApplePayHooks.md
│   ├── dw_extensions.facebook
│   │   ├── FacebookFeedHooks.md
│   │   └── FacebookProduct.md
│   ├── dw_extensions.paymentrequest
│   │   ├── PaymentRequestHookResult.md
│   │   └── PaymentRequestHooks.md
│   ├── dw_extensions.payments
│   │   ├── SalesforceBancontactPaymentDetails.md
│   │   ├── SalesforceCardPaymentDetails.md
│   │   ├── SalesforceEpsPaymentDetails.md
│   │   ├── SalesforceIdealPaymentDetails.md
│   │   ├── SalesforceKlarnaPaymentDetails.md
│   │   ├── SalesforcePaymentDetails.md
│   │   ├── SalesforcePaymentIntent.md
│   │   ├── SalesforcePaymentMethod.md
│   │   ├── SalesforcePaymentRequest.md
│   │   ├── SalesforcePaymentsHooks.md
│   │   ├── SalesforcePaymentsMgr.md
│   │   ├── SalesforcePaymentsSiteConfiguration.md
│   │   ├── SalesforcePayPalOrder.md
│   │   ├── SalesforcePayPalOrderAddress.md
│   │   ├── SalesforcePayPalOrderPayer.md
│   │   ├── SalesforcePayPalPaymentDetails.md
│   │   ├── SalesforceSepaDebitPaymentDetails.md
│   │   └── SalesforceVenmoPaymentDetails.md
│   ├── dw_extensions.pinterest
│   │   ├── PinterestAvailability.md
│   │   ├── PinterestFeedHooks.md
│   │   ├── PinterestOrder.md
│   │   ├── PinterestOrderHooks.md
│   │   └── PinterestProduct.md
│   ├── dw_io
│   │   ├── CSVStreamReader.md
│   │   ├── CSVStreamWriter.md
│   │   ├── File.md
│   │   ├── FileReader.md
│   │   ├── FileWriter.md
│   │   ├── InputStream.md
│   │   ├── OutputStream.md
│   │   ├── PrintWriter.md
│   │   ├── RandomAccessFileReader.md
│   │   ├── Reader.md
│   │   ├── StringWriter.md
│   │   ├── Writer.md
│   │   ├── XMLIndentingStreamWriter.md
│   │   ├── XMLStreamConstants.md
│   │   ├── XMLStreamReader.md
│   │   └── XMLStreamWriter.md
│   ├── dw_job
│   │   ├── JobExecution.md
│   │   └── JobStepExecution.md
│   ├── dw_net
│   │   ├── FTPClient.md
│   │   ├── FTPFileInfo.md
│   │   ├── HTTPClient.md
│   │   ├── HTTPRequestPart.md
│   │   ├── Mail.md
│   │   ├── SFTPClient.md
│   │   ├── SFTPFileInfo.md
│   │   ├── WebDAVClient.md
│   │   └── WebDAVFileInfo.md
│   ├── dw_object
│   │   ├── ActiveData.md
│   │   ├── CustomAttributes.md
│   │   ├── CustomObject.md
│   │   ├── CustomObjectMgr.md
│   │   ├── Extensible.md
│   │   ├── ExtensibleObject.md
│   │   ├── Note.md
│   │   ├── ObjectAttributeDefinition.md
│   │   ├── ObjectAttributeGroup.md
│   │   ├── ObjectAttributeValueDefinition.md
│   │   ├── ObjectTypeDefinition.md
│   │   ├── PersistentObject.md
│   │   ├── SimpleExtensible.md
│   │   └── SystemObjectMgr.md
│   ├── dw_order
│   │   ├── AbstractItem.md
│   │   ├── AbstractItemCtnr.md
│   │   ├── Appeasement.md
│   │   ├── AppeasementItem.md
│   │   ├── Basket.md
│   │   ├── BasketMgr.md
│   │   ├── BonusDiscountLineItem.md
│   │   ├── CouponLineItem.md
│   │   ├── CreateAgentBasketLimitExceededException.md
│   │   ├── CreateBasketFromOrderException.md
│   │   ├── CreateCouponLineItemException.md
│   │   ├── CreateOrderException.md
│   │   ├── CreateTemporaryBasketLimitExceededException.md
│   │   ├── GiftCertificate.md
│   │   ├── GiftCertificateLineItem.md
│   │   ├── GiftCertificateMgr.md
│   │   ├── GiftCertificateStatusCodes.md
│   │   ├── Invoice.md
│   │   ├── InvoiceItem.md
│   │   ├── LineItem.md
│   │   ├── LineItemCtnr.md
│   │   ├── Order.md
│   │   ├── OrderAddress.md
│   │   ├── OrderItem.md
│   │   ├── OrderMgr.md
│   │   ├── OrderPaymentInstrument.md
│   │   ├── OrderProcessStatusCodes.md
│   │   ├── PaymentCard.md
│   │   ├── PaymentInstrument.md
│   │   ├── PaymentMethod.md
│   │   ├── PaymentMgr.md
│   │   ├── PaymentProcessor.md
│   │   ├── PaymentStatusCodes.md
│   │   ├── PaymentTransaction.md
│   │   ├── PriceAdjustment.md
│   │   ├── PriceAdjustmentLimitTypes.md
│   │   ├── ProductLineItem.md
│   │   ├── ProductShippingCost.md
│   │   ├── ProductShippingLineItem.md
│   │   ├── ProductShippingModel.md
│   │   ├── Return.md
│   │   ├── ReturnCase.md
│   │   ├── ReturnCaseItem.md
│   │   ├── ReturnItem.md
│   │   ├── Shipment.md
│   │   ├── ShipmentShippingCost.md
│   │   ├── ShipmentShippingModel.md
│   │   ├── ShippingLineItem.md
│   │   ├── ShippingLocation.md
│   │   ├── ShippingMethod.md
│   │   ├── ShippingMgr.md
│   │   ├── ShippingOrder.md
│   │   ├── ShippingOrderItem.md
│   │   ├── SumItem.md
│   │   ├── TaxGroup.md
│   │   ├── TaxItem.md
│   │   ├── TaxMgr.md
│   │   ├── TrackingInfo.md
│   │   └── TrackingRef.md
│   ├── dw_order.hooks
│   │   ├── CalculateHooks.md
│   │   ├── OrderHooks.md
│   │   ├── PaymentHooks.md
│   │   ├── ReturnHooks.md
│   │   └── ShippingOrderHooks.md
│   ├── dw_rpc
│   │   ├── SOAPUtil.md
│   │   ├── Stub.md
│   │   └── WebReference.md
│   ├── dw_suggest
│   │   ├── BrandSuggestions.md
│   │   ├── CategorySuggestions.md
│   │   ├── ContentSuggestions.md
│   │   ├── CustomSuggestions.md
│   │   ├── ProductSuggestions.md
│   │   ├── SearchPhraseSuggestions.md
│   │   ├── SuggestedCategory.md
│   │   ├── SuggestedContent.md
│   │   ├── SuggestedPhrase.md
│   │   ├── SuggestedProduct.md
│   │   ├── SuggestedTerm.md
│   │   ├── SuggestedTerms.md
│   │   ├── Suggestions.md
│   │   └── SuggestModel.md
│   ├── dw_svc
│   │   ├── FTPService.md
│   │   ├── FTPServiceDefinition.md
│   │   ├── HTTPFormService.md
│   │   ├── HTTPFormServiceDefinition.md
│   │   ├── HTTPService.md
│   │   ├── HTTPServiceDefinition.md
│   │   ├── LocalServiceRegistry.md
│   │   ├── Result.md
│   │   ├── Service.md
│   │   ├── ServiceCallback.md
│   │   ├── ServiceConfig.md
│   │   ├── ServiceCredential.md
│   │   ├── ServiceDefinition.md
│   │   ├── ServiceProfile.md
│   │   ├── ServiceRegistry.md
│   │   ├── SOAPService.md
│   │   └── SOAPServiceDefinition.md
│   ├── dw_system
│   │   ├── AgentUserStatusCodes.md
│   │   ├── Cache.md
│   │   ├── CacheMgr.md
│   │   ├── HookMgr.md
│   │   ├── InternalObject.md
│   │   ├── JobProcessMonitor.md
│   │   ├── Log.md
│   │   ├── Logger.md
│   │   ├── LogNDC.md
│   │   ├── OrganizationPreferences.md
│   │   ├── Pipeline.md
│   │   ├── PipelineDictionary.md
│   │   ├── RemoteInclude.md
│   │   ├── Request.md
│   │   ├── RequestHooks.md
│   │   ├── Response.md
│   │   ├── RESTErrorResponse.md
│   │   ├── RESTResponseMgr.md
│   │   ├── RESTSuccessResponse.md
│   │   ├── SearchStatus.md
│   │   ├── Session.md
│   │   ├── Site.md
│   │   ├── SitePreferences.md
│   │   ├── Status.md
│   │   ├── StatusItem.md
│   │   ├── System.md
│   │   └── Transaction.md
│   ├── dw_util
│   │   ├── ArrayList.md
│   │   ├── Assert.md
│   │   ├── BigInteger.md
│   │   ├── Bytes.md
│   │   ├── Calendar.md
│   │   ├── Collection.md
│   │   ├── Currency.md
│   │   ├── DateUtils.md
│   │   ├── Decimal.md
│   │   ├── FilteringCollection.md
│   │   ├── Geolocation.md
│   │   ├── HashMap.md
│   │   ├── HashSet.md
│   │   ├── Iterator.md
│   │   ├── LinkedHashMap.md
│   │   ├── LinkedHashSet.md
│   │   ├── List.md
│   │   ├── Locale.md
│   │   ├── Map.md
│   │   ├── MapEntry.md
│   │   ├── MappingKey.md
│   │   ├── MappingMgr.md
│   │   ├── PropertyComparator.md
│   │   ├── SecureEncoder.md
│   │   ├── SecureFilter.md
│   │   ├── SeekableIterator.md
│   │   ├── Set.md
│   │   ├── SortedMap.md
│   │   ├── SortedSet.md
│   │   ├── StringUtils.md
│   │   ├── Template.md
│   │   └── UUIDUtils.md
│   ├── dw_value
│   │   ├── EnumValue.md
│   │   ├── MimeEncodedText.md
│   │   ├── Money.md
│   │   └── Quantity.md
│   ├── dw_web
│   │   ├── ClickStream.md
│   │   ├── ClickStreamEntry.md
│   │   ├── Cookie.md
│   │   ├── Cookies.md
│   │   ├── CSRFProtection.md
│   │   ├── Form.md
│   │   ├── FormAction.md
│   │   ├── FormElement.md
│   │   ├── FormElementValidationResult.md
│   │   ├── FormField.md
│   │   ├── FormFieldOption.md
│   │   ├── FormFieldOptions.md
│   │   ├── FormGroup.md
│   │   ├── FormList.md
│   │   ├── FormListItem.md
│   │   ├── Forms.md
│   │   ├── HttpParameter.md
│   │   ├── HttpParameterMap.md
│   │   ├── LoopIterator.md
│   │   ├── PageMetaData.md
│   │   ├── PageMetaTag.md
│   │   ├── PagingModel.md
│   │   ├── Resource.md
│   │   ├── URL.md
│   │   ├── URLAction.md
│   │   ├── URLParameter.md
│   │   ├── URLRedirect.md
│   │   ├── URLRedirectMgr.md
│   │   └── URLUtils.md
│   ├── sfra
│   │   ├── account.md
│   │   ├── address.md
│   │   ├── billing.md
│   │   ├── cart.md
│   │   ├── categories.md
│   │   ├── content.md
│   │   ├── locale.md
│   │   ├── order.md
│   │   ├── payment.md
│   │   ├── price-default.md
│   │   ├── price-range.md
│   │   ├── price-tiered.md
│   │   ├── product-bundle.md
│   │   ├── product-full.md
│   │   ├── product-line-items.md
│   │   ├── product-search.md
│   │   ├── product-tile.md
│   │   ├── querystring.md
│   │   ├── render.md
│   │   ├── request.md
│   │   ├── response.md
│   │   ├── server.md
│   │   ├── shipping.md
│   │   ├── store.md
│   │   ├── stores.md
│   │   └── totals.md
│   └── TopLevel
│       ├── APIException.md
│       ├── arguments.md
│       ├── Array.md
│       ├── ArrayBuffer.md
│       ├── BigInt.md
│       ├── Boolean.md
│       ├── ConversionError.md
│       ├── DataView.md
│       ├── Date.md
│       ├── Error.md
│       ├── ES6Iterator.md
│       ├── EvalError.md
│       ├── Fault.md
│       ├── Float32Array.md
│       ├── Float64Array.md
│       ├── Function.md
│       ├── Generator.md
│       ├── global.md
│       ├── Int16Array.md
│       ├── Int32Array.md
│       ├── Int8Array.md
│       ├── InternalError.md
│       ├── IOError.md
│       ├── Iterable.md
│       ├── Iterator.md
│       ├── JSON.md
│       ├── Map.md
│       ├── Math.md
│       ├── Module.md
│       ├── Namespace.md
│       ├── Number.md
│       ├── Object.md
│       ├── QName.md
│       ├── RangeError.md
│       ├── ReferenceError.md
│       ├── RegExp.md
│       ├── Set.md
│       ├── StopIteration.md
│       ├── String.md
│       ├── Symbol.md
│       ├── SyntaxError.md
│       ├── SystemError.md
│       ├── TypeError.md
│       ├── Uint16Array.md
│       ├── Uint32Array.md
│       ├── Uint8Array.md
│       ├── Uint8ClampedArray.md
│       ├── URIError.md
│       ├── WeakMap.md
│       ├── WeakSet.md
│       ├── XML.md
│       ├── XMLList.md
│       └── XMLStreamError.md
├── docs-site
│   ├── .gitignore
│   ├── App.tsx
│   ├── components
│   │   ├── Badge.tsx
│   │   ├── BreadcrumbSchema.tsx
│   │   ├── CodeBlock.tsx
│   │   ├── Collapsible.tsx
│   │   ├── ConfigBuilder.tsx
│   │   ├── ConfigHero.tsx
│   │   ├── ConfigModeTabs.tsx
│   │   ├── icons.tsx
│   │   ├── Layout.tsx
│   │   ├── LightCodeContainer.tsx
│   │   ├── NewcomerCTA.tsx
│   │   ├── NextStepsStrip.tsx
│   │   ├── OnThisPage.tsx
│   │   ├── Search.tsx
│   │   ├── SEO.tsx
│   │   ├── Sidebar.tsx
│   │   ├── StructuredData.tsx
│   │   ├── ToolCard.tsx
│   │   ├── ToolFilters.tsx
│   │   ├── Typography.tsx
│   │   └── VersionBadge.tsx
│   ├── constants.tsx
│   ├── index.html
│   ├── main.tsx
│   ├── metadata.json
│   ├── package-lock.json
│   ├── package.json
│   ├── pages
│   │   ├── AIInterfacesPage.tsx
│   │   ├── ConfigurationPage.tsx
│   │   ├── DevelopmentPage.tsx
│   │   ├── ExamplesPage.tsx
│   │   ├── FeaturesPage.tsx
│   │   ├── HomePage.tsx
│   │   ├── SecurityPage.tsx
│   │   ├── ToolsPage.tsx
│   │   └── TroubleshootingPage.tsx
│   ├── postcss.config.js
│   ├── public
│   │   ├── .well-known
│   │   │   └── security.txt
│   │   ├── 404.html
│   │   ├── android-chrome-192x192.png
│   │   ├── android-chrome-512x512.png
│   │   ├── apple-touch-icon.png
│   │   ├── explain-product-pricing-methods-no-mcp.png
│   │   ├── explain-product-pricing-methods.png
│   │   ├── favicon-16x16.png
│   │   ├── favicon-32x32.png
│   │   ├── favicon.ico
│   │   ├── llms.txt
│   │   ├── robots.txt
│   │   ├── site.webmanifest
│   │   └── sitemap.xml
│   ├── README.md
│   ├── scripts
│   │   ├── generate-search-index.js
│   │   ├── generate-sitemap.js
│   │   └── search-dev.js
│   ├── src
│   │   └── styles
│   │       ├── input.css
│   │       └── prism-theme.css
│   ├── tailwind.config.js
│   ├── tsconfig.json
│   ├── types.ts
│   ├── utils
│   │   ├── search.ts
│   │   └── toolsData.ts
│   └── vite.config.ts
├── eslint.config.js
├── jest.config.js
├── LICENSE
├── package-lock.json
├── package.json
├── README.md
├── scripts
│   └── convert-docs.js
├── SECURITY.md
├── server.json
├── src
│   ├── clients
│   │   ├── base
│   │   │   ├── http-client.ts
│   │   │   ├── oauth-token.ts
│   │   │   └── ocapi-auth-client.ts
│   │   ├── best-practices-client.ts
│   │   ├── cartridge-generation-client.ts
│   │   ├── docs
│   │   │   ├── class-content-parser.ts
│   │   │   ├── class-name-resolver.ts
│   │   │   ├── documentation-scanner.ts
│   │   │   ├── index.ts
│   │   │   └── referenced-types-extractor.ts
│   │   ├── docs-client.ts
│   │   ├── log-client.ts
│   │   ├── logs
│   │   │   ├── index.ts
│   │   │   ├── log-analyzer.ts
│   │   │   ├── log-client.ts
│   │   │   ├── log-constants.ts
│   │   │   ├── log-file-discovery.ts
│   │   │   ├── log-file-reader.ts
│   │   │   ├── log-formatter.ts
│   │   │   ├── log-processor.ts
│   │   │   ├── log-types.ts
│   │   │   └── webdav-client-manager.ts
│   │   ├── ocapi
│   │   │   ├── code-versions-client.ts
│   │   │   ├── site-preferences-client.ts
│   │   │   └── system-objects-client.ts
│   │   ├── ocapi-client.ts
│   │   └── sfra-client.ts
│   ├── config
│   │   ├── configuration-factory.ts
│   │   └── dw-json-loader.ts
│   ├── core
│   │   ├── handlers
│   │   │   ├── abstract-log-tool-handler.ts
│   │   │   ├── base-handler.ts
│   │   │   ├── best-practices-handler.ts
│   │   │   ├── cartridge-handler.ts
│   │   │   ├── client-factory.ts
│   │   │   ├── code-version-handler.ts
│   │   │   ├── docs-handler.ts
│   │   │   ├── job-log-handler.ts
│   │   │   ├── job-log-tool-config.ts
│   │   │   ├── log-handler.ts
│   │   │   ├── log-tool-config.ts
│   │   │   ├── sfra-handler.ts
│   │   │   ├── system-object-handler.ts
│   │   │   └── validation-helpers.ts
│   │   ├── server.ts
│   │   └── tool-definitions.ts
│   ├── index.ts
│   ├── main.ts
│   ├── services
│   │   ├── file-system-service.ts
│   │   ├── index.ts
│   │   └── path-service.ts
│   ├── tool-configs
│   │   ├── best-practices-tool-config.ts
│   │   ├── cartridge-tool-config.ts
│   │   ├── code-version-tool-config.ts
│   │   ├── docs-tool-config.ts
│   │   ├── job-log-tool-config.ts
│   │   ├── log-tool-config.ts
│   │   ├── sfra-tool-config.ts
│   │   └── system-object-tool-config.ts
│   ├── types
│   │   └── types.ts
│   └── utils
│       ├── cache.ts
│       ├── job-log-tool-config.ts
│       ├── job-log-utils.ts
│       ├── log-cache.ts
│       ├── log-tool-config.ts
│       ├── log-tool-constants.ts
│       ├── log-tool-utils.ts
│       ├── logger.ts
│       ├── ocapi-url-builder.ts
│       ├── path-resolver.ts
│       ├── query-builder.ts
│       ├── utils.ts
│       └── validator.ts
├── tests
│   ├── __mocks__
│   │   ├── docs-client.ts
│   │   ├── src
│   │   │   └── clients
│   │   │       └── base
│   │   │           └── http-client.js
│   │   └── webdav.js
│   ├── base-handler.test.ts
│   ├── base-http-client.test.ts
│   ├── best-practices-handler.test.ts
│   ├── cache.test.ts
│   ├── cartridge-handler.test.ts
│   ├── class-content-parser.test.ts
│   ├── class-name-resolver.test.ts
│   ├── client-factory.test.ts
│   ├── code-version-handler.test.ts
│   ├── code-versions-client.test.ts
│   ├── config.test.ts
│   ├── configuration-factory.test.ts
│   ├── docs-handler.test.ts
│   ├── documentation-scanner.test.ts
│   ├── file-system-service.test.ts
│   ├── job-log-handler.test.ts
│   ├── job-log-utils.test.ts
│   ├── log-client.test.ts
│   ├── log-handler.test.ts
│   ├── log-processor.test.ts
│   ├── logger.test.ts
│   ├── mcp
│   │   ├── AGENTS.md
│   │   ├── node
│   │   │   ├── activate-code-version-advanced.full-mode.programmatic.test.js
│   │   │   ├── code-versions.full-mode.programmatic.test.js
│   │   │   ├── generate-cartridge-structure.docs-only.programmatic.test.js
│   │   │   ├── get-available-best-practice-guides.docs-only.programmatic.test.js
│   │   │   ├── get-available-sfra-documents.programmatic.test.js
│   │   │   ├── get-best-practice-guide.docs-only.programmatic.test.js
│   │   │   ├── get-hook-reference.docs-only.programmatic.test.js
│   │   │   ├── get-job-execution-summary.full-mode.programmatic.test.js
│   │   │   ├── get-job-log-entries.full-mode.programmatic.test.js
│   │   │   ├── get-latest-debug.full-mode.programmatic.test.js
│   │   │   ├── get-latest-error.full-mode.programmatic.test.js
│   │   │   ├── get-latest-info.full-mode.programmatic.test.js
│   │   │   ├── get-latest-job-log-files.full-mode.programmatic.test.js
│   │   │   ├── get-latest-warn.full-mode.programmatic.test.js
│   │   │   ├── get-log-file-contents.full-mode.programmatic.test.js
│   │   │   ├── get-sfcc-class-documentation.docs-only.programmatic.test.js
│   │   │   ├── get-sfcc-class-info.docs-only.programmatic.test.js
│   │   │   ├── get-sfra-categories.docs-only.programmatic.test.js
│   │   │   ├── get-sfra-document.programmatic.test.js
│   │   │   ├── get-sfra-documents-by-category.docs-only.programmatic.test.js
│   │   │   ├── get-system-object-definition.full-mode.programmatic.test.js
│   │   │   ├── get-system-object-definitions.docs-only.programmatic.test.js
│   │   │   ├── get-system-object-definitions.full-mode.programmatic.test.js
│   │   │   ├── list-log-files.full-mode.programmatic.test.js
│   │   │   ├── list-sfcc-classes.docs-only.programmatic.test.js
│   │   │   ├── search-best-practices.docs-only.programmatic.test.js
│   │   │   ├── search-custom-object-attribute-definitions.full-mode.programmatic.test.js
│   │   │   ├── search-job-logs-by-name.full-mode.programmatic.test.js
│   │   │   ├── search-job-logs.full-mode.programmatic.test.js
│   │   │   ├── search-logs.full-mode.programmatic.test.js
│   │   │   ├── search-sfcc-classes.docs-only.programmatic.test.js
│   │   │   ├── search-sfcc-methods.docs-only.programmatic.test.js
│   │   │   ├── search-sfra-documentation.docs-only.programmatic.test.js
│   │   │   ├── search-site-preferences.full-mode.programmatic.test.js
│   │   │   ├── search-system-object-attribute-definitions.full-mode.programmatic.test.js
│   │   │   ├── search-system-object-attribute-groups.full-mode.programmatic.test.js
│   │   │   ├── summarize-logs.full-mode.programmatic.test.js
│   │   │   ├── tools.docs-only.programmatic.test.js
│   │   │   └── tools.full-mode.programmatic.test.js
│   │   ├── README.md
│   │   ├── test-fixtures
│   │   │   └── dw.json
│   │   └── yaml
│   │       ├── activate-code-version.docs-only.test.mcp.yml
│   │       ├── activate-code-version.full-mode.test.mcp.yml
│   │       ├── get_latest_error.test.mcp.yml
│   │       ├── get-available-best-practice-guides.docs-only.test.mcp.yml
│   │       ├── get-available-best-practice-guides.full-mode.test.mcp.yml
│   │       ├── get-available-sfra-documents.docs-only.test.mcp.yml
│   │       ├── get-available-sfra-documents.full-mode.test.mcp.yml
│   │       ├── get-best-practice-guide.docs-only.test.mcp.yml
│   │       ├── get-best-practice-guide.full-mode.test.mcp.yml
│   │       ├── get-code-versions.docs-only.test.mcp.yml
│   │       ├── get-code-versions.full-mode.test.mcp.yml
│   │       ├── get-hook-reference.docs-only.test.mcp.yml
│   │       ├── get-hook-reference.full-mode.test.mcp.yml
│   │       ├── get-job-execution-summary.full-mode.test.mcp.yml
│   │       ├── get-job-log-entries.full-mode.test.mcp.yml
│   │       ├── get-latest-debug.full-mode.test.mcp.yml
│   │       ├── get-latest-error.full-mode.test.mcp.yml
│   │       ├── get-latest-info.full-mode.test.mcp.yml
│   │       ├── get-latest-job-log-files.full-mode.test.mcp.yml
│   │       ├── get-latest-warn.full-mode.test.mcp.yml
│   │       ├── get-log-file-contents.full-mode.test.mcp.yml
│   │       ├── get-sfcc-class-documentation.docs-only.test.mcp.yml
│   │       ├── get-sfcc-class-documentation.full-mode.test.mcp.yml
│   │       ├── get-sfcc-class-info.docs-only.test.mcp.yml
│   │       ├── get-sfcc-class-info.full-mode.test.mcp.yml
│   │       ├── get-sfra-categories.docs-only.test.mcp.yml
│   │       ├── get-sfra-categories.full-mode.test.mcp.yml
│   │       ├── get-sfra-document.docs-only.test.mcp.yml
│   │       ├── get-sfra-document.full-mode.test.mcp.yml
│   │       ├── get-sfra-documents-by-category.docs-only.test.mcp.yml
│   │       ├── get-sfra-documents-by-category.full-mode.test.mcp.yml
│   │       ├── get-system-object-definition.docs-only.test.mcp.yml
│   │       ├── get-system-object-definition.full-mode.test.mcp.yml
│   │       ├── get-system-object-definitions.docs-only.test.mcp.yml
│   │       ├── get-system-object-definitions.full-mode.test.mcp.yml
│   │       ├── list-log-files.full-mode.test.mcp.yml
│   │       ├── list-sfcc-classes.docs-only.test.mcp.yml
│   │       ├── list-sfcc-classes.full-mode.test.mcp.yml
│   │       ├── search-best-practices.docs-only.test.mcp.yml
│   │       ├── search-best-practices.full-mode.test.mcp.yml
│   │       ├── search-custom-object-attribute-definitions.docs-only.test.mcp.yml
│   │       ├── search-custom-object-attribute-definitions.test.mcp.yml
│   │       ├── search-job-logs-by-name.full-mode.test.mcp.yml
│   │       ├── search-job-logs.full-mode.test.mcp.yml
│   │       ├── search-logs.full-mode.test.mcp.yml
│   │       ├── search-sfcc-classes.docs-only.test.mcp.yml
│   │       ├── search-sfcc-classes.full-mode.test.mcp.yml
│   │       ├── search-sfcc-methods.docs-only.test.mcp.yml
│   │       ├── search-sfcc-methods.full-mode.test.mcp.yml
│   │       ├── search-sfra-documentation.docs-only.test.mcp.yml
│   │       ├── search-sfra-documentation.full-mode.test.mcp.yml
│   │       ├── search-site-preferences.docs-only.test.mcp.yml
│   │       ├── search-site-preferences.full-mode.test.mcp.yml
│   │       ├── search-system-object-attribute-definitions.docs-only.test.mcp.yml
│   │       ├── search-system-object-attribute-definitions.full-mode.test.mcp.yml
│   │       ├── search-system-object-attribute-groups.docs-only.test.mcp.yml
│   │       ├── search-system-object-attribute-groups.full-mode.test.mcp.yml
│   │       ├── summarize-logs.full-mode.test.mcp.yml
│   │       ├── tools.docs-only.test.mcp.yml
│   │       └── tools.full-mode.test.mcp.yml
│   ├── oauth-token.test.ts
│   ├── ocapi-auth-client.test.ts
│   ├── ocapi-client.test.ts
│   ├── path-service.test.ts
│   ├── query-builder.test.ts
│   ├── referenced-types-extractor.test.ts
│   ├── servers
│   │   ├── sfcc-mock-server
│   │   │   ├── mock-data
│   │   │   │   └── ocapi
│   │   │   │       ├── code-versions.json
│   │   │   │       ├── custom-object-attributes-customapi.json
│   │   │   │       ├── custom-object-attributes-globalsettings.json
│   │   │   │       ├── custom-object-attributes-versionhistory.json
│   │   │   │       ├── site-preferences-ccv.json
│   │   │   │       ├── site-preferences-fastforward.json
│   │   │   │       ├── site-preferences-sfra.json
│   │   │   │       ├── site-preferences-storefront.json
│   │   │   │       ├── site-preferences-system.json
│   │   │   │       ├── system-object-attribute-groups-campaign.json
│   │   │   │       ├── system-object-attribute-groups-category.json
│   │   │   │       ├── system-object-attribute-groups-order.json
│   │   │   │       ├── system-object-attribute-groups-product.json
│   │   │   │       ├── system-object-attribute-groups-sitepreferences.json
│   │   │   │       ├── system-object-attributes-customeraddress.json
│   │   │   │       ├── system-object-attributes-product-expanded.json
│   │   │   │       ├── system-object-attributes-product.json
│   │   │   │       ├── system-object-definition-category.json
│   │   │   │       ├── system-object-definition-customer.json
│   │   │   │       ├── system-object-definition-customeraddress.json
│   │   │   │       ├── system-object-definition-order.json
│   │   │   │       ├── system-object-definition-product.json
│   │   │   │       ├── system-object-definitions-old.json
│   │   │   │       └── system-object-definitions.json
│   │   │   ├── package-lock.json
│   │   │   ├── package.json
│   │   │   ├── README.md
│   │   │   ├── scripts
│   │   │   │   └── setup-logs.js
│   │   │   ├── server.js
│   │   │   └── src
│   │   │       ├── app.js
│   │   │       ├── config
│   │   │       │   └── server-config.js
│   │   │       ├── middleware
│   │   │       │   ├── auth.js
│   │   │       │   ├── cors.js
│   │   │       │   └── logging.js
│   │   │       ├── routes
│   │   │       │   ├── ocapi
│   │   │       │   │   ├── code-versions-handler.js
│   │   │       │   │   ├── oauth-handler.js
│   │   │       │   │   ├── ocapi-error-utils.js
│   │   │       │   │   ├── ocapi-utils.js
│   │   │       │   │   ├── site-preferences-handler.js
│   │   │       │   │   └── system-objects-handler.js
│   │   │       │   ├── ocapi.js
│   │   │       │   └── webdav.js
│   │   │       └── utils
│   │   │           ├── mock-data-loader.js
│   │   │           └── webdav-xml.js
│   │   └── sfcc-mock-server-manager.ts
│   ├── sfcc-mock-server.test.ts
│   ├── site-preferences-client.test.ts
│   ├── system-objects-client.test.ts
│   ├── utils.test.ts
│   ├── validation-helpers.test.ts
│   └── validator.test.ts
├── tsconfig.json
└── tsconfig.test.json
```

# Files

--------------------------------------------------------------------------------
/tests/sfcc-mock-server.test.ts:
--------------------------------------------------------------------------------

```typescript
import { describe, test, expect, beforeAll, afterAll } from '@jest/globals';
import { SFCCMockServerManager, withSFCCMockServer } from './servers/sfcc-mock-server-manager';

/**
 * Integration tests for the Unified SFCC Mock Server
 *
 * These tests demonstrate how to use the unified SFCC mock server
 * for testing both WebDAV log functionality and OCAPI simulation.
 * The server combines both protocols into a single endpoint.
 */

describe('Unified SFCC Mock Server Integration', () => {
  let serverManager: SFCCMockServerManager;

  beforeAll(async () => {
    serverManager = new SFCCMockServerManager({
      port: 3002, // Use different port for tests
      dev: false,
      autoSetup: true,
    });

    // Check if server is available before running tests
    const isAvailable = await serverManager.isServerAvailable();
    if (!isAvailable) {
      console.warn('⚠️  SFCC mock server not available, skipping tests');
      return;
    }

    await serverManager.start();
  }, 20000); // 20 second timeout for server startup (includes log setup)

  afterAll(async () => {
    if (serverManager?.isRunning()) {
      await serverManager.stop();
    }
  }, 10000); // 10 second timeout for server shutdown

  describe('Server Startup and Basic Functionality', () => {
    test('should start server and be accessible', async () => {
      if (!await serverManager.isServerAvailable()) {
        console.warn('⚠️  Skipping test - SFCC mock server not available');
        return;
      }

      expect(serverManager.isRunning()).toBe(true);
      expect(serverManager.getServerUrl()).toBe('http://localhost:3002');
      expect(serverManager.getWebDAVLogsUrl()).toBe('http://localhost:3002/on/demandware.servlet/webdav/Sites/Logs/');
      expect(serverManager.getDirectLogsUrl()).toBe('http://localhost:3002/Logs/');
      expect(serverManager.getOCAPIUrl()).toBe('http://localhost:3002/s/-/dw/data/v23_2');
      expect(serverManager.getOAuthUrl()).toBe('http://localhost:3002/dw/oauth2/access_token');
    });

    test('should respond to health check', async () => {
      if (!await serverManager.isServerAvailable()) {
        console.warn('⚠️  Skipping test - SFCC mock server not available');
        return;
      }

      const response = await fetch(`${serverManager.getServerUrl()}/health`);
      expect(response.status).toBe(200);

      const healthData = await response.json();
      expect(healthData).toHaveProperty('status', 'ok');
      expect(healthData).toHaveProperty('message');
    });
  });

  describe('WebDAV Functionality', () => {
    test('should serve WebDAV directory listing', async () => {
      if (!await serverManager.isServerAvailable()) {
        console.warn('⚠️  Skipping test - SFCC mock server not available');
        return;
      }

      // Test SFCC WebDAV path
      const response = await fetch(serverManager.getWebDAVLogsUrl(), {
        method: 'PROPFIND',
        headers: {
          'Depth': '1',
          'Content-Type': 'application/xml',
        },
      });

      expect(response.status).toBe(207); // Multi-Status (WebDAV response)

      const responseText = await response.text();
      expect(responseText).toContain('error-blade-');
      expect(responseText).toContain('warn-blade-');
      expect(responseText).toContain('info-blade-');
      expect(responseText).toContain('debug-blade-');
      expect(responseText).toContain('jobs');

      // Also test direct path for backward compatibility
      const directResponse = await fetch(serverManager.getDirectLogsUrl(), {
        method: 'PROPFIND',
        headers: {
          'Depth': '1',
          'Content-Type': 'application/xml',
        },
      });

      expect(directResponse.status).toBe(207);
    });

    test('should serve log file content', async () => {
      if (!await serverManager.isServerAvailable()) {
        console.warn('⚠️  Skipping test - SFCC mock server not available');
        return;
      }

      // First get the directory listing to find an actual log file
      const listResponse = await fetch(serverManager.getWebDAVLogsUrl(), {
        method: 'PROPFIND',
        headers: {
          'Depth': '1',
          'Content-Type': 'application/xml',
        },
      });

      const listingXml = await listResponse.text();

      // Extract error log filename from the XML response
      const errorLogMatch = listingXml.match(/error-blade-[^<]+\.log/);
      if (!errorLogMatch) {
        throw new Error('No error log file found in directory listing');
      }

      const errorLogFile = errorLogMatch[0];
      const logFileUrl = `${serverManager.getWebDAVLogsUrl()}${errorLogFile}`;

      // Get the log file content
      const logResponse = await fetch(logFileUrl);
      expect(logResponse.status).toBe(200);

      const logContent = await logResponse.text();
      expect(logContent).toContain('ERROR');
      expect(logContent).toContain('SystemJobThread');
      expect(logContent).toContain('PipelineCallServlet');
    });

    test('should serve job logs directory', async () => {
      if (!await serverManager.isServerAvailable()) {
        console.warn('⚠️  Skipping test - SFCC mock server not available');
        return;
      }

      const jobsUrl = `${serverManager.getWebDAVLogsUrl()}jobs/`;
      const response = await fetch(jobsUrl, {
        method: 'PROPFIND',
        headers: {
          'Depth': '1',
          'Content-Type': 'application/xml',
        },
      });

      expect(response.status).toBe(207); // Multi-Status (WebDAV response)

      const responseText = await response.text();
      expect(responseText).toContain('ProcessOrders');
      expect(responseText).toContain('ImportCatalog');
    });

    test('should serve job log file content', async () => {
      if (!await serverManager.isServerAvailable()) {
        console.warn('⚠️  Skipping test - SFCC mock server not available');
        return;
      }

      const jobLogUrl = `${serverManager.getWebDAVLogsUrl()}jobs/ProcessOrders/Job-ProcessOrders-1234567890.log`;
      const response = await fetch(jobLogUrl);

      expect(response.status).toBe(200);

      const logContent = await response.text();
      expect(logContent).toContain('Executing job [ProcessOrders][1234567890]...');
      expect(logContent).toContain('INFO');
      expect(logContent).toContain('SystemJobThread');
      expect(logContent).toContain('ValidateOrdersStep');
    });

    test('should support range requests for log files', async () => {
      if (!await serverManager.isServerAvailable()) {
        console.warn('⚠️  Skipping test - SFCC mock server not available');
        return;
      }

      // Get a log file with range request (last 100 bytes)
      const listResponse = await fetch(serverManager.getWebDAVLogsUrl(), {
        method: 'PROPFIND',
        headers: { 'Depth': '1' },
      });

      const listingXml = await listResponse.text();
      const errorLogMatch = listingXml.match(/error-blade-[^<]+\.log/);

      if (!errorLogMatch) {
        console.warn('⚠️  No error log file found, skipping range request test');
        return;
      }

      const errorLogFile = errorLogMatch[0];
      const logFileUrl = `${serverManager.getWebDAVLogsUrl()}${errorLogFile}`;

      const rangeResponse = await fetch(logFileUrl, {
        headers: {
          'Range': 'bytes=-100', // Last 100 bytes
        },
      });

      expect([200, 206, 416])
        .toContain(rangeResponse.status); // 200 OK, 206 Partial Content, or 416 Range Not Satisfiable
    });
  });

  describe('OCAPI Functionality', () => {
    test('should handle OAuth token request', async () => {
      if (!await serverManager.isServerAvailable()) {
        console.warn('⚠️  Skipping test - SFCC mock server not available');
        return;
      }

      const response = await fetch(serverManager.getOAuthUrl(), {
        method: 'POST',
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded',
          'Authorization': 'Basic dGVzdC1jbGllbnQtaWQ6dGVzdC1jbGllbnQtc2VjcmV0', // test-client-id:test-client-secret
        },
        body: 'grant_type=client_credentials',
      });

      expect(response.status).toBe(200);

      const tokenData = await response.json();
      expect(tokenData).toHaveProperty('access_token');
      expect(tokenData).toHaveProperty('token_type', 'Bearer');
      expect(tokenData).toHaveProperty('expires_in');
    });

    test('should serve system object types', async () => {
      if (!await serverManager.isServerAvailable()) {
        console.warn('⚠️  Skipping test - SFCC mock server not available');
        return;
      }

      // First get OAuth token
      const tokenResponse = await fetch(serverManager.getOAuthUrl(), {
        method: 'POST',
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded',
          'Authorization': 'Basic dGVzdC1jbGllbnQtaWQ6dGVzdC1jbGllbnQtc2VjcmV0',
        },
        body: 'grant_type=client_credentials',
      });

      const tokenData = await tokenResponse.json();
      const accessToken = tokenData.access_token;

      // Test system object types endpoint
      const response = await fetch(`${serverManager.getOCAPIUrl()}/system_object_definitions`, {
        headers: {
          'Authorization': `Bearer ${accessToken}`,
          'Content-Type': 'application/json',
        },
      });

      expect(response.status).toBe(200);

      const data = await response.json();
      expect(data).toHaveProperty('count');
      expect(data).toHaveProperty('data');
      expect(Array.isArray(data.data)).toBe(true);

      // Check for some common system objects
      const objectIds = data.data.map((obj: any) => obj.object_type);
      expect(objectIds).toContain('Basket');
      expect(objectIds).toContain('CustomObject');
    });

    test('should serve site preferences', async () => {
      if (!await serverManager.isServerAvailable()) {
        console.warn('⚠️  Skipping test - SFCC mock server not available');
        return;
      }

      // First get OAuth token
      const tokenResponse = await fetch(serverManager.getOAuthUrl(), {
        method: 'POST',
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded',
          'Authorization': 'Basic dGVzdC1jbGllbnQtaWQ6dGVzdC1jbGllbnQtc2VjcmV0',
        },
        body: 'grant_type=client_credentials',
      });

      const tokenData = await tokenResponse.json();
      const accessToken = tokenData.access_token;

      // Test site preferences search endpoint
      const searchBody = {
        query: {
          match_all_query: {},
        },
        select: '(**)',
        count: 200,
      };

      const response = await fetch(`${serverManager.getOCAPIUrl()}/site_preferences/preference_groups/CCV/sandbox/preference_search`, {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${accessToken}`,
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(searchBody),
      });

      expect(response.status).toBe(200);

      const data = await response.json();
      expect(data).toHaveProperty('count');
      expect(data).toHaveProperty('hits');
      expect(Array.isArray(data.hits)).toBe(true);
    });

    test('should handle invalid OAuth requests', async () => {
      if (!await serverManager.isServerAvailable()) {
        console.warn('⚠️  Skipping test - SFCC mock server not available');
        return;
      }

      const response = await fetch(serverManager.getOAuthUrl(), {
        method: 'POST',
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded',
          'Authorization': 'Basic invalid_credentials',
        },
        body: 'grant_type=client_credentials',
      });

      expect(response.status).toBe(401);
    });

    test('should handle unauthorized OCAPI requests', async () => {
      if (!await serverManager.isServerAvailable()) {
        console.warn('⚠️  Skipping test - SFCC mock server not available');
        return;
      }

      const response = await fetch(`${serverManager.getOCAPIUrl()}/system_object_definitions`, {
        headers: {
          'Content-Type': 'application/json',
        },
      });

      expect(response.status).toBe(401);
    });
  });

  describe('CORS and Cross-Origin Support', () => {
    test('should include CORS headers', async () => {
      if (!await serverManager.isServerAvailable()) {
        console.warn('⚠️  Skipping test - SFCC mock server not available');
        return;
      }

      const response = await fetch(serverManager.getServerUrl(), {
        method: 'OPTIONS',
      });

      expect(response.headers.get('Access-Control-Allow-Origin')).toBe('*');
      expect(response.headers.get('Access-Control-Allow-Methods')).toContain('GET');
      expect(response.headers.get('Access-Control-Allow-Methods')).toContain('POST');
      expect(response.headers.get('Access-Control-Allow-Methods')).toContain('PROPFIND');
    });
  });
});

/**
 * Example of how to use withSFCCMockServer utility
 */
describe('SFCC Mock Server Utility Function', () => {
  test('should work with utility function', async () => {
    const manager = new SFCCMockServerManager();
    const isAvailable = await manager.isServerAvailable();
    if (!isAvailable) {
      console.warn('⚠️  Skipping test - SFCC mock server not available');
      return;
    }

    const result = await withSFCCMockServer(
      async (serverUrl, webdavLogsUrl, directLogsUrl, ocapiUrl, oauthUrl) => {
        expect(serverUrl).toContain('http://localhost:');
        expect(webdavLogsUrl).toContain('/on/demandware.servlet/webdav/Sites/Logs/');
        expect(directLogsUrl).toContain('/Logs/');
        expect(ocapiUrl).toContain('/s/-/dw/data');
        expect(oauthUrl).toContain('/dw/oauth2/access_token');

        // Test both WebDAV and OCAPI functionality
        const webdavResponse = await fetch(webdavLogsUrl, {
          method: 'PROPFIND',
          headers: { 'Depth': '1' },
        });

        const oauthResponse = await fetch(oauthUrl, {
          method: 'POST',
          headers: {
            'Content-Type': 'application/x-www-form-urlencoded',
            'Authorization': 'Basic dGVzdC1jbGllbnQtaWQ6dGVzdC1jbGllbnQtc2VjcmV0',
          },
          body: 'grant_type=client_credentials',
        });

        return {
          webdavStatus: webdavResponse.status,
          oauthStatus: oauthResponse.status,
        };
      },
      { port: 3005 },
    );

    expect(result.webdavStatus).toBe(207); // WebDAV Multi-Status
    expect(result.oauthStatus).toBe(200); // OAuth success
  }, 25000); // 25 second timeout for utility test
});

```

--------------------------------------------------------------------------------
/tests/mcp/yaml/get-sfra-documents-by-category.full-mode.test.mcp.yml:
--------------------------------------------------------------------------------

```yaml
# ==================================================================================
# SFCC MCP Server - get_sfra_documents_by_category Tool YAML Tests (full-mode mode)
# Tests SFRA document category filtering functionality with comprehensive validation
# 
# Tool: get_sfra_documents_by_category
# Purpose: Get SFRA documents filtered by category (core, product, order, customer, pricing, store, other)
# Parameters: category (required) - Category to filter by
# 
# Quick Test Commands:
# aegis "tests/mcp/yaml/get-sfra-documents-by-category.full-mode.test.mcp.yml" --config "aegis.config.with-dw.json" --verbose
# aegis "tests/mcp/yaml/get-sfra-documents-by-category.full-mode.test.mcp.yml" --config "aegis.config.with-dw.json" --debug --timing
# aegis query get_sfra_documents_by_category '{"category": "core"}' --config "aegis.config.with-dw.json"
# ==================================================================================
description: "SFCC MCP Server - get_sfra_documents_by_category tool comprehensive tests"

# ==================================================================================
# SUCCESSFUL OPERATIONS - VALID CATEGORIES
# ==================================================================================
tests:
  - it: "should retrieve core SFRA documents with proper structure"
    request:
      jsonrpc: "2.0"
      id: "core-docs-1"
      method: "tools/call"
      params:
        name: "get_sfra_documents_by_category"
        arguments:
          category: "core"
    expect:
      response:
        jsonrpc: "2.0"
        id: "core-docs-1"
        result:
          content:
            - type: "text"
              text: "match:regex:\\[\\s*\\{[\\s\\S]*\\}\\s*\\]"  # Valid JSON array structure
          isError: false
      performance:
        maxResponseTime: "500ms"
      stderr: "toBeEmpty"

  - it: "should return valid JSON array for core category"
    request:
      jsonrpc: "2.0"
      id: "core-json-1"
      method: "tools/call"
      params:
        name: "get_sfra_documents_by_category"
        arguments:
          category: "core"
    expect:
      response:
        jsonrpc: "2.0"
        id: "core-json-1"
        result:
          content:
            - type: "text"
              text: "match:contains:server"  # Core category should contain server document
          isError: false
      stderr: "toBeEmpty"

  - it: "should include required document fields for core category"
    request:
      jsonrpc: "2.0"
      id: "core-fields-1"
      method: "tools/call"
      params:
        name: "get_sfra_documents_by_category"
        arguments:
          category: "core"
    expect:
      response:
        jsonrpc: "2.0"
        id: "core-fields-1"
        result:
          content:
            - type: "text"
              text: "match:regex:[\\s\\S]*name[\\s\\S]*title[\\s\\S]*description[\\s\\S]*type[\\s\\S]*category[\\s\\S]*filename"
          isError: false
      stderr: "toBeEmpty"

  - it: "should contain expected core documents"
    request:
      jsonrpc: "2.0"
      id: "core-content-1"
      method: "tools/call"
      params:
        name: "get_sfra_documents_by_category"
        arguments:
          category: "core"
    expect:
      response:
        jsonrpc: "2.0"
        id: "core-content-1"
        result:
          content:
            - type: "text"
              text: "match:regex:[\\s\\S]*querystring[\\s\\S]*render[\\s\\S]*request[\\s\\S]*response[\\s\\S]*server"  # Core SFRA classes in alphabetical order
          isError: false
      stderr: "toBeEmpty"

  - it: "should retrieve product SFRA documents with proper structure"
    request:
      jsonrpc: "2.0"
      id: "product-docs-1"
      method: "tools/call"
      params:
        name: "get_sfra_documents_by_category"
        arguments:
          category: "product"
    expect:
      response:
        jsonrpc: "2.0"
        id: "product-docs-1"
        result:
          content:
            - type: "text"
              text: "match:regex:\\[\\s*\\{[\\s\\S]*\\}\\s*\\]"  # Valid JSON array structure
          isError: false
      performance:
        maxResponseTime: "500ms"
      stderr: "toBeEmpty"

  - it: "should contain product model documents"
    request:
      jsonrpc: "2.0"
      id: "product-content-1"
      method: "tools/call"
      params:
        name: "get_sfra_documents_by_category"
        arguments:
          category: "product"
    expect:
      response:
        jsonrpc: "2.0"
        id: "product-content-1"
        result:
          content:
            - type: "text"
              text: "match:regex:[\\s\\S]*product-full[\\s\\S]*product-tile"  # Product models
          isError: false
      stderr: "toBeEmpty"

  - it: "should retrieve order category documents"
    request:
      jsonrpc: "2.0"
      id: "order-docs-1"
      method: "tools/call"
      params:
        name: "get_sfra_documents_by_category"
        arguments:
          category: "order"
    expect:
      response:
        jsonrpc: "2.0"
        id: "order-docs-1"
        result:
          content:
            - type: "text"
              text: "match:regex:\\[[\\s\\S]*\\]"  # Valid JSON array (may be empty)
          isError: false
      stderr: "toBeEmpty"

  - it: "should retrieve customer category documents"
    request:
      jsonrpc: "2.0"
      id: "customer-docs-1"
      method: "tools/call"
      params:
        name: "get_sfra_documents_by_category"
        arguments:
          category: "customer"
    expect:
      response:
        jsonrpc: "2.0"
        id: "customer-docs-1"
        result:
          content:
            - type: "text"
              text: "match:regex:\\[[\\s\\S]*\\]"  # Valid JSON array
          isError: false
      stderr: "toBeEmpty"

  - it: "should retrieve pricing category documents"
    request:
      jsonrpc: "2.0"
      id: "pricing-docs-1"
      method: "tools/call"
      params:
        name: "get_sfra_documents_by_category"
        arguments:
          category: "pricing"
    expect:
      response:
        jsonrpc: "2.0"
        id: "pricing-docs-1"
        result:
          content:
            - type: "text"
              text: "match:regex:\\[[\\s\\S]*\\]"  # Valid JSON array
          isError: false
      stderr: "toBeEmpty"

  - it: "should retrieve store category documents"
    request:
      jsonrpc: "2.0"
      id: "store-docs-1"
      method: "tools/call"
      params:
        name: "get_sfra_documents_by_category"
        arguments:
          category: "store"
    expect:
      response:
        jsonrpc: "2.0"
        id: "store-docs-1"
        result:
          content:
            - type: "text"
              text: "match:regex:\\[[\\s\\S]*\\]"  # Valid JSON array
          isError: false
      stderr: "toBeEmpty"

  - it: "should retrieve other category documents"
    request:
      jsonrpc: "2.0"
      id: "other-docs-1"
      method: "tools/call"
      params:
        name: "get_sfra_documents_by_category"
        arguments:
          category: "other"
    expect:
      response:
        jsonrpc: "2.0"
        id: "other-docs-1"
        result:
          content:
            - type: "text"
              text: "match:regex:\\[[\\s\\S]*\\]"  # Valid JSON array
          isError: false
      stderr: "toBeEmpty"

# ==================================================================================
# EDGE CASES - INVALID/EMPTY CATEGORIES
# ==================================================================================

  - it: "should handle invalid category gracefully"
    request:
      jsonrpc: "2.0"
      id: "invalid-category-1"
      method: "tools/call"
      params:
        name: "get_sfra_documents_by_category"
        arguments:
          category: "invalid_category_xyz"
    expect:
      response:
        jsonrpc: "2.0"
        id: "invalid-category-1"
        result:
          content:
            - type: "text"
              text: "match:regex:^\\[\\s*\\]$"  # Empty array for invalid category
          isError: false
      stderr: "toBeEmpty"

  - it: "should handle empty category gracefully"
    request:
      jsonrpc: "2.0"
      id: "empty-category-1"
      method: "tools/call"
      params:
        name: "get_sfra_documents_by_category"
        arguments:
          category: ""
    expect:
      response:
        jsonrpc: "2.0"
        id: "empty-category-1"
        result:
          content:
            - type: "text"
              text: "match:contains:Error"
          isError: true
      stderr: "toBeEmpty"

# ==================================================================================
# ERROR HANDLING - MISSING PARAMETERS
# ==================================================================================

  - it: "should require category parameter"
    request:
      jsonrpc: "2.0"
      id: "missing-category-1"
      method: "tools/call"
      params:
        name: "get_sfra_documents_by_category"
        arguments: {}
    expect:
      response:
        jsonrpc: "2.0"
        id: "missing-category-1"
        result:
          content:
            - type: "text"
              text: "match:contains:category must be a non-empty string"
          isError: true
      stderr: "toBeEmpty"

  - it: "should handle null category parameter"
    request:
      jsonrpc: "2.0"
      id: "null-category-1"
      method: "tools/call"
      params:
        name: "get_sfra_documents_by_category"
        arguments:
          category: null
    expect:
      response:
        jsonrpc: "2.0"
        id: "null-category-1"
        result:
          content:
            - type: "text"
              text: "match:contains:Error"
          isError: true
      stderr: "toBeEmpty"

# ==================================================================================
# DATA VALIDATION - CONTENT STRUCTURE
# ==================================================================================

  - it: "should return documents with valid category field in core"
    request:
      jsonrpc: "2.0"
      id: "category-field-1"
      method: "tools/call"
      params:
        name: "get_sfra_documents_by_category"
        arguments:
          category: "core"
    expect:
      response:
        jsonrpc: "2.0"
        id: "category-field-1"
        result:
          content:
            - type: "text"
              text: "match:regex:[\\s\\S]*category[\\s\\S]*:[\\s\\S]*core"  # Category field should match request
          isError: false
      stderr: "toBeEmpty"

  - it: "should return documents with type field in product category"
    request:
      jsonrpc: "2.0"
      id: "type-field-1"
      method: "tools/call"
      params:
        name: "get_sfra_documents_by_category"
        arguments:
          category: "product"
    expect:
      response:
        jsonrpc: "2.0"
        id: "type-field-1"
        result:
          content:
            - type: "text"
              text: "match:regex:[\\s\\S]*type[\\s\\S]*:[\\s\\S]*(model|class|module)"  # Valid type values
          isError: false
      stderr: "toBeEmpty"

  - it: "should return documents with filename field"
    request:
      jsonrpc: "2.0"
      id: "filename-field-1"
      method: "tools/call"
      params:
        name: "get_sfra_documents_by_category"
        arguments:
          category: "core"
    expect:
      response:
        jsonrpc: "2.0"
        id: "filename-field-1"
        result:
          content:
            - type: "text"
              text: "match:regex:[\\s\\S]*filename[\\s\\S]*:[\\s\\S]*\\.md"  # Markdown filename
          isError: false
      stderr: "toBeEmpty"

# ==================================================================================
# PERFORMANCE VALIDATION
# ==================================================================================

  - it: "should respond quickly for core category lookup"
    request:
      jsonrpc: "2.0"
      id: "perf-core-1"
      method: "tools/call"
      params:
        name: "get_sfra_documents_by_category"
        arguments:
          category: "core"
    expect:
      response:
        jsonrpc: "2.0"
        id: "perf-core-1"
        result:
          content:
            - type: "text"
              text: "match:type:string"
          isError: false
      performance:
        maxResponseTime: "300ms"  # Fast metadata operation
      stderr: "toBeEmpty"

  - it: "should respond quickly for product category lookup"
    request:
      jsonrpc: "2.0"
      id: "perf-product-1"
      method: "tools/call"
      params:
        name: "get_sfra_documents_by_category"
        arguments:
          category: "product"
    expect:
      response:
        jsonrpc: "2.0"
        id: "perf-product-1"
        result:
          content:
            - type: "text"
              text: "match:type:string"
          isError: false
      performance:
        maxResponseTime: "300ms"  # Fast metadata operation
      stderr: "toBeEmpty"

  - it: "should handle error cases quickly"
    request:
      jsonrpc: "2.0"
      id: "perf-error-1"
      method: "tools/call"
      params:
        name: "get_sfra_documents_by_category"
        arguments:
          category: ""
    expect:
      response:
        jsonrpc: "2.0"
        id: "perf-error-1"
        result:
          content:
            - type: "text"
              text: "match:contains:Error"
          isError: true
      performance:
        maxResponseTime: "200ms"  # Error handling should be very fast
      stderr: "toBeEmpty"

# ==================================================================================
# CASE SENSITIVITY TESTING
# ==================================================================================

  - it: "should handle uppercase category names"
    request:
      jsonrpc: "2.0"
      id: "case-upper-1"
      method: "tools/call"
      params:
        name: "get_sfra_documents_by_category"
        arguments:
          category: "CORE"
    expect:
      response:
        jsonrpc: "2.0"
        id: "case-upper-1"
        result:
          content:
            - type: "text"
              text: "match:regex:^\\[\\s*\\]$"  # Expect empty array for case mismatch
          isError: false
      stderr: "toBeEmpty"

  - it: "should handle mixed case category names"
    request:
      jsonrpc: "2.0"
      id: "case-mixed-1"
      method: "tools/call"
      params:
        name: "get_sfra_documents_by_category"
        arguments:
          category: "Core"
    expect:
      response:
        jsonrpc: "2.0"
        id: "case-mixed-1"
        result:
          content:
            - type: "text"
              text: "match:regex:^\\[\\s*\\]$"  # Expect empty array for case mismatch
          isError: false
      stderr: "toBeEmpty"

```

--------------------------------------------------------------------------------
/tests/mcp/yaml/get-sfra-documents-by-category.docs-only.test.mcp.yml:
--------------------------------------------------------------------------------

```yaml
# ==================================================================================
# SFCC MCP Server - get_sfra_documents_by_category Tool YAML Tests (docs-only mode)
# Tests SFRA document category filtering functionality with comprehensive validation
# 
# Tool: get_sfra_documents_by_category
# Purpose: Get SFRA documents filtered by category (core, product, order, customer, pricing, store, other)
# Parameters: category (required) - Category to filter by
# 
# Quick Test Commands:
# aegis "tests/mcp/yaml/get-sfra-documents-by-category.docs-only.test.mcp.yml" --config "aegis.config.docs-only.json" --verbose
# aegis "tests/mcp/yaml/get-sfra-documents-by-category.docs-only.test.mcp.yml" --config "aegis.config.docs-only.json" --debug --timing
# aegis query get_sfra_documents_by_category '{"category": "core"}' --config "aegis.config.docs-only.json"
# ==================================================================================
description: "SFCC MCP Server - get_sfra_documents_by_category tool comprehensive tests"

# ==================================================================================
# SUCCESSFUL OPERATIONS - VALID CATEGORIES
# ==================================================================================
tests:
  - it: "should retrieve core SFRA documents with proper structure"
    request:
      jsonrpc: "2.0"
      id: "core-docs-1"
      method: "tools/call"
      params:
        name: "get_sfra_documents_by_category"
        arguments:
          category: "core"
    expect:
      response:
        jsonrpc: "2.0"
        id: "core-docs-1"
        result:
          content:
            - type: "text"
              text: "match:regex:\\[\\s*\\{[\\s\\S]*\\}\\s*\\]"  # Valid JSON array structure
          isError: false
      performance:
        maxResponseTime: "500ms"
      stderr: "toBeEmpty"

  - it: "should return valid JSON array for core category"
    request:
      jsonrpc: "2.0"
      id: "core-json-1"
      method: "tools/call"
      params:
        name: "get_sfra_documents_by_category"
        arguments:
          category: "core"
    expect:
      response:
        jsonrpc: "2.0"
        id: "core-json-1"
        result:
          content:
            - type: "text"
              text: "match:contains:server"  # Core category should contain server document
          isError: false
      stderr: "toBeEmpty"

  - it: "should include required document fields for core category"
    request:
      jsonrpc: "2.0"
      id: "core-fields-1"
      method: "tools/call"
      params:
        name: "get_sfra_documents_by_category"
        arguments:
          category: "core"
    expect:
      response:
        jsonrpc: "2.0"
        id: "core-fields-1"
        result:
          content:
            - type: "text"
              text: "match:regex:[\\s\\S]*name[\\s\\S]*title[\\s\\S]*description[\\s\\S]*type[\\s\\S]*category[\\s\\S]*filename"
          isError: false
      stderr: "toBeEmpty"

  - it: "should contain expected core documents"
    request:
      jsonrpc: "2.0"
      id: "core-content-1"
      method: "tools/call"
      params:
        name: "get_sfra_documents_by_category"
        arguments:
          category: "core"
    expect:
      response:
        jsonrpc: "2.0"
        id: "core-content-1"
        result:
          content:
            - type: "text"
              text: "match:regex:[\\s\\S]*querystring[\\s\\S]*render[\\s\\S]*request[\\s\\S]*response[\\s\\S]*server"  # Core SFRA classes in alphabetical order
          isError: false
      stderr: "toBeEmpty"

  - it: "should retrieve product SFRA documents with proper structure"
    request:
      jsonrpc: "2.0"
      id: "product-docs-1"
      method: "tools/call"
      params:
        name: "get_sfra_documents_by_category"
        arguments:
          category: "product"
    expect:
      response:
        jsonrpc: "2.0"
        id: "product-docs-1"
        result:
          content:
            - type: "text"
              text: "match:regex:\\[\\s*\\{[\\s\\S]*\\}\\s*\\]"  # Valid JSON array structure
          isError: false
      performance:
        maxResponseTime: "500ms"
      stderr: "toBeEmpty"

  - it: "should contain product model documents"
    request:
      jsonrpc: "2.0"
      id: "product-content-1"
      method: "tools/call"
      params:
        name: "get_sfra_documents_by_category"
        arguments:
          category: "product"
    expect:
      response:
        jsonrpc: "2.0"
        id: "product-content-1"
        result:
          content:
            - type: "text"
              text: "match:regex:[\\s\\S]*product-full[\\s\\S]*product-tile"  # Product models
          isError: false
      stderr: "toBeEmpty"

  - it: "should retrieve order category documents"
    request:
      jsonrpc: "2.0"
      id: "order-docs-1"
      method: "tools/call"
      params:
        name: "get_sfra_documents_by_category"
        arguments:
          category: "order"
    expect:
      response:
        jsonrpc: "2.0"
        id: "order-docs-1"
        result:
          content:
            - type: "text"
              text: "match:regex:\\[[\\s\\S]*\\]"  # Valid JSON array (may be empty)
          isError: false
      stderr: "toBeEmpty"

  - it: "should retrieve customer category documents"
    request:
      jsonrpc: "2.0"
      id: "customer-docs-1"
      method: "tools/call"
      params:
        name: "get_sfra_documents_by_category"
        arguments:
          category: "customer"
    expect:
      response:
        jsonrpc: "2.0"
        id: "customer-docs-1"
        result:
          content:
            - type: "text"
              text: "match:regex:\\[[\\s\\S]*\\]"  # Valid JSON array
          isError: false
      stderr: "toBeEmpty"

  - it: "should retrieve pricing category documents"
    request:
      jsonrpc: "2.0"
      id: "pricing-docs-1"
      method: "tools/call"
      params:
        name: "get_sfra_documents_by_category"
        arguments:
          category: "pricing"
    expect:
      response:
        jsonrpc: "2.0"
        id: "pricing-docs-1"
        result:
          content:
            - type: "text"
              text: "match:regex:\\[[\\s\\S]*\\]"  # Valid JSON array
          isError: false
      stderr: "toBeEmpty"

  - it: "should retrieve store category documents"
    request:
      jsonrpc: "2.0"
      id: "store-docs-1"
      method: "tools/call"
      params:
        name: "get_sfra_documents_by_category"
        arguments:
          category: "store"
    expect:
      response:
        jsonrpc: "2.0"
        id: "store-docs-1"
        result:
          content:
            - type: "text"
              text: "match:regex:\\[[\\s\\S]*\\]"  # Valid JSON array
          isError: false
      stderr: "toBeEmpty"

  - it: "should retrieve other category documents"
    request:
      jsonrpc: "2.0"
      id: "other-docs-1"
      method: "tools/call"
      params:
        name: "get_sfra_documents_by_category"
        arguments:
          category: "other"
    expect:
      response:
        jsonrpc: "2.0"
        id: "other-docs-1"
        result:
          content:
            - type: "text"
              text: "match:regex:\\[[\\s\\S]*\\]"  # Valid JSON array
          isError: false
      stderr: "toBeEmpty"

# ==================================================================================
# EDGE CASES - INVALID/EMPTY CATEGORIES
# ==================================================================================

  - it: "should handle invalid category gracefully"
    request:
      jsonrpc: "2.0"
      id: "invalid-category-1"
      method: "tools/call"
      params:
        name: "get_sfra_documents_by_category"
        arguments:
          category: "invalid_category_xyz"
    expect:
      response:
        jsonrpc: "2.0"
        id: "invalid-category-1"
        result:
          content:
            - type: "text"
              text: "match:regex:^\\[\\s*\\]$"  # Empty array for invalid category
          isError: false
      stderr: "toBeEmpty"

  - it: "should handle empty category gracefully"
    request:
      jsonrpc: "2.0"
      id: "empty-category-1"
      method: "tools/call"
      params:
        name: "get_sfra_documents_by_category"
        arguments:
          category: ""
    expect:
      response:
        jsonrpc: "2.0"
        id: "empty-category-1"
        result:
          content:
            - type: "text"
              text: "match:contains:Error"
          isError: true
      stderr: "toBeEmpty"

# ==================================================================================
# ERROR HANDLING - MISSING PARAMETERS
# ==================================================================================

  - it: "should require category parameter"
    request:
      jsonrpc: "2.0"
      id: "missing-category-1"
      method: "tools/call"
      params:
        name: "get_sfra_documents_by_category"
        arguments: {}
    expect:
      response:
        jsonrpc: "2.0"
        id: "missing-category-1"
        result:
          content:
            - type: "text"
              text: "match:contains:category must be a non-empty string"
          isError: true
      stderr: "toBeEmpty"

  - it: "should handle null category parameter"
    request:
      jsonrpc: "2.0"
      id: "null-category-1"
      method: "tools/call"
      params:
        name: "get_sfra_documents_by_category"
        arguments:
          category: null
    expect:
      response:
        jsonrpc: "2.0"
        id: "null-category-1"
        result:
          content:
            - type: "text"
              text: "match:contains:Error"
          isError: true
      stderr: "toBeEmpty"

# ==================================================================================
# DATA VALIDATION - CONTENT STRUCTURE
# ==================================================================================

  - it: "should return documents with valid category field in core"
    request:
      jsonrpc: "2.0"
      id: "category-field-1"
      method: "tools/call"
      params:
        name: "get_sfra_documents_by_category"
        arguments:
          category: "core"
    expect:
      response:
        jsonrpc: "2.0"
        id: "category-field-1"
        result:
          content:
            - type: "text"
              text: "match:regex:[\\s\\S]*category[\\s\\S]*:[\\s\\S]*core"  # Category field should match request
          isError: false
      stderr: "toBeEmpty"

  - it: "should return documents with type field in product category"
    request:
      jsonrpc: "2.0"
      id: "type-field-1"
      method: "tools/call"
      params:
        name: "get_sfra_documents_by_category"
        arguments:
          category: "product"
    expect:
      response:
        jsonrpc: "2.0"
        id: "type-field-1"
        result:
          content:
            - type: "text"
              text: "match:regex:[\\s\\S]*type[\\s\\S]*:[\\s\\S]*(model|class|module)"  # Valid type values
          isError: false
      stderr: "toBeEmpty"

  - it: "should return documents with filename field"
    request:
      jsonrpc: "2.0"
      id: "filename-field-1"
      method: "tools/call"
      params:
        name: "get_sfra_documents_by_category"
        arguments:
          category: "core"
    expect:
      response:
        jsonrpc: "2.0"
        id: "filename-field-1"
        result:
          content:
            - type: "text"
              text: "match:regex:[\\s\\S]*filename[\\s\\S]*:[\\s\\S]*\\.md"  # Markdown filename
          isError: false
      stderr: "toBeEmpty"

# ==================================================================================
# PERFORMANCE VALIDATION
# ==================================================================================

  - it: "should respond quickly for core category lookup"
    request:
      jsonrpc: "2.0"
      id: "perf-core-1"
      method: "tools/call"
      params:
        name: "get_sfra_documents_by_category"
        arguments:
          category: "core"
    expect:
      response:
        jsonrpc: "2.0"
        id: "perf-core-1"
        result:
          content:
            - type: "text"
              text: "match:type:string"
          isError: false
      performance:
        maxResponseTime: "300ms"  # Fast metadata operation
      stderr: "toBeEmpty"

  - it: "should respond quickly for product category lookup"
    request:
      jsonrpc: "2.0"
      id: "perf-product-1"
      method: "tools/call"
      params:
        name: "get_sfra_documents_by_category"
        arguments:
          category: "product"
    expect:
      response:
        jsonrpc: "2.0"
        id: "perf-product-1"
        result:
          content:
            - type: "text"
              text: "match:type:string"
          isError: false
      performance:
        maxResponseTime: "300ms"  # Fast metadata operation
      stderr: "toBeEmpty"

  - it: "should handle error cases quickly"
    request:
      jsonrpc: "2.0"
      id: "perf-error-1"
      method: "tools/call"
      params:
        name: "get_sfra_documents_by_category"
        arguments:
          category: ""
    expect:
      response:
        jsonrpc: "2.0"
        id: "perf-error-1"
        result:
          content:
            - type: "text"
              text: "match:contains:Error"
          isError: true
      performance:
        maxResponseTime: "200ms"  # Error handling should be very fast
      stderr: "toBeEmpty"

# ==================================================================================
# CASE SENSITIVITY TESTING
# ==================================================================================

  - it: "should handle uppercase category names"
    request:
      jsonrpc: "2.0"
      id: "case-upper-1"
      method: "tools/call"
      params:
        name: "get_sfra_documents_by_category"
        arguments:
          category: "CORE"
    expect:
      response:
        jsonrpc: "2.0"
        id: "case-upper-1"
        result:
          content:
            - type: "text"
              text: "match:regex:^\\[\\s*\\]$"  # Expect empty array for case mismatch
          isError: false
      stderr: "toBeEmpty"

  - it: "should handle mixed case category names"
    request:
      jsonrpc: "2.0"
      id: "case-mixed-1"
      method: "tools/call"
      params:
        name: "get_sfra_documents_by_category"
        arguments:
          category: "Core"
    expect:
      response:
        jsonrpc: "2.0"
        id: "case-mixed-1"
        result:
          content:
            - type: "text"
              text: "match:regex:^\\[\\s*\\]$"  # Expect empty array for case mismatch
          isError: false
      stderr: "toBeEmpty"

```

--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------

```markdown
# Changelog

All notable changes to this project will be documented in this file.

The format loosely follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and versions follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

Release comparison links are provided at the bottom. Earlier patch releases on the same day may represent rapid iterations (e.g. architectural + documentation expansions). Dates are derived from git tag timestamps.

## [1.0.15] - 2025-10-03
### Added
- **SFRA Best Practices Expansion**: 
  - SFRA SCSS best practices guide with theming and override patterns
  - SFRA client-side JavaScript guide covering AJAX flows, validation, and accessibility
- **OCAPI Select Parameter Support**: Comprehensive support for OCAPI select syntax to control response field selection
- **System Object Pagination**: Added pagination support for system object definitions with configurable start/count parameters
- **Chronological Log Sorting**: Enhanced log file sorting by last modification time for accurate recency ordering
- **OCAPI Mock Server**: Complete OCAPI mock server implementation for testing with site preferences and system objects
- **Documentation Site Enhancements**:
  - Vite React SSG migration for improved build performance and SSR capabilities
  - GitHub link integration in sidebar
  - Newcomer CTA component for better onboarding
  - Mobile web app capability with enhanced PWA support
  - Enhanced schema.org metadata for better SEO
- **Performance Best Practices**: Added detailed SCAPI web-tier cache fundamentals, personalized cache keys, and script-level cache controls
- **Custom Endpoint Caching**: Comprehensive caching strategies documentation for custom SCAPI endpoints with two-tier pattern examples

### Changed
- **Testing Framework Migration**: Replaced Conductor with Aegis for MCP testing with improved declarative YAML patterns
- **Documentation Modernization**:
  - Revamped documentation site with improved layout and readability
  - Consolidated agent instructions with enhanced clarity
  - Updated all Aegis usage examples to use `npx` commands
  - Added `-y` flag to npx commands in documentation
- **Code Quality Improvements**:
  - Modularized OCAPI route handling for better maintainability
  - Centralized site date constants
  - Improved code block rendering with LightCodeContainer component
  - Enhanced sidebar header display
- **Node.js Version Updates**: Updated Node.js versions and related documentation
- **URL Structure**: Enforced trailing slashes for routes with consistent URL patterns
- **AI Interface Enhancements**: Improved AI interface and configuration documentation

### Fixed
- **SSR Hydration**: Fixed SSR hydration mismatch in OnThisPage component
- **Hash Navigation**: Resolved hash navigation issues after search operations

### Documentation
- **CSRF Middleware**: Clarified CSRF middleware usage patterns in SFRA
- **Remote Include Architecture**: Added detailed explanation of remote include patterns for dynamic content
- **Aegis Testing**: Comprehensive updates to Aegis testing documentation with best practices
- **Performance Guidance**: Enhanced performance best practices with SCAPI-specific caching strategies

### Testing
- **Comprehensive Test Coverage**:
  - OCAPI error handling and validation tests
  - Site preferences search tool tests
  - System object attribute search tests with complex query support
  - Full mode tests for object definitions and search logs
  - Comprehensive select parameter validation tests
  - MCP tool tests with Aegis framework
- **Test Infrastructure**:
  - OCAPI test server setup integrated into CI/CD pipeline
  - Refactored tests to use centralized SFCC mock server
  - Enhanced test targeting and organization

### Dependencies
- **GitHub Actions Updates**:
  - `actions/checkout` from 4 to 5
  - `actions/configure-pages` from 4 to 5
  - `actions/setup-node` from 4 to 5
  - `actions/upload-pages-artifact` from 3 to 4
  - `codecov/codecov-action` from 5.5.0 to 5.5.1
- **Development Dependencies**:
  - `browserslist` from 4.25.2 to 4.26.2
  - `vite-react-ssg` to v0.8.9
  - Updated ESLint group packages
  - Updated `ts-jest` in Jest group

### Notes
- Major testing infrastructure modernization with Aegis framework adoption
- Significant documentation site improvements with SSG migration and enhanced UX
- Expanded SFRA best practices coverage for complete development lifecycle
- Enhanced OCAPI functionality with select parameter support and comprehensive mocking

## [1.0.14] - 2025-09-16
### Added
- **SFCC Class Information Filtering**: Enhanced `get_sfcc_class_info` tool with comprehensive filtering capabilities including search parameter, inclusion/exclusion of descriptions, constants, properties, methods, and inheritance hierarchy.
- **AI Response Comparison Modals**: Interactive modals on documentation site showing side-by-side comparison of AI responses with and without MCP server, including zoom functionality for detailed inspection.
- **Documentation Site Enhancements**: 
  - Examples page with practical usage scenarios and filtering demonstrations
  - Tools page documenting all available MCP tools
  - Features page highlighting key capabilities
  - Configuration documentation page with setup instructions
  - AI Instruction Files section for different AI platforms
  - LLMs documentation file for AI assistant integration
  - Troubleshooting page for common issues
  - Development and security documentation pages
- **Homepage Value Proposition**: Enhanced homepage with clear value proposition and practical examples.
- **Anchor Link Navigation**: Added IDs to documentation headers for direct linking.

### Changed
- **Project Licensing**: Aligned to MIT License (replaced ISC LICENSE text, updated `package.json` license field).
- **CI/CD Pipeline**: Enhanced with improved linting and security checks.
- **Documentation Structure**: Comprehensive reorganization and expansion of documentation site structure.
- **Code Examples**: Updated with full path references for better clarity.
- **Configuration Examples**: Updated example configurations for better usability.
- **UI/UX Polish**: Improved padding, layout adjustments, and site navigation structure.

### Fixed
- **URL Fragment Handling**: Fixed URL-encoded hash fragment handling in documentation site.
- **Workflow Deployment**: Corrected path issues for page deployment.
- **Log Tool Validation**: Improved argument validation robustness for log analysis tools.

### Documentation
- **AI Interface Setup**: Comprehensive guides for Claude Desktop, Cursor, and GitHub Copilot integration.
- **Security Guidance**: Enhanced security considerations and best practices documentation.
- **Troubleshooting**: Added comprehensive troubleshooting guide for common setup and usage issues.
- **Development Workflow**: Detailed development guidelines and contribution instructions.

### Testing
- **Enhanced Test Coverage**: 
  - Comprehensive programmatic tests for SFCC class info filtering in documentation mode
  - Enhanced YAML-based MCP tests for class information tools
  - Job execution summary tests and job log analysis tests
  - Improved test setup reliability and CI stability

### Notes
- Major documentation site expansion with React/Vite architecture
- Enhanced developer experience with comprehensive filtering and search capabilities
- Improved AI assistant integration with detailed setup guides for multiple platforms

## [1.0.13] - 2025-09-15
### Added
- `engines` field in `package.json` enforcing Node >=18 and npm >=8.
- Comprehensive architectural documentation (handler modularization, capability gating, services layer, log subsystem, tool-configs, caching).
- Initial `CHANGELOG.md` introduction.

### Changed
- Server reported version synchronized with `package.json`.
- Development guide: migrated from legacy Jekyll instructions to Vite workflow; updated tool addition workflow for new handler architecture.

### Fixed
- Removed references to non-existent config files (`config.ts`, `constants.ts`).
- Corrected debug flag examples (`--debug` vs `--debug true`).
- Escaping/format fixes in development guide code blocks.

### Notes
- Pre-1.0.14 license mismatch (ISC vs MIT badge) resolved in 1.0.14.

## [1.0.12] - 2025-08-19
### Added
- Code version management tools (listing & activation) with supporting documentation.
- Cartridge generation enhancements: page layout & styling improvements; prevention of overwriting existing files.
- Security and OCAPI configuration warnings; highlighted AI instruction files.
- Additional SFRA model and best practice documentation (ISML decorators, LocalServiceRegistry, Auth examples, BM configuration guide).

### Changed
- ESLint configuration (global vars, lint fix script), table styling, documentation site theme updates, repository URL in config, branch protection for deploy (restricted to main), improved instance type check.
- Documentation structure reorganized (multiple passes consolidating guides, theme adjustments, layout evolution and subsequent refinements / reverts).

### Fixed
- Removal of `resourceState` from activateCodeVersion request.

### Documentation
- Large expansion of SFRA models, cartridge creation, ISML templates, decorators warnings, URL patterns, customer context, authentication flows, endpoint security guidance.

### Notes
- Multiple rapid doc iterations (additions, reverts, restyles) before stabilization.

## [1.0.11] - 2025-08-15
### Added
- SFCC development rules and SFRA controllers best practices guide.
- AI interface instruction documentation.

### Changed
- Refactored rule configurations; enhanced SFCC debugging workflows; streamlined documentation tools; removed improvement roadmap.

### Fixed
- Log files now sorted by last modification for accurate recency ordering.

### Testing
- Enhanced log client test coverage.

### Notes
- Documentation emphasis on rule context explanation and operational clarity.

## [1.0.10] - 2025-08-15
### Added
- Custom object attribute search capability.
- Progressive development guide (subsequently refined) and job framework best practices.
- Additional documentation: steptypes configuration, ISML templates, SCAPI custom endpoint guide, path parameter & search query usage clarifications, SFRA documentation support expansion.

### Changed
- Auth examples refactored into appendix; logging improvements and build output cleanliness.

### Fixed
- Reversal / clarification cycles for job framework status codes and default values (cleanup of earlier docs ambiguities).

### Notes
- Foundation for expanded SCAPI / SFRA documentation just before rapid rule & controller additions in 1.0.11.

## [1.0.9-2] - 2025-08-13
### Changed
- Enhanced release workflow (iteration on same-day release of 1.0.9).

## [1.0.9] - 2025-08-13
### Added
- Initial modular handler & directory architecture groundwork: secure config loading, debug log support, documentation-only mode, system object exposure, site preferences & attribute search, OCAPI client integration.
- CI workflow, caching layer for documentation, expanded class details, path resolver, pre-commit hooks, NPM publishing & Dependabot configuration, issue templates.

### Changed
- Large-scale codebase reorganization (directory structure, authentication & logging refactors, configuration loading improvements, handler refactors, OAuth token management relocation, package metadata updates, JSON serialization, system object description refinements, server architecture refactor).
- Log tool naming alignment & tool description clarity improvements.

### Fixed
- File path security validation enhancements.

### Documentation
- Extensive expansion: best practices (security, performance, cartridge creation), contributing guidelines, search tool description, quick setup, system object definitions, Copilot instructions, local dev focus clarification.

### Testing
- Added Jest framework and early test coverage (config factory, OAuth token manager, log client, attribute definitions, best practices client).

### Notes
- Represents the foundational public baseline preceding rapid feature layering in 1.0.10+.

## [1.0.8] - 2025-08-13
### Changed
- Package version alignment & metadata updates; project structure and documentation improvements; Node version CI expansions.

### Added
- Security & performance best practices guides, contributing guidelines, AI assistant integration guide, deprecation support, attribute definition search, site preferences search.

### Notes
- Last pre-architecture refactor baseline before major handler and structural reorganization in 1.0.9.

## [1.0.2] - 2025-08-08
### Added
- Debug logging capabilities, caching for documentation, expanded class details, initial SFCC MCP server feature set (system object & attribute tools, OCAPI integration, documentation retrieval).
- Jest testing framework & initial unit tests.

### Changed
- Centralized logging infrastructure; configuration logging & security tightening; authentication config refactors.

### Documentation
- Cartridge creation guide, npx usage instructions, API docs, system object definitions resource.

### Notes
- Early stabilization phase; intermediate patch releases between 1.0.2 and 1.0.8 consolidated here (internal iteration without tags not reconstructed individually).

## [1.0.0] - 2025-08-08
### Added
- Initial commit introducing SFCC Dev MCP Server core (base server, tooling scaffolding, initial documentation framework).

### Notes
- Foundation commit history includes scaffolding, early capability extensions, and initial architectural decisions.

---

---

### Future
- Add automation for changelog validation in CI (ensure categories & links present).
- Add script to generate comparison links automatically when tagging.
- Potential provenance notes for security-impacting changes (e.g., file path validation hardening).

---

### Comparison Links
[1.0.15]: https://github.com/taurgis/sfcc-dev-mcp/compare/v1.0.14...v1.0.15
[1.0.14]: https://github.com/taurgis/sfcc-dev-mcp/compare/v1.0.13...v1.0.14
[1.0.13]: https://github.com/taurgis/sfcc-dev-mcp/compare/v1.0.12...v1.0.13
[1.0.12]: https://github.com/taurgis/sfcc-dev-mcp/compare/v1.0.11...v1.0.12
[1.0.11]: https://github.com/taurgis/sfcc-dev-mcp/compare/v1.0.10...v1.0.11
[1.0.10]: https://github.com/taurgis/sfcc-dev-mcp/compare/v1.0.9-2...v1.0.10
[1.0.9-2]: https://github.com/taurgis/sfcc-dev-mcp/compare/v1.0.9...v1.0.9-2
[1.0.9]: https://github.com/taurgis/sfcc-dev-mcp/compare/v1.0.8...v1.0.9
[1.0.8]: https://github.com/taurgis/sfcc-dev-mcp/compare/v1.0.2...v1.0.8
[1.0.2]: https://github.com/taurgis/sfcc-dev-mcp/compare/v1.0.0...v1.0.2
[1.0.0]: https://github.com/taurgis/sfcc-dev-mcp/tree/v1.0.0


```

--------------------------------------------------------------------------------
/docs/dw_order/LineItem.md:
--------------------------------------------------------------------------------

```markdown
## Package: dw.order

# Class LineItem

## Inheritance Hierarchy

- Object
  - dw.object.PersistentObject
  - dw.object.ExtensibleObject
    - dw.order.LineItem

## Description

Common line item base class.

## Properties

### basePrice

**Type:** Money

The base price for the line item, which is the price of the unit before applying adjustments, in the
 purchase currency. The base price may be net or gross of tax depending on the configured taxation policy.

### grossPrice

**Type:** Money

The gross price for the line item, which is the price of the unit before applying adjustments, in the
 purchase currency, including tax.

### lineItemCtnr

**Type:** LineItemCtnr (Read Only)

The line item ctnr of the line item.

### lineItemText

**Type:** String

The display text for the line item.

### netPrice

**Type:** Money

The net price for the line item, which is the price of the unit before applying adjustments, in the
 purchase currency, excluding tax.

### price

**Type:** Money (Read Only)

Get the price of the line item. If the line item is based on net pricing then the net price is returned. If the
 line item is based on gross pricing then the gross price is returned.

### priceValue

**Type:** Number

Return the price amount for the line item. Same as getPrice().getValue().

### tax

**Type:** Money

The tax for the line item, which is the tax of the unit before applying adjustments, in the purchase
 currency.

### taxBasis

**Type:** Money (Read Only)

Get the price used to calculate the tax for this line item.

### taxClassID

**Type:** String

The tax class ID for the line item or null if no tax class ID is associated with the line item. In the
 case where the tax class ID is null, you should use the default tax class ID.

### taxRate

**Type:** Number

The tax rate, which is the decimal tax rate to be applied to the product represented by this line item. A
 value of 0.175 represents a percentage of 17.5%.

## Constructor Summary

## Method Summary

### getBasePrice

**Signature:** `getBasePrice() : Money`

Returns the base price for the line item, which is the price of the unit before applying adjustments, in the purchase currency.

### getGrossPrice

**Signature:** `getGrossPrice() : Money`

Returns the gross price for the line item, which is the price of the unit before applying adjustments, in the purchase currency, including tax.

### getLineItemCtnr

**Signature:** `getLineItemCtnr() : LineItemCtnr`

Returns the line item ctnr of the line item.

### getLineItemText

**Signature:** `getLineItemText() : String`

Returns the display text for the line item.

### getNetPrice

**Signature:** `getNetPrice() : Money`

Returns the net price for the line item, which is the price of the unit before applying adjustments, in the purchase currency, excluding tax.

### getPrice

**Signature:** `getPrice() : Money`

Get the price of the line item.

### getPriceValue

**Signature:** `getPriceValue() : Number`

Return the price amount for the line item.

### getTax

**Signature:** `getTax() : Money`

Returns the tax for the line item, which is the tax of the unit before applying adjustments, in the purchase currency.

### getTaxBasis

**Signature:** `getTaxBasis() : Money`

Get the price used to calculate the tax for this line item.

### getTaxClassID

**Signature:** `getTaxClassID() : String`

Returns the tax class ID for the line item or null if no tax class ID is associated with the line item.

### getTaxRate

**Signature:** `getTaxRate() : Number`

Returns the tax rate, which is the decimal tax rate to be applied to the product represented by this line item.

### setBasePrice

**Signature:** `setBasePrice(aValue : Money) : void`

Sets the base price for the line item, which is the price of the unit before applying adjustments, in the purchase currency.

### setGrossPrice

**Signature:** `setGrossPrice(aValue : Money) : void`

Sets the gross price for the line item, which is the Price of the unit before applying adjustments, in the purchase currency, including tax.

### setLineItemText

**Signature:** `setLineItemText(aText : String) : void`

Sets the display text for the line item.

### setNetPrice

**Signature:** `setNetPrice(aValue : Money) : void`

Sets the value for the net price, which is the price of the unit before applying adjustments, in the purchase currency, excluding tax.

### setPriceValue

**Signature:** `setPriceValue(value : Number) : void`

Sets price attributes of the line item based on the current purchase currency and taxation policy.

### setTax

**Signature:** `setTax(aValue : Money) : void`

Sets the value for the tax of the line item, which is the the tax of the unit before applying adjustments, in the purchase currency.

### setTaxClassID

**Signature:** `setTaxClassID(aValue : String) : void`

Sets the tax class ID for the line item.

### setTaxRate

**Signature:** `setTaxRate(taxRate : Number) : void`

Sets the tax rate, which is the decimal tax rate to be applied to the product represented by this line item.

### updatePrice

**Signature:** `updatePrice(price : Money) : void`

Updates the price attributes of the line item based on the specified price.

### updateTax

**Signature:** `updateTax(taxRate : Number) : void`

Updates the tax-related attributes of the line item based on the specified tax rate, a tax basis determined by the system and the "Tax Rounding Mode" order preference.

### updateTax

**Signature:** `updateTax(taxRate : Number, taxBasis : Money) : void`

Updates the tax-related attributes of the line item based on the specified tax rate, the passed tax basis and the "Tax Rounding Mode" order preference.

### updateTaxAmount

**Signature:** `updateTaxAmount(tax : Money) : void`

Updates tax amount of the line item setting the provided value.

## Method Detail

## Method Details

### getBasePrice

**Signature:** `getBasePrice() : Money`

**Description:** Returns the base price for the line item, which is the price of the unit before applying adjustments, in the purchase currency. The base price may be net or gross of tax depending on the configured taxation policy.

**Returns:**

the base price for the line item.

---

### getGrossPrice

**Signature:** `getGrossPrice() : Money`

**Description:** Returns the gross price for the line item, which is the price of the unit before applying adjustments, in the purchase currency, including tax.

**Returns:**

the value of the gross price.

---

### getLineItemCtnr

**Signature:** `getLineItemCtnr() : LineItemCtnr`

**Description:** Returns the line item ctnr of the line item.

**Returns:**

Line item ctnr of the line item

---

### getLineItemText

**Signature:** `getLineItemText() : String`

**Description:** Returns the display text for the line item.

**Returns:**

the display text.

---

### getNetPrice

**Signature:** `getNetPrice() : Money`

**Description:** Returns the net price for the line item, which is the price of the unit before applying adjustments, in the purchase currency, excluding tax.

**Returns:**

the value for the net price.

---

### getPrice

**Signature:** `getPrice() : Money`

**Description:** Get the price of the line item. If the line item is based on net pricing then the net price is returned. If the line item is based on gross pricing then the gross price is returned.

**Returns:**

either the net or the gross price

---

### getPriceValue

**Signature:** `getPriceValue() : Number`

**Description:** Return the price amount for the line item. Same as getPrice().getValue().

**Returns:**

the price for the line item

---

### getTax

**Signature:** `getTax() : Money`

**Description:** Returns the tax for the line item, which is the tax of the unit before applying adjustments, in the purchase currency.

**Returns:**

the tax for the line item.

---

### getTaxBasis

**Signature:** `getTaxBasis() : Money`

**Description:** Get the price used to calculate the tax for this line item.

**Returns:**

The tax basis used to calculate tax for this line item, or Money.NOT_AVAILABLE if tax has not been set for this line item yet.

---

### getTaxClassID

**Signature:** `getTaxClassID() : String`

**Description:** Returns the tax class ID for the line item or null if no tax class ID is associated with the line item. In the case where the tax class ID is null, you should use the default tax class ID.

**Returns:**

the tax class ID for the line item or null if no tax class ID is associated with the line item.

**See Also:**

TaxMgr.getDefaultTaxClassID()

---

### getTaxRate

**Signature:** `getTaxRate() : Number`

**Description:** Returns the tax rate, which is the decimal tax rate to be applied to the product represented by this line item. A value of 0.175 represents a percentage of 17.5%.

**Returns:**

the value of the tax rate.

---

### setBasePrice

**Signature:** `setBasePrice(aValue : Money) : void`

**Description:** Sets the base price for the line item, which is the price of the unit before applying adjustments, in the purchase currency. The base price may be net or gross of tax depending on the configured taxation policy.

**Deprecated:**

Use updatePrice(Money) instead.

**Parameters:**

- `aValue`: the new value of the base price.

---

### setGrossPrice

**Signature:** `setGrossPrice(aValue : Money) : void`

**Description:** Sets the gross price for the line item, which is the Price of the unit before applying adjustments, in the purchase currency, including tax.

**Deprecated:**

Use updatePrice(Money) which sets the base price and also the gross price if the line item is based on gross pricing.

**Parameters:**

- `aValue`: the new value of the attribute

---

### setLineItemText

**Signature:** `setLineItemText(aText : String) : void`

**Description:** Sets the display text for the line item.

**Parameters:**

- `aText`: line item text.

---

### setNetPrice

**Signature:** `setNetPrice(aValue : Money) : void`

**Description:** Sets the value for the net price, which is the price of the unit before applying adjustments, in the purchase currency, excluding tax.

**Deprecated:**

Use updatePrice(Money) which sets the base price and also the net price if the line item is based on net pricing.

**Parameters:**

- `aValue`: the new value for the net price

---

### setPriceValue

**Signature:** `setPriceValue(value : Number) : void`

**Description:** Sets price attributes of the line item based on the current purchase currency and taxation policy. The methods sets the 'basePrice' attribute of the line item. Additionally, it sets the 'netPrice' attribute of the line item if the current taxation policy is 'net', and the 'grossPrice' attribute, if the current taxation policy is 'gross'. If null is specified as value, the price attributes are reset to Money.NOT_AVAILABLE.

**Parameters:**

- `value`: Price value or null

---

### setTax

**Signature:** `setTax(aValue : Money) : void`

**Description:** Sets the value for the tax of the line item, which is the the tax of the unit before applying adjustments, in the purchase currency.

**Parameters:**

- `aValue`: the new value for the tax.

---

### setTaxClassID

**Signature:** `setTaxClassID(aValue : String) : void`

**Description:** Sets the tax class ID for the line item.

**Parameters:**

- `aValue`: the tax class ID for the line item.

---

### setTaxRate

**Signature:** `setTaxRate(taxRate : Number) : void`

**Description:** Sets the tax rate, which is the decimal tax rate to be applied to the product represented by this line item. A value of 0.175 represents a percentage of 17.5%.

**Parameters:**

- `taxRate`: the new value for the tax rate.

---

### updatePrice

**Signature:** `updatePrice(price : Money) : void`

**Description:** Updates the price attributes of the line item based on the specified price. The base price is set to the specified value. If the line item is based on net pricing then the net price attribute is set. If the line item is based on gross pricing then the gross price attribute is set. Whether or not a line item is based on net or gross pricing is a site-wide configuration parameter.

**Deprecated:**

Use setPriceValue(Number) instead.

**Parameters:**

- `price`: The price to use when performing the update. This price must not be null and must either be equal to NOT_AVAIALBLE or must have a currency code equal to that of the parent container.

---

### updateTax

**Signature:** `updateTax(taxRate : Number) : void`

**Description:** Updates the tax-related attributes of the line item based on the specified tax rate, a tax basis determined by the system and the "Tax Rounding Mode" order preference. This method sets the tax basis as an attribute, and is not affected by the previous value of this attribute. The value used as a basis depends on the type of line item this is and on the promotion preferences for the current site. If you tax products, shipping, and discounts based on price (default), then the tax basis will simply be equal to getPrice(). If you tax products and shipping only based on adjusted price, then the tax basis depends upon line item type as follows: ProductLineItem: basis equals ProductLineItem.getProratedPrice(). ShippingLineItem: basis equals ShippingLineItem.getAdjustedPrice(). ProductShippingLineItem: basis equals ProductShippingLineItem.getAdjustedPrice(). PriceAdjustment: basis equals 0.00. All other line item types: basis equals getPrice(). If null is passed as tax rate, tax-related attribute fields are set to N/A.

**Parameters:**

- `taxRate`: taxRate the tax rate to use or null.

---

### updateTax

**Signature:** `updateTax(taxRate : Number, taxBasis : Money) : void`

**Description:** Updates the tax-related attributes of the line item based on the specified tax rate, the passed tax basis and the "Tax Rounding Mode" order preference. If null is passed as tax rate or tax basis, tax-related attribute fields are set to N/A.

**Parameters:**

- `taxRate`: the tax rate to use or null.
- `taxBasis`: the tax basis to use or null.

---

### updateTaxAmount

**Signature:** `updateTaxAmount(tax : Money) : void`

**Description:** Updates tax amount of the line item setting the provided value. Depending on the way how the tax is calculated (based on net or gross price), the corresponding gross or net price is updated accordingly. For tax calculation based on net price, the gross price is calculated by adding the tax to the net price. For tax calculation based on gross price, the net price is calculated by subtracting the tax from the gross price. If null is passed as tax amount, the item tax and resulting net or gross price are set to N/A. Note that tax rate is not calculated and it is not updated.

**Parameters:**

- `tax`: the tax amount of the line item to set

---
```

--------------------------------------------------------------------------------
/docs/dw_object/SystemObjectMgr.md:
--------------------------------------------------------------------------------

```markdown
## Package: dw.object

# Class SystemObjectMgr

## Inheritance Hierarchy

- Object
  - dw.object.SystemObjectMgr

## Description

Manager class which provides methods for querying of system objects with meta data using the Commerce Cloud Digital query language. See individual API methods for details on the query language. Note: Other manager classes such as CustomerMgr, ProductMgr, etc provide more specific and fine-grained querying methods that can not be achieved using the general query language. The following system object types are supported: GiftCertificate SourceCodeGroup Store ProductList Support for the following system object types is deprecated: Order Profile Use the search methods from CustomerMgr and OrderMgr, respectively for querying these types. To search for custom objects, use CustomObjectMgr. Note: this class allows access to sensitive information through operations that retrieve the Profile and Order objects. Pay attention to appropriate legal and regulatory requirements related to this data.

## Constructor Summary

## Method Summary

### describe

**Signature:** `static describe(type : String) : ObjectTypeDefinition`

Returns the object type definition for the given system object type.

### getAllSystemObjects

**Signature:** `static getAllSystemObjects(type : String) : SeekableIterator`

Returns all system objects of a specific type.

### querySystemObject

**Signature:** `static querySystemObject(type : String, queryString : String, args : Object...) : PersistentObject`

Searches for a single system object instance.

### querySystemObjects

**Signature:** `static querySystemObjects(type : String, queryString : String, sortString : String, args : Object...) : SeekableIterator`

Searches for system object instances.

### querySystemObjects

**Signature:** `static querySystemObjects(type : String, queryAttributes : Map, sortString : String) : SeekableIterator`

Searches for system object instances.

## Method Detail

## Method Details

### describe

**Signature:** `static describe(type : String) : ObjectTypeDefinition`

**Description:** Returns the object type definition for the given system object type. This method can be used for all system object types that are derived from ExtensibleObject.

**Parameters:**

- `type`: system object type whose type definition should be returned

**Returns:**

the matching object type definition or null in case no such type definition exists.

---

### getAllSystemObjects

**Signature:** `static getAllSystemObjects(type : String) : SeekableIterator`

**Description:** Returns all system objects of a specific type. The following system object types are supported: GiftCertificate Order Profile SourceCodeGroup Store ProductList The method throws an exception in case of another system type. It is strongly recommended to call close() on the returned SeekableIterator if not all of its elements are being retrieved. This will ensure the proper cleanup of system resources.

**Parameters:**

- `type`: The name of the system object type. If a matching type definition cannot be found for the given type a MetaDataException will be thrown.

**Returns:**

SeekableIterator containing all system objects of a specific type.

**See Also:**

SeekableIterator.close()

---

### querySystemObject

**Signature:** `static querySystemObject(type : String, queryString : String, args : Object...) : PersistentObject`

**Description:** Searches for a single system object instance. The following system object types are supported: GiftCertificate Order Profile SourceCodeGroup Store ProductList The method throws an exception in case of another system type. The search can be configured using a simple query language, which provides most common filter and operator functionality. The identifier for an attribute to use in a query condition is always the ID of the attribute as defined in the type definition. For custom defined attributes the prefix custom is required in the search term (e.g. custom.color = {1}), while for system attributes no prefix is used (e.g. name = {4}). Supported attribute value types with sample expression values: String 'String', 'Str*', 'Strin?' Integer 1, 3E4 Number 1.0, 3.99E5 Date yyyy-MM-dd e.g. 2007-05-31 (Default TimeZone = UTC) DateTime yyyy-MM-dd'T'hh:mm:ss+Z e.g. 2007-05-31T00:00+Z (Z TimeZone = UTC) or 2007-05-31T00:00:00 Boolean true, false Email '[email protected]', '*@demandware.com' Set of String 'String', 'Str*', 'Strin?' Set of Integer 1, 3E4 Set of Number 1.0, 3.99E5 Enum of String 'String', 'Str*', 'Strin?' Enum of Integer 1, 3E4 The following types of attributes are not queryable: Image HTML Text Quantity Password Note, that some system attributes are not queryable by default regardless of the actual value type code. The following operators are supported in a condition: = Equals - All types; supports NULL value (thumbnail = NULL) != Not equals - All types; supports NULL value (thumbnail != NULL) < Less than - Integer, Number and Date types only > Greater than - Integer, Number and Date types only <= Less or equals than - Integer, Number and Date types only >= Greater or equals than - Integer, Number and Date types only LIKE Like - String types and Email only; use if leading or trailing wildcards will be used to support substring search(custom.country LIKE 'US*') ILIKE Caseindependent Like - String types and Email only, use to support case insensitive query (custom.country ILIKE 'usa'), does also support wildcards for substring matching Conditions can be combined using logical expressions 'AND', 'OR' and 'NOT' and nested using parenthesis e.g. gender = {1} AND (age >= {2} OR (NOT profession LIKE {3})). The query language provides a placeholder syntax to pass objects as additional search parameters. Each passed object is related to a placeholder in the query string. The placeholder must be an Integer that is surrounded by braces. The first Integer value must be '0', the second '1' and so on, e.g. querySystemObjects("sample", "age = {0} or creationDate >= {1}", 18, date) If there is more than one object matching the specified query criteria, the result is not deterministic. In order to retrieve a single object from a sorted result set it is recommended to use the following code: querySystemObjects("", "custom.myAttr asc", null).first(). The method first() returns only the next element and closes the iterator. It is strongly recommended to call close() on the returned SeekableIterator if not all of its elements are being processed. This will enable the cleanup of system resources. This method does not consider locale specific attributes. It returns all objects by checking the default non-localizable attributes. Any locale specific filtering after fetching the objects must be done by other custom code. Example: For store objects, such a locale specific filtering can be: Get the store objects using this method with non-localized attributes query. Access the store.getCustom("myattr"). It returns the localized value of the attribute.

**Parameters:**

- `type`: the system object type for the query.
- `queryString`: the actual query.
- `args`: optional parameters for the queryString.

**Returns:**

the system object defined by type which was found when executing the queryString.

**See Also:**

SeekableIterator.close()

---

### querySystemObjects

**Signature:** `static querySystemObjects(type : String, queryString : String, sortString : String, args : Object...) : SeekableIterator`

**Description:** Searches for system object instances. The following system object types are supported: GiftCertificate Order Profile SourceCodeGroup Store ProductList The method throws an exception in case of another system type. The search can be configured using a simple query language, which provides most common filter and operator functionality. The identifier for an attribute to use in a query condition is always the ID of the attribute as defined in the type definition. For custom defined attributes the prefix custom is required in the search term (e.g. custom.color = {1}), while for system attributes no prefix is used (e.g. name = {4}). Supported attribute value types with sample expression values: String 'String', 'Str*', 'Strin?' Integer 1, 3E4 Number 1.0, 3.99E5 Date yyyy-MM-dd e.g. 2007-05-31 (Default TimeZone = UTC) DateTime yyyy-MM-dd'T'hh:mm:ss+Z e.g. 2007-05-31T00:00+Z (Z TimeZone = UTC) or 2007-05-31T00:00:00 Boolean true, false Email '[email protected]', '*@demandware.com' Set of String 'String', 'Str*', 'Strin?' Set of Integer 1, 3E4 Set of Number 1.0, 3.99E5 Enum of String 'String', 'Str*', 'Strin?' Enum of Integer 1, 3E4 The following types of attributes are not queryable: Image HTML Text Quantity Password Note, that some system attributes are not queryable by default regardless of the actual value type code. The following operators are supported in a condition: = Equals - All types; supports NULL value (thumbnail = NULL) != Not equals - All types; supports NULL value (thumbnail != NULL) < Less than - Integer, Number and Date types only > Greater than - Integer, Number and Date types only <= Less or equals than - Integer, Number and Date types only >= Greater or equals than - Integer, Number and Date types only LIKE Like - String types and Email only; use if leading or trailing wildcards will be used to support substring search(custom.country LIKE 'US*') ILIKE Caseindependent Like - String types and Email only, use to support case insensitive query (custom.country ILIKE 'usa'), does also support wildcards for substring matching Conditions can be combined using logical expressions 'AND', 'OR' and 'NOT' and nested using parenthesis e.g. gender = {1} AND (age >= {2} OR (NOT profession LIKE {3})). The query language provides a placeholder syntax to pass objects as additional search parameters. Each passed object is related to a placeholder in the query string. The placeholder must be an Integer that is surrounded by braces. The first Integer value must be '0', the second '1' and so on, e.g. querySystemObjects("sample", "age = {0} or creationDate >= {1}", 18, date) The sorting parameter is optional and may contain a comma separated list of attribute names to sort by. Each sort attribute name may be followed by an optional sort direction specifier ('asc' | 'desc'). Default sorting directions is ascending, if no direction was specified. Example: age desc, name Please note that specifying a localized custom attribute as the sorting attribute is currently not supported. Sometimes it is desired to get all instances of specified type with a special sorting condition. This can be easily done by providing the 'type' of the system object and the 'sortString' in combination with an empty 'queryString', e.g. querySystemObjects("sample", "", "ID asc") It is strongly recommended to call close() on the returned SeekableIterator if not all of its elements are being retrieved. This will ensure the proper cleanup of system resources. This method does not consider locale specific attributes. It returns all objects by checking the default non-localizable attributes. Any locale specific filtering after fetching the objects must be done by other custom code. Example: For store objects, such a locale specific filtering can be: Get the store objects using this method with non-localized attributes query. Access the store.getCustom("myattr"). It returns the localized value of the attribute.

**Parameters:**

- `type`: the system object type for the query.
- `queryString`: the actual query.
- `sortString`: an optional sorting or null if no sorting is necessary.
- `args`: optional parameters for the queryString.

**Returns:**

SeekableIterator containing the result set of the query.

**See Also:**

SeekableIterator.close()

---

### querySystemObjects

**Signature:** `static querySystemObjects(type : String, queryAttributes : Map, sortString : String) : SeekableIterator`

**Description:** Searches for system object instances. The following system object types are supported: GiftCertificate Order Profile SourceCodeGroup Store ProductList The method throws an exception in case of another system type. The search can be configured with a map, which key-value pairs are converted into a query expression. The key-value pairs are turned into a sequence of '=' or 'like' conditions, which are combined with AND statements. Example: A map with the key/value pairs: 'name'/'tom*', 'age'/66 will be converted as follows: "name like 'tom*' and age = 66" The identifier for an attribute to use in a query condition is always the ID of the attribute as defined in the type definition. For custom defined attributes the prefix custom is required in the search term (e.g. custom.color = {1}), while for system attributes no prefix is used (e.g. name = {4}). Supported attribute value types with sample expression values: String 'String', 'Str*', 'Strin?' Integer 1, 3E4 Number 1.0, 3.99E5 Date yyyy-MM-dd e.g. 2007-05-31 (Default TimeZone = UTC) DateTime yyyy-MM-dd'T'hh:mm:ss+Z e.g. 2007-05-31T00:00+Z (Z TimeZone = UTC) or 2007-05-31T00:00:00 Boolean true, false Email '[email protected]', '*@demandware.com' Set of String 'String', 'Str*', 'Strin?' Set of Integer 1, 3E4 Set of Number 1.0, 3.99E5 Enum of String 'String', 'Str*', 'Strin?' Enum of Integer 1, 3E4 The following types of attributes are not queryable: Image HTML Text Quantity Password Note, that some system attributes are not queryable by default regardless of the actual value type code. The sorting parameter is optional and may contain a comma separated list of attribute names to sort by. Each sort attribute name may be followed by an optional sort direction specifier ('asc' | 'desc'). Default sorting directions is ascending, if no direction was specified. Example: age desc, name Please note that specifying a localized custom attribute as the sorting attribute is currently not supported. It is strongly recommended to call close() on the returned SeekableIterator if not all of its elements are being retrieved. This will ensure the proper cleanup of system resources. This method does not consider locale specific attributes. It returns all objects by checking the default non-localizable attributes. Any locale specific filtering after fetching the objects must be done by other custom code. Example: For store objects, such a locale specific filtering can be: Get the store objects using this method with non-localized attributes query. Access the store.getCustom("myattr"). It returns the localized value of the attribute.

**Parameters:**

- `type`: the system object type for the query.
- `queryAttributes`: key-value pairs, which define the query.
- `sortString`: an optional sorting or null if no sorting is necessary.

**Returns:**

SeekableIterator containing the result set of the query.

**See Also:**

SeekableIterator.close()

---
```

--------------------------------------------------------------------------------
/docs/dw_extensions.applepay/ApplePayHooks.md:
--------------------------------------------------------------------------------

```markdown
## Package: dw.extensions.applepay

# Class ApplePayHooks

## Inheritance Hierarchy

- dw.extensions.applepay.ApplePayHooks

## Description

ApplePayHooks interface containing extension points for customizing Apple Pay. These hooks are executed in a transaction. The extension points (hook names), and the functions that are called by each extension point. A function must be defined inside a JavaScript source and must be exported. The script with the exported hook function must be located inside a site cartridge. Inside the site cartridge a 'package.json' file with a 'hooks' entry must exist. "hooks": "./hooks.json" The hooks entry links to a json file, relative to the 'package.json' file. This file lists all registered hooks inside the hooks property: "hooks": [ {"name": "dw.extensions.applepay.getRequest", "script": "./applepay.ds"} {"name": "dw.extensions.applepay.shippingContactSelected", "script": "./applepay.ds"} ] A hook entry has a 'name' and a 'script' property. The 'name' contains the extension point, the hook name. The 'script' contains the script relative to the hooks file, with the exported hook function.

## Constants

## Properties

## Constructor Summary

## Method Summary

### authorizeOrderPayment

**Signature:** `authorizeOrderPayment(order : Order, event : Object) : Status`

Called to authorize the Apple Pay payment for the order.

### cancel

**Signature:** `cancel(basket : Basket) : ApplePayHookResult`

Called after the Apple Pay payment sheet was canceled.

### createOrder

**Signature:** `createOrder(basket : Basket, event : Object) : Order`

Called after handling the given ApplePayPaymentAuthorizedEvent for the given basket.

### failOrder

**Signature:** `failOrder(order : Order, status : Status) : ApplePayHookResult`

Called after payment authorization is unsuccessful and the given Apple Pay order must be failed.

### getRequest

**Signature:** `getRequest(basket : Basket, request : Object) : ApplePayHookResult`

Called to get the Apple Pay JS PaymentRequest for the given basket.

### paymentMethodSelected

**Signature:** `paymentMethodSelected(basket : Basket, event : Object, response : Object) : ApplePayHookResult`

Called after handling the given ApplePayPaymentMethodSelectedEvent for the given basket.

### placeOrder

**Signature:** `placeOrder(order : Order) : ApplePayHookResult`

Called after payment has been authorized and the given Apple Pay order is ready to be placed.

### prepareBasket

**Signature:** `prepareBasket(basket : Basket, parameters : Object) : ApplePayHookResult`

Called to prepare the given basket for an Apple Pay checkout.

### shippingContactSelected

**Signature:** `shippingContactSelected(basket : Basket, event : Object, response : Object) : ApplePayHookResult`

Called after handling the given ApplePayShippingContactSelectedEvent for the given basket.

### shippingMethodSelected

**Signature:** `shippingMethodSelected(basket : Basket, shippingMethod : ShippingMethod, event : Object, response : Object) : ApplePayHookResult`

Called after handling the given ApplePayShippingMethodSelectedEvent for the given basket.

## Method Detail

## Method Details

### authorizeOrderPayment

**Signature:** `authorizeOrderPayment(order : Order, event : Object) : Status`

**Description:** Called to authorize the Apple Pay payment for the order. The given order will have been created by the extensionPointPaymentAuthorizedCreateOrder hook, after the basket was populated with data from the ApplePayPaymentAuthorizedEvent. Return a non-error status if you have successfully authorized the payment with your payment service provider. Your hook implementation must set the necessary payment status and transaction identifier data on the order as returned by the provider. Return an error status to indicate a problem, including unsuccessful authorization. See ApplePayHookResult for how to indicate error statuses with detail information to be provided to Apple Pay. See the Apple Pay JS API Reference for more information.

**Parameters:**

- `order`: the order paid using Apple Pay
- `event`: ApplePayPaymentAuthorizedEvent object

**Returns:**

a non-null status ends the hook execution

---

### cancel

**Signature:** `cancel(basket : Basket) : ApplePayHookResult`

**Description:** Called after the Apple Pay payment sheet was canceled. There is no Apple Pay JS event object for this case. The given basket is the one that was passed to other hooks earlier in the Apple Pay checkout process. It is not guaranteed that this hook will be executed for all Apple Pay payment sheets canceled by shoppers or otherwise ended without a successful order. Calls to this hook are provided on a best-effort basis. If the returned result includes a redirect URL, the shopper browser will be navigated to that URL if possible. It is not guaranteed that the response with the hook result will be handled in the shopper browser in all cases.

**Parameters:**

- `basket`: the basket that was being checked out using Apple Pay

**Returns:**

a non-null result ends the hook execution

---

### createOrder

**Signature:** `createOrder(basket : Basket, event : Object) : Order`

**Description:** Called after handling the given ApplePayPaymentAuthorizedEvent for the given basket. Customer information, billing address, and/or shipping address for the default shipment will have already been updated to reflect the available contact information provided by Apple Pay based on the Apple Pay configuration for your site. Any preexisting payment instruments on the basket will have been removed, and a single DW_APPLE_PAY payment instrument added for the total amount. The purpose of this hook is to populate the created order with any necessary information from the basket or the Apple Pay event. Do not use this hook for address verification, or any other validation. Instead use the extensionPointPaymentAuthorizedAuthorizeOrderPayment hook which allows you to return an ApplePayHookResult with error status information. The default implementation of this hook simply calls OrderMgr.createOrder and returns the created order. Throw an error to indicate a problem creating the order.

**Parameters:**

- `basket`: the basket being checked out using Apple Pay
- `event`: ApplePayPaymentAuthorizedEvent object

**Returns:**

a non-null order ends the hook execution

---

### failOrder

**Signature:** `failOrder(order : Order, status : Status) : ApplePayHookResult`

**Description:** Called after payment authorization is unsuccessful and the given Apple Pay order must be failed. The purpose of this hook is to fail the order, or return a redirect URL that results in the order being failed when the shopper browser is navigated to it. The given status object is the result of calling the extensionPointPaymentAuthorizedAuthorizeOrderPayment hook. The default implementation of this hook simply calls OrderMgr.failOrder, and returns a result with the given status and no redirect URL. Return a result with an error status to indicate a problem. See ApplePayHookResult for how to indicate error statuses with detail information to be provided to Apple Pay. If the returned result includes a redirect URL, the shopper browser will be navigated to that URL if the Apple Pay payment sheet is canceled.

**Parameters:**

- `order`: the order created for a failed Apple Pay checkout
- `status`: status code returned by the extensionPointPaymentAuthorizedAuthorizeOrderPayment hook

**Returns:**

ApplePayHookResult containing a status code to be provided to Apple Pay. A non-null result ends the hook execution

---

### getRequest

**Signature:** `getRequest(basket : Basket, request : Object) : ApplePayHookResult`

**Description:** Called to get the Apple Pay JS PaymentRequest for the given basket. You can set properties in the given request object to extend or override default properties set automatically based on the Apple Pay configuration for your site. Return a result with an error status to indicate a problem. See ApplePayHookResult for how to indicate error statuses with detail information to be provided to Apple Pay. If the returned result includes a redirect URL, the shopper browser will be navigated to that URL if the Apple Pay payment sheet is canceled. See the Apple Pay JS API Reference for more information.

**Parameters:**

- `basket`: the basket for the Apple Pay request
- `request`: the Apple Pay payment request object

**Returns:**

a non-null result ends the hook execution

---

### paymentMethodSelected

**Signature:** `paymentMethodSelected(basket : Basket, event : Object, response : Object) : ApplePayHookResult`

**Description:** Called after handling the given ApplePayPaymentMethodSelectedEvent for the given basket. This Apple Pay event does not contain payment card or device information. The given response object will contain properties whose values are to be passed as parameters to the ApplePaySession.completePaymentMethodSelection event callback: total - Updated total line item object lineItems - Array of updated line item objects Return a result with an error status to indicate a problem. See ApplePayHookResult for how to indicate error statuses with detail information to be provided to Apple Pay. If the returned result includes a redirect URL, the shopper browser will be navigated to that URL if the Apple Pay payment sheet is canceled. See the Apple Pay JS API Reference for more information.

**Parameters:**

- `basket`: the basket being checked out using Apple Pay
- `event`: ApplePayPaymentMethodSelectedEvent object
- `response`: JS object containing Apple Pay event callback parameters

**Returns:**

a non-null result ends the hook execution

---

### placeOrder

**Signature:** `placeOrder(order : Order) : ApplePayHookResult`

**Description:** Called after payment has been authorized and the given Apple Pay order is ready to be placed. The purpose of this hook is to place the order, or return a redirect URL that results in the order being placed when the shopper browser is navigated to it. The default implementation of this hook returns a redirect to COPlaceOrder-Submit with URL parameters order_id set to Order.getOrderNo() and order_token set to Order.getOrderToken() which corresponds to SiteGenesis-based implementations. Your hook implementation should return a result with a different redirect URL as necessary to place the order and show an order confirmation. Alternatively, your hook implementation itself can place the order and return a result with a redirect URL to an order confirmation page that does not place the order. This is inconsistent with SiteGenesis-based implementations so is not the default. Return an error status to indicate a problem. See ApplePayHookResult for how to indicate error statuses with detail information to be provided to Apple Pay. If the returned result includes a redirect URL, the shopper browser will be navigated to that URL if the Apple Pay payment sheet is canceled.

**Parameters:**

- `order`: the order paid using Apple Pay

**Returns:**

a non-null result ends the hook execution

---

### prepareBasket

**Signature:** `prepareBasket(basket : Basket, parameters : Object) : ApplePayHookResult`

**Description:** Called to prepare the given basket for an Apple Pay checkout. This hook will be executed after the user clicks the Apple Pay button. The default implementation of this hook calculates the basket. A custom hook implementation that returns a non-null result must calculate the basket. The given parameters object will contain properties whose values are passed from the <isapplepay></isapplepay> tag: sku - SKU of product to checkout exclusively Return a result with an error status to indicate a problem. For this hook there is no opportunity to provide user feedback, so if any error status is returned, the Apple Pay payment sheet will be aborted. If the returned result includes a redirect URL, the shopper browser will be navigated to that URL after the Apple Pay payment sheet is aborted.

**Parameters:**

- `basket`: the basket for the Apple Pay request
- `parameters`: parameters from the <isapplepay></isapplepay> tag

**Returns:**

a non-null result ends the hook execution

---

### shippingContactSelected

**Signature:** `shippingContactSelected(basket : Basket, event : Object, response : Object) : ApplePayHookResult`

**Description:** Called after handling the given ApplePayShippingContactSelectedEvent for the given basket. Basket customer information and/or shipping address for the default shipment will have already been updated to reflect the available shipping contact information provided by Apple Pay based on the Apple Pay configuration for your site. The basket will have already been calculated before this hook is called. The given response object will contain properties whose values are to be passed as parameters to the ApplePaySession.completeShippingContactSelection event callback: shippingMethods - Array of applicable shipping method JS objects total - Updated total line item object lineItems - Array of updated line item objects Return a result with an error status to indicate a problem. See ApplePayHookResult for how to indicate error statuses with detail information to be provided to Apple Pay. If the returned result includes a redirect URL, the shopper browser will be navigated to that URL if the Apple Pay payment sheet is canceled. See the Apple Pay JS API Reference for more information.

**Parameters:**

- `basket`: the basket being checked out using Apple Pay
- `event`: ApplePayShippingContactSelectedEvent object
- `response`: JS object containing Apple Pay event callback parameters

**Returns:**

a non-null result ends the hook execution

---

### shippingMethodSelected

**Signature:** `shippingMethodSelected(basket : Basket, shippingMethod : ShippingMethod, event : Object, response : Object) : ApplePayHookResult`

**Description:** Called after handling the given ApplePayShippingMethodSelectedEvent for the given basket. The given shipping method will have already been set on the basket. The basket will have already been calculated before this hook is called. The given response object will contain properties whose values are to be passed as parameters to the ApplePaySession.completeShippingMethodSelection event callback: total - Updated total line item object lineItems - Array of updated line item objects Return a result with an error status to indicate a problem. See ApplePayHookResult for how to indicate error statuses with detail information to be provided to Apple Pay. If the returned result includes a redirect URL, the shopper browser will be navigated to that URL if the Apple Pay payment sheet is canceled. See the Apple Pay JS API Reference for more information.

**Parameters:**

- `basket`: the basket being checked out using Apple Pay
- `shippingMethod`: the shipping method that was selected
- `event`: ApplePayShippingMethodSelectedEvent object
- `response`: JS object containing Apple Pay event callback parameters

**Returns:**

a non-null result ends the hook execution

---
```

--------------------------------------------------------------------------------
/tests/class-content-parser.test.ts:
--------------------------------------------------------------------------------

```typescript
import { ClassContentParser } from '../src/clients/docs/class-content-parser.js';
import { Logger } from '../src/utils/logger.js';

describe('ClassContentParser', () => {
  let mockLogger: jest.Mocked<Logger>;
  let parser: ClassContentParser;

  beforeEach(() => {
    mockLogger = {
      debug: jest.fn(),
      log: jest.fn(),
      error: jest.fn(),
      timing: jest.fn(),
      methodEntry: jest.fn(),
      methodExit: jest.fn(),
    } as any;

    jest.spyOn(Logger, 'getChildLogger').mockReturnValue(mockLogger);
    parser = new ClassContentParser();
  });

  afterEach(() => {
    jest.clearAllMocks();
  });

  describe('parseClassContent', () => {
    it('should parse basic class information correctly', () => {
      const content = `
# Class Product

## Package: dw.catalog

## Description
Represents a product in the catalog system.
This is a multi-line description.

## Constructor Summary
Product(id: String)
Creates a new product instance.
      `.trim();

      const result = parser.parseClassContent(content);

      expect(result).toEqual({
        className: 'Product',
        packageName: 'dw.catalog',
        description: 'Represents a product in the catalog system. This is a multi-line description.',
        constants: [],
        properties: [],
        methods: [],
        inheritance: undefined,
        constructorInfo: 'Product(id: String) Creates a new product instance.',
      });
    });

    it('should parse inheritance hierarchy correctly', () => {
      const content = `
# Class Product

## Package: dw.catalog

## Inheritance Hierarchy
- dw.object.PersistentObject
- dw.catalog.CatalogObject
- dw.catalog.Product
      `.trim();

      const result = parser.parseClassContent(content);

      expect(result.inheritance).toEqual([
        'dw.object.PersistentObject',
        'dw.catalog.CatalogObject',
        'dw.catalog.Product',
      ]);
    });

    it('should parse constants correctly', () => {
      const content = `
# Class Product

## Package: dw.catalog

## Constants

### STATUS_ACTIVE

**Type:** String = 'ACTIVE'

This constant represents an active product status.

### MAX_QUANTITY

**Type:** Number = 100

Maximum quantity allowed for this product.

### DEPRECATED_FLAG

**Type:** Boolean

**Deprecated:** This flag is no longer used. Use isActive instead.

This is the description for the deprecated flag.
      `.trim();

      const result = parser.parseClassContent(content);

      expect(result.constants).toHaveLength(3);

      expect(result.constants[0]).toEqual({
        name: 'STATUS_ACTIVE',
        type: 'String',
        value: "'ACTIVE'",
        description: 'This constant represents an active product status.',
        deprecated: undefined,
        deprecationMessage: undefined,
      });

      expect(result.constants[1]).toEqual({
        name: 'MAX_QUANTITY',
        type: 'Number',
        value: '100',
        description: 'Maximum quantity allowed for this product.',
        deprecated: undefined,
        deprecationMessage: undefined,
      });

      expect(result.constants[2]).toEqual({
        name: 'DEPRECATED_FLAG',
        type: 'Boolean',
        value: undefined,
        description: 'This is the description for the deprecated flag.',
        deprecated: true,
        deprecationMessage: 'This flag is no longer used. Use isActive instead.',
      });
    });

    it('should parse properties correctly', () => {
      const content = `
# Class Product

## Package: dw.catalog

## Properties

### name

**Type:** String (Read Only)

The name of the product.

### price

**Type:** Money (Static)

The price of the product.

### oldProperty

**Type:** String

**Deprecated:** Use newProperty instead.

This property is deprecated.
      `.trim();

      const result = parser.parseClassContent(content);

      expect(result.properties).toHaveLength(3);

      expect(result.properties[0]).toEqual({
        name: 'name',
        type: 'String',
        description: 'The name of the product.',
        modifiers: ['Read Only'],
        deprecated: undefined,
        deprecationMessage: undefined,
      });

      expect(result.properties[1]).toEqual({
        name: 'price',
        type: 'Money',
        description: 'The price of the product.',
        modifiers: ['Static'],
        deprecated: undefined,
        deprecationMessage: undefined,
      });

      expect(result.properties[2]).toEqual({
        name: 'oldProperty',
        type: 'String',
        description: 'This property is deprecated.',
        modifiers: undefined,
        deprecated: true,
        deprecationMessage: 'Use newProperty instead.',
      });
    });

    it('should parse methods correctly', () => {
      const content = `
# Class Product

## Package: dw.catalog

## Method Summary

### getName

**Signature:** \`getName() : String\`

**Description:** Returns the product name.

### setPrice

**Signature:** \`setPrice(price: Money) : void\`

Sets the product price.

### oldMethod

**Signature:** \`oldMethod() : String\`

**Deprecated:** This method is deprecated. Use newMethod instead.

This method should not be used anymore.
      `.trim();

      const result = parser.parseClassContent(content);

      expect(result.methods).toHaveLength(3);

      expect(result.methods[0]).toEqual({
        name: 'getName',
        signature: 'getName() : String',
        description: 'Returns the product name.',
        deprecated: undefined,
        deprecationMessage: undefined,
      });

      expect(result.methods[1]).toEqual({
        name: 'setPrice',
        signature: 'setPrice(price: Money) : void',
        description: 'Sets the product price.',
        deprecated: undefined,
        deprecationMessage: undefined,
      });

      expect(result.methods[2]).toEqual({
        name: 'oldMethod',
        signature: 'oldMethod() : String',
        description: 'This method should not be used anymore.',
        deprecated: true,
        deprecationMessage: 'This method is deprecated. Use newMethod instead.',
      });
    });

    it('should handle Method Details section correctly', () => {
      const content = `
# Class Product

## Package: dw.catalog

## Method Details

### getDetails

**Signature:** \`getDetails() : ProductDetails\`

**Description:** Returns detailed product information.
      `.trim();

      const result = parser.parseClassContent(content);

      expect(result.methods).toHaveLength(1);
      expect(result.methods[0]).toEqual({
        name: 'getDetails',
        signature: 'getDetails() : ProductDetails',
        description: 'Returns detailed product information.',
        deprecated: undefined,
        deprecationMessage: undefined,
      });
    });

    it('should handle methods without explicit signature', () => {
      const content = `
# Class Product

## Package: dw.catalog

## Method Summary

### toString

Returns string representation of the product.
      `.trim();

      const result = parser.parseClassContent(content);

      expect(result.methods).toHaveLength(1);
      expect(result.methods[0]).toEqual({
        name: 'toString',
        signature: 'toString',
        description: 'Returns string representation of the product.',
        deprecated: undefined,
        deprecationMessage: undefined,
      });
    });

    it('should handle deprecation messages spanning multiple lines', () => {
      const content = `
# Class Product

## Package: dw.catalog

## Constants

### OLD_CONSTANT

**Type:** String

**Deprecated:**
This constant is deprecated because it was replaced
by a more efficient implementation.
Use NEW_CONSTANT instead.

Description after deprecation.
      `.trim();

      const result = parser.parseClassContent(content);

      expect(result.constants).toHaveLength(1);
      expect(result.constants[0]).toEqual({
        name: 'OLD_CONSTANT',
        type: 'String',
        value: undefined,
        description: 'This constant is deprecated because it was replaced by a more efficient implementation. Use NEW_CONSTANT instead. Description after deprecation.',
        deprecated: true,
        deprecationMessage: 'This constant is deprecated because it was replaced by a more efficient implementation. Use NEW_CONSTANT instead. Description after deprecation.',
      });
    });

    it('should handle empty sections gracefully', () => {
      const content = `
# Class Product

## Package: dw.catalog

## Description

## Constants

## Properties

## Method Summary
      `.trim();

      const result = parser.parseClassContent(content);

      expect(result).toEqual({
        className: 'Product',
        packageName: 'dw.catalog',
        description: '',
        constants: [],
        properties: [],
        methods: [],
        inheritance: undefined,
        constructorInfo: undefined,
      });
    });

    it('should handle complex class names correctly', () => {
      const content = `
# Class ContentMgr

## Package: dw.content

## Description
Content manager class.
      `.trim();

      const result = parser.parseClassContent(content);

      expect(result.className).toBe('ContentMgr');
      expect(result.packageName).toBe('dw.content');
    });

    it('should handle properties with both Read Only and Static modifiers', () => {
      const content = `
# Class Product

## Package: dw.catalog

## Properties

### INSTANCE

**Type:** Product (Read Only) (Static)

The singleton instance.
      `.trim();

      const result = parser.parseClassContent(content);

      expect(result.properties).toHaveLength(1);
      expect(result.properties[0]).toEqual({
        name: 'INSTANCE',
        type: 'Product',
        description: 'The singleton instance.',
        modifiers: ['Read Only', 'Static'],
        deprecated: undefined,
        deprecationMessage: undefined,
      });
    });

    it('should ignore separator lines and handle complex formatting', () => {
      const content = `
# Class Product

## Package: dw.catalog

## Description
This is a product class.

---

## Constants

### STATUS

**Type:** String

The status of the product.

---

Some random separator that should be ignored.

## Properties

### id

**Type:** String

The product ID.
      `.trim();

      const result = parser.parseClassContent(content);

      expect(result.description).toBe('This is a product class. ---');
      expect(result.constants).toHaveLength(1);
      expect(result.constants[0].description).toBe('The status of the product. --- Some random separator that should be ignored.');
      expect(result.properties).toHaveLength(1);
      expect(result.properties[0].description).toBe('The product ID.');
    });

    it('should handle malformed content gracefully', () => {
      const content = `
Some random content without proper headers

### Random Header

Random content
      `.trim();

      const result = parser.parseClassContent(content);

      expect(result).toEqual({
        className: '',
        packageName: '',
        description: '',
        constants: [],
        properties: [],
        methods: [],
        inheritance: undefined,
        constructorInfo: undefined,
      });
    });

    it('should handle complex inheritance with special characters', () => {
      const content = `
# Class Product

## Package: dw.catalog

## Inheritance Hierarchy
- dw.object.PersistentObject
  - dw.catalog.CatalogObject
    - dw.catalog.Product
      `.trim();

      const result = parser.parseClassContent(content);

      expect(result.inheritance).toEqual([
        'dw.object.PersistentObject',
        'dw.catalog.CatalogObject',
        'dw.catalog.Product',
      ]);
    });

    it('should handle constants with complex type values', () => {
      const content = `
# Class Product

## Package: dw.catalog

## Constants

### COMPLEX_VALUE

**Type:** Object = {key: 'value', number: 42}

A complex constant value.
      `.trim();

      const result = parser.parseClassContent(content);

      expect(result.constants).toHaveLength(1);
      expect(result.constants[0]).toEqual({
        name: 'COMPLEX_VALUE',
        type: 'Object',
        value: "{key: 'value', number: 42}",
        description: 'A complex constant value.',
        deprecated: undefined,
        deprecationMessage: undefined,
      });
    });

    it('should handle methods with descriptions that contain signature-like text', () => {
      const content = `
# Class Product

## Package: dw.catalog

## Method Summary

### processSignature

**Signature:** \`processSignature(data: String) : void\`

This method processes a signature. Note that it doesn't contain Signature: in the description.
The signature parameter is important.
      `.trim();

      const result = parser.parseClassContent(content);

      expect(result.methods).toHaveLength(1);
      expect(result.methods[0]).toEqual({
        name: 'processSignature',
        signature: 'processSignature(data: String) : void',
        description: 'The signature parameter is important.',
        deprecated: undefined,
        deprecationMessage: undefined,
      });
    });
  });

  describe('edge cases and error handling', () => {
    it('should handle empty string input', () => {
      const result = parser.parseClassContent('');

      expect(result).toEqual({
        className: '',
        packageName: '',
        description: '',
        constants: [],
        properties: [],
        methods: [],
        inheritance: undefined,
        constructorInfo: undefined,
      });
    });

    it('should handle input with only whitespace', () => {
      const result = parser.parseClassContent('   \n\n   \t  \n  ');

      expect(result).toEqual({
        className: '',
        packageName: '',
        description: '',
        constants: [],
        properties: [],
        methods: [],
        inheritance: undefined,
        constructorInfo: undefined,
      });
    });

    it('should handle single line input', () => {
      const result = parser.parseClassContent('# Class TestClass');

      expect(result.className).toBe('TestClass');
      expect(result.packageName).toBe('');
    });

    it('should trim whitespace from all fields correctly', () => {
      const content = `
   # Class    Product   

   ## Package:    dw.catalog   

   ## Description
   This is a description with extra spaces.   

   ## Constants

   ### STATUS_ACTIVE   

   **Type:**   String = 'ACTIVE'   

   This constant has extra spaces.   
      `;

      const result = parser.parseClassContent(content);

      expect(result.className).toBe('Product');
      expect(result.packageName).toBe('dw.catalog');
      expect(result.description).toBe('This is a description with extra spaces.');
      expect(result.constants[0].name).toBe('STATUS_ACTIVE');
      expect(result.constants[0].type).toBe('String');
      expect(result.constants[0].description).toBe('This constant has extra spaces.');
    });
  });

  describe('logger integration', () => {
    it('should create logger with correct name', () => {
      expect(Logger.getChildLogger).toHaveBeenCalledWith('ClassContentParser');
    });
  });
});

```

--------------------------------------------------------------------------------
/docs/dw_system/Session.md:
--------------------------------------------------------------------------------

```markdown
## Package: dw.system

# Class Session

## Inheritance Hierarchy

- Object
  - dw.system.Session

## Description

Represents a session in B2C Commerce. The session has some well-defined attributes like the current authenticated customer or the click stream, but also supports storing custom values in the session. The Digital session handling works in the following way: A session is created in Digital on the first user click. This is guaranteed even if B2C Commerce caches the HTML pages. It is not guaranteed when the pages are cached by a CDN. A session is identified with a unique ID, called the session ID. When a session is created, the application server calls the pipeline OnSession-Start. It can be used to pre-initialize the session, before the actual request hits the server. Digital uses session stickiness and always routes requests within a single session to the same application server. Session data is also stored in a persistent location. In case of a fail-over situation, requests are re-routed to another application server, which then loads the session data from the persistent storage. There are two session timeouts. A soft timeout occurs 30 minutes after the last request has been made. The soft timeout logs out and clears all privacy data, but it is still possible to use the session ID to reopen the session. A hard timeout renders a session ID invalid after six hours, even if the session is still in use. The hard timeout prevents a session from being reopened. For example, if the session ID is pasted into a URL after the hard timeout, the session doesn't reopen. Certain rules apply for what and how much data can be stored in a session: All primitive types (boolean, number, string, Number, String, Boolean, Date) are supported. All B2C Commerce value types (Money, Quantity, Decimal, Calendar) are supported. Strings are limited to 2000 characters. No other types can be stored in a session. In particular, persistent objects, collections, and scripted objects cannot be stored in a session. B2C Commerce will report unsupported values with a deprecation message in the log files. An unsupported value will be stored in the session, but the results are undefined. Since version compatibility mode 19.10 unsupported types will no longer be accepted, and an exception will be thrown. There is a 10 KB size limit for the overall serialized session.

## Properties

### clickStream

**Type:** ClickStream (Read Only)

The current click stream if this is an HTTP session, null otherwise.

### currency

**Type:** Currency

Get the currency associated with the current session. The session
 currency is established at session construction time and is typically
 equal to the site default currency. In the case of a multi-currency site,
 the session currency may be different than the site default currency.

### custom

**Type:** CustomAttributes (Read Only)

The session's custom attributes. The
 attributes are stored for the lifetime of the session and are not
 cleared when the customer logs out.

### customer

**Type:** Customer (Read Only)

The customer associated with this storefront session. The method
 always returns null if called for a non-storefront session
 (e.g., within a job or within Business Manager). For a storefront
 session, the method always returns a customer. The returned customer
 may be anonymous if the customer could not be identified via the
 customer cookie.

### customerAuthenticated

**Type:** boolean (Read Only)

Identifies whether the customer associated with this session
 is authenticated. This call is equivalent to customer.isAuthenticated().

### customerExternallyAuthenticated

**Type:** boolean (Read Only)

Identifies whether the customer associated with this session
 is externally authenticated.

### forms

**Type:** Forms (Read Only)

The forms object that provides access to all current forms of a customer in the session.

### lastReceivedSourceCodeInfo

**Type:** SourceCodeInfo (Read Only)

Returns information on the last source code handled by the session.
 This may or may not be the session's active source code, e.g., the
 last received source code was inactive and therefore was not
 set as the session's active source code.

### privacy

**Type:** CustomAttributes (Read Only)

The session's custom privacy attributes.
 The attributes are stored for the lifetime of the session and are
 automatically cleared when the customer logs out.

### sessionID

**Type:** String (Read Only)

The unique session id. This can safely be used as an identifier
 against external systems.

### sourceCodeInfo

**Type:** SourceCodeInfo (Read Only)

Returns information on the session's active source-code.

### trackingAllowed

**Type:** boolean

Returns whether the tracking allowed flag is set in the session.
 The value for newly created sessions defaults to the Site Preference "TrackingAllowed" unless
 a cookie named "dw_dnt" is found in which case the cookie value takes precedence.

### userAuthenticated

**Type:** boolean (Read Only)

Identifies whether the agent user associated with this session
 is authenticated.

### userName

**Type:** String (Read Only)

The current agent user name associated with this session.
 
 Note: this class allows access to sensitive security-related data.
 Pay special attention to PCI DSS v3 requirements 2, 4, and 12.

## Constructor Summary

## Method Summary

### generateGuestSessionSignature

**Signature:** `generateGuestSessionSignature() : String`

Generates a new guest session signature.

### generateRegisteredSessionSignature

**Signature:** `generateRegisteredSessionSignature() : String`

Generates a new registered session signature.

### getClickStream

**Signature:** `getClickStream() : ClickStream`

Returns the current click stream if this is an HTTP session, null otherwise.

### getCurrency

**Signature:** `getCurrency() : Currency`

Get the currency associated with the current session.

### getCustom

**Signature:** `getCustom() : CustomAttributes`

Returns the session's custom attributes.

### getCustomer

**Signature:** `getCustomer() : Customer`

Returns the customer associated with this storefront session.

### getForms

**Signature:** `getForms() : Forms`

Returns the forms object that provides access to all current forms of a customer in the session.

### getLastReceivedSourceCodeInfo

**Signature:** `getLastReceivedSourceCodeInfo() : SourceCodeInfo`

Returns information on the last source code handled by the session.

### getPrivacy

**Signature:** `getPrivacy() : CustomAttributes`

Returns the session's custom privacy attributes.

### getSessionID

**Signature:** `getSessionID() : String`

Returns the unique session id.

### getSourceCodeInfo

**Signature:** `getSourceCodeInfo() : SourceCodeInfo`

Returns information on the session's active source-code.

### getUserName

**Signature:** `getUserName() : String`

Returns the current agent user name associated with this session.

### isCustomerAuthenticated

**Signature:** `isCustomerAuthenticated() : boolean`

Identifies whether the customer associated with this session is authenticated.

### isCustomerExternallyAuthenticated

**Signature:** `isCustomerExternallyAuthenticated() : boolean`

Identifies whether the customer associated with this session is externally authenticated.

### isTrackingAllowed

**Signature:** `isTrackingAllowed() : boolean`

Returns whether the tracking allowed flag is set in the session.

### isUserAuthenticated

**Signature:** `isUserAuthenticated() : boolean`

Identifies whether the agent user associated with this session is authenticated.

### setCurrency

**Signature:** `setCurrency(newCurrency : Currency) : void`

Sets the session currency.

### setSourceCode

**Signature:** `setSourceCode(sourceCode : String) : Status`

Applies the specified source code to the current session and basket.

### setTrackingAllowed

**Signature:** `setTrackingAllowed(trackingAllowed : boolean) : void`

Sets the tracking allowed flag for the session.

## Method Detail

## Method Details

### generateGuestSessionSignature

**Signature:** `generateGuestSessionSignature() : String`

**Description:** Generates a new guest session signature. This is intended for guest authentication with the Shopper Login and API Access Service (SLAS).

**Returns:**

A new signed session token.

---

### generateRegisteredSessionSignature

**Signature:** `generateRegisteredSessionSignature() : String`

**Description:** Generates a new registered session signature. This is intended for use with registered session-bridge call of Shopper Login and API Access Service (SLAS).

**Returns:**

A new signed session token for registered dwsid.

---

### getClickStream

**Signature:** `getClickStream() : ClickStream`

**Description:** Returns the current click stream if this is an HTTP session, null otherwise.

**Returns:**

the current click stream if this is an HTTP session, null otherwise.

---

### getCurrency

**Signature:** `getCurrency() : Currency`

**Description:** Get the currency associated with the current session. The session currency is established at session construction time and is typically equal to the site default currency. In the case of a multi-currency site, the session currency may be different than the site default currency.

**Returns:**

the currency associated with this storefront session, never null.

---

### getCustom

**Signature:** `getCustom() : CustomAttributes`

**Description:** Returns the session's custom attributes. The attributes are stored for the lifetime of the session and are not cleared when the customer logs out.

**Returns:**

the session's custom attributes.

---

### getCustomer

**Signature:** `getCustomer() : Customer`

**Description:** Returns the customer associated with this storefront session. The method always returns null if called for a non-storefront session (e.g., within a job or within Business Manager). For a storefront session, the method always returns a customer. The returned customer may be anonymous if the customer could not be identified via the customer cookie.

**Returns:**

the customer associated with this storefront session.

---

### getForms

**Signature:** `getForms() : Forms`

**Description:** Returns the forms object that provides access to all current forms of a customer in the session.

**Returns:**

the forms.

---

### getLastReceivedSourceCodeInfo

**Signature:** `getLastReceivedSourceCodeInfo() : SourceCodeInfo`

**Description:** Returns information on the last source code handled by the session. This may or may not be the session's active source code, e.g., the last received source code was inactive and therefore was not set as the session's active source code.

**Returns:**

source code information for the last received source code.

---

### getPrivacy

**Signature:** `getPrivacy() : CustomAttributes`

**Description:** Returns the session's custom privacy attributes. The attributes are stored for the lifetime of the session and are automatically cleared when the customer logs out.

**Returns:**

the session's custom privacy attributes.

---

### getSessionID

**Signature:** `getSessionID() : String`

**Description:** Returns the unique session id. This can safely be used as an identifier against external systems.

**Returns:**

the unique identifier for the session.

---

### getSourceCodeInfo

**Signature:** `getSourceCodeInfo() : SourceCodeInfo`

**Description:** Returns information on the session's active source-code.

**Returns:**

the session's source-code information.

---

### getUserName

**Signature:** `getUserName() : String`

**Description:** Returns the current agent user name associated with this session. Note: this class allows access to sensitive security-related data. Pay special attention to PCI DSS v3 requirements 2, 4, and 12.

**Returns:**

the current agent user name associated with this session.

---

### isCustomerAuthenticated

**Signature:** `isCustomerAuthenticated() : boolean`

**Description:** Identifies whether the customer associated with this session is authenticated. This call is equivalent to customer.isAuthenticated().

**Returns:**

true if the customer is authenticated, false otherwise.

---

### isCustomerExternallyAuthenticated

**Signature:** `isCustomerExternallyAuthenticated() : boolean`

**Description:** Identifies whether the customer associated with this session is externally authenticated.

**Returns:**

true if the customer is authenticated, false otherwise.

---

### isTrackingAllowed

**Signature:** `isTrackingAllowed() : boolean`

**Description:** Returns whether the tracking allowed flag is set in the session. The value for newly created sessions defaults to the Site Preference "TrackingAllowed" unless a cookie named "dw_dnt" is found in which case the cookie value takes precedence.

**Returns:**

true if the tracking allowed flag is set in the session, false otherwise.

---

### isUserAuthenticated

**Signature:** `isUserAuthenticated() : boolean`

**Description:** Identifies whether the agent user associated with this session is authenticated.

**Returns:**

true if the agent user is authenticated, false otherwise.

---

### setCurrency

**Signature:** `setCurrency(newCurrency : Currency) : void`

**Description:** Sets the session currency.

**Parameters:**

- `newCurrency`: the new currency to use. Must not be null. Method will throw an exception if a currency not allowed by the current site is passed.

---

### setSourceCode

**Signature:** `setSourceCode(sourceCode : String) : Status`

**Description:** Applies the specified source code to the current session and basket. This API processes the source code exactly as if it were supplied on the URL query string, with the additional benefit of returning error information. If no input parameter is passed, then the active source code in the session and basket is removed. If a basket exists, and the modification fails, then the session is not written to either. This method may open and commit a transaction, if none is currently active.

**Parameters:**

- `sourceCode`: the source code to set as active in the session and basket. If a null parameter is passed, then the active source code in the session is removed.

**Returns:**

an OK status if the source code was applied, otherwise an ERROR status. In the latter case, the possible error codes are: CODE_INVALID and CODE_INACTIVE. See documentation for SourceCodeStatusCodes for further descriptions.

---

### setTrackingAllowed

**Signature:** `setTrackingAllowed(trackingAllowed : boolean) : void`

**Description:** Sets the tracking allowed flag for the session. If tracking is not allowed, multiple services depending on tracking will be restricted or disabled: Predictive Intelligence recommendations, Active Data, Analytics of the customer behavior in the storefront. Additionally, collected clicks in the session click stream will be cleared. Setting this property to either value also results in setting a session-scoped cookie named "dw_dnt" (1=DoNotTrack; 0=Track)

**Parameters:**

- `trackingAllowed`: true if tracking is allowed, false otherwise.

---
```

--------------------------------------------------------------------------------
/tests/mcp/yaml/get-system-object-definitions.full-mode.test.mcp.yml:
--------------------------------------------------------------------------------

```yaml
# ==================================================================================
# SFCC MCP Server - get_system_object_definitions Tool YAML Tests
# Focused testing for SFCC system object definitions retrieval functionality
# Tests core functionality, select parameters, error scenarios, and edge cases
# 
# Quick Test Commands:
# aegis "tests/mcp/yaml/get-system-object-definitions.full-mode.test.mcp.yml" --config "aegis.config.with-dw.json" --verbose
# aegis "tests/mcp/yaml/get-system-object-definitions.full-mode.test.mcp.yml" --config "aegis.config.with-dw.json" --debug --timing
# aegis query get_system_object_definitions '{}' --config "aegis.config.with-dw.json"
# aegis query get_system_object_definitions '{"start": 0, "count": 3}' --config "aegis.config.with-dw.json"
# aegis query get_system_object_definitions '{"select": "(start, count, data.(object_type, display_name))", "count": 3}' --config "aegis.config.with-dw.json"
# ==================================================================================

description: "get_system_object_definitions tool tests - Retrieve all SFCC system object definitions"

# ==================================================================================
# TOOL AVAILABILITY VALIDATION
# ==================================================================================
tests:
  - it: "should include get_system_object_definitions tool in available tools"
    request:
      jsonrpc: "2.0"
      id: "tool-available"
      method: "tools/list"
      params: {}
    expect:
      response:
        jsonrpc: "2.0"
        id: "tool-available"
        result:
          tools: "match:arrayContains:name:get_system_object_definitions"
      stderr: "toBeEmpty"

# ==================================================================================
# CORE FUNCTIONALITY TESTS
# ==================================================================================

  - it: "should retrieve system object definitions with default parameters"
    request:
      jsonrpc: "2.0"
      id: "default-params"
      method: "tools/call"
      params:
        name: "get_system_object_definitions"
        arguments: {}
    expect:
      response:
        jsonrpc: "2.0"
        id: "default-params"
        result:
          content:
            match:arrayElements:
              match:partial:
                type: "text"
                text: "match:type:string"
          isError: false
      performance:
        maxResponseTime: "3000ms"
      stderr: "toBeEmpty"

  - it: "should return valid JSON structure with OCAPI metadata"
    request:
      jsonrpc: "2.0"
      id: "json-structure"
      method: "tools/call"
      params:
        name: "get_system_object_definitions"
        arguments:
          count: 5
    expect:
      response:
        jsonrpc: "2.0"
        id: "json-structure"
        result:
          content:
            match:arrayElements:
              match:partial:
                type: "text"
                text: "match:regex:[\\s\\S]*\"_type\"[\\s\\S]*\"object_type_definitions\"[\\s\\S]*\"count\"[\\s\\S]*\"start\"[\\s\\S]*"
          isError: false

  - it: "should contain SFCC system object types in response"
    request:
      jsonrpc: "2.0"
      id: "system-objects-content"
      method: "tools/call"
      params:
        name: "get_system_object_definitions"
        arguments:
          count: 10
    expect:
      response:
        jsonrpc: "2.0"
        id: "system-objects-content"
        result:
          content:
            match:arrayElements:
              match:partial:
                type: "text"
                text: "match:regex:[\\s\\S]*\"object_type\"[\\s\\S]*(Product|Category|Order|Customer|Basket)[\\s\\S]*"
          isError: false

# ==================================================================================
# PAGINATION PARAMETER TESTS
# ==================================================================================

  - it: "should handle pagination with start and count parameters"
    request:
      jsonrpc: "2.0"
      id: "pagination-basic"
      method: "tools/call"
      params:
        name: "get_system_object_definitions"
        arguments:
          start: 2
          count: 3
    expect:
      response:
        jsonrpc: "2.0"
        id: "pagination-basic"
        result:
          content:
            match:arrayElements:
              match:partial:
                type: "text"
                text: "match:regex:[\\s\\S]*\"count\"[\\s\\S]*:[\\s]*3[\\s\\S]*\"start\"[\\s\\S]*:[\\s]*2[\\s\\S]*"
          isError: false
      performance:
        maxResponseTime: "2500ms"

  - it: "should handle zero start parameter"
    request:
      jsonrpc: "2.0"
      id: "zero-start"
      method: "tools/call"
      params:
        name: "get_system_object_definitions"
        arguments:
          start: 0
          count: 3
    expect:
      response:
        jsonrpc: "2.0"
        id: "zero-start"
        result:
          content:
            match:arrayElements:
              match:partial:
                type: "text"
                text: "match:regex:[\\s\\S]*\"start\"[\\s\\S]*:[\\s]*0[\\s\\S]*"
          isError: false

# ==================================================================================
# SELECT PARAMETER TESTS - OCAPI Field Selection
# ==================================================================================

  - it: "should handle wildcard select parameter (**)"
    request:
      jsonrpc: "2.0"
      id: "select-wildcard"
      method: "tools/call"
      params:
        name: "get_system_object_definitions"
        arguments:
          select: "(**)"
          count: 3
    expect:
      response:
        jsonrpc: "2.0"
        id: "select-wildcard"
        result:
          content:
            match:arrayElements:
              match:partial:
                type: "text"
                text: "match:regex:[\\s\\S]*\"_type\"[\\s\\S]*\"count\"[\\s\\S]*\"data\"[\\s\\S]*\"start\"[\\s\\S]*\"total\"[\\s\\S]*"
          isError: false

  - it: "should handle root-level field selection"
    request:
      jsonrpc: "2.0"
      id: "select-root-fields"
      method: "tools/call"
      params:
        name: "get_system_object_definitions"
        arguments:
          select: "(start, count, total)"
          count: 3
    expect:
      response:
        jsonrpc: "2.0"
        id: "select-root-fields"
        result:
          content:
            match:arrayElements:
              match:partial:
                type: "text"
                text: "match:regex:[\\s\\S]*\"start\"[\\s\\S]*\"count\"[\\s\\S]*\"total\"[\\s\\S]*"
          isError: false

  - it: "should exclude non-selected fields when using specific selection"
    request:
      jsonrpc: "2.0"
      id: "select-exclude-fields"
      method: "tools/call"
      params:
        name: "get_system_object_definitions"
        arguments:
          select: "(start, count)"
          count: 2
    expect:
      response:
        jsonrpc: "2.0"
        id: "select-exclude-fields"
        result:
          content:
            match:arrayElements:
              match:partial:
                type: "text"
                text: "match:regex:[\\s\\S]*\"start\"[\\s\\S]*\"count\"[\\s\\S]*"
          isError: false

  - it: "should handle data-level field selection"
    request:
      jsonrpc: "2.0"
      id: "select-data-fields"
      method: "tools/call"
      params:
        name: "get_system_object_definitions"
        arguments:
          select: "(start, count, data.(object_type, display_name))"
          count: 3
    expect:
      response:
        jsonrpc: "2.0"
        id: "select-data-fields"
        result:
          content:
            match:arrayElements:
              match:partial:
                type: "text"
                text: "match:regex:[\\s\\S]*\"start\"[\\s\\S]*\"count\"[\\s\\S]*\"data\"[\\s\\S]*\"object_type\"[\\s\\S]*\"display_name\"[\\s\\S]*"
          isError: false

# ==================================================================================
# EDGE CASES AND BOUNDARY CONDITIONS  
# ==================================================================================

  - it: "should handle minimum count parameter"
    request:
      jsonrpc: "2.0"
      id: "edge-min-count"
      method: "tools/call"
      params:
        name: "get_system_object_definitions"
        arguments:
          count: 1
    expect:
      response:
        jsonrpc: "2.0"
        id: "edge-min-count"
        result:
          content:
            match:arrayElements:
              match:partial:
                type: "text"
                text: "match:regex:[\\s\\S]*\"count\"[\\s\\S]*:[\\s]*1[\\s\\S]*"
          isError: false

  - it: "should handle large start parameter gracefully"
    request:
      jsonrpc: "2.0"
      id: "edge-large-start"
      method: "tools/call"
      params:
        name: "get_system_object_definitions"
        arguments:
          start: 1000
          count: 5
    expect:
      response:
        jsonrpc: "2.0"
        id: "edge-large-start"
        result:
          content:
            match:arrayElements:
              match:partial:
                type: "text"
                text: "match:type:string"
          isError: false

  - it: "should handle maximum reasonable count parameter"
    request:
      jsonrpc: "2.0"
      id: "edge-max-count"
      method: "tools/call"
      params:
        name: "get_system_object_definitions"
        arguments:
          count: 200
    expect:
      response:
        jsonrpc: "2.0"
        id: "edge-max-count"
        result:
          content:
            match:arrayElements:
              match:partial:
                type: "text"
                text: "match:type:string"
          isError: false
      performance:
        maxResponseTime: "5000ms"

# ==================================================================================
# PARAMETER VALIDATION TESTS
# ==================================================================================

  - it: "should handle string start parameter (type coercion)"
    request:
      jsonrpc: "2.0"
      id: "param-string-start"
      method: "tools/call"
      params:
        name: "get_system_object_definitions"
        arguments:
          start: "5"
          count: 2
    expect:
      response:
        jsonrpc: "2.0"
        id: "param-string-start"
        result:
          content:
            match:arrayElements:
              match:partial:
                type: "text"
                text: "match:type:string"
          isError: false

  - it: "should handle string count parameter (type coercion)"
    request:
      jsonrpc: "2.0"
      id: "param-string-count"
      method: "tools/call"
      params:
        name: "get_system_object_definitions"
        arguments:
          start: 0
          count: "3"
    expect:
      response:
        jsonrpc: "2.0"
        id: "param-string-count"
        result:
          content:
            match:arrayElements:
              match:partial:
                type: "text"
                text: "match:type:string"
          isError: false

  - it: "should handle negative start parameter gracefully"
    request:
      jsonrpc: "2.0"
      id: "negative-start"
      method: "tools/call"
      params:
        name: "get_system_object_definitions"
        arguments:
          start: -1
          count: 3
    expect:
      response:
        jsonrpc: "2.0"
        id: "negative-start"
        result:
          content:
            match:arrayElements:
              match:partial:
                type: "text"
                text: "match:type:string"
          isError: false

  - it: "should handle zero count parameter"
    request:
      jsonrpc: "2.0"
      id: "zero-count"
      method: "tools/call"
      params:
        name: "get_system_object_definitions"
        arguments:
          start: 0
          count: 0
    expect:
      response:
        jsonrpc: "2.0"
        id: "zero-count"
        result:
          content:
            match:arrayElements:
              match:partial:
                type: "text"
                text: "match:type:string"
          isError: false

  - it: "should handle invalid select patterns gracefully"
    request:
      jsonrpc: "2.0"
      id: "select-invalid"
      method: "tools/call"
      params:
        name: "get_system_object_definitions"
        arguments:
          select: "invalid_pattern_without_parentheses"
          count: 2
    expect:
      response:
        jsonrpc: "2.0"
        id: "select-invalid"
        result:
          content:
            match:arrayElements:
              match:partial:
                type: "text"
                text: "match:type:string"
          isError: false

  - it: "should handle empty select parameter"
    request:
      jsonrpc: "2.0"
      id: "select-empty"
      method: "tools/call"
      params:
        name: "get_system_object_definitions"
        arguments:
          select: ""
          count: 2
    expect:
      response:
        jsonrpc: "2.0"
        id: "select-empty"
        result:
          content:
            match:arrayElements:
              match:partial:
                type: "text"
                text: "match:type:string"
          isError: false

# ==================================================================================
# DATA VALIDATION AND CONSISTENCY
# ==================================================================================

  - it: "should return proper SFCC object type definition structure"
    request:
      jsonrpc: "2.0"
      id: "data-structure"
      method: "tools/call"
      params:
        name: "get_system_object_definitions"
        arguments:
          count: 3
    expect:
      response:
        jsonrpc: "2.0"
        id: "data-structure"
        result:
          content:
            match:arrayElements:
              match:partial:
                type: "text"
                text: "match:regex:[\\s\\S]*\"_type\"[\\s\\S]*\"object_type_definition\"[\\s\\S]*\"object_type\"[\\s\\S]*"
          isError: false

  - it: "should maintain consistent results across multiple calls"
    request:
      jsonrpc: "2.0"
      id: "consistency-check"
      method: "tools/call"
      params:
        name: "get_system_object_definitions"
        arguments:
          start: 0
          count: 3
    expect:
      response:
        jsonrpc: "2.0"
        id: "consistency-check"
        result:
          content:
            match:arrayElements:
              match:partial:
                type: "text"
                text: "match:regex:[\\s\\S]*\"count\"[\\s\\S]*:[\\s]*3[\\s\\S]*"
          isError: false

  - it: "should include API version information"
    request:
      jsonrpc: "2.0"
      id: "api-version"
      method: "tools/call"
      params:
        name: "get_system_object_definitions"
        arguments:
          count: 1
    expect:
      response:
        jsonrpc: "2.0"
        id: "api-version"
        result:
          content:
            match:arrayElements:
              match:partial:
                type: "text"
                text: "match:regex:[\\s\\S]*\"_v\"[\\s\\S]*\"\\d+\\.\\d+\"[\\s\\S]*"
          isError: false
```

--------------------------------------------------------------------------------
/docs/dw_util/SecureEncoder.md:
--------------------------------------------------------------------------------

```markdown
## Package: dw.util

# Class SecureEncoder

## Inheritance Hierarchy

- Object
  - dw.util.SecureEncoder

## Description

SecureEncoder contains many methods for manipulating untrusted data Strings into RFC-Compliant Strings for a given context by encoding "bad" data into the proper format.

## Constructor Summary

## Method Summary

### forHtmlContent

**Signature:** `static forHtmlContent(input : String) : String`

Encodes a given input for use in a general HTML context.

### forHtmlInDoubleQuoteAttribute

**Signature:** `static forHtmlInDoubleQuoteAttribute(input : String) : String`

Encodes a given input for use in an HTML Attribute guarded by a double quote.

### forHtmlInSingleQuoteAttribute

**Signature:** `static forHtmlInSingleQuoteAttribute(input : String) : String`

Encodes a given input for use in an HTML Attribute guarded by a single quote.

### forHtmlUnquotedAttribute

**Signature:** `static forHtmlUnquotedAttribute(input : String) : String`

Encodes a given input for use in an HTML Attribute left unguarded.

### forJavaScriptInAttribute

**Signature:** `static forJavaScriptInAttribute(input : String) : String`

Encodes a given input for use in JavaScript inside an HTML attribute.

### forJavaScriptInBlock

**Signature:** `static forJavaScriptInBlock(input : String) : String`

Encodes a given input for use in JavaScript inside an HTML block.

### forJavaScriptInHTML

**Signature:** `static forJavaScriptInHTML(input : String) : String`

Encodes a given input for use in JavaScript inside an HTML context.

### forJavaScriptInSource

**Signature:** `static forJavaScriptInSource(input : String) : String`

Encodes a given input for use in JavaScript inside a JavaScript source file.

### forJSONValue

**Signature:** `static forJSONValue(input : String) : String`

Encodes a given input for use in a JSON Object Value to prevent escaping into a trusted context.

### forUriComponent

**Signature:** `static forUriComponent(input : String) : String`

Encodes a given input for use as a component of a URI.

### forUriComponentStrict

**Signature:** `static forUriComponentStrict(input : String) : String`

Encodes a given input for use as a component of a URI.

### forXmlCommentContent

**Signature:** `static forXmlCommentContent(input : String) : String`

Encodes a given input for use in an XML comments.

### forXmlContent

**Signature:** `static forXmlContent(input : String) : String`

Encodes a given input for use in a general XML context.

### forXmlInDoubleQuoteAttribute

**Signature:** `static forXmlInDoubleQuoteAttribute(input : String) : String`

Encodes a given input for use in an XML attribute guarded by a double quote.

### forXmlInSingleQuoteAttribute

**Signature:** `static forXmlInSingleQuoteAttribute(input : String) : String`

Encodes a given input for use in an XML attribute guarded by a single quote.

## Method Detail

## Method Details

### forHtmlContent

**Signature:** `static forHtmlContent(input : String) : String`

**Description:** Encodes a given input for use in a general HTML context. E.g. text content and text attributes. This method takes the UNION of allowed characters between the two context, so may be more imprecise that the more specific contexts. Generally, this method is preferred unless you specifically understand the context in which untrusted data will be output. Example Usage: <div>${SecureEncoder.forHtmlContent(unsafeData)}</div> <input value="${SecureEncoder.forHtmlContent(unsafeData)}" /> Flow: Allow AlphaNumerics and some Special characters Replace Illegal Control Characters (Below 0x1F or between 0x7F and 0x9F) with &#xfffd;, the Unicode Replacement Character Replace special HTML characters with their HTML Entity equivalents

**Parameters:**

- `input`: untrusted input to be encoded, if necessary

**Returns:**

a properly encoded string for the given input

---

### forHtmlInDoubleQuoteAttribute

**Signature:** `static forHtmlInDoubleQuoteAttribute(input : String) : String`

**Description:** Encodes a given input for use in an HTML Attribute guarded by a double quote. This method is preferred if you understand exactly how the output of this will be used in the HTML document. Example Usage: <div id="${SecureEncoder.forHtmlInDoubleQuoteAttribute(unsafeData)}"></div> Flow: Allow AlphaNumerics and some Special characters Replace Illegal Control Characters (Below 0x1F or between 0x7F and 0x9F) with &#xfffd;, the Unicode Replacement Character Replace special HTML characters with their HTML Entity equivalents

**Parameters:**

- `input`: untrusted input to be encoded, if necessary

**Returns:**

a properly encoded string for the given input

---

### forHtmlInSingleQuoteAttribute

**Signature:** `static forHtmlInSingleQuoteAttribute(input : String) : String`

**Description:** Encodes a given input for use in an HTML Attribute guarded by a single quote. This method is preferred if you understand exactly how the output of this will be used in the HTML document. Example Usage: <div id='${SecureEncoder.forHtmlInSingleQuoteAttribute(unsafeData)}'></div> Flow: Allow AlphaNumerics and some Special characters Replace Illegal Control Characters (Below 0x1F or between 0x7F and 0x9F) with &#xfffd;, the Unicode Replacement Character Replace special HTML characters with their HTML Entity equivalents

**Parameters:**

- `input`: untrusted input to be encoded, if necessary

**Returns:**

a properly encoded string for the given input

---

### forHtmlUnquotedAttribute

**Signature:** `static forHtmlUnquotedAttribute(input : String) : String`

**Description:** Encodes a given input for use in an HTML Attribute left unguarded. This method is preferred if you understand exactly how the output of this will be used in the HTML document. Example Usage: <div id=${SecureEncoder.forHtmlUnquotedAttribute(unsafeData)}></div> Flow: Allow AlphaNumerics and some Special characters Replace Illegal Control Characters (Below 0x1F or between 0x7F and 0x9F) with &#xfffd;, the Unicode Replacement Character Replace special HTML characters with their HTML Entity equivalents

**Parameters:**

- `input`: untrusted input to be encoded, if necessary

**Returns:**

a properly encoded string for the given input

---

### forJavaScriptInAttribute

**Signature:** `static forJavaScriptInAttribute(input : String) : String`

**Description:** Encodes a given input for use in JavaScript inside an HTML attribute. This method is preferred if you understand exactly how the output of the will be used in the page Example Usage: <button onclick="alert('${SecureEncoder.forJavaScriptInAttribute(unsafeData)}');"> Flow: Allow AlphaNumerics and some Special characters Slash escape certain illegal characters Replace special JavaScript characters with their Hex Encoded equivalents prepended with \\x for character codes under 128 and \\u for character codes over 128

**Parameters:**

- `input`: untrusted input to be encoded, if necessary

**Returns:**

a properly encoded string for the given input

---

### forJavaScriptInBlock

**Signature:** `static forJavaScriptInBlock(input : String) : String`

**Description:** Encodes a given input for use in JavaScript inside an HTML block. This method is preferred if you understand exactly how the output of the will be used in the page Example Usage: <script type="text/javascript"> var data = "${SecureEncoder.forJavaScriptInBlock(unsafeData)}"; </script> Flow: Allow AlphaNumerics and some Special characters Slash escape certain illegal characters Replace special JavaScript characters with their Hex Encoded equivalents prepended with \\x for character codes under 128 and \\u for character codes over 128

**Parameters:**

- `input`: untrusted input to be encoded, if necessary

**Returns:**

a properly encoded string for the given input

---

### forJavaScriptInHTML

**Signature:** `static forJavaScriptInHTML(input : String) : String`

**Description:** Encodes a given input for use in JavaScript inside an HTML context. This method takes the UNION of allowed characters among the other contexts, so may be more imprecise that the more specific contexts. Generally, this method is preferred unless you specifically understand the context in which untrusted data will be output. Example Usage: <script type="text/javascript"> var data = "${SecureEncoder.forJavaScriptInHTML(unsafeData)}"; </script> <button onclick="alert('${SecureEncoder.forJavaScriptInHTML(unsafeData)}');"> Flow: Allow AlphaNumerics and some Special characters Slash escape certain illegal characters Replace special JavaScript characters with their Hex Encoded equivalents prepended with \\x for character codes under 128 and \\u for character codes over 128

**Parameters:**

- `input`: untrusted input to be encoded, if necessary

**Returns:**

a properly encoded string for the given input

---

### forJavaScriptInSource

**Signature:** `static forJavaScriptInSource(input : String) : String`

**Description:** Encodes a given input for use in JavaScript inside a JavaScript source file. This method is preferred if you understand exactly how the output of the will be used in the page Example Usage: <...inside foobar.js...> var data = "${SecureEncoder.forJavaScriptInSource(unsafeData)}"; Flow: Allow AlphaNumerics and some Special characters Slash escape certain illegal characters Replace special JavaScript characters with their Hex Encoded equivalents prepended with \\x for character codes under 128 and \\u for character codes over 128

**Parameters:**

- `input`: untrusted input to be encoded, if necessary

**Returns:**

a properly encoded string for the given input

---

### forJSONValue

**Signature:** `static forJSONValue(input : String) : String`

**Description:** Encodes a given input for use in a JSON Object Value to prevent escaping into a trusted context. Example Usage: var json = {"trusted_data" : SecureEncoder.forJSONValue(unsafeData)}; return JSON.stringify(json); Flow: Allow AlphaNumerics Slash escape certain illegal characters Replace all other characters with their Hex Encoded equivalents prepended with \\u

**Parameters:**

- `input`: untrusted input to be encoded, if necessary

**Returns:**

a properly encoded string for the given input

---

### forUriComponent

**Signature:** `static forUriComponent(input : String) : String`

**Description:** Encodes a given input for use as a component of a URI. This is equivalent to javascript's encodeURIComponent and does a realistic job of encoding. Example Usage: <a href="http://host.com?value=${SecureEncoder.forUriComponent(unsafeData)}"/> Allows: A-Z, a-z, 0-9, -, _, ., ~, !, *, ', (, ) Flow: Allow AlphaNumerics and some Special characters Percent encode all other characters

**Parameters:**

- `input`: untrusted input to be encoded, if necessary

**Returns:**

a properly encoded string for the given input

---

### forUriComponentStrict

**Signature:** `static forUriComponentStrict(input : String) : String`

**Description:** Encodes a given input for use as a component of a URI. This is a strict encoder and fully complies with RFC3986. Example Usage: <a href="http://host.com?value=${SecureEncoder.forUriComponentStrict(unsafeData)}"/> Allows: A-Z, a-z, 0-9, -, _, ., ~ Flow: Allow AlphaNumerics and some Special characters Percent encode all other characters

**Parameters:**

- `input`: untrusted input to be encoded, if necessary

**Returns:**

a properly encoded string for the given input

---

### forXmlCommentContent

**Signature:** `static forXmlCommentContent(input : String) : String`

**Description:** Encodes a given input for use in an XML comments. This method is preferred if you understand the context in which untrusted data will be output. Note: It is recommended that you use a real parser, as this method can be misused, but is left here if a parser is unavailable to you Example Usage: <!-- ${SecureEncoder.forXmlCommentContent(unsafeData)} --> Flow: Allow AlphaNumerics and some Special characters Replace Illegal Control Characters (Below 0x1F or between 0x7F and 0x84 or between 0x86 and 0x9F or between 0xFDD0 and 0xFDDF) with an empty string Replace special XML characters with their default XML Entity equivalents

**Parameters:**

- `input`: untrusted input to be encoded, if necessary

**Returns:**

a properly encoded string for the given input

---

### forXmlContent

**Signature:** `static forXmlContent(input : String) : String`

**Description:** Encodes a given input for use in a general XML context. E.g. text content and text attributes. This method takes the UNION of allowed characters between the other contexts, so may be more imprecise that the more specific contexts. Generally, this method is preferred unless you specifically understand the context in which untrusted data will be output. Note: It is recommended that you use a real parser, as this method can be misused, but is left here if a parser is unavailable to you Example Usage: <foo>${SecureEncoder.forXmlContent(unsafeData)}</foo> <bar attr="${SecureEncoder.forXmlContent(unsafeData)}"></bar> Flow: Allow AlphaNumerics and some Special characters Replace Illegal Control Characters (Below 0x1F or between 0x7F and 0x84 or between 0x86 and 0x9F or between 0xFDD0 and 0xFDDF) with an empty string Replace special XML characters with their default XML Entity equivalents

**Parameters:**

- `input`: untrusted input to be encoded, if necessary

**Returns:**

a properly encoded string for the given input

---

### forXmlInDoubleQuoteAttribute

**Signature:** `static forXmlInDoubleQuoteAttribute(input : String) : String`

**Description:** Encodes a given input for use in an XML attribute guarded by a double quote. This method is preferred if you understand the context in which untrusted data will be output. Note: It is recommended that you use a real parser, as this method can be misused, but is left here if a parser is unavailable to you Example Usage: <bar attr="${SecureEncoder.forXmlInDoubleQuoteAttribute(unsafeData)}"></bar> Flow: Allow AlphaNumerics and some Special characters Replace Illegal Control Characters (Below 0x1F or between 0x7F and 0x84 or between 0x86 and 0x9F or between 0xFDD0 and 0xFDDF) with an empty string Replace special XML characters with their default XML Entity equivalents

**Parameters:**

- `input`: untrusted input to be encoded, if necessary

**Returns:**

a properly encoded string for the given input

---

### forXmlInSingleQuoteAttribute

**Signature:** `static forXmlInSingleQuoteAttribute(input : String) : String`

**Description:** Encodes a given input for use in an XML attribute guarded by a single quote. This method is preferred if you understand the context in which untrusted data will be output. Note: It is recommended that you use a real parser, as this method can be misused, but is left here if a parser is unavailable to you Example Usage: <bar attr='${SecureEncoder.forXmlInSingleQuoteAttribute(unsafeData)}'></bar> Flow: Allow AlphaNumerics and some Special characters Replace Illegal Control Characters (Below 0x1F or between 0x7F and 0x84 or between 0x86 and 0x9F or between 0xFDD0 and 0xFDDF) with an empty string Replace special XML characters with their default XML Entity equivalents

**Parameters:**

- `input`: untrusted input to be encoded, if necessary

**Returns:**

a properly encoded string for the given input

---
```

--------------------------------------------------------------------------------
/tests/mcp/node/get-latest-info.full-mode.programmatic.test.js:
--------------------------------------------------------------------------------

```javascript
import { test, describe, before, after, beforeEach } from 'node:test';
import { strict as assert } from 'node:assert';
import { connect } from 'mcp-aegis';

describe('get_latest_info Tool - Advanced Programmatic Tests (Full Mode)', () => {
  let client;

  before(async () => {
    client = await connect('./aegis.config.with-dw.json');
  });

  after(async () => {
    if (client?.connected) {
      await client.disconnect();
    }
  });

  beforeEach(() => {
    // CRITICAL: Clear all buffers to prevent leaking into next tests
    client.clearAllBuffers();
  });

  // Helper function to get current date in YYYYMMDD format
  function getCurrentDateString() {
    const now = new Date();
    const year = now.getFullYear();
    const month = String(now.getMonth() + 1).padStart(2, '0');
    const day = String(now.getDate()).padStart(2, '0');
    return `${year}${month}${day}`;
  }

  // ========================================
  // COMPLEX BUSINESS LOGIC VALIDATION
  // ========================================

  describe('Complex Business Logic Validation', () => {
    test('should return info messages in chronological order with detailed parsing', async () => {
      const result = await client.callTool('get_latest_info', { limit: 2 });
      
      assertValidMCPResponse(result);
      const text = result.content[0].text;
      
      // Complex chronological order validation - requires detailed parsing and comparison
      const jobExecution = 'Executing job [sfcc-export-dw-analytics-site-config][2664334]';
      const stepExecution = 'Executing step [ExportDWAnalyticsSiteConfigurationStep][5846619] for [Organization]';
      
      assert.ok(text.includes(jobExecution), 'Should contain job execution entry');
      assert.ok(text.includes(stepExecution), 'Should contain step execution entry');
      
      // Verify chronological ordering through position analysis
      const jobIndex = text.indexOf(jobExecution);
      const stepIndex = text.indexOf(stepExecution);
      assert.ok(jobIndex < stepIndex && jobIndex !== -1 && stepIndex !== -1,
        'Newest info (job) should appear before older info (step) in response');
    });

    test('should validate business logic for SFCC info-level log filtering', async () => {
      const result = await client.callTool('get_latest_info', { limit: 10 });
      
      assertValidMCPResponse(result);
      const logText = result.content[0].text;
      
      // Complex business logic validation - SFCC-specific log filtering
      assert.ok(logText.includes('info-blade'), 'Should reference info log files specifically');
      assert.ok(logText.includes('INFO'), 'Should contain INFO log level entries');
      
      // Critical: Verify log level isolation (complex filtering validation)
      assert.ok(!logText.includes('ERROR'), 'Should not contain ERROR entries');
      assert.ok(!logText.includes('WARN'), 'Should not contain WARN entries');
      assert.ok(!logText.includes('DEBUG'), 'Should not contain DEBUG entries');
    });

    test('should parse and validate complex SFCC log entry structure', async () => {
      const result = await client.callTool('get_latest_info', { limit: 1 });
      
      assertValidMCPResponse(result);
      const logText = result.content[0].text;
      
      // Complex log structure parsing and validation
      const timestampPattern = /\[\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3} GMT\]/;
      const sfccPattern = /(SystemJobThread|PipelineCallServlet|Sites-)/;
      
      assert.ok(timestampPattern.test(logText), 'Should contain valid SFCC timestamp format');
      assert.ok(sfccPattern.test(logText), 'Should contain SFCC-specific system components');
      
      // Complex structure validation
      assert.ok(logText.includes('['), 'Should contain log file reference brackets');
      assert.ok(logText.includes('] ['), 'Should contain proper timestamp delimiters');
      assert.ok(logText.includes('GMT]'), 'Should contain GMT timezone specification');
    });
  });

  // ========================================
  // DYNAMIC PARAMETER VALIDATION
  // ========================================

  describe('Dynamic Parameter Validation', () => {
    test('should validate parameter types dynamically with complex logic', async () => {
      const testCases = [
        { params: { limit: null }, shouldSucceed: false, description: 'null limit' },
        { params: { limit: undefined }, shouldSucceed: true, description: 'undefined limit (uses default)' },
        { params: { limit: [] }, shouldSucceed: false, description: 'array limit' },
        { params: { limit: {} }, shouldSucceed: false, description: 'object limit' },
        { params: { date: null }, shouldSucceed: true, description: 'null date (uses default)' },
        { params: { date: 123 }, shouldSucceed: true, description: 'numeric date (handled gracefully)' }
      ];

      // Complex dynamic validation with detailed result analysis
      for (const testCase of testCases) {
        const result = await client.callTool('get_latest_info', testCase.params);
        assertValidMCPResponse(result);
        
        if (testCase.shouldSucceed) {
          assert.ok(result.content.length > 0, 
            `Should have content for ${testCase.description}: ${JSON.stringify(testCase.params)}`);
        } else {
          // Complex validation: either error response or graceful handling
          assert.ok(result.isError || result.content.length > 0,
            `Should either error or handle gracefully for ${testCase.description}`);
        }
      }
    });

    test('should handle complex boundary condition matrix', async () => {
      const boundaryTests = [
        { limit: 1, shouldSucceed: true, category: 'minimum valid' },
        { limit: 1000, shouldSucceed: true, category: 'maximum valid' },
        { limit: 1001, shouldSucceed: false, category: 'over maximum' },
        { limit: 0, shouldSucceed: false, category: 'zero (invalid)' },
        { limit: -1, shouldSucceed: false, category: 'negative' }
      ];
      
      // Complex boundary validation with categorization
      for (const test of boundaryTests) {
        const result = await client.callTool('get_latest_info', { limit: test.limit });
        assertValidMCPResponse(result);
        
        if (test.shouldSucceed) {
          assert.equal(result.isError, false, 
            `Boundary test ${test.category} (limit: ${test.limit}) should succeed`);
        } else {
          assert.equal(result.isError, true, 
            `Boundary test ${test.category} (limit: ${test.limit}) should fail validation`);
        }
      }
    });
  });

  // ========================================
  // MULTI-STEP WORKFLOWS AND CONSISTENCY
  // ========================================

  describe('Multi-Step Workflows and Consistency', () => {
    test('should maintain consistency across sequential operations', async () => {
      const results = [];
      
      // Complex multi-step workflow simulation
      for (let i = 0; i < 5; i++) {
        const result = await client.callTool('get_latest_info', { limit: 5 });
        results.push(result);
      }
      
      // Complex consistency validation across multiple calls
      results.forEach((result, index) => {
        assertValidMCPResponse(result);
        assert.equal(result.isError, false, `Sequential call ${index + 1} should succeed`);
        assert.ok(result.content[0].text.includes('Latest 5 info messages'), 
          `Sequential call ${index + 1} should show consistent limit`);
      });
      
      // Complex cross-result consistency validation
      const firstText = results[0].content[0].text;
      const lastText = results[results.length - 1].content[0].text;
      assert.equal(firstText, lastText, 'Sequential calls should return identical results for same parameters');
    });

    test('should handle complex parameter combination workflows', async () => {
      const paramCombinations = [
        {},
        { limit: 5 },
        { date: getCurrentDateString() },
        { limit: 3, date: getCurrentDateString() },
        { limit: 1 },
        { limit: 50 }
      ];
      
      // Complex workflow validation with parameter combinations
      for (const params of paramCombinations) {
        const result = await client.callTool('get_latest_info', params);
        assertValidMCPResponse(result);
        
        // Complex validation logic for parameter combinations
        const hasValidLimit = !params.limit || (params.limit > 0 && params.limit <= 1000);
        if (hasValidLimit) {
          assert.equal(result.isError, false, 
            `Valid parameter combination should succeed: ${JSON.stringify(params)}`);
          
          // Verify expected limit is reflected in response
          const expectedLimit = params.limit || 10; // default limit
          assert.ok(result.content[0].text.includes(`Latest ${expectedLimit} info messages`),
            `Should show correct limit for combination: ${JSON.stringify(params)}`);
        }
      }
    });

    test('should validate complex limit range processing', async () => {
      const limitTests = [1, 5, 10, 25, 50, 100];
      
      // Complex range validation with detailed analysis
      for (const limit of limitTests) {
        const result = await client.callTool('get_latest_info', { limit });
        
        assertValidMCPResponse(result);
        assert.equal(result.isError, false, `Limit ${limit} should process successfully`);
        assert.ok(result.content[0].text.includes(`Latest ${limit} info messages`), 
          `Should correctly process limit ${limit}`);
        
        // Complex content length analysis
        const logText = result.content[0].text;
        const separatorCount = (logText.match(/---/g) || []).length;
        
        // Validate separator count matches expected entries (limit - 1 separators for limit entries)
        if (limit > 1) {
          assert.ok(separatorCount >= 1, 
            `Should have separators for limit ${limit} (found ${separatorCount})`);
        }
      }
    });
  });

  // ========================================
  // ERROR RECOVERY AND RESILIENCE
  // ========================================

  describe('Error Recovery and Resilience', () => {
    test('should demonstrate complex error recovery workflow', async () => {
      // Complex error recovery scenario with state validation
      
      // Step 1: Trigger error condition
      const errorResult = await client.callTool('get_latest_info', { limit: -1 });
      assert.equal(errorResult.isError, true, 'Should error with negative limit');
      
      // Step 2: Verify normal operation resumes immediately
      const normalResult = await client.callTool('get_latest_info', { limit: 5 });
      assertValidMCPResponse(normalResult);
      assert.equal(normalResult.isError, false, 'Should recover and work normally');
      
      // Step 3: Verify complex recovery with different parameters
      const recoveryResult = await client.callTool('get_latest_info', { 
        limit: 3, 
        date: getCurrentDateString() 
      });
      assertValidMCPResponse(recoveryResult);
      assert.equal(recoveryResult.isError, false, 'Should handle complex parameters after error');
    });

    test('should maintain state integrity after complex invalid operations', async () => {
      // Complex state integrity validation
      const invalidOperations = [
        { limit: -10, description: 'negative limit' },
        { limit: 'abc', description: 'string limit' },
        { date: 'invalid', description: 'invalid date' },
        { limit: null, description: 'null limit' },
        { limit: 1001, description: 'over-limit' }
      ];
      
      // Execute complex series of invalid operations
      for (const invalidOp of invalidOperations) {
        await client.callTool('get_latest_info', invalidOp);
        // Note: Don't assert on individual results as some may be handled gracefully
      }
      
      // Complex state validation after error series
      const result = await client.callTool('get_latest_info', { limit: 3 });
      assertValidMCPResponse(result);
      assert.equal(result.isError, false, 'Should work normally after series of invalid operations');
      assert.ok(result.content[0].text.includes('Latest 3 info messages'),
        'Should produce correct output after error recovery');
    });
  });

  // ========================================
  // INTEGRATION AND PROTOCOL COMPLIANCE
  // ========================================

  describe('Integration and Protocol Compliance', () => {
    test('should integrate properly with MCP protocol and tool discovery', async () => {
      // Complex MCP protocol compliance validation
      const tools = await client.listTools();
      const infoTool = tools.find(tool => tool.name === 'get_latest_info');
      
      assert.ok(infoTool, 'get_latest_info tool should be discoverable via MCP protocol');
      assert.ok(infoTool.description, 'Tool should have comprehensive description');
      assert.ok(infoTool.inputSchema, 'Tool should have valid input schema');
      
      // Complex schema validation
      const schema = infoTool.inputSchema;
      assert.equal(schema.type, 'object', 'Input schema should be object type');
      assert.ok(schema.properties, 'Schema should define properties');
      
      // Verify tool execution works through MCP protocol
      const result = await client.callTool('get_latest_info', {});
      assertValidMCPResponse(result);
      assert.equal(result.isError, false, 'Tool should execute successfully via MCP protocol');
    });

    test('should validate complex date parameter integration', async () => {
      // Complex date parameter validation with current date integration
      const testDate = getCurrentDateString();
      
      const result = await client.callTool('get_latest_info', { 
        date: testDate, 
        limit: 2 
      });
      
      assertValidMCPResponse(result);
      assert.equal(result.isError, false, 'Should handle current date parameter');
      assert.ok(result.content[0].text.includes('Latest 2 info messages'), 
        'Should show correct limit with date parameter');
      
      // Complex validation: date parameter should not affect content structure
      const defaultResult = await client.callTool('get_latest_info', { limit: 2 });
      assertValidMCPResponse(defaultResult);
      
      // Compare structure consistency
      const dateTextLines = result.content[0].text.split('\n').length;
      const defaultTextLines = defaultResult.content[0].text.split('\n').length;
      assert.ok(Math.abs(dateTextLines - defaultTextLines) <= 1,
        'Date parameter should not significantly alter response structure');
    });
  });
});

// ========================================
// HELPER FUNCTIONS
// ========================================

/**
 * Validates that a result follows the MCP response structure
 */
function assertValidMCPResponse(result) {
  assert.ok(result, 'Result should exist');
  assert.ok(result.content, 'Result should have content');
  assert.ok(Array.isArray(result.content), 'Content should be array');
  assert.equal(typeof result.isError, 'boolean', 'isError should be boolean');
  assert.ok(result.content.length > 0, 'Content should not be empty');
}

```
Page 19/43FirstPrevNextLast