This is page 6 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 -------------------------------------------------------------------------------- /src/clients/ocapi/system-objects-client.ts: -------------------------------------------------------------------------------- ```typescript /** * OCAPI System Objects Client * * This module handles all SFCC system object related operations including * object definitions, attribute definitions, and attribute groups. */ import { OCAPIConfig } from '../../types/types.js'; import { OCAPIAuthClient } from '../base/ocapi-auth-client.js'; import { QueryBuilder } from '../../utils/query-builder.js'; import { Validator } from '../../utils/validator.js'; import { buildOCAPIBaseUrl } from '../../utils/ocapi-url-builder.js'; /** * Interface for common query parameters */ interface BaseQueryParams { start?: number; count?: number; select?: string; } /** * Interface for search request structure */ interface SearchRequest { query?: { text_query?: { fields: string[]; search_phrase: string; }; term_query?: { fields: string[]; operator: string; values: any[]; }; filtered_query?: { filter: any; query: any; }; bool_query?: { must?: any[]; must_not?: any[]; should?: any[]; }; match_all_query?: {}; }; sorts?: Array<{ field: string; sort_order?: 'asc' | 'desc'; }>; start?: number; count?: number; select?: string; } /** * OCAPI System Objects Client * Specialized client for system object operations */ export class OCAPISystemObjectsClient extends OCAPIAuthClient { constructor(config: OCAPIConfig) { super(config); // Override the baseUrl for this specialized client this.baseUrl = buildOCAPIBaseUrl(config); } /** * Get all system object definitions */ async getSystemObjectDefinitions(params?: BaseQueryParams): Promise<any> { let endpoint = '/system_object_definitions'; if (params) { const queryString = QueryBuilder.fromObject(params); if (queryString) { endpoint += `?${queryString}`; } } return this.get(endpoint); } /** * Get a specific system object definition by object type */ async getSystemObjectDefinition(objectType: string): Promise<any> { Validator.validateRequired({ objectType }, ['objectType']); Validator.validateObjectType(objectType); const endpoint = `/system_object_definitions/${encodeURIComponent(objectType)}`; return this.get(endpoint); } /** * Search for system object definitions using complex queries */ async searchSystemObjectDefinitions(searchRequest: SearchRequest): Promise<any> { Validator.validateSearchRequest(searchRequest); const endpoint = '/system_object_definition_search'; return this.post(endpoint, searchRequest); } /** * Search attribute definitions for a specific system object type */ async searchSystemObjectAttributeDefinitions( objectType: string, searchRequest: SearchRequest, ): Promise<any> { Validator.validateRequired({ objectType }, ['objectType']); Validator.validateObjectType(objectType); Validator.validateSearchRequest(searchRequest); const endpoint = `/system_object_definitions/${encodeURIComponent(objectType)}/attribute_definition_search`; return this.post(endpoint, searchRequest); } /** * Search attribute groups for a specific system object type */ async searchSystemObjectAttributeGroups( objectType: string, searchRequest: SearchRequest, ): Promise<any> { Validator.validateRequired({ objectType }, ['objectType']); Validator.validateObjectType(objectType); Validator.validateSearchRequest(searchRequest); const endpoint = `/system_object_definitions/${encodeURIComponent(objectType)}/attribute_group_search`; return this.post(endpoint, searchRequest); } /** * Search attribute definitions for a specific custom object type */ async searchCustomObjectAttributeDefinitions( objectType: string, searchRequest: SearchRequest, ): Promise<any> { Validator.validateRequired({ objectType }, ['objectType']); Validator.validateSearchRequest(searchRequest); const endpoint = `/custom_object_definitions/${encodeURIComponent(objectType)}/attribute_definition_search`; return this.post(endpoint, searchRequest); } } ``` -------------------------------------------------------------------------------- /src/utils/log-tool-utils.ts: -------------------------------------------------------------------------------- ```typescript import { ToolArguments } from '../core/handlers/base-handler.js'; import { SFCCLogClient } from '../clients/log-client.js'; import { LogLevel, isValidLogLevel } from './log-tool-constants.js'; /** * Configuration interface for tool dispatch */ export interface ToolSpec<T = any> { validate?: (args: ToolArguments, toolName: string) => void; defaults?: (args: ToolArguments) => Record<string, any>; exec: (args: ToolArguments, client: SFCCLogClient) => Promise<T>; logMessage: (args: ToolArguments) => string; } /** * Validation utilities for log tools */ export class LogToolValidators { static validateLogLevel(level: string, toolName: string): void { if (!isValidLogLevel(level)) { throw new Error(`Invalid log level '${level}' for ${toolName}. Valid levels: ${Object.values(LogLevel).join(', ')}`); } } static validateLimit(limit: number | undefined, toolName: string): void { if (limit !== undefined) { // Validate type first if (typeof limit !== 'number' || isNaN(limit)) { throw new Error(`Invalid limit '${limit}' for ${toolName}. Must be a valid number`); } // Then validate range if (limit <= 0 || limit > 1000) { throw new Error(`Invalid limit '${limit}' for ${toolName}. Must be between 1 and 1000`); } } } static validateMaxBytes(maxBytes: number | undefined, toolName: string): void { if (maxBytes !== undefined) { // Validate type first if (typeof maxBytes !== 'number' || isNaN(maxBytes)) { throw new Error(`Invalid maxBytes '${maxBytes}' for ${toolName}. Must be a valid number`); } // Then validate range if (maxBytes <= 0 || maxBytes > 10_000_000) { // 10MB limit throw new Error(`Invalid maxBytes '${maxBytes}' for ${toolName}. Must be between 1 and 10,000,000`); } } } static validateFilename(filename: string, toolName: string): void { if (!filename || filename.trim().length === 0) { throw new Error(`Filename is required for ${toolName}`); } // Prevent path traversal if (filename.includes('..') || filename.includes('\\')) { throw new Error(`Invalid filename '${filename}' for ${toolName}. Path traversal not allowed`); } } } /** * Message formatting utilities for log tools */ export class LogMessageFormatter { static formatLatestLogs(level: string, limit: number, date?: string): string { return `Fetching latest ${level} logs limit=${limit} date=${date ?? 'today'}`; } static formatSummarizeLogs(date?: string): string { return `Summarizing logs for date ${date ?? 'today'}`; } static formatSearchLogs(pattern: string, logLevel?: string, limit?: number, _date?: string): string { // For backward compatibility with existing tests, don't include date in message return `Searching logs pattern="${pattern}" level=${logLevel ?? 'all'} limit=${limit ?? 20}`; } static formatListLogFiles(): string { return 'Listing log files'; } static formatGetLogFileContents(filename: string, maxBytes?: number, tailOnly?: boolean): string { return `Reading log file contents: ${filename} (maxBytes=${maxBytes ?? 'default'}, tailOnly=${tailOnly ?? false})`; } static formatJobLogMessage(operation: string, params: Record<string, any>): string { const paramStr = Object.entries(params) .filter(([_, value]) => value !== undefined) .map(([key, value]) => `${key}=${value}`) .join(' '); return paramStr ? `${operation} ${paramStr}` : operation; } } /** * Utility functions for argument processing */ export class LogToolUtils { static applyDefaults(spec: ToolSpec, args: ToolArguments): ToolArguments { if (!spec.defaults) { return args; } const defaults = spec.defaults(args); return { ...args, ...defaults }; } static createValidatedArgs(spec: ToolSpec, args: ToolArguments, toolName: string): ToolArguments { // Apply defaults first const processedArgs = LogToolUtils.applyDefaults(spec, args); // Validate if validator exists if (spec.validate) { spec.validate(processedArgs, toolName); } return processedArgs; } } ``` -------------------------------------------------------------------------------- /docs/dw_order/AbstractItem.md: -------------------------------------------------------------------------------- ```markdown ## Package: dw.order # Class AbstractItem ## Inheritance Hierarchy - Object - dw.object.Extensible - dw.order.AbstractItem ## Description An item which references, or in other words is based upon, an OrderItem. Provides methods to access the OrderItem, the order LineItem which has been extended, and the Order. In addition it defines methods to access item level prices and the item id. Supports custom-properties. ## Properties ### grossPrice **Type:** Money (Read Only) Gross price of item. ### itemID **Type:** String (Read Only) The item-id used for referencing between items ### lineItem **Type:** LineItem (Read Only) The Order Product- or Shipping- LineItem associated with this item. Should never return null. ### netPrice **Type:** Money (Read Only) Net price of item. ### orderItem **Type:** OrderItem (Read Only) The order item extensions related to this item. Should never return null. ### orderItemID **Type:** String (Read Only) The order-item-id used for referencing the OrderItem ### tax **Type:** Money (Read Only) Total tax for item. ### taxBasis **Type:** Money (Read Only) Price of entire item on which tax calculation is based. Same as getNetPrice() or getGrossPrice() depending on whether the order is based on net or gross prices. ### taxItems **Type:** Collection (Read Only) Tax items representing a tax breakdown ## Constructor Summary ## Method Summary ### getGrossPrice **Signature:** `getGrossPrice() : Money` Gross price of item. ### getItemID **Signature:** `getItemID() : String` The item-id used for referencing between items ### getLineItem **Signature:** `getLineItem() : LineItem` Returns the Order Product- or Shipping- LineItem associated with this item. ### getNetPrice **Signature:** `getNetPrice() : Money` Net price of item. ### getOrderItem **Signature:** `getOrderItem() : OrderItem` Returns the order item extensions related to this item. ### getOrderItemID **Signature:** `getOrderItemID() : String` The order-item-id used for referencing the OrderItem ### getTax **Signature:** `getTax() : Money` Total tax for item. ### getTaxBasis **Signature:** `getTaxBasis() : Money` Price of entire item on which tax calculation is based. ### getTaxItems **Signature:** `getTaxItems() : Collection` Tax items representing a tax breakdown ## Method Detail ## Method Details ### getGrossPrice **Signature:** `getGrossPrice() : Money` **Description:** Gross price of item. **Returns:** Gross price of item. --- ### getItemID **Signature:** `getItemID() : String` **Description:** The item-id used for referencing between items **Returns:** the item-id used for referencing between items --- ### getLineItem **Signature:** `getLineItem() : LineItem` **Description:** Returns the Order Product- or Shipping- LineItem associated with this item. Should never return null. **Returns:** the Order Product- or Shipping- LineItem associated with this item --- ### getNetPrice **Signature:** `getNetPrice() : Money` **Description:** Net price of item. **Returns:** Net price of item. --- ### getOrderItem **Signature:** `getOrderItem() : OrderItem` **Description:** Returns the order item extensions related to this item. Should never return null. **Returns:** the order item extensions related to this item --- ### getOrderItemID **Signature:** `getOrderItemID() : String` **Description:** The order-item-id used for referencing the OrderItem **Returns:** the order-item-id used for referencing the OrderItem --- ### getTax **Signature:** `getTax() : Money` **Description:** Total tax for item. **Returns:** Total tax for item. --- ### getTaxBasis **Signature:** `getTaxBasis() : Money` **Description:** Price of entire item on which tax calculation is based. Same as getNetPrice() or getGrossPrice() depending on whether the order is based on net or gross prices. **Returns:** Price of entire item on which tax calculation is based --- ### getTaxItems **Signature:** `getTaxItems() : Collection` **Description:** Tax items representing a tax breakdown **Returns:** tax items representing a tax breakdown **See Also:** TaxItem --- ``` -------------------------------------------------------------------------------- /docs/dw_crypto/JWE.md: -------------------------------------------------------------------------------- ```markdown ## Package: dw.crypto # Class JWE ## Inheritance Hierarchy - Object - dw.crypto.JWE ## Description This class represents a JSON Web Encryption (JWE) object. Note: this class handles sensitive security-related data. Pay special attention to PCI DSS v3 requirements 2, 4, and 12. ## Properties ### algorithm **Type:** String (Read Only) Get the algorithm (alg) from the header. ### encryptionMethod **Type:** String (Read Only) Get the encryption method (enc) from the header. ### headerMap **Type:** Map (Read Only) Get a copy of the JWE headers as a Map. ### keyID **Type:** String (Read Only) Get the key id (kid) from the header. ### payload **Type:** String (Read Only) Get the decrypted payload. ## Constructor Summary JWE(header : JWEHeader, payload : String) Construct a new JWE for encryption. JWE(header : JWEHeader, payload : Bytes) Construct a new JWE for encryption. ## Method Summary ### decrypt **Signature:** `decrypt(privateKey : KeyRef) : void` Decrypt the payload of this JWE object. ### encrypt **Signature:** `encrypt(publicKey : CertificateRef) : void` Encrypt the payload of this JWE object. ### getAlgorithm **Signature:** `getAlgorithm() : String` Get the algorithm (alg) from the header. ### getEncryptionMethod **Signature:** `getEncryptionMethod() : String` Get the encryption method (enc) from the header. ### getHeaderMap **Signature:** `getHeaderMap() : Map` Get a copy of the JWE headers as a Map. ### getKeyID **Signature:** `getKeyID() : String` Get the key id (kid) from the header. ### getPayload **Signature:** `getPayload() : String` Get the decrypted payload. ### parse **Signature:** `static parse(jwe : String) : JWE` Parse a JSON Web Encryption (JWE) object from its compact serialization format. ### serialize **Signature:** `serialize() : String` Get this JWE in compact serialization form. ## Constructor Detail ## Method Detail ## Method Details ### decrypt **Signature:** `decrypt(privateKey : KeyRef) : void` **Description:** Decrypt the payload of this JWE object. Elliptic Curve (EC) and RSA keys are both supported. Supported EC key management algorithms: ECDH-ES ECDH-ES+A128KW ECDH-ES+A192KW ECDH-ES+A256KW Supported EC curves: P-256 P-384 P-521 Supported RSA key management algorithms: RSA-OAEP-256 RSA-OAEP-384 RSA-OAEP-512 Supported content encryption algorithms: A128CBC-HS256 A128CBC-HS384 A128CBC-HS512 A128GCM A192GCM A256GCM **Parameters:** - `privateKey`: Reference to private RSA or EC key to use for decryption. --- ### encrypt **Signature:** `encrypt(publicKey : CertificateRef) : void` **Description:** Encrypt the payload of this JWE object. Elliptic Curve (EC) and RSA keys are both supported. See decrypt(KeyRef) for the list of supported algorithms and encryption methods. **Parameters:** - `publicKey`: Reference to public RSA or EC key to use for decryption. --- ### getAlgorithm **Signature:** `getAlgorithm() : String` **Description:** Get the algorithm (alg) from the header. **Returns:** Value of the algorithm or null if missing. --- ### getEncryptionMethod **Signature:** `getEncryptionMethod() : String` **Description:** Get the encryption method (enc) from the header. **Returns:** Value of the encryption method or null if missing. --- ### getHeaderMap **Signature:** `getHeaderMap() : Map` **Description:** Get a copy of the JWE headers as a Map. **Returns:** Copy of the JWE headers. --- ### getKeyID **Signature:** `getKeyID() : String` **Description:** Get the key id (kid) from the header. **Returns:** Value of the key id or null if missing. --- ### getPayload **Signature:** `getPayload() : String` **Description:** Get the decrypted payload. **Returns:** Payload or null if the payload is encrypted. --- ### parse **Signature:** `static parse(jwe : String) : JWE` **Description:** Parse a JSON Web Encryption (JWE) object from its compact serialization format. **Parameters:** - `jwe`: JWE in compact serialization format. **Returns:** JWE object. --- ### serialize **Signature:** `serialize() : String` **Description:** Get this JWE in compact serialization form. **Returns:** Compact serialized object. --- ``` -------------------------------------------------------------------------------- /docs/dw_order/AbstractItemCtnr.md: -------------------------------------------------------------------------------- ```markdown ## Package: dw.order # Class AbstractItemCtnr ## Inheritance Hierarchy - Object - dw.object.Extensible - dw.order.AbstractItemCtnr ## Description Basis for item-based objects stemming from a single Order, with these common properties (Invoice is used as an example): The object has been created from an Order accessible using getOrder() Contains a collection of items, each item related to exactly one OrderItem which in turn represents an extension to one of the order ProductLineItem or one ShippingLineItem. Example: an Invoice has InvoiceItems The items hold various prices which are summed, resulting in a product-subtotal, a service-subtotal and a grand-total, each represented by a SumItem. The object is customizable using custom properties ## Properties ### createdBy **Type:** String (Read Only) Created by this user. ### creationDate **Type:** Date (Read Only) The time of creation. ### grandTotal **Type:** SumItem (Read Only) The sum-item representing the grandtotal for all items. ### items **Type:** FilteringCollection (Read Only) The unsorted collection of items ### lastModified **Type:** Date (Read Only) The last modification time. ### modifiedBy **Type:** String (Read Only) Last modified by this user. ### order **Type:** Order (Read Only) The Order this object was created for. ### productSubtotal **Type:** SumItem (Read Only) The sum-item representing the subtotal for product items. ### serviceSubtotal **Type:** SumItem (Read Only) The sum-item representing the subtotal for service items such as shipping. ## Constructor Summary ## Method Summary ### getCreatedBy **Signature:** `getCreatedBy() : String` Created by this user. ### getCreationDate **Signature:** `getCreationDate() : Date` The time of creation. ### getGrandTotal **Signature:** `getGrandTotal() : SumItem` Returns the sum-item representing the grandtotal for all items. ### getItems **Signature:** `getItems() : FilteringCollection` Returns the unsorted collection of items ### getLastModified **Signature:** `getLastModified() : Date` The last modification time. ### getModifiedBy **Signature:** `getModifiedBy() : String` Last modified by this user. ### getOrder **Signature:** `getOrder() : Order` Returns the Order this object was created for. ### getProductSubtotal **Signature:** `getProductSubtotal() : SumItem` Returns the sum-item representing the subtotal for product items. ### getServiceSubtotal **Signature:** `getServiceSubtotal() : SumItem` Returns the sum-item representing the subtotal for service items such as shipping. ## Method Detail ## Method Details ### getCreatedBy **Signature:** `getCreatedBy() : String` **Description:** Created by this user. **Returns:** Created by this user --- ### getCreationDate **Signature:** `getCreationDate() : Date` **Description:** The time of creation. **Returns:** time of creation. --- ### getGrandTotal **Signature:** `getGrandTotal() : SumItem` **Description:** Returns the sum-item representing the grandtotal for all items. **Returns:** sum-item for all items --- ### getItems **Signature:** `getItems() : FilteringCollection` **Description:** Returns the unsorted collection of items **Returns:** the unsorted collection of items --- ### getLastModified **Signature:** `getLastModified() : Date` **Description:** The last modification time. **Returns:** last modification time.. --- ### getModifiedBy **Signature:** `getModifiedBy() : String` **Description:** Last modified by this user. **Returns:** Last modified by this user --- ### getOrder **Signature:** `getOrder() : Order` **Description:** Returns the Order this object was created for. **Returns:** the Order this object was created for. --- ### getProductSubtotal **Signature:** `getProductSubtotal() : SumItem` **Description:** Returns the sum-item representing the subtotal for product items. **Returns:** sum-item for product items --- ### getServiceSubtotal **Signature:** `getServiceSubtotal() : SumItem` **Description:** Returns the sum-item representing the subtotal for service items such as shipping. **Returns:** sum-item for service items such as shipping --- ``` -------------------------------------------------------------------------------- /src/utils/utils.ts: -------------------------------------------------------------------------------- ```typescript /** * Utility functions for SFCC MCP Server * * This module contains helper functions for date formatting, file size conversion, * and other common operations used throughout the application. */ /** * Get current date in YYYYMMDD format * Used for filtering log files by date * * @returns Current date string in YYYYMMDD format */ export function getCurrentDate(): string { 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}`; } /** * Convert bytes to human-readable format * * @param bytes - Number of bytes to format * @returns Formatted string with appropriate unit (Bytes, KB, MB, GB) */ export function formatBytes(bytes: number): string { if (bytes === 0) {return '0 Bytes';} const k = 1024; const sizes = ['Bytes', 'KB', 'MB', 'GB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2)) } ${ sizes[i]}`; } /** * Parse log content into individual entries based on log level * Handles multi-line log entries properly by grouping lines that belong together * * @param content - Raw log file content * @param level - Log level to filter for (ERROR, WARN, INFO) * @returns Array of complete log entries */ export function parseLogEntries(content: string, level: string): string[] { const lines = content.split('\n'); const entries: string[] = []; let currentEntry = ''; for (const line of lines) { // Check if this line starts a new log entry for the specified level if (line.includes(`] ${level} `) && line.includes('GMT]')) { // Save the previous entry if it exists if (currentEntry) { entries.push(currentEntry.trim()); } // Start a new entry currentEntry = line; } else if (currentEntry && line.trim()) { // Add continuation lines to the current entry currentEntry += `\n${ line}`; } } // Don't forget the last entry if (currentEntry) { entries.push(currentEntry.trim()); } return entries; } /** * Extract timestamp from a log entry * @param logEntry - Complete log entry string * @returns Date object or null if timestamp cannot be parsed */ export function extractTimestampFromLogEntry(logEntry: string): Date | null { // Match pattern: [2025-08-19T10:30:00.000 GMT] or [2025-09-19 20:47:32.324 GMT] const timestampMatch = logEntry.match(/^\[(\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}\.\d{3}) GMT\]/); if (!timestampMatch) { return null; } try { // Normalize the timestamp format for parsing let timestampStr = timestampMatch[1]; // Convert space format to ISO format if needed if (timestampStr.includes(' ')) { timestampStr = timestampStr.replace(' ', 'T'); } // Parse the ISO timestamp (adding 'Z' for UTC) const date = new Date(`${timestampStr}Z`); // Check if the date is valid if (isNaN(date.getTime())) { return null; } return date; } catch { return null; } } /** * Extract unique error patterns from error log entries * Removes timestamps and common formatting to identify core error messages * * @param errors - Array of error log entries * @returns Array of unique error patterns (limited to top 10) */ export function extractUniqueErrors(errors: string[]): string[] { const patterns = new Set<string>(); for (const error of errors) { // Extract main error message after the class name // Pattern: [timestamp] ERROR ClassName - ErrorMessage const match = error.match(/] ERROR [^-]+ - (.+?)(?:\n|$)/); if (match) { patterns.add(match[1].trim()); } } return Array.from(patterns).slice(0, 10); // Limit to top 10 unique errors } /** * Normalize file path by removing leading slash if present * SFCC WebDAV sometimes returns paths with leading slashes that need to be handled * * @param filePath - File path that may have a leading slash * @returns Normalized file path without leading slash */ export function normalizeFilePath(filePath: string): string { return filePath.startsWith('/') ? filePath.substring(1) : filePath; } ``` -------------------------------------------------------------------------------- /src/clients/base/http-client.ts: -------------------------------------------------------------------------------- ```typescript /** * Base HTTP Client for SFCC API requests * * This module provides a foundation for making authenticated HTTP requests to SFCC APIs. * It handles common concerns like authentication, request/response formatting, and error handling. */ import { Logger } from '../../utils/logger.js'; /** * HTTP request options interface */ export interface HttpRequestOptions extends RequestInit { headers?: Record<string, string>; } /** * Base HTTP client for SFCC API communication */ export abstract class BaseHttpClient { protected baseUrl: string; protected logger: Logger; constructor(baseUrl: string, loggerContext: string) { this.baseUrl = baseUrl; this.logger = Logger.getChildLogger(loggerContext); } /** * Get authentication headers - must be implemented by subclasses */ protected abstract getAuthHeaders(): Promise<Record<string, string>>; /** * Handle authentication errors - can be overridden by subclasses */ protected async handleAuthError(): Promise<void> { // Default implementation does nothing // Subclasses can override to clear tokens, retry, etc. } /** * Make an authenticated HTTP request */ protected async makeRequest<T>( endpoint: string, options: HttpRequestOptions = {}, ): Promise<T> { const url = `${this.baseUrl}${endpoint}`; const method = options.method ?? 'GET'; this.logger.debug(`Making ${method} request to: ${endpoint}`); // Get authentication headers const authHeaders = await this.getAuthHeaders(); const requestOptions: RequestInit = { ...options, headers: { 'Content-Type': 'application/json', ...authHeaders, ...options.headers, }, }; try { const response = await fetch(url, requestOptions); if (!response.ok) { // Handle authentication errors if (response.status === 401) { this.logger.debug('Received 401, attempting to handle auth error'); await this.handleAuthError(); // Retry with fresh authentication const newAuthHeaders = await this.getAuthHeaders(); requestOptions.headers = { ...requestOptions.headers, ...newAuthHeaders, }; const retryResponse = await fetch(url, requestOptions); if (!retryResponse.ok) { const errorText = await retryResponse.text(); throw new Error( `Request failed after retry: ${retryResponse.status} ${retryResponse.statusText} - ${errorText}`, ); } this.logger.debug('Retry request successful'); return retryResponse.json(); } const errorText = await response.text(); throw new Error(`Request failed: ${response.status} ${response.statusText} - ${errorText}`); } this.logger.debug(`Request to ${endpoint} completed successfully`); return response.json(); } catch (error) { this.logger.error(`Network error during request to ${endpoint}: ${error}`); throw error; } } /** * GET request */ protected async get<T>(endpoint: string): Promise<T> { return this.makeRequest<T>(endpoint, { method: 'GET' }); } /** * POST request */ protected async post<T>(endpoint: string, data?: any): Promise<T> { const options: HttpRequestOptions = { method: 'POST' }; if (data) { options.body = JSON.stringify(data); } return this.makeRequest<T>(endpoint, options); } /** * PUT request */ protected async put<T>(endpoint: string, data?: any): Promise<T> { const options: HttpRequestOptions = { method: 'PUT' }; if (data) { options.body = JSON.stringify(data); } return this.makeRequest<T>(endpoint, options); } /** * PATCH request */ protected async patch<T>(endpoint: string, data?: any): Promise<T> { const options: HttpRequestOptions = { method: 'PATCH' }; if (data) { options.body = JSON.stringify(data); } return this.makeRequest<T>(endpoint, options); } /** * DELETE request */ protected async delete<T>(endpoint: string): Promise<T> { return this.makeRequest<T>(endpoint, { method: 'DELETE' }); } } ``` -------------------------------------------------------------------------------- /docs/dw_extensions.pinterest/PinterestOrder.md: -------------------------------------------------------------------------------- ```markdown ## Package: dw.extensions.pinterest # Class PinterestOrder ## Inheritance Hierarchy - Object - dw.extensions.pinterest.PinterestOrder ## Description An order that was placed through Pinterest. ## Constants ### PAYMENT_STATUS_NOT_PAID **Type:** String = "NOT_PAID" Indicates that payment has not been made. ### PAYMENT_STATUS_PAID **Type:** String = "PAID" Indicates that payment is complete. ### PAYMENT_STATUS_PART_PAID **Type:** String = "PART_PAID" Indicates that payment is incomplete. ### STATUS_BACKORDER **Type:** String = "BACKORDER" Indicates an order on backorder. ### STATUS_CANCELLED **Type:** String = "CANCELLED" Indicates an order that has been canceled. ### STATUS_DELIVERED **Type:** String = "DELIVERED" Indicates an order that has been delivered. ### STATUS_IN_PROGRESS **Type:** String = "IN_PROGRESS" Indicates an order in progress. ### STATUS_NEW **Type:** String = "NEW" Indicates a new order. ### STATUS_RETURNED **Type:** String = "RETURNED" Indicates an order that has been returned. ### STATUS_SHIPPED **Type:** String = "SHIPPED" Indicates an order that has shipped. ## Properties ### itemId **Type:** String The item ID for this Pinterest order. ### orderNo **Type:** String (Read Only) The order number for this Pinterest order. This is the same as the order number of the Demandware order. ### paymentStatus **Type:** String The status of this Pinterest order. Possible values are PAYMENT_STATUS_PAID, PAYMENT_STATUS_NOT_PAID, or PAYMENT_STATUS_PART_PAID. ### status **Type:** String The status of this Pinterest order. Possible values are STATUS_NEW, STATUS_IN_PROGRESS, STATUS_SHIPPED, STATUS_BACKORDER, STATUS_CANCELLED, STATUS_DELIVERED, or STATUS_RETURNED. ## Constructor Summary ## Method Summary ### getItemId **Signature:** `getItemId() : String` Returns the item ID for this Pinterest order. ### getOrderNo **Signature:** `getOrderNo() : String` Returns the order number for this Pinterest order. ### getPaymentStatus **Signature:** `getPaymentStatus() : String` Returns the status of this Pinterest order. ### getStatus **Signature:** `getStatus() : String` Returns the status of this Pinterest order. ### setItemId **Signature:** `setItemId(itemId : String) : void` Sets the item ID for this Pinterest order. ### setPaymentStatus **Signature:** `setPaymentStatus(status : String) : void` Sets the status of this Pinterest order. ### setStatus **Signature:** `setStatus(status : String) : void` Sets the status of this Pinterest order. ## Method Detail ## Method Details ### getItemId **Signature:** `getItemId() : String` **Description:** Returns the item ID for this Pinterest order. --- ### getOrderNo **Signature:** `getOrderNo() : String` **Description:** Returns the order number for this Pinterest order. This is the same as the order number of the Demandware order. **Returns:** order number --- ### getPaymentStatus **Signature:** `getPaymentStatus() : String` **Description:** Returns the status of this Pinterest order. Possible values are PAYMENT_STATUS_PAID, PAYMENT_STATUS_NOT_PAID, or PAYMENT_STATUS_PART_PAID. --- ### getStatus **Signature:** `getStatus() : String` **Description:** Returns the status of this Pinterest order. Possible values are STATUS_NEW, STATUS_IN_PROGRESS, STATUS_SHIPPED, STATUS_BACKORDER, STATUS_CANCELLED, STATUS_DELIVERED, or STATUS_RETURNED. --- ### setItemId **Signature:** `setItemId(itemId : String) : void` **Description:** Sets the item ID for this Pinterest order. **Parameters:** - `itemId`: item ID --- ### setPaymentStatus **Signature:** `setPaymentStatus(status : String) : void` **Description:** Sets the status of this Pinterest order. Possible values are PAYMENT_STATUS_PAID, PAYMENT_STATUS_NOT_PAID, or PAYMENT_STATUS_PART_PAID. **Parameters:** - `status`: the status to set for this order --- ### setStatus **Signature:** `setStatus(status : String) : void` **Description:** Sets the status of this Pinterest order. Possible values are STATUS_NEW, STATUS_IN_PROGRESS, STATUS_SHIPPED, STATUS_BACKORDER, STATUS_CANCELLED, STATUS_DELIVERED, or STATUS_RETURNED. **Parameters:** - `status`: the status to set for this order --- ``` -------------------------------------------------------------------------------- /docs/dw_campaign/ApproachingDiscount.md: -------------------------------------------------------------------------------- ```markdown ## Package: dw.campaign # Class ApproachingDiscount ## Inheritance Hierarchy - Object - dw.campaign.ApproachingDiscount ## Description Transient class representing a discount that a LineItemCtnr "almost" qualifies for based on the amount of merchandise in it. Storefronts can display information about approaching discounts to customers in order to entice them to buy more merchandise. Approaching discounts are calculated on the basis of a DiscountPlan instead of a LineItemCtnr itself. When one of PromotionMgr.getDiscounts(LineItemCtnr) or PromotionMgr.getDiscounts(LineItemCtnr, PromotionPlan) is called, the promotions engine calculates the discounts the LineItemCtnr receives based on the promotions in context, and also tries to determine the discounts the LineItemCtnr would receive if additional merchandise were added. DiscountPlan provides different methods to retrieve this approaching discount info. Merchants can use these fine-grained methods to display information about approaching order discounts on the cart page, and approaching shipping discounts on the shipping method page during checkout, for example. The merchant may include or exclude individual promotions from being included in this list, and define distance thresholds when configuring their promotions. ## Properties ### conditionThreshold **Type:** Money (Read Only) The amount of merchandise required in the cart in order to receive the discount. For an order promotion "Get 15% off orders of $100 or more", the condition threshold is $100.00. ### discount **Type:** Discount (Read Only) The discount that the customer will receive if he adds more merchandise to the cart. For an order promotion "Get 15% off orders of $100 or more", the discount is a PercentageDiscount object. ### distanceFromConditionThreshold **Type:** Money (Read Only) Convenience method that returns getConditionThreshold().subtract(getMerchandiseValue()) ### merchandiseTotal **Type:** Money (Read Only) The amount of merchandise in the cart contributing towards the condition threshold. This will always be less than the condition threshold. ## Constructor Summary ## Method Summary ### getConditionThreshold **Signature:** `getConditionThreshold() : Money` The amount of merchandise required in the cart in order to receive the discount. ### getDiscount **Signature:** `getDiscount() : Discount` The discount that the customer will receive if he adds more merchandise to the cart. ### getDistanceFromConditionThreshold **Signature:** `getDistanceFromConditionThreshold() : Money` Convenience method that returns getConditionThreshold().subtract(getMerchandiseValue()) ### getMerchandiseTotal **Signature:** `getMerchandiseTotal() : Money` The amount of merchandise in the cart contributing towards the condition threshold. ## Method Detail ## Method Details ### getConditionThreshold **Signature:** `getConditionThreshold() : Money` **Description:** The amount of merchandise required in the cart in order to receive the discount. For an order promotion "Get 15% off orders of $100 or more", the condition threshold is $100.00. **Returns:** The amount of merchandise required in the cart in order to receive the discount. --- ### getDiscount **Signature:** `getDiscount() : Discount` **Description:** The discount that the customer will receive if he adds more merchandise to the cart. For an order promotion "Get 15% off orders of $100 or more", the discount is a PercentageDiscount object. **Returns:** The discount that the customer will receive if he adds more merchandise to the cart. --- ### getDistanceFromConditionThreshold **Signature:** `getDistanceFromConditionThreshold() : Money` **Description:** Convenience method that returns getConditionThreshold().subtract(getMerchandiseValue()) **Returns:** The amount of money needed to add to the order or shipment in order to receive the discount. --- ### getMerchandiseTotal **Signature:** `getMerchandiseTotal() : Money` **Description:** The amount of merchandise in the cart contributing towards the condition threshold. This will always be less than the condition threshold. **Returns:** The amount of merchandise in the cart contributing towards the condition threshold. --- ``` -------------------------------------------------------------------------------- /tests/mcp/yaml/get-job-execution-summary.full-mode.test.mcp.yml: -------------------------------------------------------------------------------- ```yaml --- description: "Test get_job_execution_summary tool in full mode (YAML/Aegis framework validation)" tests: # Core functionality - test basic success case with actual response format - it: "should retrieve job execution summary with proper structure" request: jsonrpc: "2.0" id: "job-summary-basic" method: "tools/call" params: name: "get_job_execution_summary" arguments: jobName: "ImportCatalog" expect: response: jsonrpc: "2.0" id: "job-summary-basic" result: content: match:arrayLength:1 isError: false stderr: "toBeEmpty" performance: maxResponseTime: "2000ms" # Test response content format for existing job (based on aegis discovery) - it: "should return formatted execution summary with timing and status sections" request: jsonrpc: "2.0" id: "job-summary-format" method: "tools/call" params: name: "get_job_execution_summary" arguments: jobName: "ImportCatalog" expect: response: jsonrpc: "2.0" id: "job-summary-format" result: content: match:arrayElements: match:partial: type: "text" text: "match:regex:Job Execution Summary: ImportCatalog[\\s\\S]*⏱️ Timing:[\\s\\S]*📊 Status:" isError: false stderr: "toBeEmpty" performance: maxResponseTime: "2000ms" # Test non-existent job handling (based on aegis discovery) - it: "should handle non-existent job gracefully" request: jsonrpc: "2.0" id: "job-summary-nonexistent" method: "tools/call" params: name: "get_job_execution_summary" arguments: jobName: "NonExistentJob" expect: response: jsonrpc: "2.0" id: "job-summary-nonexistent" result: content: match:arrayElements: match:partial: type: "text" text: "match:contains:No job logs found for job name: NonExistentJob" isError: false stderr: "toBeEmpty" performance: maxResponseTime: "1500ms" # Essential error validation - missing parameter (based on aegis discovery) - it: "should return error for missing jobName parameter" request: jsonrpc: "2.0" id: "job-summary-missing-param" method: "tools/call" params: name: "get_job_execution_summary" arguments: {} expect: response: jsonrpc: "2.0" id: "job-summary-missing-param" result: content: match:arrayElements: match:partial: type: "text" text: "match:contains:Error: jobName must be a non-empty string" isError: true stderr: "toBeEmpty" performance: maxResponseTime: "800ms" # Essential error validation - empty string (based on aegis discovery) - it: "should return error for empty jobName parameter" request: jsonrpc: "2.0" id: "job-summary-empty-param" method: "tools/call" params: name: "get_job_execution_summary" arguments: jobName: "" expect: response: jsonrpc: "2.0" id: "job-summary-empty-param" result: content: match:arrayElements: match:partial: type: "text" text: "match:contains:Error: jobName must be a non-empty string" isError: true stderr: "toBeEmpty" performance: maxResponseTime: "800ms" # Test response structure consistency - it: "should return consistent MCP response structure" request: jsonrpc: "2.0" id: "job-summary-structure" method: "tools/call" params: name: "get_job_execution_summary" arguments: jobName: "ImportCatalog" expect: response: jsonrpc: "2.0" id: "job-summary-structure" result: content: match:arrayElements: match:partial: type: "text" text: "match:type:string" isError: "match:type:boolean" stderr: "toBeEmpty" performance: maxResponseTime: "2000ms" ``` -------------------------------------------------------------------------------- /docs/dw_order/InvoiceItem.md: -------------------------------------------------------------------------------- ```markdown ## Package: dw.order # Class InvoiceItem ## Inheritance Hierarchy - Object - dw.object.Extensible - dw.order.AbstractItem - dw.order.InvoiceItem ## Description Represents a specific item in an Invoice. Invoice items are added to the invoice on its creation, each item references exactly one order-item. Order post-processing APIs (gillian) are now inactive by default and will throw an exception if accessed. Activation needs preliminary approval by Product Management. Please contact support in this case. Existing customers using these APIs are not affected by this change and can use the APIs until further notice. ## Properties ### basePrice **Type:** Money (Read Only) Price of a single unit before discount application. ### capturedAmount **Type:** Money The captured amount for this item. ### invoiceNumber **Type:** String (Read Only) The number of the invoice to which this item belongs. ### parentItem **Type:** InvoiceItem Returns null or the parent item. ### quantity **Type:** Quantity (Read Only) The quantity of this item. ### refundedAmount **Type:** Money The refunded amount for this item. ## Constructor Summary ## Method Summary ### getBasePrice **Signature:** `getBasePrice() : Money` Price of a single unit before discount application. ### getCapturedAmount **Signature:** `getCapturedAmount() : Money` Returns the captured amount for this item. ### getInvoiceNumber **Signature:** `getInvoiceNumber() : String` Returns the number of the invoice to which this item belongs. ### getParentItem **Signature:** `getParentItem() : InvoiceItem` Returns null or the parent item. ### getQuantity **Signature:** `getQuantity() : Quantity` Returns the quantity of this item. ### getRefundedAmount **Signature:** `getRefundedAmount() : Money` Returns the refunded amount for this item. ### setCapturedAmount **Signature:** `setCapturedAmount(capturedAmount : Money) : void` Updates the captured amount for this item. ### setParentItem **Signature:** `setParentItem(parentItem : InvoiceItem) : void` Set a parent item. ### setRefundedAmount **Signature:** `setRefundedAmount(refundedAmount : Money) : void` Updates the refunded amount for this item. ## Method Detail ## Method Details ### getBasePrice **Signature:** `getBasePrice() : Money` **Description:** Price of a single unit before discount application. **Returns:** Price of a single unit before discount application. --- ### getCapturedAmount **Signature:** `getCapturedAmount() : Money` **Description:** Returns the captured amount for this item. **Returns:** the captured amount for this item --- ### getInvoiceNumber **Signature:** `getInvoiceNumber() : String` **Description:** Returns the number of the invoice to which this item belongs. **Returns:** the number of the invoice to which this item belongs --- ### getParentItem **Signature:** `getParentItem() : InvoiceItem` **Description:** Returns null or the parent item. **Returns:** null or the parent item. --- ### getQuantity **Signature:** `getQuantity() : Quantity` **Description:** Returns the quantity of this item. **Returns:** quantity of this item --- ### getRefundedAmount **Signature:** `getRefundedAmount() : Money` **Description:** Returns the refunded amount for this item. **Returns:** the refunded amount for this item --- ### setCapturedAmount **Signature:** `setCapturedAmount(capturedAmount : Money) : void` **Description:** Updates the captured amount for this item. **Parameters:** - `capturedAmount`: the captured amount for this item --- ### setParentItem **Signature:** `setParentItem(parentItem : InvoiceItem) : void` **Description:** Set a parent item. The parent item must belong to the same Invoice. An infinite parent-child loop is disallowed as is a parent-child depth greater than 10. Setting a parent item indicates a dependency of the child item on the parent item, and can be used to form a parallel structure to that accessed using ProductLineItem.getParent(). **Parameters:** - `parentItem`: The parent item, null is allowed --- ### setRefundedAmount **Signature:** `setRefundedAmount(refundedAmount : Money) : void` **Description:** Updates the refunded amount for this item. **Parameters:** - `refundedAmount`: the refunded amount for this item --- ``` -------------------------------------------------------------------------------- /docs/dw_order/PaymentMgr.md: -------------------------------------------------------------------------------- ```markdown ## Package: dw.order # Class PaymentMgr ## Inheritance Hierarchy - Object - dw.order.PaymentMgr ## Description PaymentMgr is used to access payment methods and payment cards of the current site. To access payment methods and payment cards explicitly, use methods getPaymentMethod(String) and getPaymentCard(String). To access active payment methods use method getActivePaymentMethods(). To access applicable payment methods for a customer, country and/or payment amount use method getApplicablePaymentMethods(Customer, String, Number). ## Properties ### activePaymentMethods **Type:** List (Read Only) The sorted list of all enabled payment methods of the current site, regardless of any customer group, country, payment amount or currency restrictions. The payment methods are sorted as defined in the Business Manager. ## Constructor Summary ## Method Summary ### getActivePaymentMethods **Signature:** `static getActivePaymentMethods() : List` Returns the sorted list of all enabled payment methods of the current site, regardless of any customer group, country, payment amount or currency restrictions. ### getApplicablePaymentMethods **Signature:** `static getApplicablePaymentMethods(customer : Customer, countryCode : String, paymentAmount : Number) : List` Returns the sorted list of all enabled payment methods of the current site applicable for the session currency, specified customer, country and payment amount. ### getPaymentCard **Signature:** `static getPaymentCard(cardType : String) : PaymentCard` Returns the payment card for the specified cardType or null if no such card exists in the current site. ### getPaymentMethod **Signature:** `static getPaymentMethod(id : String) : PaymentMethod` Returns the payment method for the specified ID or null if no such method exists in the current site. ## Method Detail ## Method Details ### getActivePaymentMethods **Signature:** `static getActivePaymentMethods() : List` **Description:** Returns the sorted list of all enabled payment methods of the current site, regardless of any customer group, country, payment amount or currency restrictions. The payment methods are sorted as defined in the Business Manager. **Returns:** List of enabled payment methods of current site --- ### getApplicablePaymentMethods **Signature:** `static getApplicablePaymentMethods(customer : Customer, countryCode : String, paymentAmount : Number) : List` **Description:** Returns the sorted list of all enabled payment methods of the current site applicable for the session currency, specified customer, country and payment amount. The payment methods are sorted as defined in the Business Manager. A payment method is applicable if the method is restricted by customer group, and at least one of the groups of the specified customer is assigned to the method the method is restricted by billing country, and the specified country code is assigned to the method the method is restricted by payment amount for the session currency, and the specified payment amount is within the limits of the min/max payment amount defined for the method and the session currency the method is restricted by currency code, and the specified currency code matches session currency. All parameters are optional, and if not specified, the respective restriction won't be validated. For example, if a method is restricted by billing country, but no country code is specified, this method will be returned, unless it is filtered out by customer group or payment amount. **Parameters:** - `customer`: Customer or null - `countryCode`: Billing country code or null - `paymentAmount`: Payment amount or null **Returns:** List of applicable payment methods of current site --- ### getPaymentCard **Signature:** `static getPaymentCard(cardType : String) : PaymentCard` **Description:** Returns the payment card for the specified cardType or null if no such card exists in the current site. **Parameters:** - `cardType`: PaymentCard type **Returns:** PaymentCard or null --- ### getPaymentMethod **Signature:** `static getPaymentMethod(id : String) : PaymentMethod` **Description:** Returns the payment method for the specified ID or null if no such method exists in the current site. **Parameters:** - `id`: PaymentMethod ID **Returns:** PaymentMethod or null --- ``` -------------------------------------------------------------------------------- /docs/sfra/account.md: -------------------------------------------------------------------------------- ```markdown # SFRA Account Model ## Overview The Account model represents a customer's profile dashboard, containing profile information, addresses, payment instruments, and order history. It provides methods for handling customer account data in SFRA applications. ## Constructor ```javascript function account(currentCustomer, addressModel, orderModel) ``` Creates an Account model instance that represents the current customer's profile dashboard. ### Parameters - `currentCustomer` (Object) - Current customer object - `addressModel` (Object) - The current customer's preferred address - `orderModel` (Object) - The current customer's order history ## Properties ### profile **Type:** Object | null Contains the customer's profile information including: - `firstName` (string) - Customer's first name - `lastName` (string) - Customer's last name - `email` (string) - Customer's email address - `phone` (string) - Customer's phone number - `password` (string) - Masked password (always "********") ### addresses **Type:** Array<Object> Array of customer's address book addresses. Each address object contains standard address fields. ### preferredAddress **Type:** Object | null The customer's preferred/default address from their address book. ### orderHistory **Type:** Object The customer's order history information. ### payment **Type:** Object | null Primary payment instrument information including: - `maskedCreditCardNumber` (string) - Masked card number - `creditCardType` (string) - Type of credit card - `creditCardExpirationMonth` (number) - Expiration month - `creditCardExpirationYear` (number) - Expiration year ### registeredUser **Type:** boolean Indicates if the customer is both authenticated and registered. ### isExternallyAuthenticated **Type:** boolean Indicates if the customer is authenticated through an external provider. ### customerPaymentInstruments **Type:** Array<Object> | null Array of customer's saved payment instruments. Each payment instrument contains: - `creditCardHolder` (string) - Name on the credit card - `maskedCreditCardNumber` (string) - Masked card number - `creditCardType` (string) - Type of credit card - `creditCardExpirationMonth` (number) - Expiration month - `creditCardExpirationYear` (number) - Expiration year - `UUID` (string) - Unique identifier - `cardTypeImage` (Object) - Image source and alt text for card type - `src` (string) - Image source URL - `alt` (string) - Alt text for the image ## Helper Functions ### getProfile(profile) Creates a plain object containing profile information. **Parameters:** - `profile` (Object) - Customer's profile object **Returns:** Object | null - Profile information or null if no profile ### getAddresses(addressBook) Creates an array of address objects from the customer's address book. **Parameters:** - `addressBook` (Object) - Customer's address book **Returns:** Array<Object> - Array of address objects ### getPreferredAddress(addressBook) Gets the customer's preferred address. **Parameters:** - `addressBook` (Object) - Customer's address book **Returns:** Object | null - Preferred address or null ### getPayment(wallet) Gets the primary payment instrument information. **Parameters:** - `wallet` (Object) - Customer's wallet containing payment instruments **Returns:** Object | null - Payment instrument information or null ### getCustomerPaymentInstruments(userPaymentInstruments) Creates an array of payment instrument objects with card type images. **Parameters:** - `userPaymentInstruments` (Array) - Array of customer's payment instruments **Returns:** Array<Object> - Array of formatted payment instruments ## Usage Example ```javascript var AccountModel = require('*/cartridge/models/account'); var currentCustomer = customer; var addressModel = null; // or specific address model var orderModel = getOrderHistory(); var account = new AccountModel(currentCustomer, addressModel, orderModel); // Access account properties console.log(account.profile.email); console.log(account.addresses.length); console.log(account.registeredUser); console.log(account.customerPaymentInstruments); console.log(account.payment); ``` ## Related Models - **Address Model** - Used for address formatting - **Order Model** - Used for order history - **Payment Models** - Used for payment instrument handling ``` -------------------------------------------------------------------------------- /docs/sfra/locale.md: -------------------------------------------------------------------------------- ```markdown # SFRA Locale Model ## Overview The Locale model represents current locale information and provides locale switching functionality for internationalized SFRA applications. It manages country codes, currency codes, language settings, and available locale options for site visitors. ## Constructor ```javascript function Locale(currentLocale, allowedLocales, siteId) ``` Creates a Locale model instance with current locale information and available locale options. ### Parameters - `currentLocale` (dw.util.Locale) - Current locale of the request - `allowedLocales` (string) - List of allowed locales for the site - `siteId` (string) - ID of the current site ## Properties ### locale **Type:** Object Object containing comprehensive locale information: - `countryCode` (string) - Country code for the current locale - `name` (string) - Display name of the country - `currencyCode` (string) - Currency code for the locale - `displayName` (string) - Full display name of the locale - `language` (string) - Language code - `displayLanguage` (string) - Display name of the language - `localeLinks` (Array<Object>) - Available locale options for switching - `localLinks` (Array<Object>) - **Deprecated** - Same as localeLinks (kept for backward compatibility) ### Locale Link Objects Each object in `localeLinks` contains: - `localID` (string) - Locale identifier - `country` (string) - Country code - `displayCountry` (string) - Country display name - `currencyCode` (string) - Currency code for the locale - `displayName` (string) - Full locale display name - `language` (string) - Language code - `displayLanguage` (string) - Language display name ## Helper Functions ### getLocaleLinks(allowedLocales, siteId, currentLocaleID) Returns available locale options for site locale switching. **Parameters:** - `allowedLocales` (string) - List of allowed locales for the site - `siteId` (string) - Current site ID - `currentLocaleID` (string) - Current locale ID **Returns:** Array<Object> - Array of available locale options (excluding current locale) ### isLocaleValid(currentLocale) Validates that a locale object is properly formed. **Parameters:** - `currentLocale` (dw.util.Locale) - Locale to validate **Returns:** boolean - True if locale has required ID property ## Usage Example ```javascript var LocaleModel = require('*/cartridge/models/locale'); var Site = require('dw/system/Site'); var currentLocale = request.getLocale(); var allowedLocales = Site.getCurrent().getAllowedLocales(); var siteId = Site.getCurrent().getID(); var localeModel = new LocaleModel(currentLocale, allowedLocales, siteId); // Access current locale information console.log(localeModel.locale.countryCode); // "US" console.log(localeModel.locale.currencyCode); // "USD" console.log(localeModel.locale.displayLanguage); // "English" // Access available locale options localeModel.locale.localeLinks.forEach(function(link) { console.log(link.displayName + ' (' + link.currencyCode + ')'); // Output: "English (United Kingdom) (GBP)", "Français (France) (EUR)", etc. }); ``` ## Backward Compatibility The model includes both `localeLinks` and `localLinks` properties: - **localeLinks** - Correct property name (use this) - **localLinks** - Deprecated typo maintained for backward compatibility **Note**: The SFRA team plans to remove the `localLinks` property in a future version. ## Fallback Handling If the current locale is invalid or missing: - Falls back to the first country in the countries configuration - Ensures the model always has valid locale information - Prevents errors in locale-dependent functionality ## Integration with Countries Configuration The model relies on a countries configuration file (`*/cartridge/config/countries`) that defines: - Available countries and locales - Currency codes for each locale - Locale-specific configurations ## Notes - Excludes the current locale from the locale switching links - Provides comprehensive locale information for internationalization - Handles invalid locales gracefully with fallbacks - Supports multi-currency and multi-language sites - Integrates with SFCC's built-in locale system ## Related Models - **Site Configuration** - Defines allowed locales - **Currency Models** - May use currency information - **Address Models** - May use country information for formatting ``` -------------------------------------------------------------------------------- /docs/dw_crypto/CertificateUtils.md: -------------------------------------------------------------------------------- ```markdown ## Package: dw.crypto # Class CertificateUtils ## Inheritance Hierarchy - Object - dw.crypto.CertificateUtils ## Description Utilities for managing certificates and keys. ## Constructor Summary CertificateUtils() ## Method Summary ### getCertificate **Signature:** `static getCertificate(certificateRef : CertificateRef) : X509Certificate` Gets the certificate from the given certificate reference. ### getCertificate **Signature:** `static getCertificate(keyRef : KeyRef) : X509Certificate` Gets the public certificate from the given private key reference. ### getEncodedCertificate **Signature:** `static getEncodedCertificate(certificateRef : CertificateRef) : String` Encode the certificate to the base64-encoded DER format. ### getEncodedPublicKey **Signature:** `static getEncodedPublicKey(certificateRef : CertificateRef) : String` Gets the public key from the given certificate reference. ### parseEncodedCertificate **Signature:** `static parseEncodedCertificate(certificate : String) : CertificateRef` Parse the certificate from the base64-encoded DER format. ### parseEncodedPublicKey **Signature:** `static parseEncodedPublicKey(algorithm : String, encodedKey : String) : CertificateRef` Parse the public key from the given key in X.509 SubjectPublicKeyInfo format. ### parsePublicKeyFromJWK **Signature:** `static parsePublicKeyFromJWK(jwk : String) : CertificateRef` Parse the public key from the given base64-encoded JWK string. ## Constructor Detail ## Method Detail ## Method Details ### getCertificate **Signature:** `static getCertificate(certificateRef : CertificateRef) : X509Certificate` **Description:** Gets the certificate from the given certificate reference. **Parameters:** - `certificateRef`: the certificate reference **Returns:** The X509Certificate **Throws:** Exception - if the reference is invalid or does not refer to an X.509 certificate --- ### getCertificate **Signature:** `static getCertificate(keyRef : KeyRef) : X509Certificate` **Description:** Gets the public certificate from the given private key reference. **Parameters:** - `keyRef`: the key reference **Returns:** The X509Certificate **Throws:** Exception - if the reference is invalid or there is no X.509 certificate --- ### getEncodedCertificate **Signature:** `static getEncodedCertificate(certificateRef : CertificateRef) : String` **Description:** Encode the certificate to the base64-encoded DER format. **Parameters:** - `certificateRef`: the certificate to encode **Returns:** base64-encoded DER certificate --- ### getEncodedPublicKey **Signature:** `static getEncodedPublicKey(certificateRef : CertificateRef) : String` **Description:** Gets the public key from the given certificate reference. It is exported in the standard X.509 SubjectPublicKeyInfo format and base64-encoded. **Parameters:** - `certificateRef`: the certificate reference with the public key to encode **Returns:** The encoded public key --- ### parseEncodedCertificate **Signature:** `static parseEncodedCertificate(certificate : String) : CertificateRef` **Description:** Parse the certificate from the base64-encoded DER format. **Parameters:** - `certificate`: The encoded certificate **Returns:** Reference to the parsed certificate --- ### parseEncodedPublicKey **Signature:** `static parseEncodedPublicKey(algorithm : String, encodedKey : String) : CertificateRef` **Description:** Parse the public key from the given key in X.509 SubjectPublicKeyInfo format. The resulting reference contains only the public key. It can be used for cryptographic operations, but not anything that requires the full certificate. **Parameters:** - `algorithm`: The public key algorithm, either EC or RSA - `encodedKey`: The encoded key **Returns:** Reference to the public key --- ### parsePublicKeyFromJWK **Signature:** `static parsePublicKeyFromJWK(jwk : String) : CertificateRef` **Description:** Parse the public key from the given base64-encoded JWK string. This returns the public key portion of the JWK, not the x5c certificate chain. Only RSA and EC keys are supported. The resulting reference contains only the public key. It can be used for cryptographic operations, but not anything that requires the full certificate. **Parameters:** - `jwk`: Encoded JWK **Returns:** Reference to the public key --- ``` -------------------------------------------------------------------------------- /docs-site/components/Sidebar.tsx: -------------------------------------------------------------------------------- ```typescript import React from 'react'; import { NavLink, useLocation } from 'react-router-dom'; import { NAVIGATION_LINKS } from '../constants'; import { NavGroup, NavItem } from '../types'; import Search from './Search'; import VersionBadge from './VersionBadge'; const Sidebar: React.FC = () => { const location = useLocation(); const isLinkActive = (path: string) => { if (path === '/') return location.pathname === '/'; // Normalize paths to have trailing slashes for comparison const normalizedLocationPath = location.pathname.endsWith('/') ? location.pathname : location.pathname + '/'; const normalizedPath = path.endsWith('/') ? path : path + '/'; return normalizedLocationPath === normalizedPath; } return ( <div className="h-full flex flex-col p-4 sm:p-6"> {/* Desktop header - hidden on mobile since we have it in Layout */} <div className="hidden lg:block mb-8"> <div className="flex items-center gap-2"> <span className="text-2xl font-bold text-slate-800">SFCC Dev</span> <span className="text-2xl font-light text-orange-500">MCP</span> </div> <div className="flex justify-start"> <VersionBadge /> </div> </div> {/* Mobile header spacing */} <div className="lg:hidden mb-6" /> <Search /> <nav className="flex-1 overflow-y-auto mt-4 sm:mt-6"> {NAVIGATION_LINKS.map((group: NavGroup) => ( <div key={group.title} className="mb-6"> <h2 className="text-xs font-bold text-slate-500 uppercase tracking-wider mb-3">{group.title}</h2> <ul> {group.items.map((item: NavItem) => ( <li key={item.path}> <NavLink to={item.path} className={`block py-2 px-3 text-sm rounded-md transition-colors ${ isLinkActive(item.path) ? 'text-orange-600 font-semibold bg-orange-50' : 'text-slate-600 hover:text-slate-900 hover:bg-slate-100' }`} > {item.label} </NavLink> </li> ))} </ul> </div> ))} </nav> {/* Links Section */} <div className="mt-4 pt-4 border-t border-slate-200"> <div className="flex justify-center gap-4"> <a href="https://www.rhino-inquisitor.com/" target="_blank" rel="noopener noreferrer" className="inline-flex items-center gap-2 px-3 py-2 text-sm text-slate-600 hover:text-slate-900 hover:bg-slate-100 rounded-md transition-colors" title="Rhino Inquisitor - Personal Site" > <img src="https://www.rhino-inquisitor.com/wp-content/uploads/2022/02/rhino-inquisitor.svg" alt="Rhino Inquisitor" className="w-5 h-6" /> <span>Blog</span> </a> <a href="https://github.com/taurgis/sfcc-dev-mcp" target="_blank" rel="noopener noreferrer" className="inline-flex items-center gap-2 px-3 py-2 text-sm text-slate-600 hover:text-slate-900 hover:bg-slate-100 rounded-md transition-colors" title="SFCC Dev MCP on GitHub" > <svg className="w-5 h-5" fill="currentColor" viewBox="0 0 20 20"> <path fillRule="evenodd" d="M10 0C4.477 0 0 4.484 0 10.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0110 4.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.203 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.942.359.31.678.921.678 1.856 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0020 10.017C20 4.484 15.522 0 10 0z" clipRule="evenodd" /> </svg> <span>GitHub</span> </a> </div> </div> </div> ); }; export default Sidebar; ``` -------------------------------------------------------------------------------- /src/clients/base/ocapi-auth-client.ts: -------------------------------------------------------------------------------- ```typescript /** * OCAPI Authentication Client * * This module handles OAuth 2.0 authentication specifically for SFCC OCAPI requests. * It extends the base HTTP client with OCAPI-specific authentication logic. */ import { OCAPIConfig, OAuthTokenResponse } from '../../types/types.js'; import { TokenManager } from './oauth-token.js'; import { BaseHttpClient } from './http-client.js'; import { buildOCAPIAuthUrl } from '../../utils/ocapi-url-builder.js'; // OCAPI authentication constants const OCAPI_AUTH_CONSTANTS = { DEFAULT_AUTH_URL: 'https://account.demandware.com/dwsso/oauth2/access_token', GRANT_TYPE: 'client_credentials', FORM_CONTENT_TYPE: 'application/x-www-form-urlencoded', } as const; /** * OCAPI Authentication Client * Handles OAuth 2.0 Client Credentials flow for OCAPI access */ export class OCAPIAuthClient extends BaseHttpClient { private config: OCAPIConfig; private tokenManager: TokenManager; constructor(config: OCAPIConfig) { super('', 'OCAPIAuthClient'); // Initialize BaseHttpClient with logger this.config = config; this.tokenManager = TokenManager.getInstance(); } /** * Get authentication headers for OCAPI requests */ protected async getAuthHeaders(): Promise<Record<string, string>> { const accessToken = await this.getAccessToken(); return { 'Authorization': `Bearer ${accessToken}`, }; } /** * Handle authentication errors by clearing the stored token */ protected async handleAuthError(): Promise<void> { this.logger.debug('Clearing token due to authentication error'); this.tokenManager.clearToken(this.config.hostname, this.config.clientId); } /** * Get the appropriate auth URL based on the hostname * Uses localhost-based auth for mock servers, production auth otherwise */ private getAuthUrl(): string { return buildOCAPIAuthUrl(this.config); } /** * Get a valid OAuth access token */ private async getAccessToken(): Promise<string> { this.logger.debug('Attempting to get access token'); // Check if we have a valid token first const existingToken = this.tokenManager.getValidToken(this.config.hostname, this.config.clientId); if (existingToken) { this.logger.debug('Using existing valid token'); return existingToken; } this.logger.debug('No valid token found, requesting new token'); return this.requestNewToken(); } /** * Request a new OAuth token from SFCC */ private async requestNewToken(): Promise<string> { // Create Basic Auth header using client credentials const credentials = `${this.config.clientId}:${this.config.clientSecret}`; const encodedCredentials = Buffer.from(credentials).toString('base64'); // Get the appropriate auth URL (localhost for mock, production for real SFCC) const authUrl = this.getAuthUrl(); this.logger.debug(`Requesting token from: ${authUrl}`); try { const response = await fetch(authUrl, { method: 'POST', headers: { 'Authorization': `Basic ${encodedCredentials}`, 'Content-Type': OCAPI_AUTH_CONSTANTS.FORM_CONTENT_TYPE, }, body: `grant_type=${OCAPI_AUTH_CONSTANTS.GRANT_TYPE}`, }); if (!response.ok) { const errorText = await response.text(); throw new Error(`OAuth authentication failed: ${response.status} ${response.statusText} - ${errorText}`); } const tokenResponse: OAuthTokenResponse = await response.json(); this.logger.debug('Successfully obtained new access token'); // Store the token for future use this.tokenManager.storeToken(this.config.hostname, this.config.clientId, tokenResponse); return tokenResponse.access_token; } catch (error) { this.logger.error(`Failed to get access token: ${error}`); throw new Error(`Failed to get access token: ${error}`); } } /** * Get current token expiration for debugging */ getTokenExpiration(): Date | null { return this.tokenManager.getTokenExpiration(this.config.hostname, this.config.clientId); } /** * Force refresh the token */ async refreshToken(): Promise<void> { this.logger.debug('Forcing token refresh'); this.tokenManager.clearToken(this.config.hostname, this.config.clientId); await this.getAccessToken(); this.logger.debug('Token refresh completed'); } } ``` -------------------------------------------------------------------------------- /docs/dw_web/ClickStreamEntry.md: -------------------------------------------------------------------------------- ```markdown ## Package: dw.web # Class ClickStreamEntry ## Inheritance Hierarchy - Object - dw.web.ClickStreamEntry ## Description Represent an entry in the click stream. ## Properties ### host **Type:** String (Read Only) The host. ### locale **Type:** String (Read Only) The locale sent from the user agent. ### path **Type:** String (Read Only) The path. ### pipelineName **Type:** String (Read Only) The name of the called pipeline. In most cases the name can be derived from the path, but not in all cases. If with URL rewritting a special landing page is defined for a DNS name, than the system internally might use a specific pipeline associated with this landing page. ### queryString **Type:** String (Read Only) The query string. ### referer **Type:** String (Read Only) The referer. ### remoteAddress **Type:** String (Read Only) The remote address. ### timestamp **Type:** Number (Read Only) The entry's timestamp. ### url **Type:** String (Read Only) The full URL for this click. The URL is returned as relative URL. ### userAgent **Type:** String (Read Only) The user agent. ## Constructor Summary ## Method Summary ### getHost **Signature:** `getHost() : String` Returns the host. ### getLocale **Signature:** `getLocale() : String` Returns the locale sent from the user agent. ### getParameter **Signature:** `getParameter(name : String) : String` Returns a specific parameter value from the stored query string. ### getPath **Signature:** `getPath() : String` Returns the path. ### getPipelineName **Signature:** `getPipelineName() : String` Returns the name of the called pipeline. ### getQueryString **Signature:** `getQueryString() : String` Returns the query string. ### getReferer **Signature:** `getReferer() : String` Returns the referer. ### getRemoteAddress **Signature:** `getRemoteAddress() : String` Returns the remote address. ### getTimestamp **Signature:** `getTimestamp() : Number` Returns the entry's timestamp. ### getUrl **Signature:** `getUrl() : String` Returns the full URL for this click. ### getUserAgent **Signature:** `getUserAgent() : String` Returns the user agent. ## Method Detail ## Method Details ### getHost **Signature:** `getHost() : String` **Description:** Returns the host. **Returns:** the host. --- ### getLocale **Signature:** `getLocale() : String` **Description:** Returns the locale sent from the user agent. **Returns:** the locale sent from the user agent. --- ### getParameter **Signature:** `getParameter(name : String) : String` **Description:** Returns a specific parameter value from the stored query string. The method can be used to extract a source code or affiliate id out of the URLs in the click stream. The method returns null if there is no parameter with the given name. **Parameters:** - `name`: the name of the parameter. **Returns:** the value associated with the specified parameter, or null. --- ### getPath **Signature:** `getPath() : String` **Description:** Returns the path. **Returns:** the path. --- ### getPipelineName **Signature:** `getPipelineName() : String` **Description:** Returns the name of the called pipeline. In most cases the name can be derived from the path, but not in all cases. If with URL rewritting a special landing page is defined for a DNS name, than the system internally might use a specific pipeline associated with this landing page. **Returns:** the name of the called pipeline. --- ### getQueryString **Signature:** `getQueryString() : String` **Description:** Returns the query string. **Returns:** the query string. --- ### getReferer **Signature:** `getReferer() : String` **Description:** Returns the referer. **Returns:** the referer. --- ### getRemoteAddress **Signature:** `getRemoteAddress() : String` **Description:** Returns the remote address. **Returns:** the remote address. --- ### getTimestamp **Signature:** `getTimestamp() : Number` **Description:** Returns the entry's timestamp. **Returns:** the entry's timestamp. --- ### getUrl **Signature:** `getUrl() : String` **Description:** Returns the full URL for this click. The URL is returned as relative URL. **Returns:** the full URL for this click. --- ### getUserAgent **Signature:** `getUserAgent() : String` **Description:** Returns the user agent. **Returns:** the user agent. --- ``` -------------------------------------------------------------------------------- /tests/code-versions-client.test.ts: -------------------------------------------------------------------------------- ```typescript /** * Tests for OCAPICodeVersionsClient * Tests code version management functionality */ import { OCAPICodeVersionsClient } from '../src/clients/ocapi/code-versions-client.js'; import { TokenManager } from '../src/clients/base/oauth-token.js'; import { OCAPIConfig } from '../src/types/types.js'; // Mock fetch globally global.fetch = jest.fn(); // Mock TokenManager jest.mock('../src/clients/base/oauth-token.js'); // Mock Logger jest.mock('../src/utils/logger.js', () => ({ Logger: { initialize: jest.fn(), getInstance: jest.fn(() => ({ methodEntry: jest.fn(), methodExit: jest.fn(), debug: jest.fn(), warn: jest.fn(), error: jest.fn(), timing: jest.fn(), log: jest.fn(), info: jest.fn(), })), getChildLogger: jest.fn(() => ({ methodEntry: jest.fn(), methodExit: jest.fn(), debug: jest.fn(), warn: jest.fn(), error: jest.fn(), timing: jest.fn(), log: jest.fn(), info: jest.fn(), })), }, })); // Mock BaseHttpClient jest.mock('../src/clients/base/http-client.js'); // Mock Validator jest.mock('../src/utils/validator.js'); describe('OCAPICodeVersionsClient', () => { let client: OCAPICodeVersionsClient; let mockTokenManager: jest.Mocked<TokenManager>; const mockConfig: OCAPIConfig = { hostname: 'test-instance.demandware.net', clientId: 'test-client-id', clientSecret: 'test-client-secret', version: 'v21_3', }; beforeEach(() => { jest.clearAllMocks(); // Setup TokenManager mock mockTokenManager = { getValidToken: jest.fn(), storeToken: jest.fn(), clearToken: jest.fn(), getTokenExpiration: jest.fn(), isTokenValid: jest.fn(), clearAllTokens: jest.fn(), } as any; (TokenManager.getInstance as jest.Mock).mockReturnValue(mockTokenManager); client = new OCAPICodeVersionsClient(mockConfig); }); describe('getCodeVersions', () => { it('should make GET request to /code_versions endpoint', async () => { const mockCodeVersions = { _v: '23.2', _type: 'code_version_result', count: 1, data: [ { _type: 'code_version', id: 'version1', active: true, cartridges: 'app_storefront_base', compatibility_mode: '23.2', activation_time: '2024-01-01T00:00:00Z', total_size: '1024 KB', }, ], total: 1, }; // Mock the get method from BaseHttpClient const mockGet = jest.fn().mockResolvedValue(mockCodeVersions); (client as any).get = mockGet; const result = await client.getCodeVersions(); expect(mockGet).toHaveBeenCalledWith('/code_versions'); expect(result).toBe(mockCodeVersions); }); }); describe('activateCodeVersion', () => { it('should make PATCH request to activate code version', async () => { const mockActivatedVersion = { _v: '23.2', _type: 'code_version', _resource_state: 'new-resource-state-12345', id: 'version2', active: true, cartridges: 'app_storefront_base', compatibility_mode: '23.2', activation_time: '2024-01-15T10:30:00Z', total_size: '1024 KB', }; // Mock the patch method from BaseHttpClient const mockPatch = jest.fn().mockResolvedValue(mockActivatedVersion); (client as any).patch = mockPatch; const codeVersionId = 'version2'; const result = await client.activateCodeVersion(codeVersionId); expect(mockPatch).toHaveBeenCalledWith('/code_versions/version2', { active: true, }); expect(result).toBe(mockActivatedVersion); }); it('should validate required parameters', async () => { // Import the actual validator to test parameter validation const { Validator } = await import('../src/utils/validator.js'); const mockValidateRequired = jest.fn(); (Validator as any).validateRequired = mockValidateRequired; const codeVersionId = 'version2'; // Mock the patch method const mockPatch = jest.fn().mockResolvedValue({}); (client as any).patch = mockPatch; await client.activateCodeVersion(codeVersionId); expect(mockValidateRequired).toHaveBeenCalledWith( { codeVersionId }, ['codeVersionId'], ); }); }); }); ``` -------------------------------------------------------------------------------- /docs/dw_content/MarkupText.md: -------------------------------------------------------------------------------- ```markdown ## Package: dw.content # Class MarkupText ## Inheritance Hierarchy - Object - dw.content.MarkupText ## Description The class represents a content snippet with markup. This is typically a HTML content snippet. The class also processes the special links from Commerce Cloud Digital content management and automatically rewrites them into links for use in the storefront. The following special links can be used inside of a MarkupText: $url('<pipeline>' [, '<key1>', '<value1>', '<key2>', '<value2>', ...])$ Description: The $url()$ function creates and absolute URL and retains the protocol incoming request. Example: MarkupText: $url('MyLinkPipeline-Start', 'key1', 'value1', 'key2', 'value2')$ is rewritten to: http://<host>:<port>/on/demandware.store/<current site>/default/MyLinkPipeline-Start?key1=value1&key2=value2 Note that the incoming protocol was http in the example above. $httpUrl('<pipeline>' [, '<key1>', '<value1>', '<key2>', '<value2>', ...])$ Description: The $httpUrl()$ function creates an absolute URL but always with the fix protocol "http". The protocol type of the incomming request is ignored. Example: MarkupText: $httpUrl('MyLinkPipeline-Start', 'key1', 'value1', 'key2', 'value2')$ is rewritten to: http://<host>:'<port>/on/demandware.store/<current site>/default/MyLinkPipeline-Start?key1=value1&key2=value2 $httpsUrl('<pipeline>' [, '<key1>', '<value1>', '<key2>', '<value2>', ...])$ Description: The $httpsUrl()$ function creates an absolute URL but always with the fix protocol "https". The protocol type of the incomming request is ignored. Example: MarkupText: $httpsUrl('MyLinkPipeline-Start', 'key1', 'value1', 'key2', 'value2')$ is rewritten to: https://<host>:<port>/on/demandware.store/<current site>/default/MyLinkPipeline-Start?key1=value1&key2=value2 $include('<pipeline>' [, '<key1>', '<value1>', '<key2>', '<value2>', ...])$ Description: The $include()$ function creates a relative URL which is post processed by the Commerce Cloud Digital Webadapter. The result is the content generated by the given pipeline call. Example: MarkupText: $include('MyIncludePipeline-Start','key1', 'value1', 'key2' ,'value2')$ results in the content delivered by the 'MyIncludePipeline-Start' pipeline. ...?$staticlink$ Description: The $staticlink$ function can be used to create a URL to a static resource (such as an image). The URL being generated depends on the owner of the MarkupText instance. For example, a product's long description (which is a MarkupText) will generate links to static resources within the catalog. Possible URL targets are catalogs (for catalog related objects like products and categories), the content library (for library related objects like folders and assets) or the organization (for all objects that are not catalog or library related). Example: MarkupText: (owned by a content asset) <img src="demo/content/bullet.gif?$staticlink$"> is rewritten to: <img src="/on/demandware.static/<current site>/<library>/default/v1178201405900/demo/content/bullet.gif"> Note: The comma symbol , is not supported in parameter values for the link functions. ## Properties ### markup **Type:** String (Read Only) The content with all links rewritten for storefront use. ### source **Type:** String (Read Only) The original content source, without any links re-written. ## Constructor Summary ## Method Summary ### getMarkup **Signature:** `getMarkup() : String` Returns the content with all links rewritten for storefront use. ### getSource **Signature:** `getSource() : String` Returns the original content source, without any links re-written. ### toString **Signature:** `toString() : String` Returns a string representation of this class, the same as getMarkup(). ## Method Detail ## Method Details ### getMarkup **Signature:** `getMarkup() : String` **Description:** Returns the content with all links rewritten for storefront use. **Returns:** the content with all links rewritten for storefront use. --- ### getSource **Signature:** `getSource() : String` **Description:** Returns the original content source, without any links re-written. **Returns:** the original content source, without any links re-written. --- ### toString **Signature:** `toString() : String` **Description:** Returns a string representation of this class, the same as getMarkup(). **Returns:** a string representation of this class, the same as getMarkup(). --- ``` -------------------------------------------------------------------------------- /docs-site/src/styles/input.css: -------------------------------------------------------------------------------- ```css @tailwind base; @tailwind components; @tailwind utilities; /* Custom Prism.js theme for SFCC Development MCP Server docs */ /* Override default Prism styles with a clean, modern theme */ pre[class*="language-"] { background: transparent !important; margin: 0 !important; padding: 1rem !important; /* Force proper padding */ overflow: visible; } code[class*="language-"] { background: transparent !important; text-shadow: none; font-family: ui-monospace, SFMono-Regular, "SF Mono", Monaco, Consolas, "Liberation Mono", "Courier New", monospace; font-size: 0.875rem; line-height: 1.5; color: #374151; /* slate-700 */ padding: 0 !important; /* Remove any inherited padding from code element */ } /* Tokens */ .token.comment, .token.prolog, .token.doctype, .token.cdata { color: #6b7280; /* slate-500 */ font-style: italic; } .token.punctuation { color: #6b7280; /* slate-500 */ } .token.property, .token.tag, .token.boolean, .token.number, .token.constant, .token.symbol, .token.deleted { color: #dc2626; /* red-600 */ } .token.selector, .token.attr-name, .token.string, .token.char, .token.builtin, .token.inserted { color: #059669; /* emerald-600 */ } .token.operator, .token.entity, .token.url, .language-css .token.string, .style .token.string { color: #7c3aed; /* violet-600 */ } .token.atrule, .token.attr-value, .token.keyword { color: #2563eb; /* blue-600 */ } .token.function, .token.class-name { color: #ea580c; /* orange-600 */ } .token.regex, .token.important, .token.variable { color: #dc2626; /* red-600 */ } .token.important, .token.bold { font-weight: bold; } .token.italic { font-style: italic; } .token.entity { cursor: help; } /* JSON specific */ .token.key { color: #2563eb; /* blue-600 */ } /* YAML specific */ .token.title { color: #2563eb; /* blue-600 */ } /* Bash/Shell specific */ .token.command { color: #059669; /* emerald-600 */ } .token.parameter { color: #dc2626; /* red-600 */ } /* JSX/TSX specific */ .token.tag .token.punctuation { color: #6b7280; /* slate-500 */ } .token.tag .token.script-punctuation { color: #6b7280; /* slate-500 */ } .token.attr-value .token.punctuation { color: #059669; /* emerald-600 */ } .token.attr-value .token.punctuation:first-child { color: #059669; /* emerald-600 */ } /* Mobile responsiveness and text overflow fixes */ * { box-sizing: border-box; } html { overflow-x: hidden; } body { overflow-x: hidden; width: 100vw; max-width: 100vw; } /* Ensure all text content can break appropriately */ .prose { word-wrap: break-word; overflow-wrap: break-word; word-break: break-word; } /* Force long words and URLs to break */ .prose p, .prose li, .prose td, .prose th { word-wrap: break-word; overflow-wrap: break-word; hyphens: auto; } /* Ensure code blocks don't overflow */ .prose pre { max-width: 100%; overflow-x: auto; white-space: pre; word-break: normal; } .prose code { white-space: pre; word-break: normal; } /* Allow horizontal scroll specifically in code blocks */ .prose pre code { white-space: pre; word-break: normal; overflow-wrap: normal; } /* Inline code should break words */ .prose p code, .prose li code, .prose td code, .prose th code, .prose h1 code, .prose h2 code, .prose h3 code, .prose h4 code, .prose h5 code, .prose h6 code { word-break: break-word !important; overflow-wrap: break-word !important; white-space: normal !important; } /* Tables should be responsive */ .prose table { width: 100%; table-layout: fixed; word-break: break-word; } /* Prevent horizontal scrolling on mobile */ @media (max-width: 768px) { html, body { overflow-x: hidden !important; max-width: 100vw !important; width: 100% !important; } * { max-width: 100% !important; } .prose { max-width: none; width: 100%; } .prose pre { max-width: calc(100vw - 3rem) !important; overflow-x: auto; white-space: pre; word-break: normal; } .prose pre code { white-space: pre !important; word-break: normal !important; overflow-wrap: normal !important; } .prose table { max-width: calc(100vw - 3rem) !important; overflow-x: auto; display: block; white-space: nowrap; } /* Ensure no element can be wider than viewport */ #root, .min-h-screen, main, .prose { max-width: 100vw !important; overflow-x: hidden !important; } } ``` -------------------------------------------------------------------------------- /docs/dw_web/FormFieldOption.md: -------------------------------------------------------------------------------- ```markdown ## Package: dw.web # Class FormFieldOption ## Inheritance Hierarchy - Object - dw.web.FormFieldOption ## Description Represents an option for a form field. ## Properties ### checked **Type:** boolean (Read Only) Identifies if this option is checked. ### htmlValue **Type:** String (Read Only) The value for the HTML value attribute of a HTML option element. ### label **Type:** String The value for the HTML label attribute of the HTML option element. If not specified in the form option definition the label is identical with the string representation of option value (see getValue()). ### object **Type:** Object (Read Only) The object that was bound to this option value. ### optionId **Type:** String (Read Only) The ID of the option. This is an internal ID used to uniquely reference this option. If not specified in the form option definition the ID is identical with the string representation of the option value (see getValue()). ### parent **Type:** FormField (Read Only) The parent, which is a field element. ### selected **Type:** boolean (Read Only) Identifies if this option is selected. ### value **Type:** Object (Read Only) The actual value associated with this option. This value is formatted and than returned as HTML value with the method getHtmlValue(). ## Constructor Summary ## Method Summary ### getHtmlValue **Signature:** `getHtmlValue() : String` Returns the value for the HTML value attribute of a HTML option element. ### getLabel **Signature:** `getLabel() : String` Returns the value for the HTML label attribute of the HTML option element. ### getObject **Signature:** `getObject() : Object` Returns the object that was bound to this option value. ### getOptionId **Signature:** `getOptionId() : String` Returns the ID of the option. ### getParent **Signature:** `getParent() : FormField` The parent, which is a field element. ### getValue **Signature:** `getValue() : Object` The actual value associated with this option. ### isChecked **Signature:** `isChecked() : boolean` Identifies if this option is checked. ### isSelected **Signature:** `isSelected() : boolean` Identifies if this option is selected. ### setLabel **Signature:** `setLabel(label : String) : void` Sets the label attribute for this option. ## Method Detail ## Method Details ### getHtmlValue **Signature:** `getHtmlValue() : String` **Description:** Returns the value for the HTML value attribute of a HTML option element. **Returns:** the value for the HTML value attribute of a HTML option element. --- ### getLabel **Signature:** `getLabel() : String` **Description:** Returns the value for the HTML label attribute of the HTML option element. If not specified in the form option definition the label is identical with the string representation of option value (see getValue()). **Returns:** the value for the HTML label attribute of the HTML option element. --- ### getObject **Signature:** `getObject() : Object` **Description:** Returns the object that was bound to this option value. **Returns:** the object that was bound to this option value. --- ### getOptionId **Signature:** `getOptionId() : String` **Description:** Returns the ID of the option. This is an internal ID used to uniquely reference this option. If not specified in the form option definition the ID is identical with the string representation of the option value (see getValue()). **Returns:** the ID of the option. --- ### getParent **Signature:** `getParent() : FormField` **Description:** The parent, which is a field element. **Returns:** the parent form field. --- ### getValue **Signature:** `getValue() : Object` **Description:** The actual value associated with this option. This value is formatted and than returned as HTML value with the method getHtmlValue(). **Returns:** the value associated with this option --- ### isChecked **Signature:** `isChecked() : boolean` **Description:** Identifies if this option is checked. **Returns:** true if this option is checked, false otherwise. --- ### isSelected **Signature:** `isSelected() : boolean` **Description:** Identifies if this option is selected. **Returns:** true if this option is selected, false otherwise. --- ### setLabel **Signature:** `setLabel(label : String) : void` **Description:** Sets the label attribute for this option. **Parameters:** - `label`: the label value. --- ``` -------------------------------------------------------------------------------- /docs/dw_extensions.applepay/ApplePayHookResult.md: -------------------------------------------------------------------------------- ```markdown ## Package: dw.extensions.applepay # Class ApplePayHookResult ## Inheritance Hierarchy - Object - dw.extensions.applepay.ApplePayHookResult ## Description Result of a hook handling an Apple Pay request. Use the constants in this type to indicate specific error reasons to be provided to Apple Pay JS. For example, the following code creates a Status that indicates the shipping contact information provided by Apple Pay is invalid: var ApplePayHookResult = require('dw/extensions/applepay/ApplePayHookResult'); var Status = require('dw/system/Status'); var error = new Status(Status.ERROR); error.addDetail(ApplePayHookResult.STATUS_REASON_DETAIL_KEY, ApplePayHookResult.REASON_SHIPPING_CONTACT); If a specific error reason is not provided, the generic Apple Pay STATUS_FAILURE reason will be used when necessary. ## Constants ### REASON_BILLING_ADDRESS **Type:** String = "InvalidBillingPostalAddress" Error reason code representing an invalid billing address. ### REASON_FAILURE **Type:** String = "Failure" Error reason code representing an error or failure not otherwise specified. ### REASON_PIN_INCORRECT **Type:** String = "PINIncorrect" Error reason code representing the PIN is incorrect. ### REASON_PIN_LOCKOUT **Type:** String = "PINLockout" Error reason code representing a PIN lockout. ### REASON_PIN_REQUIRED **Type:** String = "PINRequired" Error reason code representing a PIN is required. ### REASON_SHIPPING_ADDRESS **Type:** String = "InvalidShippingPostalAddress" Error reason code representing an invalid shipping address. ### REASON_SHIPPING_CONTACT **Type:** String = "InvalidShippingContact" Error reason code representing invalid shipping contact information. ### STATUS_REASON_DETAIL_KEY **Type:** String = "reason" Key for the detail to be used in Status objects to indicate the reason to communicate to Apple Pay for errors. ## Properties ### eventDetail **Type:** Object (Read Only) Detail to the JS custom event to dispatch in response to this result. ### eventName **Type:** String (Read Only) Name of the JS custom event to dispatch in response to this result. ### redirect **Type:** URL (Read Only) URL to navigate to in response to this result. ### status **Type:** Status (Read Only) Status describing the outcome of this result. ## Constructor Summary ApplePayHookResult(status : Status, redirect : URL) Constructs a result with the given outcome information. ## Method Summary ### getEventDetail **Signature:** `getEventDetail() : Object` Detail to the JS custom event to dispatch in response to this result. ### getEventName **Signature:** `getEventName() : String` Name of the JS custom event to dispatch in response to this result. ### getRedirect **Signature:** `getRedirect() : URL` URL to navigate to in response to this result. ### getStatus **Signature:** `getStatus() : Status` Status describing the outcome of this result. ### setEvent **Signature:** `setEvent(name : String) : void` Sets the name of the JS custom event to dispatch in response to this result. ### setEvent **Signature:** `setEvent(name : String, detail : Object) : void` Sets the name and detail of the JS custom event to dispatch in response to this result. ## Constructor Detail ## Method Detail ## Method Details ### getEventDetail **Signature:** `getEventDetail() : Object` **Description:** Detail to the JS custom event to dispatch in response to this result. **Returns:** event detail --- ### getEventName **Signature:** `getEventName() : String` **Description:** Name of the JS custom event to dispatch in response to this result. **Returns:** event name --- ### getRedirect **Signature:** `getRedirect() : URL` **Description:** URL to navigate to in response to this result. **Returns:** redirect URL --- ### getStatus **Signature:** `getStatus() : Status` **Description:** Status describing the outcome of this result. **Returns:** status of this result --- ### setEvent **Signature:** `setEvent(name : String) : void` **Description:** Sets the name of the JS custom event to dispatch in response to this result. **Parameters:** - `name`: JS custom event name --- ### setEvent **Signature:** `setEvent(name : String, detail : Object) : void` **Description:** Sets the name and detail of the JS custom event to dispatch in response to this result. **Parameters:** - `name`: JS custom event name - `detail`: JS custom event detail --- ``` -------------------------------------------------------------------------------- /docs-site/components/CodeBlock.tsx: -------------------------------------------------------------------------------- ```typescript import React, { useState, useEffect, useRef } from 'react'; import { CopyIcon, CheckIcon } from './icons'; // Dynamic Prism import to prevent SSR issues let Prism: any = null; interface CodeBlockProps { code: string; language: string; } const CodeBlock: React.FC<CodeBlockProps> = ({ code, language }) => { const [copied, setCopied] = useState(false); const [isMounted, setIsMounted] = useState(false); const codeRef = useRef<HTMLElement>(null); const handleCopy = () => { if (typeof window !== 'undefined' && navigator.clipboard) { navigator.clipboard.writeText(code.trim()); setCopied(true); setTimeout(() => setCopied(false), 2000); } }; // Map common language aliases to Prism language identifiers const getPrismLanguage = (lang: string): string => { const langMap: { [key: string]: string } = { 'js': 'javascript', 'ts': 'typescript', 'jsx': 'jsx', 'tsx': 'tsx', 'json': 'json', 'yml': 'yaml', 'yaml': 'yaml', 'sh': 'bash', 'shell': 'bash', 'bash': 'bash', 'zsh': 'bash', 'md': 'markdown', 'markdown': 'markdown', 'css': 'css', 'scss': 'scss', 'sass': 'scss', }; return langMap[lang.toLowerCase()] || lang.toLowerCase(); }; const prismLanguage = getPrismLanguage(language); // Apply syntax highlighting after component mounts (client-side only) useEffect(() => { setIsMounted(true); // Load Prism dynamically on client side only const loadPrismAndHighlight = async () => { if (typeof window !== 'undefined' && !Prism) { try { // Dynamically import Prism and language components const prismModule = await import('prismjs'); await import('prismjs/components/prism-javascript'); await import('prismjs/components/prism-typescript'); await import('prismjs/components/prism-jsx'); await import('prismjs/components/prism-tsx'); await import('prismjs/components/prism-json'); await import('prismjs/components/prism-yaml'); await import('prismjs/components/prism-bash'); await import('prismjs/components/prism-shell-session'); await import('prismjs/components/prism-markdown'); await import('prismjs/components/prism-css'); await import('prismjs/components/prism-scss'); Prism = prismModule.default; } catch (error) { console.warn('Failed to load Prism:', error); return; } } // Apply highlighting after a small delay to ensure hydration is complete setTimeout(() => { if (Prism && codeRef.current && Prism.languages[prismLanguage]) { const highlighted = Prism.highlight(code.trim(), Prism.languages[prismLanguage], prismLanguage); codeRef.current.innerHTML = highlighted; } }, 100); }; loadPrismAndHighlight(); }, [code, language, prismLanguage]); return ( <div className="my-6 rounded-xl border border-slate-200 bg-slate-50 not-prose overflow-hidden max-w-full"> <div className="flex justify-between items-center px-3 sm:px-4 py-2 border-b border-slate-200"> <span className="text-xs font-semibold text-slate-500 uppercase truncate">{language}</span> <button onClick={handleCopy} className="flex items-center gap-1 sm:gap-1.5 text-xs sm:text-sm text-slate-500 hover:text-slate-800 transition-colors flex-shrink-0 ml-2" > {copied ? ( <> <CheckIcon className="w-4 h-4 text-green-500" /> <span className="hidden xs:inline">Copied!</span> </> ) : ( <> <CopyIcon className="w-4 h-4" /> <span className="hidden xs:inline">Copy</span> </> )} </button> </div> <div className="overflow-x-auto max-w-full"> <pre className="p-3 sm:p-4 text-xs sm:text-sm min-w-0 m-0"> <code ref={codeRef} className={`block whitespace-pre language-${prismLanguage}`} > {code.trim()} </code> </pre> </div> </div> ); }; export const InlineCode: React.FC<{children: React.ReactNode}> = ({ children }) => ( <code className="text-sm font-mono bg-rose-100 text-rose-800 rounded-md px-1 py-0.5">{children}</code> ); export default CodeBlock; ``` -------------------------------------------------------------------------------- /docs/dw_web/URL.md: -------------------------------------------------------------------------------- ```markdown ## Package: dw.web # Class URL ## Inheritance Hierarchy - Object - dw.web.URL ## Description Represents a URL in Commerce Cloud Digital. ## Constructor Summary ## Method Summary ### abs **Signature:** `abs() : URL` Makes the URL absolute and ensures that the protocol of the request is used or http in a mail context. ### append **Signature:** `append(name : String, value : String) : URL` Append a request parameter to this URL. ### appendCSRFTokenBM **Signature:** `appendCSRFTokenBM() : URL` Appends, if applicable, a CSRF protection token to this URL. ### host **Signature:** `host(host : String) : URL` Updates the URL with the specified host name Note: This method is not applicable for static content or image transformation URLs. ### http **Signature:** `http() : URL` Makes the URL absolute and ensures that the protocol http is used. ### https **Signature:** `https() : URL` Makes the URL absolute and ensures that the protocol https is used. ### relative **Signature:** `relative() : URL` Makes the URL relative. ### remove **Signature:** `remove(name : String) : URL` Remove a request parameter from this URL. ### siteHost **Signature:** `siteHost() : URL` Updates the URL with the site host name Note: This method is not applicable for static content or image transformation URLs. ### toString **Signature:** `toString() : String` Return String representation of the URL. ## Method Detail ## Method Details ### abs **Signature:** `abs() : URL` **Description:** Makes the URL absolute and ensures that the protocol of the request is used or http in a mail context. Note: This method is not applicable for static content or image transformation URLs. In this case a runtime exception is thrown. **Returns:** A new URL instance. --- ### append **Signature:** `append(name : String, value : String) : URL` **Description:** Append a request parameter to this URL. **Parameters:** - `name`: The parameter name. Must not be null. - `value`: The parameter value. If null, then treated as empty value. **Returns:** A reference to this URL. --- ### appendCSRFTokenBM **Signature:** `appendCSRFTokenBM() : URL` **Description:** Appends, if applicable, a CSRF protection token to this URL. The CSRF token will only be appended under the following conditions: the URL is a pipeline URL the URL is for Business Manager If a CSRF token already exists in the URL, it will be replaced with a newly generated one. **Returns:** a reference to this URL, with a CSRF token appended if applicable. --- ### host **Signature:** `host(host : String) : URL` **Description:** Updates the URL with the specified host name Note: This method is not applicable for static content or image transformation URLs. In this case a runtime exception is thrown. **Parameters:** - `host`: The host name that is used to update the URL. **Returns:** A new URL instance. --- ### http **Signature:** `http() : URL` **Description:** Makes the URL absolute and ensures that the protocol http is used. Note: This method is not applicable for static content or image transformation URLs. In this case a runtime exception is thrown. **Returns:** A new URL instance. --- ### https **Signature:** `https() : URL` **Description:** Makes the URL absolute and ensures that the protocol https is used. Note: This method is not applicable for static content or image transformation URLs. In this case a runtime exception is thrown. **Returns:** A new URL instance. --- ### relative **Signature:** `relative() : URL` **Description:** Makes the URL relative. Note: This method is not applicable for static content or image transformation URLs. In this case a runtime exception is thrown. **Returns:** A new URL instance. --- ### remove **Signature:** `remove(name : String) : URL` **Description:** Remove a request parameter from this URL. If the parameter is not part of the URL, nothing is done. **Parameters:** - `name`: The parameter name. Must not be null. **Returns:** A reference to this URL. --- ### siteHost **Signature:** `siteHost() : URL` **Description:** Updates the URL with the site host name Note: This method is not applicable for static content or image transformation URLs. In this case a runtime exception is thrown. **Returns:** A new URL instance. --- ### toString **Signature:** `toString() : String` **Description:** Return String representation of the URL. **Returns:** the URL as a string. --- ``` -------------------------------------------------------------------------------- /docs/dw_crypto/SecureRandom.md: -------------------------------------------------------------------------------- ```markdown ## Package: dw.crypto # Class SecureRandom ## Inheritance Hierarchy - Object - dw.crypto.SecureRandom ## Description The SecureRandom class provides a cryptographically strong random number generator (RNG). See the Internet Engineering Task Force (IETF) RFC 1750: Randomness Recommendations for Security for more information. Typical callers of SecureRandom invoke the following methods to retrieve random bytes: Bytes bytes... SecureRandom random = new SecureRandom(); Bytes nextBytes = random.nextBytes(bytes); or more convenient to get a Bytes with the demanded length int length = 32; SecureRandom random = new SecureRandom(); Bytes nextBytes = random.nextBytes(length); dw.crypto.SecureRandom is intentionally an adapter for generating cryptographic hard random numbers. ## Constructor Summary SecureRandom() Instantiates a new secure random. ## Method Summary ### generateSeed **Signature:** `generateSeed(numBytes : Number) : Bytes` Returns the given number of seed bytes, computed using the seed generation algorithm that this class uses to seed itself. ### nextBytes **Signature:** `nextBytes(numBits : Number) : Bytes` Generates a user-specified number of random bytes. ### nextInt **Signature:** `nextInt() : Number` Returns the next pseudorandom, uniformly distributed int value from this random number generator's sequence. ### nextInt **Signature:** `nextInt(upperBound : Number) : Number` Returns a pseudorandom, uniformly distributed int value between 0 (inclusive) and the specified value (exclusive), drawn from this random number generator's sequence. ### nextNumber **Signature:** `nextNumber() : Number` Returns the next pseudorandom, uniformly distributed Number value between 0.0 (inclusive) and 1.0 (exclusive) from this random number generator's sequence. ### setSeed **Signature:** `setSeed(seed : Bytes) : void` Reseeds this random object. ## Constructor Detail ## Method Detail ## Method Details ### generateSeed **Signature:** `generateSeed(numBytes : Number) : Bytes` **Description:** Returns the given number of seed bytes, computed using the seed generation algorithm that this class uses to seed itself. This call may be used to seed other random number generators. **Parameters:** - `numBytes`: the number of seed bytes to generate. **Returns:** the seed bytes. --- ### nextBytes **Signature:** `nextBytes(numBits : Number) : Bytes` **Description:** Generates a user-specified number of random bytes. If a call to setSeed had not occurred previously, the first call to this method forces this SecureRandom object to seed itself. This self-seeding will not occur if setSeed was previously called. **Parameters:** - `numBits`: the demanded number of bits **Returns:** a randomly filled Bytes --- ### nextInt **Signature:** `nextInt() : Number` **Description:** Returns the next pseudorandom, uniformly distributed int value from this random number generator's sequence. The general contract of nextInt is that one int value is pseudorandomly generated and returned. All 2^32 possible int values are produced with (approximately) equal probability. **Returns:** the next pseudorandom, uniformly distributed int value from this random number generator's sequence --- ### nextInt **Signature:** `nextInt(upperBound : Number) : Number` **Description:** Returns a pseudorandom, uniformly distributed int value between 0 (inclusive) and the specified value (exclusive), drawn from this random number generator's sequence. **Parameters:** - `upperBound`: the bound on the random number to be returned. Must be positive. **Returns:** the next pseudorandom, uniformly distributed int value between 0 (inclusive) and upperBound (exclusive) from this random number generator's sequence **Throws:** IllegalArgumentException - if n is not positive --- ### nextNumber **Signature:** `nextNumber() : Number` **Description:** Returns the next pseudorandom, uniformly distributed Number value between 0.0 (inclusive) and 1.0 (exclusive) from this random number generator's sequence. **Returns:** the next pseudorandom, uniformly distributed Number value between 0.0 and 1.0 from this random number generator's sequence --- ### setSeed **Signature:** `setSeed(seed : Bytes) : void` **Description:** Reseeds this random object. The given seed supplements, rather than replaces, the existing seed. Thus, repeated calls are guaranteed never to reduce randomness. **Parameters:** - `seed`: the seed. --- ``` -------------------------------------------------------------------------------- /docs/dw_customer/AddressBook.md: -------------------------------------------------------------------------------- ```markdown ## Package: dw.customer # Class AddressBook ## Inheritance Hierarchy - Object - dw.customer.AddressBook ## Description Represents a set of addresses associated with a specific customer. The AddressBook object gets its data from the Profile object for the customer. When scripting, this class allows AddressBook to be treated as a separate object from the Profile. However, data is only stored in the platform in the Profile object and there is no separate AddressBook object. For this reason, the AddressBook ID is always the customer profile ID. Note: this class allows access to sensitive personal and private information. Pay attention to appropriate legal and regulatory requirements when developing. ## Properties ### addresses **Type:** List (Read Only) A sorted list of addresses in the address book. The addresses are sorted so that the preferred address is always sorted first. The remaining addresses are sorted alphabetically by ID. ### preferredAddress **Type:** CustomerAddress The address that has been defined as the customer's preferred address. ## Constructor Summary ## Method Summary ### createAddress **Signature:** `createAddress(name : String) : CustomerAddress` Creates a new, empty address object with the specified name. ### getAddress **Signature:** `getAddress(id : String) : CustomerAddress` Returns the address with the given name from the address book. ### getAddresses **Signature:** `getAddresses() : List` Returns a sorted list of addresses in the address book. ### getPreferredAddress **Signature:** `getPreferredAddress() : CustomerAddress` Returns the address that has been defined as the customer's preferred address. ### removeAddress **Signature:** `removeAddress(address : CustomerAddress) : void` Removes the specified address from the address book. ### setPreferredAddress **Signature:** `setPreferredAddress(anAddress : CustomerAddress) : void` Sets the specified address as the customer's preferred address. ## Method Detail ## Method Details ### createAddress **Signature:** `createAddress(name : String) : CustomerAddress` **Description:** Creates a new, empty address object with the specified name. **Parameters:** - `name`: the ID of the address to create, must not be null. **Returns:** the new address object or null if an address with the given name already exists in the address book. **Throws:** NullArgumentException - If passed 'name' is null. IllegalArgumentException - If passed 'name' is not null, but an empty string. --- ### getAddress **Signature:** `getAddress(id : String) : CustomerAddress` **Description:** Returns the address with the given name from the address book. The name is a unique identifier of the address within the address book. **Parameters:** - `id`: An address ID, must not be null. **Returns:** The Address object or null if the address does not exist. **Throws:** NullArgumentException - If passed 'id' is null. IllegalArgumentException - If passed 'id' is not null, but an empty string. --- ### getAddresses **Signature:** `getAddresses() : List` **Description:** Returns a sorted list of addresses in the address book. The addresses are sorted so that the preferred address is always sorted first. The remaining addresses are sorted alphabetically by ID. **Returns:** Sorted List of customer addresses in the address book. --- ### getPreferredAddress **Signature:** `getPreferredAddress() : CustomerAddress` **Description:** Returns the address that has been defined as the customer's preferred address. **Returns:** the default CustomerAddress object, or null if there is no preferred address. --- ### removeAddress **Signature:** `removeAddress(address : CustomerAddress) : void` **Description:** Removes the specified address from the address book. Because an address can be associated with a product list, you may want to verify if the address is being used by a product list. See ProductListMgr.findAddress(). **Parameters:** - `address`: the address to remove, must not be null. --- ### setPreferredAddress **Signature:** `setPreferredAddress(anAddress : CustomerAddress) : void` **Description:** Sets the specified address as the customer's preferred address. If null is passed, and there is an existing preferred address, then the address book will have no preferred address. **Parameters:** - `anAddress`: the address to be set as preferred, or null if the goal is to unset the existing preferred address. --- ``` -------------------------------------------------------------------------------- /src/core/handlers/validation-helpers.ts: -------------------------------------------------------------------------------- ```typescript /** * Validation helpers for handler arguments */ import { HandlerError, ToolArguments } from './base-handler.js'; export interface ValidationRule<T = any> { field: string; required?: boolean; type?: 'string' | 'number' | 'boolean' | 'object' | 'array'; validator?: (value: T) => boolean; errorMessage?: string; } export class ValidationHelpers { /** * Validate arguments against a set of rules */ static validateArguments( args: ToolArguments, rules: ValidationRule[], toolName: string, ): void { for (const rule of rules) { const value = args?.[rule.field]; // Check required fields if (rule.required && (value === undefined || value === null || value === '')) { throw new HandlerError( rule.errorMessage ?? `${rule.field} is required`, toolName, 'MISSING_ARGUMENT', { field: rule.field, rules }, ); } // Skip type and custom validation if value is not present and not required if (!rule.required && (value === undefined || value === null)) { continue; } // Check type (including for required fields that have values) if (rule.type && value !== undefined && value !== null && !this.validateType(value, rule.type)) { throw new HandlerError( rule.errorMessage ?? `${rule.field} must be of type ${rule.type}`, toolName, 'INVALID_TYPE', { field: rule.field, expectedType: rule.type, actualType: typeof value }, ); } // Custom validation if (rule.validator && !rule.validator(value)) { throw new HandlerError( rule.errorMessage ?? `${rule.field} validation failed`, toolName, 'VALIDATION_FAILED', { field: rule.field, value }, ); } } } /** * Quick validation for required string fields * @deprecated Use CommonValidations.requiredString() with validateArguments() instead * @example * // Old way * ValidationHelpers.requireStrings(args, ['fieldName'], 'tool_name'); * * // New way * ValidationHelpers.validateArguments(args, CommonValidations.requiredString('fieldName'), 'tool_name'); */ static requireStrings(args: ToolArguments, fields: string[], toolName: string): void { const rules: ValidationRule[] = fields.map(field => ({ field, required: true, type: 'string' as const, errorMessage: `${field} is required for ${toolName}`, })); this.validateArguments(args, rules, toolName); } /** * Validate a single field with custom validator */ static validateField<T>( args: ToolArguments, field: string, validator: (value: T) => boolean, errorMessage: string, toolName: string, ): void { const rules: ValidationRule[] = [{ field, validator, errorMessage, }]; this.validateArguments(args, rules, toolName); } private static validateType(value: any, type: ValidationRule['type']): boolean { switch (type) { case 'string': return typeof value === 'string'; case 'number': return typeof value === 'number' && !isNaN(value); case 'boolean': return typeof value === 'boolean'; case 'object': return typeof value === 'object' && value !== null && !Array.isArray(value); case 'array': return Array.isArray(value); default: return true; } } } /** * Common validation rules factory */ export const CommonValidations = { /** * Create a required string field validation */ requiredString: (field: string, customMessage?: string): ValidationRule[] => [{ field, required: true, type: 'string', validator: (value: string) => value.trim().length > 0, errorMessage: customMessage ?? `${field} must be a non-empty string`, }], /** * Create a required field validation with custom validator */ requiredField: ( field: string, type: ValidationRule['type'], validator: (value: any) => boolean, errorMessage: string, ): ValidationRule[] => [{ field, required: true, type, validator, errorMessage, }], /** * Create an optional field validation */ optionalField: ( field: string, type: ValidationRule['type'], validator: (value: any) => boolean, errorMessage: string, ): ValidationRule[] => [{ field, required: false, type, validator, errorMessage, }], }; ``` -------------------------------------------------------------------------------- /docs/dw_web/LoopIterator.md: -------------------------------------------------------------------------------- ```markdown ## Package: dw.web # Class LoopIterator ## Inheritance Hierarchy - Object - dw.util.Iterator - dw.web.LoopIterator ## Description Iterator used in <ISLOOP> implementation. It defines properties used to determine loop status. LoopIterator object is assigned to variable declared in "status" attribute of the <ISLOOP> tag. ## Properties ### begin **Type:** Number (Read Only) Return begin iteration index. By default begin index is 0. ### count **Type:** Number (Read Only) Return iteration count, starting with 1. ### end **Type:** Number (Read Only) Return end iteration index. By default end index equals 'length - 1', provided that length is determined. If length cannot be determined end index is -1. ### even **Type:** boolean (Read Only) Identifies if count is an even value. ### first **Type:** boolean (Read Only) Identifies if the iterator is positioned at first iteratable item. ### index **Type:** Number (Read Only) Return iteration index, which is the position of the iterator in the underlying iteratable object. Index is 0-based and is calculated according the following formula: Index = (Count - 1) * Step. ### last **Type:** boolean (Read Only) Identifies if the iterator is positioned at last iteratable item. ### length **Type:** Number (Read Only) Return the length of the object. If length cannot be determined, -1 is returned. ### odd **Type:** boolean (Read Only) Identifies if count is an odd value. ### step **Type:** Number (Read Only) Return iterator step. ## Constructor Summary ## Method Summary ### getBegin **Signature:** `getBegin() : Number` Return begin iteration index. ### getCount **Signature:** `getCount() : Number` Return iteration count, starting with 1. ### getEnd **Signature:** `getEnd() : Number` Return end iteration index. ### getIndex **Signature:** `getIndex() : Number` Return iteration index, which is the position of the iterator in the underlying iteratable object. ### getLength **Signature:** `getLength() : Number` Return the length of the object. ### getStep **Signature:** `getStep() : Number` Return iterator step. ### isEven **Signature:** `isEven() : boolean` Identifies if count is an even value. ### isFirst **Signature:** `isFirst() : boolean` Identifies if the iterator is positioned at first iteratable item. ### isLast **Signature:** `isLast() : boolean` Identifies if the iterator is positioned at last iteratable item. ### isOdd **Signature:** `isOdd() : boolean` Identifies if count is an odd value. ## Method Detail ## Method Details ### getBegin **Signature:** `getBegin() : Number` **Description:** Return begin iteration index. By default begin index is 0. **Returns:** the begin iteration index. --- ### getCount **Signature:** `getCount() : Number` **Description:** Return iteration count, starting with 1. **Returns:** the iteration count. --- ### getEnd **Signature:** `getEnd() : Number` **Description:** Return end iteration index. By default end index equals 'length - 1', provided that length is determined. If length cannot be determined end index is -1. --- ### getIndex **Signature:** `getIndex() : Number` **Description:** Return iteration index, which is the position of the iterator in the underlying iteratable object. Index is 0-based and is calculated according the following formula: Index = (Count - 1) * Step. **Returns:** the iteration index. --- ### getLength **Signature:** `getLength() : Number` **Description:** Return the length of the object. If length cannot be determined, -1 is returned. **Returns:** the length of the object --- ### getStep **Signature:** `getStep() : Number` **Description:** Return iterator step. **Returns:** the iterator step. --- ### isEven **Signature:** `isEven() : boolean` **Description:** Identifies if count is an even value. **Returns:** true if count is even, false otherwise. --- ### isFirst **Signature:** `isFirst() : boolean` **Description:** Identifies if the iterator is positioned at first iteratable item. **Returns:** true if the iterator is at first item, false otherwise. --- ### isLast **Signature:** `isLast() : boolean` **Description:** Identifies if the iterator is positioned at last iteratable item. **Returns:** true if iterator is at last item, false otherwise. --- ### isOdd **Signature:** `isOdd() : boolean` **Description:** Identifies if count is an odd value. **Returns:** true if count is odd, false otherwise. --- ``` -------------------------------------------------------------------------------- /tests/mcp/yaml/search-job-logs.full-mode.test.mcp.yml: -------------------------------------------------------------------------------- ```yaml --- description: "Optimized search_job_logs tool tests for aegis framework validation" tests: # Essential functionality tests - focus on MCP protocol and aegis pattern matching - it: "should search for patterns with basic functionality" request: jsonrpc: "2.0" id: "search-basic" method: "tools/call" params: name: "search_job_logs" arguments: pattern: "INFO" limit: 3 expect: response: jsonrpc: "2.0" id: "search-basic" result: content: match:arrayElements: type: "text" text: "match:contains:Found" isError: false stderr: "toBeEmpty" performance: maxResponseTime: "2000ms" - it: "should combine all parameters effectively" request: jsonrpc: "2.0" id: "search-combined" method: "tools/call" params: name: "search_job_logs" arguments: pattern: "job" level: "info" limit: 2 jobName: "ImportCatalog" expect: response: jsonrpc: "2.0" id: "search-combined" result: content: match:arrayElements: match:partial: type: "text" isError: false stderr: "toBeEmpty" performance: maxResponseTime: "2000ms" # Content validation - test response structure and format - it: "should return properly formatted job log entries with timestamps" request: jsonrpc: "2.0" id: "search-format" method: "tools/call" params: name: "search_job_logs" arguments: pattern: "Executing" limit: 1 expect: response: jsonrpc: "2.0" id: "search-format" result: content: match:arrayElements: type: "text" text: "match:regex:\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}\\.\\d{3} GMT" isError: false stderr: "toBeEmpty" performance: maxResponseTime: "2000ms" # Edge cases - essential for aegis testing - it: "should handle no matches gracefully" request: jsonrpc: "2.0" id: "search-no-matches" method: "tools/call" params: name: "search_job_logs" arguments: pattern: "ZZZNOTHINGFOUND" expect: response: jsonrpc: "2.0" id: "search-no-matches" result: content: match:arrayElements: type: "text" text: "match:contains:No matches found" isError: false stderr: "toBeEmpty" performance: maxResponseTime: "2000ms" # Critical error handling - test MCP error responses - it: "should handle missing pattern parameter" request: jsonrpc: "2.0" id: "search-missing-pattern" method: "tools/call" params: name: "search_job_logs" arguments: {} expect: response: jsonrpc: "2.0" id: "search-missing-pattern" result: content: match:arrayElements: type: "text" text: "match:contains:pattern must be a non-empty string" isError: true stderr: "toBeEmpty" performance: maxResponseTime: "1000ms" - it: "should validate parameter types" request: jsonrpc: "2.0" id: "search-invalid-limit" method: "tools/call" params: name: "search_job_logs" arguments: pattern: "INFO" limit: "invalid" expect: response: jsonrpc: "2.0" id: "search-invalid-limit" result: content: match:arrayElements: type: "text" text: "match:contains:Invalid limit" isError: true stderr: "toBeEmpty" performance: maxResponseTime: "1000ms" # Performance validation for aegis - it: "should handle large search operations efficiently" request: jsonrpc: "2.0" id: "search-performance" method: "tools/call" params: name: "search_job_logs" arguments: pattern: "step" limit: 50 expect: response: jsonrpc: "2.0" id: "search-performance" result: content: match:arrayElements: match:partial: type: "text" isError: false stderr: "toBeEmpty" performance: maxResponseTime: "3000ms" ``` -------------------------------------------------------------------------------- /docs/dw_web/ClickStream.md: -------------------------------------------------------------------------------- ```markdown ## Package: dw.web # Class ClickStream ## Inheritance Hierarchy - Object - dw.web.ClickStream ## Description Represents the click stream in the session. A maximum number of 50 clicks is recorded per session. After the maximum is reached, each time the customer clicks on a new link, the oldest click stream entry is purged. The ClickStream always remembers the first click. The click stream is consulted when the GetLastVisitedProducts pipelet is called to retrieve the products that the customer has recently visited. ## Properties ### clicks **Type:** List (Read Only) A collection with all clicks. The first entry is the oldest entry. The last entry is the latest entry. The method returns a copy of the click stream, which makes it safe to work with the click stream, while it might be modified. ### enabled **Type:** Session.isTrackingAllowed() (Read Only) Identifies if the clickstream recording is enabled or not. It is considered enabled if either: the method Session.isTrackingAllowed() returns true or if the above method returns false but the preference 'ClickstreamHonorDNT' is set to false. When clickstream tracking is not enabled the getFirst() method still operates as expected but the rest of the clicks are not collected. ### first **Type:** ClickStreamEntry (Read Only) The first click within this session. This first click is stored independent of whether entries are purged. ### last **Type:** ClickStreamEntry (Read Only) The last recorded click stream, which is also typically the current click. In where rare cases (e.g. RedirectURL pipeline) this is not the current click, but instead the last recorded click. ### partial **Type:** boolean (Read Only) Identifies if this is only a partial click stream. If the maximum number of clicks (50) is recorded, the oldest entry is automatically purged with each additional click. In this case, this flag indicates that the click stream is only partial. ## Constructor Summary ## Method Summary ### getClicks **Signature:** `getClicks() : List` Returns a collection with all clicks. ### getFirst **Signature:** `getFirst() : ClickStreamEntry` Returns the first click within this session. ### getLast **Signature:** `getLast() : ClickStreamEntry` Returns the last recorded click stream, which is also typically the current click. ### isEnabled **Signature:** `isEnabled() : boolean` Identifies if the clickstream recording is enabled or not. ### isPartial **Signature:** `isPartial() : boolean` Identifies if this is only a partial click stream. ## Method Detail ## Method Details ### getClicks **Signature:** `getClicks() : List` **Description:** Returns a collection with all clicks. The first entry is the oldest entry. The last entry is the latest entry. The method returns a copy of the click stream, which makes it safe to work with the click stream, while it might be modified. **Returns:** a collection of ClickStreamEntry instances, sorted chronologically. --- ### getFirst **Signature:** `getFirst() : ClickStreamEntry` **Description:** Returns the first click within this session. This first click is stored independent of whether entries are purged. **Returns:** the first click within this session. --- ### getLast **Signature:** `getLast() : ClickStreamEntry` **Description:** Returns the last recorded click stream, which is also typically the current click. In where rare cases (e.g. RedirectURL pipeline) this is not the current click, but instead the last recorded click. **Returns:** the last recorded click stream, which is also typically the current click. --- ### isEnabled **Signature:** `isEnabled() : boolean` **Description:** Identifies if the clickstream recording is enabled or not. It is considered enabled if either: the method Session.isTrackingAllowed() returns true or if the above method returns false but the preference 'ClickstreamHonorDNT' is set to false. When clickstream tracking is not enabled the getFirst() method still operates as expected but the rest of the clicks are not collected. **Returns:** whether clickstream tracking is enabled --- ### isPartial **Signature:** `isPartial() : boolean` **Description:** Identifies if this is only a partial click stream. If the maximum number of clicks (50) is recorded, the oldest entry is automatically purged with each additional click. In this case, this flag indicates that the click stream is only partial. **Returns:** true if this click stream is partial, false otherwise. --- ``` -------------------------------------------------------------------------------- /docs/dw_order/ProductShippingModel.md: -------------------------------------------------------------------------------- ```markdown ## Package: dw.order # Class ProductShippingModel ## Inheritance Hierarchy - Object - dw.order.ProductShippingModel ## Description Instances of ProductShippingModel provide access to product-level shipping information, such as applicable or inapplicable shipping methods and shipping cost defined for the product for a specified shipping method. Use ShippingMgr.getProductShippingModel(Product) to get the shipping model for a specific product. ## Properties ### applicableShippingMethods **Type:** Collection (Read Only) The active applicable shipping methods for the product related to this shipping model, i.e. shipping methods the product can be shipped with. A product can be shipping with a shipping methods if the shipping method is not explicitely marked as inapplicable for this product. ### inapplicableShippingMethods **Type:** Collection (Read Only) The active inapplicable shipping methods for the product related to this shipping model, i.e. shipping methods the product cannot be shipped with. A product cannot be shipping with a shipping methods if the shipping method is explicitely marked as inapplicable for this product. ### shippingMethodsWithShippingCost **Type:** Collection (Read Only) The active shipping methods for which either any fixed-price or surcharge product-level shipping cost is defined for the specified product. Note that this can include inapplicable shipping methods (see getInapplicableShippingMethods()). ## Constructor Summary ## Method Summary ### getApplicableShippingMethods **Signature:** `getApplicableShippingMethods() : Collection` Returns the active applicable shipping methods for the product related to this shipping model, i.e. ### getInapplicableShippingMethods **Signature:** `getInapplicableShippingMethods() : Collection` Returns the active inapplicable shipping methods for the product related to this shipping model, i.e. ### getShippingCost **Signature:** `getShippingCost(shippingMethod : ShippingMethod) : ProductShippingCost` Returns the shipping cost object for the related product and the specified shipping method, or null if no product-level fixed-price or surcharge shipping cost are defined for the specified product. ### getShippingMethodsWithShippingCost **Signature:** `getShippingMethodsWithShippingCost() : Collection` Returns the active shipping methods for which either any fixed-price or surcharge product-level shipping cost is defined for the specified product. ## Method Detail ## Method Details ### getApplicableShippingMethods **Signature:** `getApplicableShippingMethods() : Collection` **Description:** Returns the active applicable shipping methods for the product related to this shipping model, i.e. shipping methods the product can be shipped with. A product can be shipping with a shipping methods if the shipping method is not explicitely marked as inapplicable for this product. **Returns:** Applicable shipping methods for the product --- ### getInapplicableShippingMethods **Signature:** `getInapplicableShippingMethods() : Collection` **Description:** Returns the active inapplicable shipping methods for the product related to this shipping model, i.e. shipping methods the product cannot be shipped with. A product cannot be shipping with a shipping methods if the shipping method is explicitely marked as inapplicable for this product. **Returns:** Inapplicable shipping methods for the product --- ### getShippingCost **Signature:** `getShippingCost(shippingMethod : ShippingMethod) : ProductShippingCost` **Description:** Returns the shipping cost object for the related product and the specified shipping method, or null if no product-level fixed-price or surcharge shipping cost are defined for the specified product. The following rules apply: if fixed and surcharge shipping cost is defined for a product, the fixed cost takes precedence if a product is member of multiple shipping cost groups, the lowest shipping cost takes precedence **Parameters:** - `shippingMethod`: the shipping method to use. **Returns:** Product shipping cost --- ### getShippingMethodsWithShippingCost **Signature:** `getShippingMethodsWithShippingCost() : Collection` **Description:** Returns the active shipping methods for which either any fixed-price or surcharge product-level shipping cost is defined for the specified product. Note that this can include inapplicable shipping methods (see getInapplicableShippingMethods()). **Returns:** Shipping methods with shipping cost --- ``` -------------------------------------------------------------------------------- /tests/servers/sfcc-mock-server/mock-data/ocapi/site-preferences-fastforward.json: -------------------------------------------------------------------------------- ```json { "_v": "23.2", "_type": "preference_value_search_result", "count": 2, "hits": [ { "_type": "preference_value", "attribute_definition": { "_type": "object_attribute_definition", "_resource_state": "3a0e7b1f995f68fb1ad3a0a15ab3e1d744879da35d819fab7725ac56de0bac12", "creation_date": "2024-02-26T19:35:27.000Z", "description": { "default": "The custom attributes that are searchable in the FastForward Business Manager modules." }, "display_name": { "default": "FastForward: Category Search Custom Attributes" }, "effective_id": "c_fastforward_categorySearchCustomAttributes", "externally_defined": false, "externally_managed": false, "field_height": 10, "id": "fastforward_categorySearchCustomAttributes", "key": false, "last_modified": "2024-02-26T19:35:27.000Z", "link": "https://localhost:3000/s/-/dw/data/v23_2/system_object_definitions/SitePreferences/attribute_definitions/fastforward_categorySearchCustomAttributes", "localizable": false, "mandatory": false, "min_length": 0, "multi_value_type": false, "order_required": false, "queryable": false, "read_only": false, "requires_encoding": false, "searchable": false, "set_value_type": false, "site_specific": false, "system": false, "value_type": "text", "visible": false }, "description": { "default": "The custom attributes that are searchable in the FastForward Business Manager modules." }, "display_name": { "default": "FastForward: Category Search Custom Attributes" }, "id": "fastforward_categorySearchCustomAttributes", "site_values": { "RefArch": null, "RefArchGlobal": "[{\"id\":\"catBannerID\",\"type\":\"string\"},{\"id\":\"customCSSFile\",\"type\":\"image\"},{\"id\":\"enableCompare\",\"type\":\"boolean\"},{\"id\":\"alternativeUrl\",\"type\":\"html\"}]", "pxl_1": null, "pxl_2": null, "pxl_3": null, "pxl_4": null, "pxl_5": null, "pxl_6": null }, "value_type": "text" }, { "_type": "preference_value", "attribute_definition": { "_type": "object_attribute_definition", "_resource_state": "a8fe5c4af162e8019daab09c5a0f32c1f57bf46db00a3cb4ba4f7d930a8c9121", "creation_date": "2024-02-26T19:35:27.000Z", "description": { "default": "The custom attributes that are searchable in the FastForward Business Manager modules." }, "display_name": { "default": "FastForward: Product Search Custom Attributes" }, "effective_id": "c_fastforward_productSearchCustomAttributes", "externally_defined": false, "externally_managed": false, "field_height": 10, "id": "fastforward_productSearchCustomAttributes", "key": false, "last_modified": "2024-02-26T19:35:27.000Z", "link": "https://localhost:3000/s/-/dw/data/v23_2/system_object_definitions/SitePreferences/attribute_definitions/fastforward_productSearchCustomAttributes", "localizable": false, "mandatory": false, "min_length": 0, "multi_value_type": false, "order_required": false, "queryable": false, "read_only": false, "requires_encoding": false, "searchable": false, "set_value_type": false, "site_specific": false, "system": false, "value_type": "text", "visible": false }, "description": { "default": "The custom attributes that are searchable in the FastForward Business Manager modules." }, "display_name": { "default": "FastForward: Product Search Custom Attributes" }, "id": "fastforward_productSearchCustomAttributes", "site_values": { "RefArch": null, "RefArchGlobal": "[{\"id\":\"batteryType\",\"type\":\"string\"},{\"id\":\"bootType\",\"type\":\"enum_of_string\"},{\"id\":\"batteryLife\",\"type\":\"string\"},{\"id\":\"Wool\",\"type\":\"string\"}]", "pxl_1": null, "pxl_2": null, "pxl_3": null, "pxl_4": null, "pxl_5": null, "pxl_6": null }, "value_type": "text" } ], "query": { "match_all_query": { "_type": "match_all_query" } }, "select": "(**)", "start": 0, "total": 2 } ``` -------------------------------------------------------------------------------- /tests/mcp/yaml/search-job-logs-by-name.full-mode.test.mcp.yml: -------------------------------------------------------------------------------- ```yaml --- description: "Test search_job_logs_by_name tool in full mode - focused on aegis framework validation" tests: # Basic functionality - test aegis with simple patterns - it: "should search for job logs and validate basic structure" request: jsonrpc: "2.0" id: "search-job-basic" method: "tools/call" params: name: "search_job_logs_by_name" arguments: jobName: "Import" expect: response: jsonrpc: "2.0" id: "search-job-basic" result: content: match:arrayElements: type: "text" text: "match:regex:\"(?:Found \\d+ job logs|No job logs found)" isError: false stderr: "toBeEmpty" performance: maxResponseTime: "2000ms" - it: "should return exact empty result format for non-existent job" request: jsonrpc: "2.0" id: "search-job-empty-result" method: "tools/call" params: name: "search_job_logs_by_name" arguments: jobName: "NonExistentJobXYZ" expect: response: jsonrpc: "2.0" id: "search-job-empty-result" result: content: match:arrayElements: type: "text" text: "\"No job logs found.\"" isError: false stderr: "toBeEmpty" performance: maxResponseTime: "1500ms" - it: "should include job emoji and basic details when found" request: jsonrpc: "2.0" id: "search-job-details" method: "tools/call" params: name: "search_job_logs_by_name" arguments: jobName: "Import" limit: 1 expect: response: jsonrpc: "2.0" id: "search-job-details" result: content: match:arrayElements: type: "text" # Test for job emoji presence text: "match:contains:🔧 Job:" isError: false stderr: "toBeEmpty" performance: maxResponseTime: "2000ms" # Error validation - test exact error messages - it: "should reject empty job name with exact error message" request: jsonrpc: "2.0" id: "search-job-empty-name" method: "tools/call" params: name: "search_job_logs_by_name" arguments: jobName: "" expect: response: jsonrpc: "2.0" id: "search-job-empty-name" result: content: match:arrayElements: type: "text" text: "Error: jobName must be a non-empty string" isError: true stderr: "toBeEmpty" performance: maxResponseTime: "800ms" - it: "should reject invalid limit with specific error format" request: jsonrpc: "2.0" id: "search-job-invalid-limit" method: "tools/call" params: name: "search_job_logs_by_name" arguments: jobName: "Import" limit: -1 expect: response: jsonrpc: "2.0" id: "search-job-invalid-limit" result: content: match:arrayElements: type: "text" text: "Error: Invalid limit '-1' for tool. Must be between 1 and 1000" isError: true stderr: "toBeEmpty" performance: maxResponseTime: "800ms" # Parameter handling - test limit behavior - it: "should respect custom limit parameter" request: jsonrpc: "2.0" id: "search-job-custom-limit" method: "tools/call" params: name: "search_job_logs_by_name" arguments: jobName: "Import" limit: 5 expect: response: jsonrpc: "2.0" id: "search-job-custom-limit" result: content: match:arrayElements: type: "text" text: "match:type:string" isError: false stderr: "toBeEmpty" performance: maxResponseTime: "2000ms" # Response structure validation - it: "should maintain consistent MCP response structure" request: jsonrpc: "2.0" id: "search-job-structure" method: "tools/call" params: name: "search_job_logs_by_name" arguments: jobName: "Import" expect: response: jsonrpc: "2.0" id: "search-job-structure" result: match:partial: content: "match:arrayLength:1" isError: "match:type:boolean" stderr: "toBeEmpty" performance: maxResponseTime: "2000ms" ``` -------------------------------------------------------------------------------- /docs/TopLevel/Map.md: -------------------------------------------------------------------------------- ```markdown ## Package: TopLevel # Class Map ## Inheritance Hierarchy - Object - Map ## Description Map objects are collections of key/value pairs where both the keys and values may be arbitrary ECMAScript language values. A distinct key value may only occur in one key/value pair within the Map's collection. Key/value pairs are stored and iterated in insertion order. ## Properties ### size **Type:** Number Number of key/value pairs stored in this map. ## Constructor Summary Map() Creates an empty map. Map(values : Iterable) If the passed value is null or undefined then an empty map is constructed. ## Method Summary ### clear **Signature:** `clear() : void` Removes all key/value pairs from this map. ### delete **Signature:** `delete(key : Object) : boolean` Removes the entry for the given key. ### entries **Signature:** `entries() : ES6Iterator` Returns an iterator containing all key/value pairs of this map. ### forEach **Signature:** `forEach(callback : Function) : void` Runs the provided callback function once for each key/value pair present in this map. ### forEach **Signature:** `forEach(callback : Function, thisObject : Object) : void` Runs the provided callback function once for each key/value pair present in this map. ### get **Signature:** `get(key : Object) : Object` Returns the value associated with the given key. ### has **Signature:** `has(key : Object) : boolean` Returns if this map has value associated with the given key. ### keys **Signature:** `keys() : ES6Iterator` Returns an iterator containing all keys of this map. ### set **Signature:** `set(key : Object, value : Object) : Map` Adds or updates a key/value pair to the map. ### values **Signature:** `values() : ES6Iterator` Returns an iterator containing all values of this map. ## Constructor Detail ## Method Detail ## Method Details ### clear **Signature:** `clear() : void` **Description:** Removes all key/value pairs from this map. --- ### delete **Signature:** `delete(key : Object) : boolean` **Description:** Removes the entry for the given key. **Parameters:** - `key`: The key of the key/value pair to be removed from the map. **Returns:** true if the map contained an entry for the passed key that was removed. Else false is returned. --- ### entries **Signature:** `entries() : ES6Iterator` **Description:** Returns an iterator containing all key/value pairs of this map. The iterator produces a series of two-element arrays with the first element as the key and the second element as the value. --- ### forEach **Signature:** `forEach(callback : Function) : void` **Description:** Runs the provided callback function once for each key/value pair present in this map. **Parameters:** - `callback`: The function to call, which is invoked with three arguments: the value of the element, the key of the element, and the Map object being iterated. --- ### forEach **Signature:** `forEach(callback : Function, thisObject : Object) : void` **Description:** Runs the provided callback function once for each key/value pair present in this map. **Parameters:** - `callback`: The function to call, which is invoked with three arguments: the value of the element, the key of the element, and the Map object being iterated. - `thisObject`: The Object to use as 'this' when executing callback. --- ### get **Signature:** `get(key : Object) : Object` **Description:** Returns the value associated with the given key. **Parameters:** - `key`: The key to look for. **Returns:** The value associated with the given key if an entry with the key exists else undefined is returned. --- ### has **Signature:** `has(key : Object) : boolean` **Description:** Returns if this map has value associated with the given key. **Parameters:** - `key`: The key to look for. **Returns:** true if an entry with the key exists else false is returned. --- ### keys **Signature:** `keys() : ES6Iterator` **Description:** Returns an iterator containing all keys of this map. --- ### set **Signature:** `set(key : Object, value : Object) : Map` **Description:** Adds or updates a key/value pair to the map. You can't use JavaScript bracket notation to access map entries. JavaScript bracket notation accesses only properties for Map objects, not map entries. **Parameters:** - `key`: The key object. - `value`: The value to be associated with the key. **Returns:** This map object. --- ### values **Signature:** `values() : ES6Iterator` **Description:** Returns an iterator containing all values of this map. --- ``` -------------------------------------------------------------------------------- /src/tool-configs/docs-tool-config.ts: -------------------------------------------------------------------------------- ```typescript import { GenericToolSpec, ToolExecutionContext } from '../core/handlers/base-handler.js'; import { ToolArguments } from '../core/handlers/base-handler.js'; import { ValidationHelpers, CommonValidations } from '../core/handlers/validation-helpers.js'; import { SFCCDocumentationClient } from '../clients/docs-client.js'; export const DOC_TOOL_NAMES = [ 'get_sfcc_class_info', 'search_sfcc_classes', 'search_sfcc_methods', 'list_sfcc_classes', 'get_sfcc_class_documentation', ] as const; export type DocToolName = typeof DOC_TOOL_NAMES[number]; export const DOC_TOOL_NAMES_SET = new Set<DocToolName>(DOC_TOOL_NAMES); /** * Configuration for SFCC documentation tools * Maps each tool to its validation, execution, and messaging logic */ export const DOCS_TOOL_CONFIG: Record<DocToolName, GenericToolSpec<ToolArguments, any>> = { get_sfcc_class_info: { defaults: (args: ToolArguments) => ({ ...args, expand: args.expand ?? false, includeDescription: args.includeDescription ?? true, includeConstants: args.includeConstants ?? true, includeProperties: args.includeProperties ?? true, includeMethods: args.includeMethods ?? true, includeInheritance: args.includeInheritance ?? true, search: args.search ?? undefined, }), validate: (args: ToolArguments, toolName: string) => { ValidationHelpers.validateArguments(args, CommonValidations.requiredString('className'), toolName); }, exec: async (args: ToolArguments, context: ToolExecutionContext) => { const client = context.docsClient as SFCCDocumentationClient; const result = await client.getClassDetailsExpanded( args.className as string, args.expand as boolean, { includeDescription: args.includeDescription as boolean, includeConstants: args.includeConstants as boolean, includeProperties: args.includeProperties as boolean, includeMethods: args.includeMethods as boolean, includeInheritance: args.includeInheritance as boolean, search: args.search as string | undefined, }, ); if (!result) { throw new Error(`Class "${args.className}" not found`); } return result; }, logMessage: (args: ToolArguments) => `Class info ${args.className} expand=${args.expand ?? false} ${args.search ? `search="${args.search}"` : ''}`, }, search_sfcc_classes: { defaults: (args: ToolArguments) => args, validate: (args: ToolArguments, toolName: string) => { ValidationHelpers.validateArguments(args, CommonValidations.requiredString('query'), toolName); }, exec: async (args: ToolArguments, context: ToolExecutionContext) => { const client = context.docsClient as SFCCDocumentationClient; return client.searchClasses(args.query as string); }, logMessage: (args: ToolArguments) => `Search classes ${args.query}`, }, search_sfcc_methods: { defaults: (args: ToolArguments) => args, validate: (args: ToolArguments, toolName: string) => { ValidationHelpers.validateArguments(args, CommonValidations.requiredString('methodName'), toolName); }, exec: async (args: ToolArguments, context: ToolExecutionContext) => { const client = context.docsClient as SFCCDocumentationClient; return client.searchMethods(args.methodName as string); }, logMessage: (args: ToolArguments) => `Search methods ${args.methodName}`, }, list_sfcc_classes: { defaults: (args: ToolArguments) => args, validate: (_args: ToolArguments, _toolName: string) => { // No validation needed for list operation }, exec: async (args: ToolArguments, context: ToolExecutionContext) => { const client = context.docsClient as SFCCDocumentationClient; return client.getAvailableClasses(); }, logMessage: (_args: ToolArguments) => 'List classes', }, get_sfcc_class_documentation: { defaults: (args: ToolArguments) => args, validate: (args: ToolArguments, toolName: string) => { ValidationHelpers.validateArguments(args, CommonValidations.requiredString('className'), toolName); }, exec: async (args: ToolArguments, context: ToolExecutionContext) => { const client = context.docsClient as SFCCDocumentationClient; const result = await client.getClassDocumentation(args.className as string); if (!result) { throw new Error(`Documentation for class "${args.className}" not found`); } return result; }, logMessage: (args: ToolArguments) => `Raw doc ${args.className}`, }, }; ``` -------------------------------------------------------------------------------- /docs/dw_system/System.md: -------------------------------------------------------------------------------- ```markdown ## Package: dw.system # Class System ## Inheritance Hierarchy - Object - dw.system.System ## Description Represents the Commerce Cloud Digital server instance. An application server instance is configured to be of one of three types, "development system", "staging system" or "production system". ## Constants ### DEVELOPMENT_SYSTEM **Type:** Number = 0 Represents the development system. ### PRODUCTION_SYSTEM **Type:** Number = 2 Represents the production system. ### STAGING_SYSTEM **Type:** Number = 1 Represents the staging system. ## Properties ### calendar **Type:** Calendar (Read Only) A new Calendar object in the time zone of the current instance. ### compatibilityMode **Type:** Number (Read Only) The compatibility mode of the custom code version that is currently active. The compatibility mode is returned as a number, e.g. compatibility mode "15.5" is returned as 1505. ### instanceHostname **Type:** String (Read Only) Returns instance hostname. ### instanceTimeZone **Type:** String (Read Only) The instance time zone. The instance time zone is the time zone in which global actions like jobs or reporting are specified in the system. Keep in mind that the instance time zone is cached at the current session. Changes will affect only new sessions. ### instanceType **Type:** Number (Read Only) The type of the instance. An application server instance is configured to be of one of three types, "development system", "staging system" or "production system". This method returns a constant representing the instance type of this application server. ### preferences **Type:** OrganizationPreferences (Read Only) This method returns a container of all global preferences of this organization (instance). ## Constructor Summary ## Method Summary ### getCalendar **Signature:** `static getCalendar() : Calendar` Returns a new Calendar object in the time zone of the current instance. ### getCompatibilityMode **Signature:** `static getCompatibilityMode() : Number` Returns the compatibility mode of the custom code version that is currently active. ### getInstanceHostname **Signature:** `static getInstanceHostname() : String` Returns instance hostname. ### getInstanceTimeZone **Signature:** `static getInstanceTimeZone() : String` Returns the instance time zone. ### getInstanceType **Signature:** `static getInstanceType() : Number` Returns the type of the instance. ### getPreferences **Signature:** `static getPreferences() : OrganizationPreferences` This method returns a container of all global preferences of this organization (instance). ## Method Detail ## Method Details ### getCalendar **Signature:** `static getCalendar() : Calendar` **Description:** Returns a new Calendar object in the time zone of the current instance. **Returns:** a Calendar object in the time zone of the instance. --- ### getCompatibilityMode **Signature:** `static getCompatibilityMode() : Number` **Description:** Returns the compatibility mode of the custom code version that is currently active. The compatibility mode is returned as a number, e.g. compatibility mode "15.5" is returned as 1505. **Returns:** The currently active compatibility mode. --- ### getInstanceHostname **Signature:** `static getInstanceHostname() : String` **Description:** Returns instance hostname. **Returns:** instance hostname. --- ### getInstanceTimeZone **Signature:** `static getInstanceTimeZone() : String` **Description:** Returns the instance time zone. The instance time zone is the time zone in which global actions like jobs or reporting are specified in the system. Keep in mind that the instance time zone is cached at the current session. Changes will affect only new sessions. **Returns:** the instance time zone. --- ### getInstanceType **Signature:** `static getInstanceType() : Number` **Description:** Returns the type of the instance. An application server instance is configured to be of one of three types, "development system", "staging system" or "production system". This method returns a constant representing the instance type of this application server. **Returns:** the instance type of the application server where this method was called. **See Also:** DEVELOPMENT_SYSTEM PRODUCTION_SYSTEM STAGING_SYSTEM --- ### getPreferences **Signature:** `static getPreferences() : OrganizationPreferences` **Description:** This method returns a container of all global preferences of this organization (instance). **Returns:** a preferences object containing all global system and custom preferences of this instance --- ``` -------------------------------------------------------------------------------- /docs/sfra/payment.md: -------------------------------------------------------------------------------- ```markdown # SFRA Payment Model ## Overview The Payment model represents payment information for the current basket in SFRA applications. It provides comprehensive payment method options, applicable payment cards, and selected payment instruments for checkout processing. ## Constructor ```javascript function Payment(currentBasket, currentCustomer, countryCode) ``` Creates a Payment model instance with applicable payment methods and current payment selections. ### Parameters - `currentBasket` (dw.order.Basket) - The target Basket object - `currentCustomer` (dw.customer.Customer) - The associated Customer object - `countryCode` (string) - The associated Site country code ## Properties ### applicablePaymentMethods **Type:** Array<Object> | null Array of payment methods available for the current basket and customer. Each method object contains: - `ID` (string) - Payment method ID - `name` (string) - Display name of the payment method ### applicablePaymentCards **Type:** Array<Object> | null Array of credit card types available for the current customer and basket. Each card object contains: - `cardType` (string) - Credit card type identifier - `name` (string) - Display name of the card type ### selectedPaymentInstruments **Type:** Array<Object> | null Array of currently selected payment instruments for the basket. Each instrument object contains: - `paymentMethod` (string) - Payment method type - `amount` (number) - Payment amount value #### Credit Card Instruments For credit card payments, additional properties include: - `lastFour` (string) - Last four digits of the card number - `owner` (string) - Cardholder name - `expirationYear` (number) - Card expiration year - `type` (string) - Credit card type - `maskedCreditCardNumber` (string) - Masked card number - `expirationMonth` (number) - Card expiration month #### Gift Certificate Instruments For gift certificate payments, additional properties include: - `giftCertificateCode` (string) - Full gift certificate code - `maskedGiftCertificateCode` (string) - Masked gift certificate code ## Helper Functions ### applicablePaymentMethods(paymentMethods) Creates an array of applicable payment method objects. **Parameters:** - `paymentMethods` (dw.util.ArrayList<dw.order.PaymentMethod>) - Available payment methods **Returns:** Array<Object> - Formatted payment methods array ### applicablePaymentCards(paymentCards) Creates an array of applicable credit card objects. **Parameters:** - `paymentCards` (dw.util.Collection<dw.order.PaymentCard>) - Available payment cards **Returns:** Array<Object> - Formatted payment cards array ### getSelectedPaymentInstruments(selectedPaymentInstruments) Creates an array of selected payment instrument objects with method-specific properties. **Parameters:** - `selectedPaymentInstruments` (dw.util.ArrayList<dw.order.PaymentInstrument>) - Selected payment instruments **Returns:** Array<Object> - Formatted payment instruments array ## Usage Example ```javascript var PaymentModel = require('*/cartridge/models/payment'); var BasketMgr = require('dw/order/BasketMgr'); var currentBasket = BasketMgr.getCurrentBasket(); var currentCustomer = req.currentCustomer.raw; var countryCode = 'US'; var payment = new PaymentModel(currentBasket, currentCustomer, countryCode); // Access payment methods console.log(payment.applicablePaymentMethods); // [{ ID: 'CREDIT_CARD', name: 'Credit Card' }, { ID: 'PayPal', name: 'PayPal' }] // Access applicable cards console.log(payment.applicablePaymentCards); // [{ cardType: 'Visa', name: 'Visa' }, { cardType: 'MasterCard', name: 'MasterCard' }] // Check selected instruments if (payment.selectedPaymentInstruments) { payment.selectedPaymentInstruments.forEach(function(instrument) { console.log(instrument.paymentMethod + ': $' + instrument.amount); }); } ``` ## Payment Method Support The model supports various payment methods including: - **Credit Cards** - With full card details and masking - **Gift Certificates** - With code masking - **Other Methods** - Basic method and amount information ## Notes - Payment methods are filtered based on customer, country, and basket amount - Credit card information is automatically masked for security - Supports multiple payment instruments per basket - All monetary amounts are in the basket's currency - Payment method availability depends on site configuration and customer eligibility ## Related Models - **BillingModel** - Uses payment model for billing information - **OrderModel** - Includes payment information in order data - **Cart Model** - May include payment selection during checkout ``` -------------------------------------------------------------------------------- /docs/dw_crypto/MessageDigest.md: -------------------------------------------------------------------------------- ```markdown ## Package: dw.crypto # Class MessageDigest ## Inheritance Hierarchy - Object - dw.crypto.MessageDigest ## Description This class provides the functionality of a message digest algorithm, such as MD5 or SHA. Message digests are secure one-way hash functions that take arbitrary-sized data and output a fixed-length hash value. This implementation offers only stateless digest() methods. A Bytes object or String is passed to a digest() method and the computed hash is returned. Note: this class handles sensitive security-related data. Pay special attention to PCI DSS v3. requirements 2, 4, and 12. ## Constants ### DIGEST_MD2 **Type:** String = "MD2" Constant representing the MD2 algorithm. ### DIGEST_MD5 **Type:** String = "MD5" Constant representing the MD5 algorithm. ### DIGEST_SHA **Type:** String = "SHA" Constant representing the SHA algorithm. ### DIGEST_SHA_1 **Type:** String = "SHA-1" Constant representing the SHA 1 algorithm. ### DIGEST_SHA_256 **Type:** String = "SHA-256" Constant representing the SHA 256 algorithm ### DIGEST_SHA_512 **Type:** String = "SHA-512" Constant representing the SHA 512 algorithm ## Properties ## Constructor Summary MessageDigest(algorithm : String) Construct a MessageDigest with the specified algorithm name. ## Method Summary ### digest **Signature:** `digest(input : String) : String` Digests the passed string and returns a computed hash value as a string. ### digest **Signature:** `digest(algorithm : String, input : Bytes) : Bytes` Computes the hash value for the passed array of bytes. ### digest **Signature:** `digest() : Bytes` Completes the hash computation by performing final operations such as padding. ### digestBytes **Signature:** `digestBytes(input : Bytes) : Bytes` Computes the hash value for the passed Bytes. ### updateBytes **Signature:** `updateBytes(input : Bytes) : void` Updates the digest using the passed Bytes. ## Constructor Detail ## Method Detail ## Method Details ### digest **Signature:** `digest(input : String) : String` **Description:** Digests the passed string and returns a computed hash value as a string. The passed String is first encoded into a sequence of bytes using the platform's default encoding. The digest then performs any prerequisite padding, before computing the hash value. The hash is then converted into a string by converting all digits to hexadecimal. **Deprecated:** Deprecated because the conversion of the input to bytes using the default platform encoding and the hex-encoded return value are not generally appropriate. **Parameters:** - `input`: The value to hash as String, must not be null. **Returns:** The resulting hash value as hex-encoded string. --- ### digest **Signature:** `digest(algorithm : String, input : Bytes) : Bytes` **Description:** Computes the hash value for the passed array of bytes. The algorithm argument is optional. If null, then the algorithm established at construction time is used. The binary representation of the message is typically derived from a string and the resulting hash is typically converted with base64 back into a string. Example: Encoding.toBase64( digest( "MD5", new Bytes( "my password", "UTF-8" ) ) ); **Deprecated:** Deprecated because the digest algorithm should be the one set in the constructor. **Parameters:** - `algorithm`: The standard name of the digest algorithm, or null if the algorithm passed at construction time is to be used. The algorithm must be a supported algorithm. - `input`: The value to hash, must not be null. **Returns:** The resulting hash value. --- ### digest **Signature:** `digest() : Bytes` **Description:** Completes the hash computation by performing final operations such as padding. The binary representation of the message is typically derived from a string and the resulting hash is typically converted with base64 back into a string. Example: Encoding.toBase64( digest() ); **Returns:** The resulting hash value. --- ### digestBytes **Signature:** `digestBytes(input : Bytes) : Bytes` **Description:** Computes the hash value for the passed Bytes. The binary representation of the message is typically derived from a string and the resulting hash is typically converted with base64 back into a string. Example: Encoding.toBase64( digest( new Bytes( "my password", "UTF-8" ) ) ); **Parameters:** - `input`: The value to hash, must not be null. **Returns:** The resulting hash value. --- ### updateBytes **Signature:** `updateBytes(input : Bytes) : void` **Description:** Updates the digest using the passed Bytes. **Parameters:** - `input`: The value to hash, must not be null. --- ```