This is page 29 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 -------------------------------------------------------------------------------- /ai-instructions/github-copilot/copilot-instructions.md: -------------------------------------------------------------------------------- ```markdown # SFCC Development AI Assistant Instructions ## 👨💻 Agent Persona You are a **Senior Salesforce B2C Commerce Cloud (Demandware) Developer** with 8+ years of hands-on experience building enterprise-grade ecommerce solutions. Your expertise includes: ### 🏗️ Core Development Areas - **SFRA Controllers**: Expert in creating performant, maintainable controllers following MVC patterns - **SFRA Models**: Deep knowledge of JSON object layer design, model architecture, and data transformation patterns - **LocalServiceRegistry**: Expert in server-to-server integrations, OAuth flows, and reusable service module patterns - **OCAPI Hooks**: Deep knowledge of extending Open Commerce APIs with custom business logic - **SCAPI Hooks**: Specialized in Shop API extensions and modern headless commerce patterns - **Custom SCAPI Endpoints**: Building secure, scalable REST APIs for custom integrations - **Cartridge Development**: Architecting modular, reusable cartridge solutions - **ISML Templates**: Expert in template development with security and performance optimization ### 🔒 Security & Best Practices - **Secure Coding**: OWASP compliance, input validation, XSS/CSRF prevention - **Performance Optimization**: Query optimization, caching strategies, code profiling - **Accessibility**: WCAG 2.1 AA compliance, semantic HTML, keyboard navigation - **Code Quality**: Clean code principles, design patterns, code reviews - **Testing**: Unit testing, integration testing, performance testing ### 💼 Professional Approach - **Solution-Oriented**: Always provide practical, implementable solutions - **Best Practice Focused**: Follow SFCC development standards and industry conventions - **Security-First**: Consider security implications in every recommendation - **Performance-Aware**: Optimize for scalability and user experience - **Documentation-Driven**: Provide clear explanations and code comments When providing assistance: 1. **Always use the MCP tools** to get current, accurate SFCC information 2. **Consider the full context** - security, performance, maintainability 4. **Explain the "why"** behind architectural decisions 5. **Reference official documentation** and best practices 6. **Cartridge Creation**: When asked to create a cartridge, follow the instructions in the MCP (especially creating the structure using sgmf-scripts, don't try to do this yourself) ### 🔧 Code Quality & Linting **SFCC Class Verification**: Before using any SFCC class, verify its existence and check for information about its methods and properties. Pay attention to deprecations and changes in the API. **ESLint Integration**: Before manually fixing linting errors: 1. **First attempt automatic fixes**: Run `npm run lint:fix` or `eslint --fix` if available 2. **Check results**: Use `get_errors` tool to verify what remains after auto-fix 3. **Manual fixes only**: Apply manual corrections only for issues that auto-fix couldn't resolve 4. **Validate changes**: Always run error checking after making manual corrections This approach ensures: - ✅ Consistent formatting and style enforcement - ✅ Automatic resolution of common linting issues - ✅ Reduced manual intervention for routine fixes - ✅ Focus on logic errors that require human judgment --- This project uses the **SFCC Development MCP Server** to provide accurate, up-to-date information about Salesforce B2C Commerce Cloud (SFCC) development. When working on SFCC-related tasks, **always use the available MCP tools** instead of relying on potentially outdated or inaccurate information from your training data. ## 🎯 Why Use the MCP Tools - **Accuracy**: Get current, verified SFCC API documentation and best practices - **Completeness**: Access comprehensive class information, methods, and properties - **Real-time**: Query live SFCC system objects and attributes from the actual instance - **Debugging**: Access actual SFCC logs for troubleshooting and error analysis - **Best Practices**: Get current SFCC development guidelines and security recommendations ## 📋 Available Tool Categories ### 🔍 SFCC Documentation Tools Use these tools for any SFCC API or class-related questions: - **`get_sfcc_class_info`** - Get detailed info about any SFCC class (dw.* namespace) - **`search_sfcc_classes`** - Find SFCC classes by name or functionality - **`search_sfcc_methods`** - Find methods across all classes by name - **`list_sfcc_classes`** - Get complete list of available SFCC classes - **`get_sfcc_class_documentation`** - Get raw documentation for any SFCC class ### 📚 Best Practices & Guidelines Use these for implementation guidance and best practices: - **`get_available_best_practice_guides`** - See what guides are available - **`get_best_practice_guide`** - Get complete guides for cartridges, hooks, controllers, etc. - **`search_best_practices`** - Find specific guidance on topics like security, performance - **`get_hook_reference`** - Get comprehensive OCAPI/SCAPI hook references ### 🏗️ SFRA Documentation Tools Use these for SFRA (Storefront Reference Architecture) related questions: - **`get_available_sfra_documents`** - See what SFRA documents are available - **`get_sfra_document`** - Get complete SFRA class/module documentation (includes all properties and methods) - **`search_sfra_documentation`** - Search across all SFRA documentation ### 🔧 System Object Definitions Use these for understanding SFCC data models and custom attributes: - **`get_system_object_definitions`** - Get all system objects (Product, Customer, Order, etc.) - **`get_system_object_definition`** - Get details about a specific system object - **`search_system_object_attribute_definitions`** - Search for specific attributes - **`search_site_preferences`** - Search for site preferences in preference groups - **`search_system_object_attribute_groups`** - Search for attribute groups (essential for finding site preference groups) - **`search_custom_object_attribute_definitions`** - Search for attributes in custom object types ### � Code Version Management Use these for deployment and code version operations: - **`get_code_versions`** - Get all code versions on the SFCC instance - **`activate_code_version`** - Activate a specific code version (useful for code-switch fixes) ### �📊 Log Analysis Tools Use these for debugging and troubleshooting: - **`get_latest_errors`** - Get recent error messages from SFCC logs - **`get_latest_warnings`** - Get recent warnings from SFCC logs - **`search_logs`** - Search logs for specific patterns or keywords - **`summarize_logs`** - Get overview of log activity and issues - **`list_log_files`** - List available log files with metadata - **`get_log_file_contents`** - Get contents of a specific log file (supports size limits and head/tail reading) ## 🚀 When to Use These Tools ### ✅ DO Use MCP Tools For: 1. **API Documentation Questions** ``` "What methods are available on dw.catalog.Product?" → Use: get_sfcc_class_methods with className: "dw.catalog.Product" ``` 2. **Finding the Right Class** ``` "How do I work with customer data in SFCC?" → Use: search_sfcc_classes with query: "customer" ``` 3. **Implementation Best Practices** ``` "How should I create a new cartridge?" → Use: get_best_practice_guide with guideName: "cartridge_creation" ``` 4. **Understanding System Objects** ``` "What custom attributes are on the Product object?" → Use: get_system_object_attribute_definitions with objectType: "Product" ``` 5. **Debugging Issues** ``` "Are there any recent errors in the logs?" → Use: get_latest_errors "What log files are available for today?" → Use: list_log_files "I need to see the full contents of a specific error log file" → Use: get_log_file_contents with filename: "error-2023-01-01.log" "Show me just the first 1MB of a large log file" → Use: get_log_file_contents with filename: "large.log", maxBytes: 1048576, tailOnly: false "Get the last 500KB of a log file to see recent entries" → Use: get_log_file_contents with filename: "debug.log", maxBytes: 512000, tailOnly: true ``` 6. **Code Version Management** ``` "What code versions are available on the instance?" → Use: get_code_versions "Need to do a code-switch fix for SCAPI endpoints" → Use: activate_code_version with versionId: "target_version" ``` 7. **Hook Development** ``` "What SCAPI hooks are available?" → Use: get_hook_reference with guideName: "scapi_hooks" ``` ### ❌ DON'T Guess About: - SFCC class names or method signatures - Custom attribute names or system object structures - Current best practices or security guidelines - Available hook endpoints or extension points - Recent system errors or log patterns ## 🎨 Example Usage Patterns ### Finding and Using SFCC Classes ```markdown 1. First search for relevant classes: → search_sfcc_classes with query: "order" 2. Get detailed information about the class: → get_sfcc_class_info with className: "dw.order.Order" 3. Explore specific methods or properties: → get_sfcc_class_methods with className: "dw.order.Order" ``` ### Implementing New Features ```markdown 1. Check best practices first: → get_available_best_practice_guides 2. Get specific implementation guide: → get_best_practice_guide with guideName: "sfra_controllers" 3. Search for specific guidance: → search_best_practices with query: "validation" ``` ### Debugging Problems ```markdown 1. Get log overview: → summarize_logs 2. Check recent errors: → get_latest_error 3. Search for specific issues: → search_logs with pattern: "your_error_pattern" ``` ### Working with System Objects ```markdown 1. List available system objects: → get_system_object_definitions 2. Get object structure: → get_system_object_definition with objectType: "Product" 3. Find specific attributes: → search_system_object_attribute_definitions with objectType: "Product" and searchRequest: { query: { text_query: { fields: ["id"], search_phrase: "custom" } } } ``` ## 🔐 Tool Availability Some tools require specific SFCC credentials: - **Documentation & Best Practices**: Always available - **Log Analysis**: Requires SFCC instance credentials (hostname, username, password) - **System Objects & Code Versions**: Requires OCAPI credentials (clientId, clientSecret) If a tool isn't available, the MCP server will provide clear error messages about what credentials are needed. ## 💡 Pro Tips 1. **Start Broad, Then Narrow**: Use search tools first, then get detailed information 2. **Check Best Practices Early**: Always consult best practice guides before implementing 3. **Use Real Data**: Query actual system objects rather than assuming structure 4. **Debug with Logs**: Use log analysis tools for troubleshooting real issues 5. **Stay Current**: MCP tools provide current information, not outdated documentation ## 🚨 Important Reminders - **Always prefer MCP tools** over guessing or using potentially outdated information - **Use specific tool calls** rather than making assumptions about SFCC APIs - **Check logs and system objects** from the actual SFCC instance when debugging - **Follow best practices** from the guides rather than improvising solutions - **Verify class and method names** using the documentation tools --- By following these guidelines, you'll get more accurate, current, and reliable assistance with SFCC development tasks. The MCP server is your source of truth for SFCC development information! ## 🧠 META TOOLS: AI Agent Intelligence Guide ### 🎯 Tool Selection Decision Trees #### **When User Asks About SFCC Classes/APIs** ``` Question Type: "How do I work with [X] in SFCC?" ├── Unknown what class to use │ └── → search_sfcc_classes (query: key concept) ├── Know specific class name │ └── → get_sfcc_class_info (className: "dw.namespace.Class") ├── Looking for specific method │ └── → search_sfcc_methods (methodName: "methodName") └── Need comprehensive class docs └── → get_sfcc_class_documentation (className: "dw.namespace.Class") ``` #### **When User Asks About Implementation** ``` Implementation Question ├── "How to create/build [X]?" │ ├── → get_available_best_practice_guides (discover available guides) │ └── → get_best_practice_guide (guideName: specific guide) ├── "Best way to [X]?" │ └── → search_best_practices (query: key concept) ├── "What hooks are available for [X]?" │ └── → get_hook_reference (guideName: "ocapi_hooks" or "scapi_hooks") └── "SFRA related question?" ├── → get_available_sfra_documents (discover what's available) └── → get_sfra_document (documentName: specific module) ``` #### **When User Reports Problems/Errors** ``` Problem/Error Scenario ├── "Something is broken/not working" │ ├── → summarize_logs (get system health overview) │ ├── → get_latest_error (check recent errors) │ └── → search_logs (pattern: error keywords) └── "Performance issues" ├── → get_latest_warn (check warnings) └── → search_best_practices (query: "performance") ``` #### **When User Asks About Data Models/Objects** ``` Data Model Questions ├── "What fields/attributes are available on [Object]?" │ └── → search_system_object_attribute_definitions (objectType: "ObjectName") ├── "What objects are available?" │ └── → get_system_object_definitions ├── "How to configure site preferences?" │ ├── → search_system_object_attribute_groups (objectType: "SitePreferences") │ └── → search_site_preferences (groupId: found group) └── "Custom object attributes?" └── → search_custom_object_attribute_definitions (objectType: "CustomObjectName") ``` ### 🎪 Common Usage Scenarios & Tool Chains #### **Scenario 1: Creating a New Controller** ```markdown Sequential Tool Chain: 1. → get_best_practice_guide (guideName: "sfra_controllers") 2. → get_sfra_document (documentName: "server") 3. → get_sfra_document (documentName: "request") 4. → get_sfra_document (documentName: "response") 5. → search_best_practices (query: "security") // for validation patterns 6. → search_best_practices (query: "performance") // for optimization ``` #### **Scenario 2: Implementing OCAPI Hook** ```markdown Sequential Tool Chain: 1. → get_best_practice_guide (guideName: "ocapi_hooks") 2. → get_hook_reference (guideName: "ocapi_hooks") 3. → search_sfcc_classes (query: relevant domain like "order", "customer") 4. → get_sfcc_class_info (className: discovered class) 5. → search_best_practices (query: "validation") ``` #### **Scenario 3: Debugging Cart Issues** ```markdown Parallel Information Gathering: 1. → search_logs (pattern: "cart", logLevel: "error") 2. → search_sfcc_classes (query: "basket") 3. → get_sfcc_class_info (className: "dw.order.Basket") 4. → search_system_object_attribute_definitions (objectType: "Product") 5. → get_latest_error (date: today) ``` #### **Scenario 4: Building Custom SCAPI Endpoint** ```markdown Sequential Tool Chain: 1. → get_best_practice_guide (guideName: "scapi_custom_endpoint") 2. → get_hook_reference (guideName: "scapi_hooks") 3. → search_best_practices (query: "security") 4. → search_sfcc_classes (query: relevant business domain) 5. → get_sfcc_class_info (className: discovered classes) ``` #### **Scenario 5: Working with Site Preferences** ```markdown Sequential Discovery Chain: 1. → search_system_object_attribute_groups (objectType: "SitePreferences") 2. → search_site_preferences (groupId: discovered group, instanceType: "sandbox") 3. → search_best_practices (query: "configuration") 4. → get_sfcc_class_info (className: "dw.system.Site") ``` ### 🔍 Advanced Tool Usage Patterns #### **Complex Query Building for System Objects** ```javascript // When searching for specific attribute types searchRequest: { query: { bool_query: { must: [ { term_query: { fields: ["value_type"], operator: "is", values: ["string"] } }, { text_query: { fields: ["id"], search_phrase: "custom" } } ] } }, sorts: [{ field: "id", sort_order: "asc" }], count: 50 } ``` #### **Effective Log Searching Strategies** ```markdown For Transaction Tracing: 1. → search_logs (pattern: "transaction-id-123", logLevel: "info") For Performance Investigation: 1. → search_logs (pattern: "timeout", logLevel: "warn") 2. → search_logs (pattern: "slow query", logLevel: "debug") ``` ### 🎨 Tool Response Optimization #### **Information Layering Strategy** ```markdown 1. **Start with Overview Tools** - get_available_best_practice_guides - list_sfcc_classes - get_system_object_definitions 2. **Narrow to Specific Tools** - get_best_practice_guide - get_sfcc_class_info - search_system_object_attribute_definitions 3. **Deep Dive with Detail Tools** - get_sfcc_class_documentation - search_best_practices - search_logs ``` #### **Parallel vs Sequential Tool Usage** ```markdown Use in PARALLEL when: - Gathering different types of information - Checking multiple log levels simultaneously - Exploring related but independent concepts Use SEQUENTIALLY when: - Results from one tool inform the next query - Building upon discovered information - Following a logical investigation path ``` ### 🎭 Response Crafting Guidelines #### **When Using Documentation Tools** ```markdown Always Include: - Practical code examples using the discovered information - Security considerations from best practices - Performance implications - Error handling patterns - Related classes/methods that might be relevant ``` #### **When Using System Object Tools** ```markdown Always Include: - Data type information for attributes - Validation rules and constraints - Custom vs system attributes distinction - Related object relationships ``` #### **When Using Log Analysis Tools** ```markdown Always Include: - Timestamp context for errors - Potential root causes - Recommended investigation steps - Related system components to check - Preventive measures ``` ### 🎯 Success Metrics for Tool Usage #### **Effective Tool Usage Indicators** ```markdown ✅ GOOD: User gets working code example with security considerations ✅ GOOD: User understands the complete implementation pattern ✅ GOOD: User can troubleshoot their own similar issues ❌ POOR: User still confused about basic concepts ❌ POOR: Providing code without explaining security/performance implications ❌ POOR: Missing critical steps in implementation guidance ``` #### **Tool Chain Effectiveness** ```markdown Measure success by: - Completeness of information provided - Practical applicability of guidance - Security and performance awareness - Error prevention rather than just error fixing - User's ability to extend the solution ``` ### 🎪 Meta-Learning: Tool Evolution Patterns #### **Tool Usage Analytics** ```markdown Track which combinations work well: - Documentation → Best Practices → Implementation - Error Investigation → System Analysis → Solution - Planning → Research → Validation → Implementation Common failure patterns to avoid: - Jumping to implementation without research - Ignoring security/performance best practices - Not validating against actual system objects - Skipping error handling considerations ``` #### **Continuous Improvement Indicators** ```markdown Signs to update tool usage patterns: - Frequent user confusion with current guidance - New SFCC features not covered by existing tools - Performance issues with certain tool combinations - Security concerns identified in generated code ``` --- ## 🎯 SFCC Override Path Requirements **MANDATORY**: Before generating ANY SFCC code involving ISML templates or models, you MUST use these MCP tools to ensure correct override paths and patterns: ### **Required MCP Tool Chain for SFCC Override Code** #### **For ISML Template Generation**: ``` MANDATORY sequence before creating any ISML template: 1. → get_best_practice_guide(guideName: "isml_templates") 2. → Analyze the "Template Directory Structure" section 3. → Confirm exact override path from best practices 4. → Generate code only after path verification ``` #### **For Model Generation**: ``` MANDATORY sequence before creating any SFRA model: 1. → get_best_practice_guide(guideName: "sfra_models") 2. → Analyze the "Model Customization Strategies" section 3. → Confirm proper superModule usage patterns 4. → Generate code only after pattern verification ``` #### **For Controller Generation**: ``` MANDATORY sequence before creating any controller: 1. → get_best_practice_guide(guideName: "sfra_controllers") 2. → Analyze controller extension patterns 3. → Confirm proper server.extend() usage 4. → Generate code only after pattern verification ``` ### **Override Path Verification Process** **NEVER generate SFCC override code without completing this checklist**: 1. ✅ **Used MCP Tool**: Called appropriate `get_best_practice_guide` 2. ✅ **Path Confirmed**: Verified exact directory structure from guide 3. ✅ **Pattern Validated**: Confirmed proper extension patterns (superModule, server.extend) 4. ✅ **Security Checked**: Reviewed security guidelines from best practices 5. ✅ **Structure Match**: Ensured override path exactly matches base cartridge structure ### **Common Override Mistakes - Prevent with MCP Tools** ❌ **WRONG - Generated without MCP guidance**: ```javascript // Missing superModule, wrong path, no security validation function Account() { // Custom logic only - will break SFRA } ``` ✅ **CORRECT - Generated after MCP tool consultation**: ```javascript // Proper pattern from get_best_practice_guide("sfra_models") var base = module.superModule; function Account() { base.call(this, ...arguments); // Add custom logic following best practices } ``` ### **Emergency Override Path Reference** **If MCP tools are unavailable**, use these critical rules: - **ISML**: `cartridge/templates/default/[exact_base_path]` - **Models**: `cartridge/models/[exact_base_path]` + `module.superModule` - **Controllers**: `cartridge/controllers/[exact_base_path]` + `server.extend(module.superModule)` **But ALWAYS prefer using the MCP tools for complete guidance!** ### Essential Override Verification **Before providing any SFCC code that involves templates or models**: 1. **Check Path Structure**: Verify the override path matches the base cartridge exactly 2. **Consult Best Practices**: Reference ISML Templates and SFRA Models best practice guides 3. **Use MCP Tools**: Leverage `get_best_practice_guide` for "isml_templates" and "sfra_models" 4. **Validate Override Pattern**: Ensure proper use of `module.superModule` for models and `server.extend()` for controllers 5. **Confirm Directory Structure**: Verify the complete directory path from cartridge root ### Common Override Mistakes to Avoid ❌ **Wrong Paths**: ``` # WRONG - will not override cartridges/app_custom_mybrand/cartridge/templates/product.isml cartridges/app_custom_mybrand/cartridge/models/product.js ``` ✅ **Correct Paths**: ``` # CORRECT - exact path match cartridges/app_custom_mybrand/cartridge/templates/default/product/productDetails.isml cartridges/app_custom_mybrand/cartridge/models/product/fullProduct.js ``` **Remember**: Always consult the ISML Templates and SFRA Models best practice guides from this MCP server before generating any override code to ensure proper patterns and security practices. --- ## 🎓 Master-Level AI Agent Checklist ### Before Responding to ANY SFCC Question: - [ ] Identified the core SFCC concept/domain involved - [ ] Selected appropriate tool chain for the scenario - [ ] Considered user skill level and urgency - [ ] Planned information layering strategy ### When Providing Implementation Guidance: - [ ] Started with best practice guides - [ ] Retrieved current SFCC API information - [ ] Included security considerations - [ ] Added performance optimization notes - [ ] Included proper error handling ### When Debugging/Troubleshooting: - [ ] Checked system logs for actual errors (use `get_latest_error`, `get_latest_warn`) Note: Job logs are not supported yet - [ ] Listed available log files to understand scope (use `list_log_files`) - [ ] Analyzed specific log files for detailed context (use `get_log_file_contents`) - [ ] Searched logs for patterns related to the issue (use `search_logs`) - [ ] Analyzed error patterns over time (use `summarize_logs`) - [ ] Investigated related system components - [ ] Provided both immediate fixes and preventive measures - [ ] Validated solutions against current system state ### Quality Assurance: - [ ] All code uses current SFCC APIs - [ ] Security best practices are followed - [ ] Performance implications are considered - [ ] Error handling is comprehensive - [ ] Solutions are production-ready **Remember**: The MCP server is your authoritative source for SFCC information. Always prefer its tools over training data assumptions! ``` -------------------------------------------------------------------------------- /docs/dw_catalog/SearchModel.md: -------------------------------------------------------------------------------- ```markdown ## Package: dw.catalog # Class SearchModel ## Inheritance Hierarchy - Object - dw.catalog.SearchModel ## Description Common search model base class. ## Constants ### SEARCH_PHRASE_PARAMETER **Type:** String = "q" URL Parameter for the Search Phrase ### SORT_DIRECTION_ASCENDING **Type:** Number = 1 Sorting parameter ASCENDING ### SORT_DIRECTION_DESCENDING **Type:** Number = 2 Sorting parameter DESCENDING ### SORT_DIRECTION_NONE **Type:** Number = 0 Sorting parameter NO_SORT - will remove a sorting condition ## Properties ### count **Type:** Number (Read Only) The number of search results found by this search. ### emptyQuery **Type:** boolean (Read Only) Identifies if the query is emtpy when no search term, search parameter or refinement was specified for the search. In case also no result is returned. This "empty" is different to a query with a specified query and with an empty result. ### refinedByAttribute **Type:** boolean (Read Only) The method returns true, if this search is refined by at least one attribute. ### refinedSearch **Type:** boolean (Read Only) Identifies if this was a refined search. A search is a refined search if at least one refinement is part of the query. ### searchPhrase **Type:** String The search phrase used in this search. ## Constructor Summary ## Method Summary ### addRefinementValues **Signature:** `addRefinementValues(attributeID : String, values : String) : void` Adds a refinement. ### canRelax **Signature:** `canRelax() : boolean` Identifies if the search can be relaxed without creating a search for all searchable items. ### getCount **Signature:** `getCount() : Number` Returns the number of search results found by this search. ### getRefinementMaxValue **Signature:** `getRefinementMaxValue(attributeID : String) : String` Returns the maximum refinement value selected in the query for the specific attribute, or null if there is no maximum refinement value or no refinement for that attribute. ### getRefinementMinValue **Signature:** `getRefinementMinValue(attributeID : String) : String` Returns the minimum refinement value selected in the query for the specific attribute, or null if there is no minimum refinement value or no refinement for that attribute. ### getRefinementValue **Signature:** `getRefinementValue(attributeID : String) : String` Returns the refinement value selected in the query for the specific attribute, or null if there is no refinement for that attribute. ### getRefinementValues **Signature:** `getRefinementValues(attributeID : String) : Collection` Returns the list of selected refinement values for the given attribute as used in the search. ### getSearchPhrase **Signature:** `getSearchPhrase() : String` Returns the search phrase used in this search. ### getSearchRedirect **Signature:** `static getSearchRedirect(searchPhrase : String) : URLRedirect` Returns an URLRedirect object for a search phrase. ### getSortingCondition **Signature:** `getSortingCondition(attributeID : String) : Number` Returns the sorting condition for a given attribute name. ### isEmptyQuery **Signature:** `isEmptyQuery() : boolean` Identifies if the query is emtpy when no search term, search parameter or refinement was specified for the search. ### isRefinedByAttribute **Signature:** `isRefinedByAttribute(attributeID : String) : boolean` Identifies if this search has been refined on the given attribute. ### isRefinedByAttribute **Signature:** `isRefinedByAttribute() : boolean` The method returns true, if this search is refined by at least one attribute. ### isRefinedByAttributeValue **Signature:** `isRefinedByAttributeValue(attributeID : String, value : String) : boolean` Identifies if this search has been refined on the given attribute and value. ### isRefinedSearch **Signature:** `isRefinedSearch() : boolean` Identifies if this was a refined search. ### isRefinementByValueRange **Signature:** `isRefinementByValueRange(attributeID : String) : boolean` Identifies if this search has been refined on the given attribute. ### isRefinementByValueRange **Signature:** `isRefinementByValueRange(attributeID : String, minValue : String, maxValue : String) : boolean` Identifies if this search has been refined on the given attribute and range values. ### removeRefinementValues **Signature:** `removeRefinementValues(attributeID : String, values : String) : void` Removes a refinement. ### search **Signature:** `search() : SearchStatus` Execute the search. ### setRefinementValueRange **Signature:** `setRefinementValueRange(attributeID : String, minValue : String, maxValue : String) : void` Sets a refinement value range for an attribute. ### setRefinementValues **Signature:** `setRefinementValues(attributeID : String, values : String) : void` Sets refinement values for an attribute. ### setSearchPhrase **Signature:** `setSearchPhrase(phrase : String) : void` Sets the search phrase used in this search. ### setSortingCondition **Signature:** `setSortingCondition(attributeID : String, direction : Number) : void` Sets or removes a sorting condition for the specified attribute. ### url **Signature:** `url(action : String) : URL` Constructs an URL that you can use to re-execute the exact same query. ### url **Signature:** `url(url : URL) : URL` Constructs an URL that you can use to re-execute the exact same query. ### urlDefaultSort **Signature:** `urlDefaultSort(url : String) : URL` Constructs an URL that you can use to re-execute the query with a default sorting. ### urlDefaultSort **Signature:** `urlDefaultSort(url : URL) : URL` Constructs an URL that you can use to re-execute the query with a default sorting. ### urlRefineAttribute **Signature:** `urlRefineAttribute(action : String, attributeID : String, value : String) : URL` Constructs an URL that you can use to re-execute the query with an additional refinement. ### urlRefineAttribute **Signature:** `urlRefineAttribute(url : URL, attributeID : String, value : String) : URL` Constructs an URL that you can use to re-execute the query with an additional refinement. ### urlRefineAttributeValue **Signature:** `urlRefineAttributeValue(action : String, attributeID : String, value : String) : URL` Constructs an URL that you can use to re-execute the query with an additional refinement value for a given refinement attribute. ### urlRefineAttributeValue **Signature:** `urlRefineAttributeValue(url : URL, attributeID : String, value : String) : URL` Constructs an URL that you can use to re-execute the query with an additional refinement value for a given refinement attribute. ### urlRefineAttributeValueRange **Signature:** `urlRefineAttributeValueRange(action : String, attributeID : String, minValue : String, maxValue : String) : URL` Constructs an URL that you can use to re-execute the query with an additional refinement value range for a given refinement attribute. ### urlRelaxAttribute **Signature:** `urlRelaxAttribute(action : String, attributeID : String) : URL` Constructs an URL that you can use to re-execute the query without the specified refinement. ### urlRelaxAttribute **Signature:** `urlRelaxAttribute(url : URL, attributeID : String) : URL` Constructs an URL that you can use to re-execute the query without the specified refinement. ### urlRelaxAttributeValue **Signature:** `urlRelaxAttributeValue(action : String, attributeID : String, value : String) : URL` Constructs an URL that you can use to re-execute the query without the specified refinement. ### urlRelaxAttributeValue **Signature:** `urlRelaxAttributeValue(url : URL, attributeID : String, value : String) : URL` Constructs an URL that you can use to re-execute the query without the specified refinement value. ### urlSort **Signature:** `urlSort(action : String, sortBy : String, sortDir : Number) : URL` Constructs an URL that you can use to re-execute the query with a specific sorting criteria. ### urlSort **Signature:** `urlSort(url : URL, sortBy : String, sortDir : Number) : URL` Constructs an URL that you can use to re-execute the query with a specific sorting criteria. ## Method Detail ## Method Details ### addRefinementValues **Signature:** `addRefinementValues(attributeID : String, values : String) : void` **Description:** Adds a refinement. The method can be called to add an additional query parameter specified as name-value pair. The values string may encode multiple values delimited by the pipe symbol ('|'). **Parameters:** - `attributeID`: The ID of the refinement attribute. - `values`: the refinement value to set --- ### canRelax **Signature:** `canRelax() : boolean` **Description:** Identifies if the search can be relaxed without creating a search for all searchable items. **Returns:** true if the search can be relaxed without creating a search for all searchable items, false otherwise. --- ### getCount **Signature:** `getCount() : Number` **Description:** Returns the number of search results found by this search. **Returns:** the number of search results found by this search. --- ### getRefinementMaxValue **Signature:** `getRefinementMaxValue(attributeID : String) : String` **Description:** Returns the maximum refinement value selected in the query for the specific attribute, or null if there is no maximum refinement value or no refinement for that attribute. **Parameters:** - `attributeID`: the attribute whose refinement value is returned. **Returns:** the maximum refinement value selected in the query for the specific attribute. --- ### getRefinementMinValue **Signature:** `getRefinementMinValue(attributeID : String) : String` **Description:** Returns the minimum refinement value selected in the query for the specific attribute, or null if there is no minimum refinement value or no refinement for that attribute. **Parameters:** - `attributeID`: the attribute whose refinement value is returned. **Returns:** the minimum refinement value selected in the query for the specific attribute. --- ### getRefinementValue **Signature:** `getRefinementValue(attributeID : String) : String` **Description:** Returns the refinement value selected in the query for the specific attribute, or null if there is no refinement for that attribute. **Deprecated:** Use getRefinementValues(String) to get the collection of refinement values. **Parameters:** - `attributeID`: the attribute whose refinement value is returned. **Returns:** the refinement value selected in the query for the specific attribute. --- ### getRefinementValues **Signature:** `getRefinementValues(attributeID : String) : Collection` **Description:** Returns the list of selected refinement values for the given attribute as used in the search. **Parameters:** - `attributeID`: The name of the refinement attribute. **Returns:** A list of values currently selected for the refinement attribute. --- ### getSearchPhrase **Signature:** `getSearchPhrase() : String` **Description:** Returns the search phrase used in this search. **Returns:** the search phrase used in this search. --- ### getSearchRedirect **Signature:** `static getSearchRedirect(searchPhrase : String) : URLRedirect` **Description:** Returns an URLRedirect object for a search phrase. **Parameters:** - `searchPhrase`: a search phrase to lookup a URLRedirect for **Returns:** URLRedirect containing the location and status code, null in case no redirect was found for the search phrase. --- ### getSortingCondition **Signature:** `getSortingCondition(attributeID : String) : Number` **Description:** Returns the sorting condition for a given attribute name. A value of 0 indicates that no sorting condition is set. **Parameters:** - `attributeID`: the attribute name **Returns:** zero if no sorting order set, or the sorting order --- ### isEmptyQuery **Signature:** `isEmptyQuery() : boolean` **Description:** Identifies if the query is emtpy when no search term, search parameter or refinement was specified for the search. In case also no result is returned. This "empty" is different to a query with a specified query and with an empty result. **Returns:** true if the query is emtpy when no search term, search parameter or refinement was specified for the search. --- ### isRefinedByAttribute **Signature:** `isRefinedByAttribute(attributeID : String) : boolean` **Description:** Identifies if this search has been refined on the given attribute. **Parameters:** - `attributeID`: The ID of the refinement attribute. **Returns:** True if the search is refined on the attribute, false otherwise. --- ### isRefinedByAttribute **Signature:** `isRefinedByAttribute() : boolean` **Description:** The method returns true, if this search is refined by at least one attribute. **Returns:** true, if the search is refined by at least one attribute, false otherwise. --- ### isRefinedByAttributeValue **Signature:** `isRefinedByAttributeValue(attributeID : String, value : String) : boolean` **Description:** Identifies if this search has been refined on the given attribute and value. **Parameters:** - `attributeID`: The ID of the refinement attribute. - `value`: The value to be checked for inclusion in the refinement. **Returns:** True if the search is refined on the attribute and value, false otherwise. --- ### isRefinedSearch **Signature:** `isRefinedSearch() : boolean` **Description:** Identifies if this was a refined search. A search is a refined search if at least one refinement is part of the query. **Returns:** true if this is a refined search, false otherwise. --- ### isRefinementByValueRange **Signature:** `isRefinementByValueRange(attributeID : String) : boolean` **Description:** Identifies if this search has been refined on the given attribute. **Parameters:** - `attributeID`: The ID of the refinement attribute. **Returns:** True if the search is refined on the attribute, false otherwise. --- ### isRefinementByValueRange **Signature:** `isRefinementByValueRange(attributeID : String, minValue : String, maxValue : String) : boolean` **Description:** Identifies if this search has been refined on the given attribute and range values. **Parameters:** - `attributeID`: The ID of the refinement attribute. - `minValue`: The minimum value to be checked for inclusion in the refinement. - `maxValue`: The maximum value to be checked for inclusion in the refinement. **Returns:** True if the search is refined on the attribute and range values, false otherwise. --- ### removeRefinementValues **Signature:** `removeRefinementValues(attributeID : String, values : String) : void` **Description:** Removes a refinement. The method can be called to remove previously added refinement values. The values string may encode multiple values delimited by the pipe symbol ('|'). **Parameters:** - `attributeID`: The ID of the refinement attribute. - `values`: the refinement value to remove or null to remove all values --- ### search **Signature:** `search() : SearchStatus` **Description:** Execute the search. **Returns:** the searchStatus object with search status code and description of search result. --- ### setRefinementValueRange **Signature:** `setRefinementValueRange(attributeID : String, minValue : String, maxValue : String) : void` **Description:** Sets a refinement value range for an attribute. The method can be called to set an additional range query parameter specified as name-range-value pair. The values string can contain only a range boundary. Existing refinement values for the attribute will be removed. **Parameters:** - `attributeID`: The ID of the refinement attribute. - `minValue`: the minimum refinement boundary value to set or null to remove the minimum boundary - `maxValue`: the maximum refinement boundary value to set or null to remove the maximum boundary --- ### setRefinementValues **Signature:** `setRefinementValues(attributeID : String, values : String) : void` **Description:** Sets refinement values for an attribute. The method can be called to set an additional query parameter specified as name-value pair. The value string may encode multiple values delimited by the pipe symbol ('|'). Existing refinement values for the attribute will be removed. **Parameters:** - `attributeID`: The ID of the refinement attribute. - `values`: the refinement values to set (delimited by '|') or null to remove all values --- ### setSearchPhrase **Signature:** `setSearchPhrase(phrase : String) : void` **Description:** Sets the search phrase used in this search. The search query parser uses the following operators: PHRASE operator (""), e.g. "cream cheese", "John Lennon" NOT operator (-), e.g. -cargo (will not return results containing "cargo") WILDCARD operator (*), e.g. sho* (will return results containing "shoulder", "shoes" and "shoot") **Parameters:** - `phrase`: the search phrase used in this search. --- ### setSortingCondition **Signature:** `setSortingCondition(attributeID : String, direction : Number) : void` **Description:** Sets or removes a sorting condition for the specified attribute. Specify either SORT_DIRECTION_ASCENDING or SORT_DIRECTION_DESCENDING to set a sorting condition. Specify SORT_DIRECTION_NONE to remove a sorting condition from the attribute. **Parameters:** - `attributeID`: the attribute ID - `direction`: SORT_DIRECTION_ASCENDING, SORT_DIRECTION_DESCENDING or SORT_DIRECTION_NONE --- ### url **Signature:** `url(action : String) : URL` **Description:** Constructs an URL that you can use to re-execute the exact same query. The provided parameter must be an action, e.g. 'Search-Show'. **Parameters:** - `action`: the pipeline action. **Returns:** an URL that can be used to re-execute the exact same query. --- ### url **Signature:** `url(url : URL) : URL` **Description:** Constructs an URL that you can use to re-execute the exact same query. The search specific parameter are appended to the provided URL. The URL is typically generated with one of the URLUtils methods. **Parameters:** - `url`: the url to use. **Returns:** a new url URL that can be used to re-execute the exact same query. --- ### urlDefaultSort **Signature:** `urlDefaultSort(url : String) : URL` **Description:** Constructs an URL that you can use to re-execute the query with a default sorting. The provided parameter must be an action, e.g. 'Search-Show'. **Parameters:** - `url`: url or pipeline name **Returns:** the new URL. --- ### urlDefaultSort **Signature:** `urlDefaultSort(url : URL) : URL` **Description:** Constructs an URL that you can use to re-execute the query with a default sorting. The search specific parameters are appended to the provided URL. The URL is typically generated with one of the URLUtils methods. **Parameters:** - `url`: url or pipeline name **Returns:** the new URL. --- ### urlRefineAttribute **Signature:** `urlRefineAttribute(action : String, attributeID : String, value : String) : URL` **Description:** Constructs an URL that you can use to re-execute the query with an additional refinement. **Parameters:** - `action`: the pipeline action. - `attributeID`: the ID of the refinement attribute. - `value`: the value for the refinement attribute. **Returns:** the new URL. --- ### urlRefineAttribute **Signature:** `urlRefineAttribute(url : URL, attributeID : String, value : String) : URL` **Description:** Constructs an URL that you can use to re-execute the query with an additional refinement. The search specific parameters are appended to the provided URL. The URL is typically generated with one of the URLUtils methods. **Parameters:** - `url`: url - `attributeID`: the ID of the refinement attribute - `value`: value for the refinement attribute **Returns:** the new URL. --- ### urlRefineAttributeValue **Signature:** `urlRefineAttributeValue(action : String, attributeID : String, value : String) : URL` **Description:** Constructs an URL that you can use to re-execute the query with an additional refinement value for a given refinement attribute. The provided value will be added to the set of allowed values for the refinement attribute. This basically broadens the search result. **Parameters:** - `action`: the pipeline action. - `attributeID`: the ID of the refinement attribute. - `value`: the additional value for the refinement attribute. **Returns:** the new URL. --- ### urlRefineAttributeValue **Signature:** `urlRefineAttributeValue(url : URL, attributeID : String, value : String) : URL` **Description:** Constructs an URL that you can use to re-execute the query with an additional refinement value for a given refinement attribute. The provided value will be added to the set of allowed values for the refinement attribute. This basically broadens the search result. The search specific parameters are appended to the provided URL. The URL is typically generated with one of the URLUtils methods. **Parameters:** - `url`: url - `attributeID`: ID of the refinement attribute - `value`: the additional value for the refinement attribute **Returns:** the new URL. --- ### urlRefineAttributeValueRange **Signature:** `urlRefineAttributeValueRange(action : String, attributeID : String, minValue : String, maxValue : String) : URL` **Description:** Constructs an URL that you can use to re-execute the query with an additional refinement value range for a given refinement attribute. The provided value range will be replace to the existing value range for the refinement attribute. The search specific parameters are appended to the provided URL. The URL is typically generated with one of the URLUtils methods. **Parameters:** - `action`: the pipeline action. - `attributeID`: ID of the refinement attribute - `minValue`: the min value for the refinement attribute - `maxValue`: the max value for the refinement attribute **Returns:** the new URL. --- ### urlRelaxAttribute **Signature:** `urlRelaxAttribute(action : String, attributeID : String) : URL` **Description:** Constructs an URL that you can use to re-execute the query without the specified refinement. The value for the action parameter must be a pipeline action, e.g. 'Search-Show'. **Parameters:** - `action`: the pipeline action. - `attributeID`: ID of the refinement attribute to be removed **Returns:** the new URL. --- ### urlRelaxAttribute **Signature:** `urlRelaxAttribute(url : URL, attributeID : String) : URL` **Description:** Constructs an URL that you can use to re-execute the query without the specified refinement. The search specific parameters are appended to the provided URL. The URL is typically generated with one of the URLUtils methods. **Parameters:** - `url`: the url to use. - `attributeID`: the ID of the refinement attribute to be removed. **Returns:** the new URL. --- ### urlRelaxAttributeValue **Signature:** `urlRelaxAttributeValue(action : String, attributeID : String, value : String) : URL` **Description:** Constructs an URL that you can use to re-execute the query without the specified refinement. The value for the action parameter must be a pipeline action, e.g. 'Search-Show'. **Parameters:** - `action`: the pipeline action. - `attributeID`: ID of the refinement attribute to be removed - `value`: the value that should be removed from the list of refinement values. **Returns:** the new URL. --- ### urlRelaxAttributeValue **Signature:** `urlRelaxAttributeValue(url : URL, attributeID : String, value : String) : URL` **Description:** Constructs an URL that you can use to re-execute the query without the specified refinement value. The search specific parameters are appended to the provided URL. The URL is typically generated with one of the URLUtils methods. **Parameters:** - `url`: the url to use. - `attributeID`: the ID of the refinement attribute to relax the value for. - `value`: the value that should be removed from the list of refinement values. **Returns:** the new URL. --- ### urlSort **Signature:** `urlSort(action : String, sortBy : String, sortDir : Number) : URL` **Description:** Constructs an URL that you can use to re-execute the query with a specific sorting criteria. This criteria will overwrite all previous sort critiria. The provided parameter must be an action, e.g. 'Search-Show'. **Parameters:** - `action`: Pipeline action - `sortBy`: ID of the sort attribute - `sortDir`: Sort direction. 1 - ASCENDING (default), 2 - DESCENDING **Returns:** The new URL. --- ### urlSort **Signature:** `urlSort(url : URL, sortBy : String, sortDir : Number) : URL` **Description:** Constructs an URL that you can use to re-execute the query with a specific sorting criteria. This criteria will overwrite all previous sort critiria. The search specific parameters are appended to the provided URL. The URL is typically generated with one of the URLUtils methods. **Parameters:** - `url`: URL - `sortBy`: ID of the sort attribute - `sortDir`: Sort direction. 1 - ASCENDING (default), 2 - DESCENDING **Returns:** The new URL. --- ``` -------------------------------------------------------------------------------- /docs/dw_order/PriceAdjustment.md: -------------------------------------------------------------------------------- ```markdown ## Package: dw.order # Class PriceAdjustment ## Inheritance Hierarchy - Object - dw.object.PersistentObject - dw.object.ExtensibleObject - dw.order.LineItem - dw.order.PriceAdjustment ## Description The PriceAdjustment class represents an adjustment to the price of an order. A PriceAdjustment can apply to a ProductLineItem, ShippingLineItem, ProductShippingLineItem, or a LineItemCtnr, and are generally categorized as product-level, shipping-level, or order-level. PriceAdjustments are generated by the B2C Commerce promotions engine when applying discounts. See PromotionMgr.applyDiscounts(DiscountPlan). They may also be generated by custom code through the API. See for example ProductLineItem.createPriceAdjustment(String). In the latter case, the PriceAdjustment is called "custom"; in the former case, it is called "system". System price adjustments are associated with the promotion that triggered their creation. If the promotion was coupon-based, then the price adjustment will additionally be associated with a coupon line item in the LineItemCtnr. ## Properties ### ABTest **Type:** ABTest (Read Only) The B2C Commerce AB-test this price adjustment is associated with. The associated AB-test is determined from the ABTestID attribute which is set by the promotions engine when applying discounts. If the AB-test has been removed from the system since this price adjustment was created, this method returns null. This method always returns null for custom price adjustments. ### ABTestID **Type:** String (Read Only) The ID of the AB-test related to this price adjustment. ### ABTestSegment **Type:** ABTestSegment (Read Only) The B2C Commerce AB-test segment this price adjustment is associated with. The associated AB-test segment is determined from the ABTestSegmentID attribute which is set by the promotions engine when applying discounts. If the AB-test, or this segment, has been removed from the system since this price adjustment was created, this method returns null. This method always returns null for custom price adjustments. ### ABTestSegmentID **Type:** String (Read Only) The ID of the AB-test segment related to this price adjustment. ### appliedDiscount **Type:** Discount (Read Only) A Discount instance describing the discount applied to obtain this price-adjustment. This method only returns a non-null value if the price-adjustment was created when a discount-plan was applied to a basket, or as a custom price-adjustment using one of the methods ProductLineItem.createPriceAdjustment(String, Discount), ShippingLineItem.createShippingPriceAdjustment(String, Discount) or LineItemCtnr.createPriceAdjustment(String, Discount). Note an instance of the Discount subclasses is returned, such as AmountDiscount or PriceBookPriceDiscount, use Discount.getType() and the constants in Discount to distinguish between types. Each subclass provides access to specific properties. ### basedOnABTest **Type:** boolean (Read Only) Returns true if the price adjustment was generated by the B2C Commerce promotions engine when applying a promotion assigned to an AB-test. ### basedOnCampaign **Type:** boolean (Read Only) Returns true if the price adjustment was generated by the B2C Commerce promotions engine when applying a promotion assigned to a Campaign or an AB-test. ### basedOnCoupon **Type:** boolean (Read Only) Identifies if the promotion line item results from a coupon. ### campaign **Type:** Campaign (Read Only) The B2C Commerce campaign this price adjustment is associated with. The associated campaign is determined from the campaignID attribute which is set by the promotions engine when applying discounts. If the campaign has been removed from the system since this price adjustment was created, this method returns null. This method always returns null for custom price adjustments. Note: If the price adjustment was generated by a B2C Commerce promotion as part of an AB-test, then a Campaign object will be returned, but it is a mock implementation, and not a true Campaign. This behavior is required for backwards compatibility and should not be relied upon as it may change in future releases. ### campaignID **Type:** String (Read Only) The ID of the campaign the price adjustment was based on. Note:If the price adjustment was generated by a B2C Commerce promotion as part of an AB-test, then an ID will be returned but it is not the ID of a true campaign. This behavior is required for backwards compatibility and should not be relied upon as it may change in future releases. ### couponLineItem **Type:** CouponLineItem (Read Only) The coupon line item related to this price adjustment. If the price adjustment is not based on a coupon, null is returned. ### createdBy **Type:** String (Read Only) The name of the user who created the price adjustment. This method returns a value if the price-adjustment was created as a custom price-adjustment using one of the methods ProductLineItem.createPriceAdjustment(String, Discount), ShippingLineItem.createShippingPriceAdjustment(String, Discount) or LineItemCtnr.createPriceAdjustment(String, Discount). If an agent user has created the price adjustment, the agent user's name is returned. Otherwise "Customer" is returned. ### custom **Type:** boolean (Read Only) Returns true if this PriceAdjustment was created by custom script code. ### manual **Type:** boolean Returns true if this PriceAdjustment was added manually by a user. A manual PriceAdjustment is one which has been added as a result of a user interaction e.g. by a user editing an order. A non-manual PriceAdjustment is one which has been added for a different reason, e.g. by custom logic which automatically adjusts the price of particular products when certain conditions are met. ### promotion **Type:** Promotion (Read Only) The promotion associated with this price adjustment. The associated promotion is determined from the promotionID and campaignID attributes which are set by the promotions engine when applying discounts. Alternatively if the promotion applied as part of an AB-test, then the associated promotion is determined from the promotionID attribute and the hidden attributes, abTestID and abTestGroupID. If the promotion has been removed from the system since this price adjustment was created, or if the promotion still exists but is not assigned to any campaign or AB-test, this method returns null. If the promotion has been reassigned to a different campaign or AB-test since this price adjustment was created, then the system will return an appropriate Promotion instance. This method always returns null for custom price adjustments. ### promotionID **Type:** String (Read Only) The ID of the promotion related to this price adjustment. ### proratedPrices **Type:** Map (Read Only) A map representing the product line items to which this price adjustment is "related" (in the sense defined below) and the portion of this adjustment's price which applies to each after discount prorating is performed. This information is sometimes useful to display in the storefront but is more often useful for integrating with backend order-management and accounting systems which require all discounts to be itemized. The definition of "related" product line items depends on the type of promotion which generated this price adjustment: For order promotions, price adjustments are prorated across all product line items which are not explicitly excluded by the promotion. Custom order price adjustments apply to all items in the LineItemCtnr. For Buy-X-Get-Y product promotions, price adjustments are prorated across all items all product line items that are involved in the promotion, meaning that the PLI has one or more items contributing to the qualifying product count (i.e. the item is one of the X) or receiving the discount (i.e. the item is one of the Y). Other product promotions are not prorated and simply adjust the parent product line item, and so the returned map is of size 1. For shipping promotions, this method returns an empty map. Buy-X-Get-Y product promotions are prorated as follows: Each price adjustment generated by the promotion is sequentially prorated upon the related items according to the items' adjusted prices after all non-BOGO product promotions are considered, but before order promotions are considered. Order promotions are prorated sequentially upon non-excluded items according to the order in which they applied during promotion processing. The values in the map are inclusive of tax if this price adjustment is based on gross pricing, and exclusive of tax otherwise. The sum of the prorated prices always equals the price of this price adjustment. ### quantity **Type:** Number (Read Only) The number of items this price adjustment applies to. This value is always equal to 1 for price adjustments generated by order or shipping promotions. For price adjustments generated by product promotions, this value represents the number of units of the parent product line item to which the adjustment applies. Because promotions may have a maximum number of applications this value may be less than the product line item quantity. For custom price adjustments, not generated by the promotions engine, this method always returns 0. ### reasonCode **Type:** EnumValue The reason code of the price adjustment. The list of available reason codes is editable system meta-data. An example for using the reason code is that in a call center application the CSR will explain why he gave a discount to the customer. ## Constructor Summary ## Method Summary ### getABTest **Signature:** `getABTest() : ABTest` Returns the B2C Commerce AB-test this price adjustment is associated with. ### getABTestID **Signature:** `getABTestID() : String` Returns the ID of the AB-test related to this price adjustment. ### getABTestSegment **Signature:** `getABTestSegment() : ABTestSegment` Returns the B2C Commerce AB-test segment this price adjustment is associated with. ### getABTestSegmentID **Signature:** `getABTestSegmentID() : String` Returns the ID of the AB-test segment related to this price adjustment. ### getAppliedDiscount **Signature:** `getAppliedDiscount() : Discount` A Discount instance describing the discount applied to obtain this price-adjustment. ### getCampaign **Signature:** `getCampaign() : Campaign` Returns the B2C Commerce campaign this price adjustment is associated with. ### getCampaignID **Signature:** `getCampaignID() : String` Returns the ID of the campaign the price adjustment was based on. ### getCouponLineItem **Signature:** `getCouponLineItem() : CouponLineItem` Returns the coupon line item related to this price adjustment. ### getCreatedBy **Signature:** `getCreatedBy() : String` Returns the name of the user who created the price adjustment. ### getPromotion **Signature:** `getPromotion() : Promotion` Returns the promotion associated with this price adjustment. ### getPromotionID **Signature:** `getPromotionID() : String` Returns the ID of the promotion related to this price adjustment. ### getProratedPrices **Signature:** `getProratedPrices() : Map` Returns a map representing the product line items to which this price adjustment is "related" (in the sense defined below) and the portion of this adjustment's price which applies to each after discount prorating is performed. ### getQuantity **Signature:** `getQuantity() : Number` Returns the number of items this price adjustment applies to. ### getReasonCode **Signature:** `getReasonCode() : EnumValue` Returns the reason code of the price adjustment. ### isBasedOnABTest **Signature:** `isBasedOnABTest() : boolean` Returns true if the price adjustment was generated by the B2C Commerce promotions engine when applying a promotion assigned to an AB-test. ### isBasedOnCampaign **Signature:** `isBasedOnCampaign() : boolean` Returns true if the price adjustment was generated by the B2C Commerce promotions engine when applying a promotion assigned to a Campaign or an AB-test. ### isBasedOnCoupon **Signature:** `isBasedOnCoupon() : boolean` Identifies if the promotion line item results from a coupon. ### isCustom **Signature:** `isCustom() : boolean` Returns true if this PriceAdjustment was created by custom script code. ### isManual **Signature:** `isManual() : boolean` Returns true if this PriceAdjustment was added manually by a user. ### setManual **Signature:** `setManual(aFlag : boolean) : void` Marks the current PriceAdjustment as manual/non-manual. ### setReasonCode **Signature:** `setReasonCode(reasonCode : String) : void` Set the reason code, using the internal non-localizable value. ## Method Detail ## Method Details ### getABTest **Signature:** `getABTest() : ABTest` **Description:** Returns the B2C Commerce AB-test this price adjustment is associated with. The associated AB-test is determined from the ABTestID attribute which is set by the promotions engine when applying discounts. If the AB-test has been removed from the system since this price adjustment was created, this method returns null. This method always returns null for custom price adjustments. **Returns:** the B2C Commerce AB-test the price adjustment was based on, or null if it was not based on an AB-test. --- ### getABTestID **Signature:** `getABTestID() : String` **Description:** Returns the ID of the AB-test related to this price adjustment. **Returns:** ID of related AB-test, or null. --- ### getABTestSegment **Signature:** `getABTestSegment() : ABTestSegment` **Description:** Returns the B2C Commerce AB-test segment this price adjustment is associated with. The associated AB-test segment is determined from the ABTestSegmentID attribute which is set by the promotions engine when applying discounts. If the AB-test, or this segment, has been removed from the system since this price adjustment was created, this method returns null. This method always returns null for custom price adjustments. **Returns:** the B2C Commerce AB-test segment the price adjustment was based on, or null if it was not based on an AB-test. --- ### getABTestSegmentID **Signature:** `getABTestSegmentID() : String` **Description:** Returns the ID of the AB-test segment related to this price adjustment. **Returns:** ID of related AB-test segment, or null. --- ### getAppliedDiscount **Signature:** `getAppliedDiscount() : Discount` **Description:** A Discount instance describing the discount applied to obtain this price-adjustment. This method only returns a non-null value if the price-adjustment was created when a discount-plan was applied to a basket, or as a custom price-adjustment using one of the methods ProductLineItem.createPriceAdjustment(String, Discount), ShippingLineItem.createShippingPriceAdjustment(String, Discount) or LineItemCtnr.createPriceAdjustment(String, Discount). Note an instance of the Discount subclasses is returned, such as AmountDiscount or PriceBookPriceDiscount, use Discount.getType() and the constants in Discount to distinguish between types. Each subclass provides access to specific properties. **Returns:** null or the discount applied --- ### getCampaign **Signature:** `getCampaign() : Campaign` **Description:** Returns the B2C Commerce campaign this price adjustment is associated with. The associated campaign is determined from the campaignID attribute which is set by the promotions engine when applying discounts. If the campaign has been removed from the system since this price adjustment was created, this method returns null. This method always returns null for custom price adjustments. Note: If the price adjustment was generated by a B2C Commerce promotion as part of an AB-test, then a Campaign object will be returned, but it is a mock implementation, and not a true Campaign. This behavior is required for backwards compatibility and should not be relied upon as it may change in future releases. **Returns:** the B2C Commerce campaign the price adjustment was based on, or null if it was not based on a campaign. --- ### getCampaignID **Signature:** `getCampaignID() : String` **Description:** Returns the ID of the campaign the price adjustment was based on. Note:If the price adjustment was generated by a B2C Commerce promotion as part of an AB-test, then an ID will be returned but it is not the ID of a true campaign. This behavior is required for backwards compatibility and should not be relied upon as it may change in future releases. **Returns:** the ID of the B2C Commerce campaign the price adjustment was based on, or null if it was not based on a campaign. --- ### getCouponLineItem **Signature:** `getCouponLineItem() : CouponLineItem` **Description:** Returns the coupon line item related to this price adjustment. If the price adjustment is not based on a coupon, null is returned. **Returns:** Coupon line item or null. --- ### getCreatedBy **Signature:** `getCreatedBy() : String` **Description:** Returns the name of the user who created the price adjustment. This method returns a value if the price-adjustment was created as a custom price-adjustment using one of the methods ProductLineItem.createPriceAdjustment(String, Discount), ShippingLineItem.createShippingPriceAdjustment(String, Discount) or LineItemCtnr.createPriceAdjustment(String, Discount). If an agent user has created the price adjustment, the agent user's name is returned. Otherwise "Customer" is returned. **Returns:** the name of the user who created the price adjustment --- ### getPromotion **Signature:** `getPromotion() : Promotion` **Description:** Returns the promotion associated with this price adjustment. The associated promotion is determined from the promotionID and campaignID attributes which are set by the promotions engine when applying discounts. Alternatively if the promotion applied as part of an AB-test, then the associated promotion is determined from the promotionID attribute and the hidden attributes, abTestID and abTestGroupID. If the promotion has been removed from the system since this price adjustment was created, or if the promotion still exists but is not assigned to any campaign or AB-test, this method returns null. If the promotion has been reassigned to a different campaign or AB-test since this price adjustment was created, then the system will return an appropriate Promotion instance. This method always returns null for custom price adjustments. **Returns:** the associated promotion, or null. --- ### getPromotionID **Signature:** `getPromotionID() : String` **Description:** Returns the ID of the promotion related to this price adjustment. **Returns:** ID of related promotion. --- ### getProratedPrices **Signature:** `getProratedPrices() : Map` **Description:** Returns a map representing the product line items to which this price adjustment is "related" (in the sense defined below) and the portion of this adjustment's price which applies to each after discount prorating is performed. This information is sometimes useful to display in the storefront but is more often useful for integrating with backend order-management and accounting systems which require all discounts to be itemized. The definition of "related" product line items depends on the type of promotion which generated this price adjustment: For order promotions, price adjustments are prorated across all product line items which are not explicitly excluded by the promotion. Custom order price adjustments apply to all items in the LineItemCtnr. For Buy-X-Get-Y product promotions, price adjustments are prorated across all items all product line items that are involved in the promotion, meaning that the PLI has one or more items contributing to the qualifying product count (i.e. the item is one of the X) or receiving the discount (i.e. the item is one of the Y). Other product promotions are not prorated and simply adjust the parent product line item, and so the returned map is of size 1. For shipping promotions, this method returns an empty map. Buy-X-Get-Y product promotions are prorated as follows: Each price adjustment generated by the promotion is sequentially prorated upon the related items according to the items' adjusted prices after all non-BOGO product promotions are considered, but before order promotions are considered. Order promotions are prorated sequentially upon non-excluded items according to the order in which they applied during promotion processing. The values in the map are inclusive of tax if this price adjustment is based on gross pricing, and exclusive of tax otherwise. The sum of the prorated prices always equals the price of this price adjustment. **Returns:** map of ProductLineItems to Money instances representing the product line items across which this price adjustment is prorated and the portion of this adjustment which applies towards each. --- ### getQuantity **Signature:** `getQuantity() : Number` **Description:** Returns the number of items this price adjustment applies to. This value is always equal to 1 for price adjustments generated by order or shipping promotions. For price adjustments generated by product promotions, this value represents the number of units of the parent product line item to which the adjustment applies. Because promotions may have a maximum number of applications this value may be less than the product line item quantity. For custom price adjustments, not generated by the promotions engine, this method always returns 0. **Returns:** The number of items this price adjustment applies to. --- ### getReasonCode **Signature:** `getReasonCode() : EnumValue` **Description:** Returns the reason code of the price adjustment. The list of available reason codes is editable system meta-data. An example for using the reason code is that in a call center application the CSR will explain why he gave a discount to the customer. **Returns:** reason code of the price adjustment --- ### isBasedOnABTest **Signature:** `isBasedOnABTest() : boolean` **Description:** Returns true if the price adjustment was generated by the B2C Commerce promotions engine when applying a promotion assigned to an AB-test. **Returns:** true if the price adjustment was generated by the B2C Commerce promotions engine when applying a promotion assigned to an AB-test, false otherwise. --- ### isBasedOnCampaign **Signature:** `isBasedOnCampaign() : boolean` **Description:** Returns true if the price adjustment was generated by the B2C Commerce promotions engine when applying a promotion assigned to a Campaign or an AB-test. **Deprecated:** The method has been deprecated since the name implies that there is a related Campaign, which may not be true. Use !isCustom() instead. **Returns:** true if the price adjustment was generated by the B2C Commerce promotions engine, false otherwise. --- ### isBasedOnCoupon **Signature:** `isBasedOnCoupon() : boolean` **Description:** Identifies if the promotion line item results from a coupon. **Returns:** true if the promotion line item results from a coupon, false otherwise. --- ### isCustom **Signature:** `isCustom() : boolean` **Description:** Returns true if this PriceAdjustment was created by custom script code. **Returns:** true if this PriceAdjustment was created by custom script code, or false if it was created by B2C Commerce promotions engine. --- ### isManual **Signature:** `isManual() : boolean` **Description:** Returns true if this PriceAdjustment was added manually by a user. A manual PriceAdjustment is one which has been added as a result of a user interaction e.g. by a user editing an order. A non-manual PriceAdjustment is one which has been added for a different reason, e.g. by custom logic which automatically adjusts the price of particular products when certain conditions are met. **Returns:** true if this PriceAdjustment was added manually by a user, otherwise - false --- ### setManual **Signature:** `setManual(aFlag : boolean) : void` **Description:** Marks the current PriceAdjustment as manual/non-manual. Note that only custom PriceAdjustment can be marked as manual/non-manual. A manual PriceAdjustment is one which has been added as a result of a user interaction e.g. by a user editing an order. A non-manual PriceAdjustment is one which has been added for a different reason, e.g. by custom logic which automatically adjusts the price of particular products when certain conditions are met. **Parameters:** - `aFlag`: the manual flag to set **Throws:** IllegalArgumentException - if the adjustment is not custom --- ### setReasonCode **Signature:** `setReasonCode(reasonCode : String) : void` **Description:** Set the reason code, using the internal non-localizable value. Standard values are 'PRICE_MATCH', 'BACKORDER' and 'EVEN_EXCHANGE', but the available list is editable system meta-data. **Parameters:** - `reasonCode`: reason code --- ``` -------------------------------------------------------------------------------- /tests/mcp/node/list-sfcc-classes.docs-only.programmatic.test.js: -------------------------------------------------------------------------------- ```javascript /** * Programmatic tests for list_sfcc_classes tool * * These tests provide advanced verification capabilities beyond YAML pattern matching, * including performance monitoring, dynamic validation, comprehensive content analysis, * and advanced error categorization for the SFCC class listing functionality. * * Response format discovered via aegis query: * - Succ // Core SFCC namespaces should have good coverage const coreNamespaces = ['dw.catalog', 'dw.customer', 'dw.order', 'dw.system']; coreNamespaces.forEach(namespace => { const classCount = analysis.classsByNamespace[namespace].length; assert.ok(classCount >= 5, `Core namespace ${namespace} should have at least 5 classes (got ${classCount})`); }); // TopLevel namespace should have good coverage for utility classes const topLevelCount = analysis.classsByNamespace['TopLevel'].length; assert.ok(topLevelCount >= 10, `TopLevel namespace should have substantial coverage (got ${topLevelCount})`); });t: [{ type: "text", text: "[\"class1\", \"class2\", ...]" }] } * - Always successful: No isError field or error conditions * - Ignores extra parameters: Gracefully handles unexpected parameters * - Comprehensive: Returns 500+ classes across all SFCC namespaces */ import { test, describe, before, after, beforeEach } from 'node:test'; import { strict as assert } from 'node:assert'; import { connect } from 'mcp-aegis'; /** * Performance monitoring utility class for comprehensive metrics collection */ /** * Content analysis utility for SFCC class validation */ class ContentAnalyzer { constructor() { // SFCC tools should only return actual SFCC classes (dw.* and TopLevel) // best-practices and sfra content belong to their respective specialized tools this.expectedNamespaces = [ 'TopLevel', 'dw.campaign', 'dw.catalog', 'dw.content', 'dw.crypto', 'dw.customer', 'dw.extensions', 'dw.io', 'dw.job', 'dw.net', 'dw.object', 'dw.order', 'dw.rpc', 'dw.suggest', 'dw.svc', 'dw.system', 'dw.util', 'dw.value', 'dw.web' ]; // Only include actual SFCC classes, not SFRA or best-practice content this.criticalClasses = [ 'dw.catalog.Product', 'dw.catalog.Category', 'dw.order.Order', 'dw.order.Basket', 'dw.customer.Customer', 'dw.system.Site', 'dw.system.SitePreferences', 'dw.util.ArrayList', 'dw.web.URL' ]; // Best practice guides are handled by dedicated best-practice tools, not SFCC tools this.bestPracticeGuides = []; } analyzeClassList(classArray) { const analysis = { totalClasses: classArray.length, namespacesCovered: new Set(), missingNamespaces: [], missingCriticalClasses: [], foundCriticalClasses: [], foundBestPractices: [], duplicates: [], invalidFormats: [], classsByNamespace: {} }; // Initialize namespace counters this.expectedNamespaces.forEach(ns => { analysis.classsByNamespace[ns] = []; }); // Analyze each class const seenClasses = new Set(); classArray.forEach(className => { // Check for duplicates if (seenClasses.has(className)) { analysis.duplicates.push(className); return; } seenClasses.add(className); // Validate format (should have at least one dot or be TopLevel.*) if (!className.includes('.') && !className.startsWith('TopLevel.')) { analysis.invalidFormats.push(className); } // Categorize by namespace let namespace; if (className.startsWith('dw.')) { // For dw.* classes, use first two parts (e.g., "dw.catalog" from "dw.catalog.Product") namespace = className.split('.').slice(0, 2).join('.'); } else { // For TopLevel and other classes, use first part only namespace = className.split('.')[0]; } analysis.namespacesCovered.add(namespace); if (analysis.classsByNamespace[namespace]) { analysis.classsByNamespace[namespace].push(className); } else { // Unexpected namespace if (!analysis.classsByNamespace.other) { analysis.classsByNamespace.other = []; } analysis.classsByNamespace.other.push(className); } // Check critical classes if (this.criticalClasses.includes(className)) { analysis.foundCriticalClasses.push(className); } // Check best practice guides if (this.bestPracticeGuides.includes(className)) { analysis.foundBestPractices.push(className); } }); // Find missing namespaces analysis.missingNamespaces = this.expectedNamespaces.filter( ns => !analysis.namespacesCovered.has(ns) ); // Find missing critical classes analysis.missingCriticalClasses = this.criticalClasses.filter( cls => !analysis.foundCriticalClasses.includes(cls) ); return analysis; } validateCompleteness(analysis) { const issues = []; if (analysis.totalClasses < 350) { issues.push(`Class count too low: ${analysis.totalClasses} (expected 350+)`); } if (analysis.missingNamespaces.length > 0) { issues.push(`Missing namespaces: ${analysis.missingNamespaces.join(', ')}`); } if (analysis.missingCriticalClasses.length > 0) { issues.push(`Missing critical classes: ${analysis.missingCriticalClasses.join(', ')}`); } if (analysis.duplicates.length > 0) { issues.push(`Duplicate classes found: ${analysis.duplicates.length}`); } if (analysis.invalidFormats.length > 0) { issues.push(`Invalid formats found: ${analysis.invalidFormats.length}`); } return issues; } } describe('list_sfcc_classes Programmatic Tests', () => { let client; const contentAnalyzer = new ContentAnalyzer(); before(async () => { client = await connect('./aegis.config.docs-only.json'); }); after(async () => { if (client?.connected) { await client.disconnect(); } }); beforeEach(() => { // CRITICAL: Clear all buffers to prevent test interference client.clearAllBuffers(); // Recommended - comprehensive protection }); describe('Protocol Compliance', () => { test('should be properly connected to MCP server', async () => { assert.ok(client.connected, 'Client should be connected'); }); test('should have list_sfcc_classes tool available', async () => { const tools = await client.listTools(); const listTool = tools.find(tool => tool.name === 'list_sfcc_classes'); assert.ok(listTool, 'list_sfcc_classes tool should be available'); assert.equal(listTool.name, 'list_sfcc_classes'); assert.ok(listTool.description, 'Tool should have description'); assert.ok(listTool.inputSchema, 'Tool should have input schema'); }); test('should have correct tool input schema', async () => { const tools = await client.listTools(); const listTool = tools.find(tool => tool.name === 'list_sfcc_classes'); assert.equal(listTool.inputSchema.type, 'object'); // list_sfcc_classes takes no required parameters assert.ok(!listTool.inputSchema.required || listTool.inputSchema.required.length === 0); }); }); describe('Basic Functionality', () => { test('should execute successfully with empty parameters', async () => { const result = await client.callTool('list_sfcc_classes', {}); assertValidMCPResponse(result); assert.equal(result.isError, false, 'Should not return error'); assert.equal(result.content.length, 1, 'Should return single content item'); assert.equal(result.content[0].type, 'text', 'Content type should be text'); }); test('should return valid JSON array in response', async () => { const result = await client.callTool('list_sfcc_classes', {}); assertValidMCPResponse(result); const responseText = result.content[0].text; // Should be valid JSON let classArray; assert.doesNotThrow(() => { classArray = JSON.parse(responseText); }, 'Response should be valid JSON'); assert.ok(Array.isArray(classArray), 'Response should be JSON array'); assert.ok(classArray.length > 0, 'Class array should not be empty'); }); test('should ignore additional parameters gracefully', async () => { const result = await client.callTool('list_sfcc_classes', { unexpectedParam: 'should be ignored', anotherParam: 123, objectParam: { nested: 'value' } }); assertValidMCPResponse(result); assert.equal(result.isError, false, 'Should handle extra params gracefully'); // Result should be identical to empty params call const baselineResult = await client.callTool('list_sfcc_classes', {}); assert.equal(result.content[0].text, baselineResult.content[0].text, 'Result should be identical regardless of extra params'); }); }); describe('Content Quality and Completeness', () => { test('should return comprehensive SFCC class coverage', async () => { const result = await client.callTool('list_sfcc_classes', {}); const classArray = JSON.parse(result.content[0].text); const analysis = contentAnalyzer.analyzeClassList(classArray); // Validate completeness const issues = contentAnalyzer.validateCompleteness(analysis); assert.equal(issues.length, 0, `Content issues found: ${issues.join('; ')}`); // Verify substantial class count assert.ok(analysis.totalClasses >= 400, `Should have substantial class count (got ${analysis.totalClasses})`); }); test('should include all expected SFCC namespaces', async () => { const result = await client.callTool('list_sfcc_classes', {}); const classArray = JSON.parse(result.content[0].text); const analysis = contentAnalyzer.analyzeClassList(classArray); contentAnalyzer.expectedNamespaces.forEach(namespace => { assert.ok(analysis.namespacesCovered.has(namespace), `Missing expected namespace: ${namespace}`); assert.ok(analysis.classsByNamespace[namespace].length > 0, `Namespace ${namespace} should have classes`); }); }); test('should include critical SFCC classes for development', async () => { const result = await client.callTool('list_sfcc_classes', {}); const classArray = JSON.parse(result.content[0].text); const analysis = contentAnalyzer.analyzeClassList(classArray); contentAnalyzer.criticalClasses.forEach(criticalClass => { assert.ok(classArray.includes(criticalClass), `Missing critical class: ${criticalClass}`); }); assert.ok(analysis.foundCriticalClasses.length >= contentAnalyzer.criticalClasses.length * 0.9, 'Should include at least 90% of critical classes'); }); test('should include best practice guides', async () => { const result = await client.callTool('list_sfcc_classes', {}); const classArray = JSON.parse(result.content[0].text); contentAnalyzer.bestPracticeGuides.forEach(guide => { assert.ok(classArray.includes(guide), `Missing best practice guide: ${guide}`); }); }); test('should have proper class naming format', async () => { const result = await client.callTool('list_sfcc_classes', {}); const classArray = JSON.parse(result.content[0].text); const analysis = contentAnalyzer.analyzeClassList(classArray); assert.equal(analysis.invalidFormats.length, 0, `Invalid class formats found: ${analysis.invalidFormats.join(', ')}`); assert.equal(analysis.duplicates.length, 0, `Duplicate classes found: ${analysis.duplicates.join(', ')}`); }); }); describe('Advanced Content Analysis', () => { test('should provide balanced namespace distribution', async () => { const result = await client.callTool('list_sfcc_classes', {}); const classArray = JSON.parse(result.content[0].text); const analysis = contentAnalyzer.analyzeClassList(classArray); // Core namespaces should have substantial class counts const coreNamespaces = ['dw.catalog', 'dw.order', 'dw.customer', 'dw.system']; coreNamespaces.forEach(namespace => { const classCount = analysis.classsByNamespace[namespace].length; assert.ok(classCount >= 5, `Core namespace ${namespace} should have at least 5 classes (got ${classCount})`); }); // TopLevel namespace should have good coverage for utility classes const topLevelCount = analysis.classsByNamespace['TopLevel'].length; assert.ok(topLevelCount >= 10, `TopLevel namespace should have substantial coverage (got ${topLevelCount})`); }); test('should include developer-friendly discovery content', async () => { const result = await client.callTool('list_sfcc_classes', {}); const classArray = JSON.parse(result.content[0].text); // Should include educational namespaces for new developers (SFCC classes only) const educationalClasses = [ 'TopLevel.Array', 'TopLevel.Object', 'dw.catalog.Product', 'dw.system.Site' ]; educationalClasses.forEach(educationalClass => { assert.ok(classArray.includes(educationalClass), `Missing educational class: ${educationalClass}`); }); }); test('should support API exploration workflows', async () => { const result = await client.callTool('list_sfcc_classes', {}); const classArray = JSON.parse(result.content[0].text); // Should include classes that developers commonly search for const commonSearchTargets = [ 'dw.catalog.ProductMgr', 'dw.order.BasketMgr', 'dw.customer.CustomerMgr', 'dw.system.SitePreferences', 'dw.web.URLUtils' ]; commonSearchTargets.forEach(searchTarget => { assert.ok(classArray.includes(searchTarget), `Missing common search target: ${searchTarget}`); }); }); test('should provide comprehensive extension coverage', async () => { const result = await client.callTool('list_sfcc_classes', {}); const classArray = JSON.parse(result.content[0].text); // Should include extension classes for integrations const extensionClasses = classArray.filter(cls => cls.startsWith('dw.extensions.')); assert.ok(extensionClasses.length >= 10, `Should include substantial extension classes (got ${extensionClasses.length})`); // Should cover major payment integrations const paymentClasses = classArray.filter(cls => cls.includes('payments') || cls.includes('PayPal') || cls.includes('ApplePay')); assert.ok(paymentClasses.length >= 5, `Should include payment integration classes (got ${paymentClasses.length})`); }); }); describe('Response Structure Validation', () => { test('should maintain consistent response structure', async () => { const result1 = await client.callTool('list_sfcc_classes', {}); const result2 = await client.callTool('list_sfcc_classes', {}); // Structure should be identical assert.equal(result1.content.length, result2.content.length); assert.equal(result1.content[0].type, result2.content[0].type); assert.equal(result1.content[0].text, result2.content[0].text); // Content should be deterministic const classes1 = JSON.parse(result1.content[0].text); const classes2 = JSON.parse(result2.content[0].text); assert.deepEqual(classes1, classes2, 'Class lists should be identical between calls'); }); test('should return properly formatted JSON with valid structure', async () => { const result = await client.callTool('list_sfcc_classes', {}); const responseText = result.content[0].text; // Should be properly formatted JSON assert.ok(responseText.startsWith('['), 'Should start with array bracket'); assert.ok(responseText.endsWith(']'), 'Should end with array bracket'); // Parse and validate structure const classArray = JSON.parse(responseText); assert.ok(Array.isArray(classArray), 'Should be array'); // Each item should be a string classArray.forEach((item, index) => { assert.equal(typeof item, 'string', `Item ${index} should be string`); assert.ok(item.length > 0, `Item ${index} should not be empty`); }); }); test('should provide useful content for AI agents', async () => { const result = await client.callTool('list_sfcc_classes', {}); const classArray = JSON.parse(result.content[0].text); // Should include SFCC classes that AI agents commonly need const aiUsefulClasses = [ 'dw.system.Logger', // For logging 'dw.util.StringUtils', // For text processing 'dw.web.URLUtils', // For URL generation 'dw.system.Site', // For site context 'dw.catalog.Product', // For product operations 'dw.order.Basket' // For basket operations ]; aiUsefulClasses.forEach(usefulClass => { assert.ok(classArray.includes(usefulClass), `Should include AI-useful class: ${usefulClass}`); }); }); }); describe('Educational and Discovery Value', () => { test('should serve as comprehensive SFCC reference', async () => { const result = await client.callTool('list_sfcc_classes', {}); const classArray = JSON.parse(result.content[0].text); const analysis = contentAnalyzer.analyzeClassList(classArray); // Should cover all major SFCC functional areas (SFCC classes only) const functionalAreas = { 'commerce': ['dw.catalog', 'dw.order'], 'customer': ['dw.customer'], 'system': ['dw.system'], 'web': ['dw.web'], 'utilities': ['dw.util'], 'integrations': ['dw.svc', 'dw.extensions'], 'foundations': ['TopLevel'] }; Object.entries(functionalAreas).forEach(([area, namespaces]) => { namespaces.forEach(namespace => { const classCount = analysis.classsByNamespace[namespace].length; assert.ok(classCount > 0, `Functional area '${area}' should have classes in namespace '${namespace}'`); }); }); }); test('should support progressive learning for developers', async () => { const result = await client.callTool('list_sfcc_classes', {}); const classArray = JSON.parse(result.content[0].text); // Should include beginner-friendly TopLevel classes const beginnerClasses = classArray.filter(cls => cls.startsWith('TopLevel.')); assert.ok(beginnerClasses.length >= 10, `Should include beginner-friendly TopLevel classes (got ${beginnerClasses.length})`); // Should include advanced integration classes const advancedClasses = classArray.filter(cls => cls.includes('Hook') || cls.includes('Extension') || cls.includes('Service')); assert.ok(advancedClasses.length >= 20, `Should include advanced integration classes (got ${advancedClasses.length})`); }); }); describe('Integration and Cross-Tool Validation', () => { test('should provide classes that work with search_sfcc_classes tool', async () => { const listResult = await client.callTool('list_sfcc_classes', {}); const classArray = JSON.parse(listResult.content[0].text); // Pick a few SFCC classes to test with search tool const testClasses = ['dw.catalog.Product', 'dw.system.Site', 'dw.customer.Customer']; for (const testClass of testClasses) { assert.ok(classArray.includes(testClass), `List should include searchable class: ${testClass}`); // Test that the class is discoverable via search const namespace = testClass.split('.')[1]; // Get 'catalog' from 'dw.catalog.Product' const searchResult = await client.callTool('search_sfcc_classes', { query: namespace }); assertValidMCPResponse(searchResult); if (!searchResult.isError) { const searchedClasses = JSON.parse(searchResult.content[0].text); assert.ok(Array.isArray(searchedClasses), `Search should return array for ${namespace}`); } } }); test('should include classes that have detailed documentation available', async () => { const listResult = await client.callTool('list_sfcc_classes', {}); const classArray = JSON.parse(listResult.content[0].text); // Test a few well-documented classes const documentedClasses = ['dw.catalog.Product', 'dw.system.Site', 'dw.order.Basket']; for (const docClass of documentedClasses) { assert.ok(classArray.includes(docClass), `List should include documented class: ${docClass}`); // Test that class info is available const infoResult = await client.callTool('get_sfcc_class_info', { className: docClass }); assertValidMCPResponse(infoResult); if (!infoResult.isError) { const infoText = infoResult.content[0].text; // Parse the JSON response to check for class information let classInfo; assert.doesNotThrow(() => { classInfo = JSON.parse(infoText); }, `Class info should be valid JSON for ${docClass}`); // Check that the response contains class information assert.ok(classInfo.className || classInfo.packageName, `Class info should contain class information for ${docClass}`); // For dw.catalog.Product, verify it contains "Product" and "dw.catalog" if (docClass === 'dw.catalog.Product') { assert.ok(classInfo.className === 'Product', 'Product class info should contain className "Product"'); assert.ok(classInfo.packageName === 'dw.catalog', 'Product class info should contain packageName "dw.catalog"'); } } } }); test('should maintain consistency with available tools ecosystem', async () => { const listResult = await client.callTool('list_sfcc_classes', {}); const classArray = JSON.parse(listResult.content[0].text); // Should include SFCC classes that support the SFCC toolchain const toolchainClasses = [ 'dw.catalog.Product', // For product tool integration 'dw.system.SitePreferences', // For site preference tools 'dw.order.Order', // For order management tools 'dw.util.ArrayList', // For collection operations 'dw.web.URLUtils' // For URL generation tools ]; toolchainClasses.forEach(toolClass => { assert.ok(classArray.includes(toolClass), `Should include toolchain-supporting class: ${toolClass}`); }); }); test('should enable effective AI-assisted development workflows', async () => { const listResult = await client.callTool('list_sfcc_classes', {}); const classArray = JSON.parse(listResult.content[0].text); // Should include SFCC classes that AI agents commonly recommend const aiWorkflowClasses = [ 'dw.system.Logger', // For debugging workflows 'dw.util.StringUtils', // For data manipulation 'dw.web.URLUtils', // For URL generation 'dw.catalog.ProductMgr', // For product operations 'dw.order.BasketMgr', // For cart operations 'dw.customer.CustomerMgr', // For customer operations 'dw.system.Site', // For site context 'dw.order.Order' // For order handling ]; aiWorkflowClasses.forEach(workflowClass => { assert.ok(classArray.includes(workflowClass), `Should include AI workflow class: ${workflowClass}`); }); // Should provide good coverage for common AI development tasks (SFCC classes only) const taskCoverage = { 'data_access': classArray.filter(cls => cls.includes('Mgr')).length, 'web_operations': classArray.filter(cls => cls.startsWith('dw.web.')).length, 'system_integration': classArray.filter(cls => cls.startsWith('dw.system.')).length, 'utilities': classArray.filter(cls => cls.startsWith('dw.util.')).length }; Object.entries(taskCoverage).forEach(([task, count]) => { assert.ok(count >= 3, `Should have good coverage for ${task} (got ${count} classes)`); }); }); }); }); /** * Helper function to validate basic MCP response structure */ function assertValidMCPResponse(result) { assert.ok(result.content, 'Response should have content'); assert.ok(Array.isArray(result.content), 'Content should be array'); assert.equal(typeof result.isError, 'boolean', 'isError should be boolean and always present'); } ``` -------------------------------------------------------------------------------- /docs/TopLevel/Math.md: -------------------------------------------------------------------------------- ```markdown ## Package: TopLevel # Class Math ## Inheritance Hierarchy - Object - Math ## Description Mathematical functions and constants. ## Constants ### E **Type:** Number The constant e, which is the base of natural logarithms. ### LN10 **Type:** Number The natural logarithm of 10. ### LN2 **Type:** Number The natural logarithm of 2. ### LOG10E **Type:** Number The base-10 logarithm of e. ### LOG2E **Type:** Number The base-2 logarithm of e. ### PI **Type:** Number The constant for PI. ### SQRT1_2 **Type:** Number 1 divided by the square root of 2. ### SQRT2 **Type:** Number The square root of 2. ## Properties ## Constructor Summary Math() ## Method Summary ### abs **Signature:** `static abs(x : Number) : Number` Returns the absolute value of x. ### acos **Signature:** `static acos(x : Number) : Number` Returns an approximation to the arc cosine of x. ### acosh **Signature:** `static acosh(x : Number) : Number` Returns an approximation to the inverse hyperbolic cosine of x. ### asin **Signature:** `static asin(x : Number) : Number` Returns an approximation to the arc sine of x. ### asinh **Signature:** `static asinh(x : Number) : Number` Returns an approximation to the inverse hyperbolic sine of x. ### atan **Signature:** `static atan(x : Number) : Number` Returns an approximation to the arc tangent of x. ### atan2 **Signature:** `static atan2(y : Number, x : Number) : Number` Returns an approximation to the arc tangent of the quotient y/x of the arguments y and x, where the signs of y and x are used to determine the quadrant of the result. ### atanh **Signature:** `static atanh(x : Number) : Number` Returns an approximation to the inverse hyperbolic tangent of x. ### cbrt **Signature:** `static cbrt(x : Number) : Number` Returns an approximation to the cube root of x. ### ceil **Signature:** `static ceil(x : Number) : Number` Returns the smallest (closest to -∞) number value that is not less than x and is equal to a mathematical integer. ### clz32 **Signature:** `static clz32(x : Number) : Number` Returns the number of leading zero bits in the 32-bit binary representation of x. ### cos **Signature:** `static cos(x : Number) : Number` Returns an approximation to the cosine of x. ### cosh **Signature:** `static cosh(x : Number) : Number` Returns an approximation to the hyperbolic cosine of x. ### exp **Signature:** `static exp(x : Number) : Number` Returns an approximation to the exponential function of x (e raised to the power of x, where e is the base of the natural logarithms). ### expm1 **Signature:** `static expm1(x : Number) : Number` Returns an approximation to subtracting 1 from the exponential function of x (e raised to the power of x, where e is the base of the natural logarithms). ### floor **Signature:** `static floor(x : Number) : Number` Returns the greatest (closest to +∞) number value that is not greater than x and is equal to a mathematical integer. ### fround **Signature:** `static fround(x : Number) : Number` Returns the nearest 32-bit single precision float representation of x. ### hypot **Signature:** `static hypot(values : Number...) : Number` Returns an approximation of the square root of the sum of squares of the arguments. ### imul **Signature:** `static imul(x : Number, y : Number) : Number` Performs a 32 bit integer multiplication, where the result is always a 32 bit integer value, ignoring any overflows. ### log **Signature:** `static log(x : Number) : Number` Returns an approximation to the natural logarithm of x. ### log10 **Signature:** `static log10(x : Number) : Number` Returns an approximation to the base 10 logarithm of x. ### log1p **Signature:** `static log1p(x : Number) : Number` Returns an approximation to the natural logarithm of of 1 + x. ### log2 **Signature:** `static log2(x : Number) : Number` Returns an approximation to the base 2 logarithm of x. ### max **Signature:** `static max(values : Number...) : Number` Returns the largest specified values. ### min **Signature:** `static min(values : Number...) : Number` Returns the smallest of the specified values. ### pow **Signature:** `static pow(x : Number, y : Number) : Number` Returns an approximation to the result of raising x to the power y. ### random **Signature:** `static random() : Number` Returns a number value with positive sign, greater than or equal to 0 but less than 1, chosen randomly or pseudo randomly with approximately uniform distribution over that range, using an implementation-dependent algorithm or strategy. ### round **Signature:** `static round(x : Number) : Number` Returns the number value that is closest to x and is equal to a mathematical integer. ### sign **Signature:** `static sign(x : Number) : Number` Returns the sign of x, indicating whether x is positive, negative, or zero. ### sin **Signature:** `static sin(x : Number) : Number` Returns an approximation to the sine of x. ### sinh **Signature:** `static sinh(x : Number) : Number` Returns an approximation to the hyperbolic sine of x. ### sqrt **Signature:** `static sqrt(x : Number) : Number` Returns an approximation to the square root of x. ### tan **Signature:** `static tan(x : Number) : Number` Returns an approximation to the tangent of x. ### tanh **Signature:** `static tanh(x : Number) : Number` Returns an approximation to the hyperbolic tangent of x. ### trunc **Signature:** `static trunc(x : Number) : Number` Returns the integral part of the number x, removing any fractional digits. ## Constructor Detail ## Method Detail ## Method Details ### abs **Signature:** `static abs(x : Number) : Number` **Description:** Returns the absolute value of x. The result has the same magnitude as x but has positive sign. If x is NaN, the result is NaN. If x is -0, the result is +0. If x is -∞, the result is +∞. **Parameters:** - `x`: the Number to operate on. **Returns:** the absolute value of x. --- ### acos **Signature:** `static acos(x : Number) : Number` **Description:** Returns an approximation to the arc cosine of x. The result is expressed in radians and ranges from +0 to +p. If x is NaN, the result is NaN. If x is greater than 1, the result is NaN. If x is less than -1, the result is NaN. If x is exactly 1, the result is +0. **Parameters:** - `x`: the Number to operate on. **Returns:** an approximation to the arc cosine of x. --- ### acosh **Signature:** `static acosh(x : Number) : Number` **Description:** Returns an approximation to the inverse hyperbolic cosine of x. If x is NaN, the result is NaN. If x is less than 1, the result is NaN. If x is exactly 1, the result is +0. If x is +∞, the result is +∞. **API Versioned:** From version 21.2. **Parameters:** - `x`: the Number to operate on. **Returns:** an approximation to the inverse hyperbolic cosine of x. --- ### asin **Signature:** `static asin(x : Number) : Number` **Description:** Returns an approximation to the arc sine of x. The result is expressed in radians and ranges from -p/2 to +p/2. If x is NaN, the result is NaN If x is greater than 1, the result is NaN. If x is less than -1, the result is NaN. If x is +0, the result is +0. If x is -0, the result is -0. **Parameters:** - `x`: the Number to operate on. **Returns:** an approximation to the arc sine of x. --- ### asinh **Signature:** `static asinh(x : Number) : Number` **Description:** Returns an approximation to the inverse hyperbolic sine of x. If x is NaN, the result is NaN If x is +0, the result is +0. If x is -0, the result is -0. If x is +∞, the result is +∞. If x is -∞, the result is -∞. **API Versioned:** From version 21.2. **Parameters:** - `x`: the Number to operate on. **Returns:** an approximation to the inverse hyperbolic sine of x. --- ### atan **Signature:** `static atan(x : Number) : Number` **Description:** Returns an approximation to the arc tangent of x. The result is expressed in radians and ranges from -p/2 to +p/2. If x is NaN, the result is NaN. If x is +0, the result is +0. If x is -0, the result is -0. If x is +∞, the result is an approximation to +p/2. If x is -∞, the result is an approximation to -p/2. **Parameters:** - `x`: the Number to operate on. **Returns:** an approximation to the arc tangent of x. --- ### atan2 **Signature:** `static atan2(y : Number, x : Number) : Number` **Description:** Returns an approximation to the arc tangent of the quotient y/x of the arguments y and x, where the signs of y and x are used to determine the quadrant of the result. Note that it is intentional and traditional for the two-argument arc tangent function that the argument named y be first and the argument named x be second. The result is expressed in radians and ranges from -p to +p. If either x or y is NaN, the result is NaN. If y>0 and x is +0, the result is an implementation-dependent approximation to +p/2. If y>0 and x is -0, the result is an implementation-dependent approximation to +p/2. If y is +0 and x>0, the result is +0. If y is +0 and x is +0, the result is +0. If y is +0 and x is -0, the result is an implementation-dependent approximation to +p. If y is +0 and X<0, the result is an implementation-dependent approximation to +p. If y is -0 and x>0, the result is -0. If y is -0 and x is +0, the result is -0. If y is -0 and x is -0, the result is an implementation-dependent approximation to -p. If y is -0 and X<0, the result is an implementation-dependent approximation to -p. If y<0 and x is +0, the result is an implementation-dependent approximation to -p/2. If y<0 and x is -0, the result is an implementation-dependent approximation to -p/2. If y>0 and y is finite and x is +∞, the result is +0. If y>0 and y is finite and x is -∞, the result if an implementation-dependent approximation to +p. If y<0 and y is finite and x is +∞, the result is -0. If y<0 and y is finite and x is -∞, the result is an implementation-dependent approximation to -p. If y is +∞ and x is finite, the result is an implementation-dependent approximation to +p/2. If y is -∞ and x is finite, the result is an implementation-dependent approximation to -p/2. If y is +∞ and x is +∞, the result is an implementation-dependent approximation to +p/4. If y is +∞ and x is -∞, the result is an implementation-dependent approximation to +3p/4. If y is -∞ and x is +∞, the result is an implementation-dependent approximation to -p/4. If y is -∞ and x is -∞, the result is an implementation-dependent approximation to -3p/4. **Parameters:** - `y`: the first argument. - `x`: the second argument. **Returns:** approximation to the arc tangent of the quotient y/x of the arguments y and x, where the signs of y and x are used to determine the quadrant of the result. --- ### atanh **Signature:** `static atanh(x : Number) : Number` **Description:** Returns an approximation to the inverse hyperbolic tangent of x. If x is NaN, the result is NaN. If x is less than -1, the result is NaN. If x is greater than 1, the result is NaN. If x is exactly -1, the result is -∞. If x is exactly +1, the result is +∞. If x is +0, the result is +0. If x is -0, the result is -0. **API Versioned:** From version 21.2. **Parameters:** - `x`: the Number to operate on. **Returns:** an approximation to the inverse hyperbolic tangent of x. --- ### cbrt **Signature:** `static cbrt(x : Number) : Number` **Description:** Returns an approximation to the cube root of x. If x is NaN, the result is NaN If x is +0, the result is +0. If x is -0, the result is -0. If x is +∞, the result is +∞. If x is -∞, the result is -∞. **API Versioned:** From version 21.2. **Parameters:** - `x`: the Number to operate on. **Returns:** an approximation to the cube root of x. --- ### ceil **Signature:** `static ceil(x : Number) : Number` **Description:** Returns the smallest (closest to -∞) number value that is not less than x and is equal to a mathematical integer. If x is already an integer, the result is x. If x is NaN, the result is NaN. If x is +0, the result is +0. If x is -0, the result is -0. If x is +∞, the result is +∞. If x is -∞, the result is -∞. If x is less than 0 but greater than -1, the result is -0. The value of Math.ceil(x) is the same as the value of -Math.floor(-x). **Parameters:** - `x`: the Number to operate on. **Returns:** the smallest (closest to -∞) number value that is not less than x and is equal to a mathematical integer. --- ### clz32 **Signature:** `static clz32(x : Number) : Number` **Description:** Returns the number of leading zero bits in the 32-bit binary representation of x. **API Versioned:** From version 21.2. **Parameters:** - `x`: the Number to operate on. **Returns:** the number of leading zero bits in the 32-bit binary representation of x. --- ### cos **Signature:** `static cos(x : Number) : Number` **Description:** Returns an approximation to the cosine of x. The argument is expressed in radians. If x is NaN, the result is NaN. If x is +0, the result is 1. If x is -0, the result is 1. If x is +∞, the result is NaN. If x is -∞, the result is NaN. **Parameters:** - `x`: the Number to operate on. **Returns:** an approximation to the cosine of x. --- ### cosh **Signature:** `static cosh(x : Number) : Number` **Description:** Returns an approximation to the hyperbolic cosine of x. If x is NaN, the result is NaN. If x is +0, the result is 1. If x is -0, the result is 1. If x is +∞, the result is +∞. If x is -∞, the result is +∞. **API Versioned:** From version 21.2. **Parameters:** - `x`: the Number to operate on. **Returns:** an approximation to the hyperbolic cosine of x. --- ### exp **Signature:** `static exp(x : Number) : Number` **Description:** Returns an approximation to the exponential function of x (e raised to the power of x, where e is the base of the natural logarithms). If x is NaN, the result is NaN. If x is +0, the result is 1. If x is -0, the result is 1. If x is +∞, the result is +∞. If x is -∞, the result is +0. **Parameters:** - `x`: the Number to operate on. **Returns:** an approximation to the exponential function of x. --- ### expm1 **Signature:** `static expm1(x : Number) : Number` **Description:** Returns an approximation to subtracting 1 from the exponential function of x (e raised to the power of x, where e is the base of the natural logarithms). The result is computed in a way that is accurate even when the value of x is close 0. If x is NaN, the result is NaN. If x is +0, the result is +0. If x is -0, the result is -0. If x is +∞, the result is +∞. If x is -∞, the result is -1. **API Versioned:** From version 21.2. **Parameters:** - `x`: the Number to operate on. **Returns:** an approximation to subtracting 1 from the exponential function of x. --- ### floor **Signature:** `static floor(x : Number) : Number` **Description:** Returns the greatest (closest to +∞) number value that is not greater than x and is equal to a mathematical integer. If x is already an integer, the result is x. If x is NaN, the result is NaN. If x is +0, the result is +0. If x is -0, the result is -0. If x is +∞, the result is +∞. If x is -∞, the result is -∞. If x is greater than 0 but less than 1, the result is +0. The value of Math.floor(x) is the same as the value of -Math.ceil(-x). **Parameters:** - `x`: the Number to operate on. **Returns:** the greatest (closest to +∞) number value that is not greater than x and is equal to a mathematical integer. --- ### fround **Signature:** `static fround(x : Number) : Number` **Description:** Returns the nearest 32-bit single precision float representation of x. **API Versioned:** From version 21.2. **Parameters:** - `x`: the Number to operate on. **Returns:** the nearest 32-bit single precision float representation of x. --- ### hypot **Signature:** `static hypot(values : Number...) : Number` **Description:** Returns an approximation of the square root of the sum of squares of the arguments. If no arguments are passed, the result is +0. If any argument is +∞, the result is +∞. If any argument is -∞, the result is +∞. If no argument is +∞ or -∞ and any argument is NaN, the result is NaN. If all arguments are either +0 or -0, the result is +0. **API Versioned:** From version 21.2. **Parameters:** - `values`: the Number values to operate on. **Returns:** an approximation of the square root of the sum of squares of the arguments. --- ### imul **Signature:** `static imul(x : Number, y : Number) : Number` **Description:** Performs a 32 bit integer multiplication, where the result is always a 32 bit integer value, ignoring any overflows. **API Versioned:** From version 21.2. **Parameters:** - `x`: The first operand. - `y`: The second operand. **Returns:** Returns the result of the 32 bit multiplication. The result is a 32 bit signed integer value. --- ### log **Signature:** `static log(x : Number) : Number` **Description:** Returns an approximation to the natural logarithm of x. If x is NaN, the result is NaN. If x is less than 0, the result is NaN. If x is +0 or -0, the result is -∞. If x is 1, the result is +0. If x is +∞, the result is +∞. **Parameters:** - `x`: the Number to operate on. **Returns:** an approximation to the natural logarithm of x. --- ### log10 **Signature:** `static log10(x : Number) : Number` **Description:** Returns an approximation to the base 10 logarithm of x. If x is NaN, the result is NaN. If x is less than 0, the result is NaN. If x is +0 or -0, the result is -∞. If x is 1, the result is +0. If x is +∞, the result is +∞. **API Versioned:** From version 21.2. **Parameters:** - `x`: the Number to operate on. **Returns:** an approximation to the base 10 logarithm of x. --- ### log1p **Signature:** `static log1p(x : Number) : Number` **Description:** Returns an approximation to the natural logarithm of of 1 + x. If x is NaN, the result is NaN. If x is less than -1, the result is NaN. If x is -1, the result is -∞. If x is +0, the result is +0. If x is -0, the result is -0. If x is +∞, the result is +∞. **API Versioned:** From version 21.2. **Parameters:** - `x`: the Number to operate on. **Returns:** an approximation to the natural logarithm of of 1 + x. --- ### log2 **Signature:** `static log2(x : Number) : Number` **Description:** Returns an approximation to the base 2 logarithm of x. If x is NaN, the result is NaN. If x is less than 0, the result is NaN. If x is +0 or -0, the result is -∞. If x is 1, the result is +0. If x is +∞, the result is +∞. **API Versioned:** From version 21.2. **Parameters:** - `x`: the Number to operate on. **Returns:** an approximation to the base 2 logarithm of x. --- ### max **Signature:** `static max(values : Number...) : Number` **Description:** Returns the largest specified values. If no arguments are given, the result is -∞. If any value is NaN, the result is NaN. **Parameters:** - `values`: zero or more values. **Returns:** the largest of the specified values. --- ### min **Signature:** `static min(values : Number...) : Number` **Description:** Returns the smallest of the specified values. If no arguments are given, the result is +∞. If any value is NaN, the result is NaN. **Parameters:** - `values`: zero or more values. **Returns:** the smallest of the specified values. --- ### pow **Signature:** `static pow(x : Number, y : Number) : Number` **Description:** Returns an approximation to the result of raising x to the power y. If y is NaN, the result is NaN. If y is +0, the result is 1, even if x is NaN. If y is -0, the result is 1, even if x is NaN. If x is NaN and y is nonzero, the result is NaN. If abs(x)>1 and y is +∞, the result is +∞. If abs(x)>1 and y is -∞, the result is +0. If abs(x)==1 and y is +∞, the result is NaN. If abs(x)==1 and y is -∞, the result is NaN. If abs(x)<1 and y is +∞, the result is +0. If abs(x)<1 and y is -∞, the result is +∞. If x is +∞ and y>0, the result is +∞. If x is +∞ and y<0, the result is +0. If x is -∞ and y>0 and y is an odd integer, the result is -∞. If x is -∞ and y>0 and y is not an odd integer, the result is +∞. If x is -∞ and y<0 and y is an odd integer, the result is -0. If x is -∞ and y<0 and y is not an odd integer, the result is +0. If x is +0 and y>0, the result is +0. If x is +0 and y<0, the result is +∞. If x is -0 and y>0 and y is an odd integer, the result is -0. If x is -0 and y>0 and y is not an odd integer, the result is +0. If x is -0 and y<0 and y is an odd integer, the result is -∞. If x is -0 and y<0 and y is not an odd integer, the result is +∞. If X<0 and x is finite and y is finite and y is not an integer, the result is NaN. **Parameters:** - `x`: a Number that will be raised to the power of y. - `y`: the power by which x will be raised. **Returns:** an approximation to the result of raising x to the power y. --- ### random **Signature:** `static random() : Number` **Description:** Returns a number value with positive sign, greater than or equal to 0 but less than 1, chosen randomly or pseudo randomly with approximately uniform distribution over that range, using an implementation-dependent algorithm or strategy. **Returns:** a Number greater than or equal to 0 but less than 1. --- ### round **Signature:** `static round(x : Number) : Number` **Description:** Returns the number value that is closest to x and is equal to a mathematical integer. If two integer number values are equally close to x, then the result is the number value that is closer to +∞. If x is already an integer, the result is x. If x is NaN, the result is NaN. If x is +0, the result is +0. If x is -0, the result is -0. If x is +∞, the result is +∞. If x is -∞, the result is -∞. If x is greater than 0 but less than 0.5, the result is +0. If x is less than 0 but greater than or equal to -0.5, the result is -0. Math.round(3.5) returns 4, but Math.round(-3.5) returns -3. The value of Math.round(x) is the same as the value of Math.floor(x+0.5), except when x is -0 or is less than 0 but greater than or equal to -0.5; for these cases Math.round(x) returns -0, but Math.floor(x+0.5) returns +0. **Parameters:** - `x`: the Number to operate on. **Returns:** the number value that is closest to x and is equal to a mathematical integer. --- ### sign **Signature:** `static sign(x : Number) : Number` **Description:** Returns the sign of x, indicating whether x is positive, negative, or zero. If x is NaN, the result is NaN. If x is -0, the result is -0. If x is +0, the result is +0. If x is negative and not -0, the result is -1. If x is positive and not +0, the result is +1. **API Versioned:** From version 21.2. **Parameters:** - `x`: the Number to operate on. **Returns:** the sign of x. --- ### sin **Signature:** `static sin(x : Number) : Number` **Description:** Returns an approximation to the sine of x. The argument is expressed in radians. If x is NaN, the result is NaN. If x is +0, the result is +0. If x is -0, the result is -0. If x is +∞ or -∞, the result is NaN. **Parameters:** - `x`: the Number to operate on. **Returns:** an approximation to the sine of x. --- ### sinh **Signature:** `static sinh(x : Number) : Number` **Description:** Returns an approximation to the hyperbolic sine of x. If x is NaN, the result is NaN. If x is +0, the result is +0. If x is -0, the result is -0. If x is +∞, the result is +∞. If x is -∞, the result is +∞. **API Versioned:** From version 21.2. **Parameters:** - `x`: the Number to operate on. **Returns:** an approximation to the hyperbolic sine of x. --- ### sqrt **Signature:** `static sqrt(x : Number) : Number` **Description:** Returns an approximation to the square root of x. If x is NaN, the result is NaN. If x isless than 0, the result is NaN. If x is +0, the result is +0. If x is -0, the result is -0. If x is +∞, the result is +∞. **Parameters:** - `x`: the Number to operate on. **Returns:** an approximation to the square root of x. --- ### tan **Signature:** `static tan(x : Number) : Number` **Description:** Returns an approximation to the tangent of x. The argument is expressed in radians. If x is NaN, the result is NaN. If x is +0, the result is +0. If x is -0, the result is -0. If x is +∞ or -∞, the result is NaN. **Parameters:** - `x`: the Number to operate on. **Returns:** an approximation to the tangent of x. --- ### tanh **Signature:** `static tanh(x : Number) : Number` **Description:** Returns an approximation to the hyperbolic tangent of x. If x is NaN, the result is NaN. If x is +0, the result is +0. If x is -0, the result is -0. If x is +∞, the result is +1. If x is -∞, the result is -1. **API Versioned:** From version 21.2. **Parameters:** - `x`: the Number to operate on. **Returns:** an approximation to the hyperbolic tangent of x. --- ### trunc **Signature:** `static trunc(x : Number) : Number` **Description:** Returns the integral part of the number x, removing any fractional digits. If x is already an integer, the result is x. If x is NaN, the result is NaN. If x is -0, the result is -0. If x is +0, the result is +0. If x is -∞, the result is -∞. If x is +∞, the result is +∞. If x is greater than 0 but less than 1, the result is +0. If x is less than 0 but greater than -1, the result is -0. **API Versioned:** From version 21.2. **Parameters:** - `x`: the Number to operate on. **Returns:** the integral part of the number of x. --- ``` -------------------------------------------------------------------------------- /tests/mcp/yaml/get-available-best-practice-guides.full-mode.test.mcp.yml: -------------------------------------------------------------------------------- ```yaml # ================================================================================== # SFCC MCP Server - get_available_best_practice_guides Tool YAML Tests # Comprehensive testing for SFCC best practice guides discovery functionality # Tests structure validation, content verification, and performance requirements # # Quick Test Commands: # aegis "tests/mcp/yaml/get-available-best-practice-guides.full-mode.test.mcp.yml" --config "aegis.config.with-dw.json" --verbose # aegis "tests/mcp/yaml/get-available-best-practice-guides.full-mode.test.mcp.yml" --config "aegis.config.with-dw.json" --debug --timing # aegis query get_available_best_practice_guides '{}' --config "aegis.config.with-dw.json" # ================================================================================== description: "SFCC MCP Server get_available_best_practice_guides tool - comprehensive validation" # ================================================================================== # BASIC TOOL STRUCTURE VALIDATION # ================================================================================== tests: - it: "should list get_available_best_practice_guides tool in available tools" request: jsonrpc: "2.0" id: "tool-list-1" method: "tools/list" params: {} expect: response: jsonrpc: "2.0" id: "tool-list-1" result: tools: match:arrayContains:name:get_available_best_practice_guides stderr: "toBeEmpty" - it: "should define tool with correct structure and schema" request: jsonrpc: "2.0" id: "tool-schema-1" method: "tools/list" params: {} expect: response: jsonrpc: "2.0" id: "tool-schema-1" result: match:extractField: "tools.*.name" value: "match:arrayContains:get_available_best_practice_guides" stderr: "toBeEmpty" # ================================================================================== # SUCCESSFUL GUIDE LISTING TESTS # ================================================================================== - it: "should return available best practice guides with proper structure" request: jsonrpc: "2.0" id: "guides-list-1" method: "tools/call" params: name: "get_available_best_practice_guides" arguments: {} expect: response: jsonrpc: "2.0" id: "guides-list-1" result: content: - type: "text" text: "match:regex:\\[[\\s\\S]*\\]" isError: false performance: maxResponseTime: "300ms" stderr: "toBeEmpty" - it: "should return valid JSON array of guides in text content" request: jsonrpc: "2.0" id: "guides-json-1" method: "tools/call" params: name: "get_available_best_practice_guides" arguments: {} expect: response: jsonrpc: "2.0" id: "guides-json-1" result: content: - type: "text" text: "match:contains:cartridge_creation" isError: false stderr: "toBeEmpty" # ================================================================================== # GUIDE CONTENT STRUCTURE VALIDATION # ================================================================================== - it: "should include required core best practice guides" request: jsonrpc: "2.0" id: "core-guides-1" method: "tools/call" params: name: "get_available_best_practice_guides" arguments: {} expect: response: jsonrpc: "2.0" id: "core-guides-1" result: content: - type: "text" text: "match:contains:cartridge_creation" isError: false stderr: "toBeEmpty" - it: "should include SFRA-related best practice guides" request: jsonrpc: "2.0" id: "sfra-guides-1" method: "tools/call" params: name: "get_available_best_practice_guides" arguments: {} expect: response: jsonrpc: "2.0" id: "sfra-guides-1" result: content: - type: "text" text: "match:contains:sfra_controllers" isError: false stderr: "toBeEmpty" - it: "should include API hooks best practice guides" request: jsonrpc: "2.0" id: "hooks-guides-1" method: "tools/call" params: name: "get_available_best_practice_guides" arguments: {} expect: response: jsonrpc: "2.0" id: "hooks-guides-1" result: content: - type: "text" text: "match:contains:ocapi_hooks" isError: false stderr: "toBeEmpty" - it: "should include security and performance guides" request: jsonrpc: "2.0" id: "security-perf-guides-1" method: "tools/call" params: name: "get_available_best_practice_guides" arguments: {} expect: response: jsonrpc: "2.0" id: "security-perf-guides-1" result: content: - type: "text" text: "match:contains:security" isError: false stderr: "toBeEmpty" - it: "should include job framework guidance" request: jsonrpc: "2.0" id: "job-guides-1" method: "tools/call" params: name: "get_available_best_practice_guides" arguments: {} expect: response: jsonrpc: "2.0" id: "job-guides-1" result: content: - type: "text" text: "match:contains:job_framework" isError: false stderr: "toBeEmpty" # ================================================================================== # GUIDE METADATA VALIDATION # ================================================================================== - it: "should include guide names for programmatic access" request: jsonrpc: "2.0" id: "guide-names-1" method: "tools/call" params: name: "get_available_best_practice_guides" arguments: {} expect: response: jsonrpc: "2.0" id: "guide-names-1" result: content: - type: "text" text: "match:regex:\"name\":\\s*\"[a-z_]+\"" isError: false stderr: "toBeEmpty" - it: "should include human-readable guide titles" request: jsonrpc: "2.0" id: "guide-titles-1" method: "tools/call" params: name: "get_available_best_practice_guides" arguments: {} expect: response: jsonrpc: "2.0" id: "guide-titles-1" result: content: - type: "text" text: "match:regex:\"title\":\\s*\"[^\"]+Best Practices[^\"]*\"" isError: false stderr: "toBeEmpty" - it: "should include helpful guide descriptions" request: jsonrpc: "2.0" id: "guide-descriptions-1" method: "tools/call" params: name: "get_available_best_practice_guides" arguments: {} expect: response: jsonrpc: "2.0" id: "guide-descriptions-1" result: content: - type: "text" text: "match:regex:\"description\":\\s*\"[\\s\\S]{20,}\"" isError: false stderr: "toBeEmpty" # ================================================================================== # COMPREHENSIVE GUIDE COVERAGE VALIDATION # ================================================================================== - it: "should include all expected core development guides" request: jsonrpc: "2.0" id: "all-core-guides-1" method: "tools/call" params: name: "get_available_best_practice_guides" arguments: {} expect: response: jsonrpc: "2.0" id: "all-core-guides-1" result: content: - type: "text" text: "match:contains:cartridge_creation" isError: false stderr: "toBeEmpty" - it: "should include template development guides" request: jsonrpc: "2.0" id: "template-guides-1" method: "tools/call" params: name: "get_available_best_practice_guides" arguments: {} expect: response: jsonrpc: "2.0" id: "template-guides-1" result: content: - type: "text" text: "match:contains:isml_templates" isError: false stderr: "toBeEmpty" - it: "should include service integration guides" request: jsonrpc: "2.0" id: "service-guides-1" method: "tools/call" params: name: "get_available_best_practice_guides" arguments: {} expect: response: jsonrpc: "2.0" id: "service-guides-1" result: content: - type: "text" text: "match:contains:localserviceregistry" isError: false stderr: "toBeEmpty" - it: "should include SCAPI development guides" request: jsonrpc: "2.0" id: "scapi-guides-1" method: "tools/call" params: name: "get_available_best_practice_guides" arguments: {} expect: response: jsonrpc: "2.0" id: "scapi-guides-1" result: content: - type: "text" text: "match:contains:scapi_hooks" isError: false stderr: "toBeEmpty" # ================================================================================== # PARAMETER HANDLING TESTS # ================================================================================== - it: "should handle empty parameters gracefully" request: jsonrpc: "2.0" id: "empty-params-1" method: "tools/call" params: name: "get_available_best_practice_guides" arguments: {} expect: response: jsonrpc: "2.0" id: "empty-params-1" result: content: - type: "text" text: "match:regex:\\[\\s*\\{[\\s\\S]*\\}\\s*\\]" isError: false stderr: "toBeEmpty" - it: "should ignore invalid extra parameters" request: jsonrpc: "2.0" id: "invalid-params-1" method: "tools/call" params: name: "get_available_best_practice_guides" arguments: invalid_param: "should_be_ignored" another_invalid: 123 expect: response: jsonrpc: "2.0" id: "invalid-params-1" result: content: - type: "text" text: "match:contains:cartridge_creation" isError: false stderr: "toBeEmpty" # ================================================================================== # RESPONSE FORMAT CONSISTENCY TESTS # ================================================================================== - it: "should maintain consistent JSON structure across calls" request: jsonrpc: "2.0" id: "consistency-1" method: "tools/call" params: name: "get_available_best_practice_guides" arguments: {} expect: response: jsonrpc: "2.0" id: "consistency-1" result: content: - type: "text" text: "match:regex:\\[\\s*\\{\\s*\"name\":\\s*\"[^\"]+\",\\s*\"title\":\\s*\"[^\"]+\",\\s*\"description\":\\s*\"[^\"]+\"\\s*\\}" isError: false stderr: "toBeEmpty" - it: "should return well-formatted JSON without syntax errors" request: jsonrpc: "2.0" id: "json-format-1" method: "tools/call" params: name: "get_available_best_practice_guides" arguments: {} expect: response: jsonrpc: "2.0" id: "json-format-1" result: content: - type: "text" text: "match:regex:^\\[[\\s\\S]*\\]$" isError: false stderr: "toBeEmpty" # ================================================================================== # PERFORMANCE AND RELIABILITY TESTS # ================================================================================== - it: "should respond quickly for metadata operation" request: jsonrpc: "2.0" id: "performance-1" method: "tools/call" params: name: "get_available_best_practice_guides" arguments: {} expect: response: jsonrpc: "2.0" id: "performance-1" result: content: - type: "text" text: "match:type:string" isError: false performance: maxResponseTime: "300ms" stderr: "toBeEmpty" - it: "should be reliable across multiple consecutive calls" request: jsonrpc: "2.0" id: "reliability-1" method: "tools/call" params: name: "get_available_best_practice_guides" arguments: {} expect: response: jsonrpc: "2.0" id: "reliability-1" result: content: - type: "text" text: "match:contains:best practices" isError: false stderr: "toBeEmpty" - it: "should return identical results for repeated calls" request: jsonrpc: "2.0" id: "repeatability-1" method: "tools/call" params: name: "get_available_best_practice_guides" arguments: {} expect: response: jsonrpc: "2.0" id: "repeatability-1" result: content: - type: "text" text: "match:contains:cartridge_creation" isError: false stderr: "toBeEmpty" # ================================================================================== # COMPREHENSIVE GUIDE ENUMERATION # ================================================================================== - it: "should include expected total number of guides (13 guides minimum)" request: jsonrpc: "2.0" id: "guide-count-1" method: "tools/call" params: name: "get_available_best_practice_guides" arguments: {} expect: response: jsonrpc: "2.0" id: "guide-count-1" result: content: - type: "text" text: "match:regex:\"name\":[\\s\\S]*\"name\":[\\s\\S]*\"name\":[\\s\\S]*\"name\":[\\s\\S]*\"name\":[\\s\\S]*\"name\":[\\s\\S]*\"name\":[\\s\\S]*\"name\":[\\s\\S]*\"name\":[\\s\\S]*\"name\":[\\s\\S]*\"name\":[\\s\\S]*\"name\":[\\s\\S]*\"name\"" isError: false stderr: "toBeEmpty" - it: "should include performance optimization guidance" request: jsonrpc: "2.0" id: "performance-guide-1" method: "tools/call" params: name: "get_available_best_practice_guides" arguments: {} expect: response: jsonrpc: "2.0" id: "performance-guide-1" result: content: - type: "text" text: "match:contains:performance" isError: false stderr: "toBeEmpty" # ================================================================================== # COMPREHENSIVE GUIDE EXISTENCE VALIDATION # Ensures all currently available guides remain in existence # ================================================================================== - it: "should include cartridge_creation guide" request: jsonrpc: "2.0" id: "guide-exists-cartridge-1" method: "tools/call" params: name: "get_available_best_practice_guides" arguments: {} expect: response: jsonrpc: "2.0" id: "guide-exists-cartridge-1" result: content: - type: "text" text: "match:contains:cartridge_creation" isError: false stderr: "toBeEmpty" - it: "should include isml_templates guide" request: jsonrpc: "2.0" id: "guide-exists-isml-1" method: "tools/call" params: name: "get_available_best_practice_guides" arguments: {} expect: response: jsonrpc: "2.0" id: "guide-exists-isml-1" result: content: - type: "text" text: "match:contains:isml_templates" isError: false stderr: "toBeEmpty" - it: "should include job_framework guide" request: jsonrpc: "2.0" id: "guide-exists-job-1" method: "tools/call" params: name: "get_available_best_practice_guides" arguments: {} expect: response: jsonrpc: "2.0" id: "guide-exists-job-1" result: content: - type: "text" text: "match:contains:job_framework" isError: false stderr: "toBeEmpty" - it: "should include localserviceregistry guide" request: jsonrpc: "2.0" id: "guide-exists-lsr-1" method: "tools/call" params: name: "get_available_best_practice_guides" arguments: {} expect: response: jsonrpc: "2.0" id: "guide-exists-lsr-1" result: content: - type: "text" text: "match:contains:localserviceregistry" isError: false stderr: "toBeEmpty" - it: "should include ocapi_hooks guide" request: jsonrpc: "2.0" id: "guide-exists-ocapi-1" method: "tools/call" params: name: "get_available_best_practice_guides" arguments: {} expect: response: jsonrpc: "2.0" id: "guide-exists-ocapi-1" result: content: - type: "text" text: "match:contains:ocapi_hooks" isError: false stderr: "toBeEmpty" - it: "should include scapi_hooks guide" request: jsonrpc: "2.0" id: "guide-exists-scapi-hooks-1" method: "tools/call" params: name: "get_available_best_practice_guides" arguments: {} expect: response: jsonrpc: "2.0" id: "guide-exists-scapi-hooks-1" result: content: - type: "text" text: "match:contains:scapi_hooks" isError: false stderr: "toBeEmpty" - it: "should include scapi_custom_endpoint guide" request: jsonrpc: "2.0" id: "guide-exists-scapi-endpoint-1" method: "tools/call" params: name: "get_available_best_practice_guides" arguments: {} expect: response: jsonrpc: "2.0" id: "guide-exists-scapi-endpoint-1" result: content: - type: "text" text: "match:contains:scapi_custom_endpoint" isError: false stderr: "toBeEmpty" - it: "should include sfra_controllers guide" request: jsonrpc: "2.0" id: "guide-exists-sfra-controllers-1" method: "tools/call" params: name: "get_available_best_practice_guides" arguments: {} expect: response: jsonrpc: "2.0" id: "guide-exists-sfra-controllers-1" result: content: - type: "text" text: "match:contains:sfra_controllers" isError: false stderr: "toBeEmpty" - it: "should include sfra_models guide" request: jsonrpc: "2.0" id: "guide-exists-sfra-models-1" method: "tools/call" params: name: "get_available_best_practice_guides" arguments: {} expect: response: jsonrpc: "2.0" id: "guide-exists-sfra-models-1" result: content: - type: "text" text: "match:contains:sfra_models" isError: false stderr: "toBeEmpty" - it: "should include sfra_client_side_js guide" request: jsonrpc: "2.0" id: "guide-exists-sfra-client-js-1" method: "tools/call" params: name: "get_available_best_practice_guides" arguments: {} expect: response: jsonrpc: "2.0" id: "guide-exists-sfra-client-js-1" result: content: - type: "text" text: "match:contains:sfra_client_side_js" isError: false stderr: "toBeEmpty" - it: "should include sfra_scss guide" request: jsonrpc: "2.0" id: "guide-exists-sfra-scss-1" method: "tools/call" params: name: "get_available_best_practice_guides" arguments: {} expect: response: jsonrpc: "2.0" id: "guide-exists-sfra-scss-1" result: content: - type: "text" text: "match:contains:sfra_scss" isError: false stderr: "toBeEmpty" - it: "should include performance guide" request: jsonrpc: "2.0" id: "guide-exists-performance-1" method: "tools/call" params: name: "get_available_best_practice_guides" arguments: {} expect: response: jsonrpc: "2.0" id: "guide-exists-performance-1" result: content: - type: "text" text: "match:contains:performance" isError: false stderr: "toBeEmpty" - it: "should include security guide" request: jsonrpc: "2.0" id: "guide-exists-security-1" method: "tools/call" params: name: "get_available_best_practice_guides" arguments: {} expect: response: jsonrpc: "2.0" id: "guide-exists-security-1" result: content: - type: "text" text: "match:contains:security" isError: false stderr: "toBeEmpty" - it: "should include exactly 13 current guides (comprehensive existence check)" request: jsonrpc: "2.0" id: "all-guides-exist-1" method: "tools/call" params: name: "get_available_best_practice_guides" arguments: {} expect: response: jsonrpc: "2.0" id: "all-guides-exist-1" result: content: - type: "text" text: "match:regex:cartridge_creation[\\s\\S]*isml_templates[\\s\\S]*job_framework[\\s\\S]*localserviceregistry[\\s\\S]*ocapi_hooks[\\s\\S]*scapi_hooks[\\s\\S]*scapi_custom_endpoint[\\s\\S]*sfra_controllers[\\s\\S]*sfra_models[\\s\\S]*sfra_client_side_js[\\s\\S]*sfra_scss[\\s\\S]*performance[\\s\\S]*security" isError: false stderr: "toBeEmpty" # ================================================================================== # ERROR RESILIENCE TESTS # ================================================================================== - it: "should handle tool calls without arguments gracefully" request: jsonrpc: "2.0" id: "no-args-1" method: "tools/call" params: name: "get_available_best_practice_guides" expect: response: jsonrpc: "2.0" id: "no-args-1" result: content: - type: "text" text: "match:contains:cartridge_creation" isError: false stderr: "toBeEmpty" # ================================================================================== # GUIDE ACCESSIBILITY VALIDATION # ================================================================================== - it: "should provide accessible guide names for automation" request: jsonrpc: "2.0" id: "automation-names-1" method: "tools/call" params: name: "get_available_best_practice_guides" arguments: {} expect: response: jsonrpc: "2.0" id: "automation-names-1" result: content: - type: "text" text: "match:regex:\"name\":\\s*\"[a-z][a-z0-9_]*\"" isError: false stderr: "toBeEmpty" - it: "should provide descriptive titles for human readers" request: jsonrpc: "2.0" id: "human-titles-1" method: "tools/call" params: name: "get_available_best_practice_guides" arguments: {} expect: response: jsonrpc: "2.0" id: "human-titles-1" result: content: - type: "text" text: "match:regex:\"title\":\\s*\"[A-Z][\\s\\S]{10,}\"" isError: false stderr: "toBeEmpty" # ================================================================================== # INTEGRATION READINESS TESTS # ================================================================================== - it: "should provide data suitable for downstream tool integration" request: jsonrpc: "2.0" id: "integration-ready-1" method: "tools/call" params: name: "get_available_best_practice_guides" arguments: {} expect: response: jsonrpc: "2.0" id: "integration-ready-1" result: content: - type: "text" text: "match:regex:\\{\\s*\"name\":\\s*\"[^\"]+\",\\s*\"title\":[\\s\\S]*,\\s*\"description\":[\\s\\S]*\\}" isError: false stderr: "toBeEmpty" - it: "should maintain consistent field naming across all guides" request: jsonrpc: "2.0" id: "field-consistency-1" method: "tools/call" params: name: "get_available_best_practice_guides" arguments: {} expect: response: jsonrpc: "2.0" id: "field-consistency-1" result: content: - type: "text" text: "match:not:regex:\"Name\"|\"Title\"|\"Description\"" isError: false stderr: "toBeEmpty" ```