This is page 9 of 43. Use http://codebase.md/taurgis/sfcc-dev-mcp?lines=false&page={x} to view the full context. # Directory Structure ``` ├── .DS_Store ├── .github │ ├── dependabot.yml │ ├── instructions │ │ ├── mcp-node-tests.instructions.md │ │ └── mcp-yml-tests.instructions.md │ ├── ISSUE_TEMPLATE │ │ ├── bug_report.yml │ │ ├── config.yml │ │ ├── documentation.yml │ │ ├── feature_request.yml │ │ └── question.yml │ ├── PULL_REQUEST_TEMPLATE │ │ ├── bug_fix.md │ │ ├── documentation.md │ │ └── new_tool.md │ ├── pull_request_template.md │ └── workflows │ ├── ci.yml │ ├── deploy-pages.yml │ ├── publish.yml │ └── update-docs.yml ├── .gitignore ├── .husky │ └── pre-commit ├── aegis.config.docs-only.json ├── aegis.config.json ├── aegis.config.with-dw.json ├── AGENTS.md ├── ai-instructions │ ├── claude-desktop │ │ └── claude_custom_instructions.md │ ├── cursor │ │ └── .cursor │ │ └── rules │ │ ├── debugging-workflows.mdc │ │ ├── hooks-development.mdc │ │ ├── isml-templates.mdc │ │ ├── job-framework.mdc │ │ ├── performance-optimization.mdc │ │ ├── scapi-endpoints.mdc │ │ ├── security-patterns.mdc │ │ ├── sfcc-development.mdc │ │ ├── sfra-controllers.mdc │ │ ├── sfra-models.mdc │ │ ├── system-objects.mdc │ │ └── testing-patterns.mdc │ └── github-copilot │ └── copilot-instructions.md ├── CHANGELOG.md ├── CONTRIBUTING.md ├── docs │ ├── best-practices │ │ ├── cartridge_creation.md │ │ ├── isml_templates.md │ │ ├── job_framework.md │ │ ├── localserviceregistry.md │ │ ├── ocapi_hooks.md │ │ ├── performance.md │ │ ├── scapi_custom_endpoint.md │ │ ├── scapi_hooks.md │ │ ├── security.md │ │ ├── sfra_client_side_js.md │ │ ├── sfra_controllers.md │ │ ├── sfra_models.md │ │ └── sfra_scss.md │ ├── dw_campaign │ │ ├── ABTest.md │ │ ├── ABTestMgr.md │ │ ├── ABTestSegment.md │ │ ├── AmountDiscount.md │ │ ├── ApproachingDiscount.md │ │ ├── BonusChoiceDiscount.md │ │ ├── BonusDiscount.md │ │ ├── Campaign.md │ │ ├── CampaignMgr.md │ │ ├── CampaignStatusCodes.md │ │ ├── Coupon.md │ │ ├── CouponMgr.md │ │ ├── CouponRedemption.md │ │ ├── CouponStatusCodes.md │ │ ├── Discount.md │ │ ├── DiscountPlan.md │ │ ├── FixedPriceDiscount.md │ │ ├── FixedPriceShippingDiscount.md │ │ ├── FreeDiscount.md │ │ ├── FreeShippingDiscount.md │ │ ├── PercentageDiscount.md │ │ ├── PercentageOptionDiscount.md │ │ ├── PriceBookPriceDiscount.md │ │ ├── Promotion.md │ │ ├── PromotionMgr.md │ │ ├── PromotionPlan.md │ │ ├── SlotContent.md │ │ ├── SourceCodeGroup.md │ │ ├── SourceCodeInfo.md │ │ ├── SourceCodeStatusCodes.md │ │ └── TotalFixedPriceDiscount.md │ ├── dw_catalog │ │ ├── Catalog.md │ │ ├── CatalogMgr.md │ │ ├── Category.md │ │ ├── CategoryAssignment.md │ │ ├── CategoryLink.md │ │ ├── PriceBook.md │ │ ├── PriceBookMgr.md │ │ ├── Product.md │ │ ├── ProductActiveData.md │ │ ├── ProductAttributeModel.md │ │ ├── ProductAvailabilityLevels.md │ │ ├── ProductAvailabilityModel.md │ │ ├── ProductInventoryList.md │ │ ├── ProductInventoryMgr.md │ │ ├── ProductInventoryRecord.md │ │ ├── ProductLink.md │ │ ├── ProductMgr.md │ │ ├── ProductOption.md │ │ ├── ProductOptionModel.md │ │ ├── ProductOptionValue.md │ │ ├── ProductPriceInfo.md │ │ ├── ProductPriceModel.md │ │ ├── ProductPriceTable.md │ │ ├── ProductSearchHit.md │ │ ├── ProductSearchModel.md │ │ ├── ProductSearchRefinementDefinition.md │ │ ├── ProductSearchRefinements.md │ │ ├── ProductSearchRefinementValue.md │ │ ├── ProductVariationAttribute.md │ │ ├── ProductVariationAttributeValue.md │ │ ├── ProductVariationModel.md │ │ ├── Recommendation.md │ │ ├── SearchModel.md │ │ ├── SearchRefinementDefinition.md │ │ ├── SearchRefinements.md │ │ ├── SearchRefinementValue.md │ │ ├── SortingOption.md │ │ ├── SortingRule.md │ │ ├── Store.md │ │ ├── StoreGroup.md │ │ ├── StoreInventoryFilter.md │ │ ├── StoreInventoryFilterValue.md │ │ ├── StoreMgr.md │ │ ├── Variant.md │ │ └── VariationGroup.md │ ├── dw_content │ │ ├── Content.md │ │ ├── ContentMgr.md │ │ ├── ContentSearchModel.md │ │ ├── ContentSearchRefinementDefinition.md │ │ ├── ContentSearchRefinements.md │ │ ├── ContentSearchRefinementValue.md │ │ ├── Folder.md │ │ ├── Library.md │ │ ├── MarkupText.md │ │ └── MediaFile.md │ ├── dw_crypto │ │ ├── CertificateRef.md │ │ ├── CertificateUtils.md │ │ ├── Cipher.md │ │ ├── Encoding.md │ │ ├── JWE.md │ │ ├── JWEHeader.md │ │ ├── JWS.md │ │ ├── JWSHeader.md │ │ ├── KeyRef.md │ │ ├── Mac.md │ │ ├── MessageDigest.md │ │ ├── SecureRandom.md │ │ ├── Signature.md │ │ ├── WeakCipher.md │ │ ├── WeakMac.md │ │ ├── WeakMessageDigest.md │ │ ├── WeakSignature.md │ │ └── X509Certificate.md │ ├── dw_customer │ │ ├── AddressBook.md │ │ ├── AgentUserMgr.md │ │ ├── AgentUserStatusCodes.md │ │ ├── AuthenticationStatus.md │ │ ├── Credentials.md │ │ ├── Customer.md │ │ ├── CustomerActiveData.md │ │ ├── CustomerAddress.md │ │ ├── CustomerCDPData.md │ │ ├── CustomerContextMgr.md │ │ ├── CustomerGroup.md │ │ ├── CustomerList.md │ │ ├── CustomerMgr.md │ │ ├── CustomerPasswordConstraints.md │ │ ├── CustomerPaymentInstrument.md │ │ ├── CustomerStatusCodes.md │ │ ├── EncryptedObject.md │ │ ├── ExternalProfile.md │ │ ├── OrderHistory.md │ │ ├── ProductList.md │ │ ├── ProductListItem.md │ │ ├── ProductListItemPurchase.md │ │ ├── ProductListMgr.md │ │ ├── ProductListRegistrant.md │ │ ├── Profile.md │ │ └── Wallet.md │ ├── dw_extensions.applepay │ │ ├── ApplePayHookResult.md │ │ └── ApplePayHooks.md │ ├── dw_extensions.facebook │ │ ├── FacebookFeedHooks.md │ │ └── FacebookProduct.md │ ├── dw_extensions.paymentrequest │ │ ├── PaymentRequestHookResult.md │ │ └── PaymentRequestHooks.md │ ├── dw_extensions.payments │ │ ├── SalesforceBancontactPaymentDetails.md │ │ ├── SalesforceCardPaymentDetails.md │ │ ├── SalesforceEpsPaymentDetails.md │ │ ├── SalesforceIdealPaymentDetails.md │ │ ├── SalesforceKlarnaPaymentDetails.md │ │ ├── SalesforcePaymentDetails.md │ │ ├── SalesforcePaymentIntent.md │ │ ├── SalesforcePaymentMethod.md │ │ ├── SalesforcePaymentRequest.md │ │ ├── SalesforcePaymentsHooks.md │ │ ├── SalesforcePaymentsMgr.md │ │ ├── SalesforcePaymentsSiteConfiguration.md │ │ ├── SalesforcePayPalOrder.md │ │ ├── SalesforcePayPalOrderAddress.md │ │ ├── SalesforcePayPalOrderPayer.md │ │ ├── SalesforcePayPalPaymentDetails.md │ │ ├── SalesforceSepaDebitPaymentDetails.md │ │ └── SalesforceVenmoPaymentDetails.md │ ├── dw_extensions.pinterest │ │ ├── PinterestAvailability.md │ │ ├── PinterestFeedHooks.md │ │ ├── PinterestOrder.md │ │ ├── PinterestOrderHooks.md │ │ └── PinterestProduct.md │ ├── dw_io │ │ ├── CSVStreamReader.md │ │ ├── CSVStreamWriter.md │ │ ├── File.md │ │ ├── FileReader.md │ │ ├── FileWriter.md │ │ ├── InputStream.md │ │ ├── OutputStream.md │ │ ├── PrintWriter.md │ │ ├── RandomAccessFileReader.md │ │ ├── Reader.md │ │ ├── StringWriter.md │ │ ├── Writer.md │ │ ├── XMLIndentingStreamWriter.md │ │ ├── XMLStreamConstants.md │ │ ├── XMLStreamReader.md │ │ └── XMLStreamWriter.md │ ├── dw_job │ │ ├── JobExecution.md │ │ └── JobStepExecution.md │ ├── dw_net │ │ ├── FTPClient.md │ │ ├── FTPFileInfo.md │ │ ├── HTTPClient.md │ │ ├── HTTPRequestPart.md │ │ ├── Mail.md │ │ ├── SFTPClient.md │ │ ├── SFTPFileInfo.md │ │ ├── WebDAVClient.md │ │ └── WebDAVFileInfo.md │ ├── dw_object │ │ ├── ActiveData.md │ │ ├── CustomAttributes.md │ │ ├── CustomObject.md │ │ ├── CustomObjectMgr.md │ │ ├── Extensible.md │ │ ├── ExtensibleObject.md │ │ ├── Note.md │ │ ├── ObjectAttributeDefinition.md │ │ ├── ObjectAttributeGroup.md │ │ ├── ObjectAttributeValueDefinition.md │ │ ├── ObjectTypeDefinition.md │ │ ├── PersistentObject.md │ │ ├── SimpleExtensible.md │ │ └── SystemObjectMgr.md │ ├── dw_order │ │ ├── AbstractItem.md │ │ ├── AbstractItemCtnr.md │ │ ├── Appeasement.md │ │ ├── AppeasementItem.md │ │ ├── Basket.md │ │ ├── BasketMgr.md │ │ ├── BonusDiscountLineItem.md │ │ ├── CouponLineItem.md │ │ ├── CreateAgentBasketLimitExceededException.md │ │ ├── CreateBasketFromOrderException.md │ │ ├── CreateCouponLineItemException.md │ │ ├── CreateOrderException.md │ │ ├── CreateTemporaryBasketLimitExceededException.md │ │ ├── GiftCertificate.md │ │ ├── GiftCertificateLineItem.md │ │ ├── GiftCertificateMgr.md │ │ ├── GiftCertificateStatusCodes.md │ │ ├── Invoice.md │ │ ├── InvoiceItem.md │ │ ├── LineItem.md │ │ ├── LineItemCtnr.md │ │ ├── Order.md │ │ ├── OrderAddress.md │ │ ├── OrderItem.md │ │ ├── OrderMgr.md │ │ ├── OrderPaymentInstrument.md │ │ ├── OrderProcessStatusCodes.md │ │ ├── PaymentCard.md │ │ ├── PaymentInstrument.md │ │ ├── PaymentMethod.md │ │ ├── PaymentMgr.md │ │ ├── PaymentProcessor.md │ │ ├── PaymentStatusCodes.md │ │ ├── PaymentTransaction.md │ │ ├── PriceAdjustment.md │ │ ├── PriceAdjustmentLimitTypes.md │ │ ├── ProductLineItem.md │ │ ├── ProductShippingCost.md │ │ ├── ProductShippingLineItem.md │ │ ├── ProductShippingModel.md │ │ ├── Return.md │ │ ├── ReturnCase.md │ │ ├── ReturnCaseItem.md │ │ ├── ReturnItem.md │ │ ├── Shipment.md │ │ ├── ShipmentShippingCost.md │ │ ├── ShipmentShippingModel.md │ │ ├── ShippingLineItem.md │ │ ├── ShippingLocation.md │ │ ├── ShippingMethod.md │ │ ├── ShippingMgr.md │ │ ├── ShippingOrder.md │ │ ├── ShippingOrderItem.md │ │ ├── SumItem.md │ │ ├── TaxGroup.md │ │ ├── TaxItem.md │ │ ├── TaxMgr.md │ │ ├── TrackingInfo.md │ │ └── TrackingRef.md │ ├── dw_order.hooks │ │ ├── CalculateHooks.md │ │ ├── OrderHooks.md │ │ ├── PaymentHooks.md │ │ ├── ReturnHooks.md │ │ └── ShippingOrderHooks.md │ ├── dw_rpc │ │ ├── SOAPUtil.md │ │ ├── Stub.md │ │ └── WebReference.md │ ├── dw_suggest │ │ ├── BrandSuggestions.md │ │ ├── CategorySuggestions.md │ │ ├── ContentSuggestions.md │ │ ├── CustomSuggestions.md │ │ ├── ProductSuggestions.md │ │ ├── SearchPhraseSuggestions.md │ │ ├── SuggestedCategory.md │ │ ├── SuggestedContent.md │ │ ├── SuggestedPhrase.md │ │ ├── SuggestedProduct.md │ │ ├── SuggestedTerm.md │ │ ├── SuggestedTerms.md │ │ ├── Suggestions.md │ │ └── SuggestModel.md │ ├── dw_svc │ │ ├── FTPService.md │ │ ├── FTPServiceDefinition.md │ │ ├── HTTPFormService.md │ │ ├── HTTPFormServiceDefinition.md │ │ ├── HTTPService.md │ │ ├── HTTPServiceDefinition.md │ │ ├── LocalServiceRegistry.md │ │ ├── Result.md │ │ ├── Service.md │ │ ├── ServiceCallback.md │ │ ├── ServiceConfig.md │ │ ├── ServiceCredential.md │ │ ├── ServiceDefinition.md │ │ ├── ServiceProfile.md │ │ ├── ServiceRegistry.md │ │ ├── SOAPService.md │ │ └── SOAPServiceDefinition.md │ ├── dw_system │ │ ├── AgentUserStatusCodes.md │ │ ├── Cache.md │ │ ├── CacheMgr.md │ │ ├── HookMgr.md │ │ ├── InternalObject.md │ │ ├── JobProcessMonitor.md │ │ ├── Log.md │ │ ├── Logger.md │ │ ├── LogNDC.md │ │ ├── OrganizationPreferences.md │ │ ├── Pipeline.md │ │ ├── PipelineDictionary.md │ │ ├── RemoteInclude.md │ │ ├── Request.md │ │ ├── RequestHooks.md │ │ ├── Response.md │ │ ├── RESTErrorResponse.md │ │ ├── RESTResponseMgr.md │ │ ├── RESTSuccessResponse.md │ │ ├── SearchStatus.md │ │ ├── Session.md │ │ ├── Site.md │ │ ├── SitePreferences.md │ │ ├── Status.md │ │ ├── StatusItem.md │ │ ├── System.md │ │ └── Transaction.md │ ├── dw_util │ │ ├── ArrayList.md │ │ ├── Assert.md │ │ ├── BigInteger.md │ │ ├── Bytes.md │ │ ├── Calendar.md │ │ ├── Collection.md │ │ ├── Currency.md │ │ ├── DateUtils.md │ │ ├── Decimal.md │ │ ├── FilteringCollection.md │ │ ├── Geolocation.md │ │ ├── HashMap.md │ │ ├── HashSet.md │ │ ├── Iterator.md │ │ ├── LinkedHashMap.md │ │ ├── LinkedHashSet.md │ │ ├── List.md │ │ ├── Locale.md │ │ ├── Map.md │ │ ├── MapEntry.md │ │ ├── MappingKey.md │ │ ├── MappingMgr.md │ │ ├── PropertyComparator.md │ │ ├── SecureEncoder.md │ │ ├── SecureFilter.md │ │ ├── SeekableIterator.md │ │ ├── Set.md │ │ ├── SortedMap.md │ │ ├── SortedSet.md │ │ ├── StringUtils.md │ │ ├── Template.md │ │ └── UUIDUtils.md │ ├── dw_value │ │ ├── EnumValue.md │ │ ├── MimeEncodedText.md │ │ ├── Money.md │ │ └── Quantity.md │ ├── dw_web │ │ ├── ClickStream.md │ │ ├── ClickStreamEntry.md │ │ ├── Cookie.md │ │ ├── Cookies.md │ │ ├── CSRFProtection.md │ │ ├── Form.md │ │ ├── FormAction.md │ │ ├── FormElement.md │ │ ├── FormElementValidationResult.md │ │ ├── FormField.md │ │ ├── FormFieldOption.md │ │ ├── FormFieldOptions.md │ │ ├── FormGroup.md │ │ ├── FormList.md │ │ ├── FormListItem.md │ │ ├── Forms.md │ │ ├── HttpParameter.md │ │ ├── HttpParameterMap.md │ │ ├── LoopIterator.md │ │ ├── PageMetaData.md │ │ ├── PageMetaTag.md │ │ ├── PagingModel.md │ │ ├── Resource.md │ │ ├── URL.md │ │ ├── URLAction.md │ │ ├── URLParameter.md │ │ ├── URLRedirect.md │ │ ├── URLRedirectMgr.md │ │ └── URLUtils.md │ ├── sfra │ │ ├── account.md │ │ ├── address.md │ │ ├── billing.md │ │ ├── cart.md │ │ ├── categories.md │ │ ├── content.md │ │ ├── locale.md │ │ ├── order.md │ │ ├── payment.md │ │ ├── price-default.md │ │ ├── price-range.md │ │ ├── price-tiered.md │ │ ├── product-bundle.md │ │ ├── product-full.md │ │ ├── product-line-items.md │ │ ├── product-search.md │ │ ├── product-tile.md │ │ ├── querystring.md │ │ ├── render.md │ │ ├── request.md │ │ ├── response.md │ │ ├── server.md │ │ ├── shipping.md │ │ ├── store.md │ │ ├── stores.md │ │ └── totals.md │ └── TopLevel │ ├── APIException.md │ ├── arguments.md │ ├── Array.md │ ├── ArrayBuffer.md │ ├── BigInt.md │ ├── Boolean.md │ ├── ConversionError.md │ ├── DataView.md │ ├── Date.md │ ├── Error.md │ ├── ES6Iterator.md │ ├── EvalError.md │ ├── Fault.md │ ├── Float32Array.md │ ├── Float64Array.md │ ├── Function.md │ ├── Generator.md │ ├── global.md │ ├── Int16Array.md │ ├── Int32Array.md │ ├── Int8Array.md │ ├── InternalError.md │ ├── IOError.md │ ├── Iterable.md │ ├── Iterator.md │ ├── JSON.md │ ├── Map.md │ ├── Math.md │ ├── Module.md │ ├── Namespace.md │ ├── Number.md │ ├── Object.md │ ├── QName.md │ ├── RangeError.md │ ├── ReferenceError.md │ ├── RegExp.md │ ├── Set.md │ ├── StopIteration.md │ ├── String.md │ ├── Symbol.md │ ├── SyntaxError.md │ ├── SystemError.md │ ├── TypeError.md │ ├── Uint16Array.md │ ├── Uint32Array.md │ ├── Uint8Array.md │ ├── Uint8ClampedArray.md │ ├── URIError.md │ ├── WeakMap.md │ ├── WeakSet.md │ ├── XML.md │ ├── XMLList.md │ └── XMLStreamError.md ├── docs-site │ ├── .gitignore │ ├── App.tsx │ ├── components │ │ ├── Badge.tsx │ │ ├── BreadcrumbSchema.tsx │ │ ├── CodeBlock.tsx │ │ ├── Collapsible.tsx │ │ ├── ConfigBuilder.tsx │ │ ├── ConfigHero.tsx │ │ ├── ConfigModeTabs.tsx │ │ ├── icons.tsx │ │ ├── Layout.tsx │ │ ├── LightCodeContainer.tsx │ │ ├── NewcomerCTA.tsx │ │ ├── NextStepsStrip.tsx │ │ ├── OnThisPage.tsx │ │ ├── Search.tsx │ │ ├── SEO.tsx │ │ ├── Sidebar.tsx │ │ ├── StructuredData.tsx │ │ ├── ToolCard.tsx │ │ ├── ToolFilters.tsx │ │ ├── Typography.tsx │ │ └── VersionBadge.tsx │ ├── constants.tsx │ ├── index.html │ ├── main.tsx │ ├── metadata.json │ ├── package-lock.json │ ├── package.json │ ├── pages │ │ ├── AIInterfacesPage.tsx │ │ ├── ConfigurationPage.tsx │ │ ├── DevelopmentPage.tsx │ │ ├── ExamplesPage.tsx │ │ ├── FeaturesPage.tsx │ │ ├── HomePage.tsx │ │ ├── SecurityPage.tsx │ │ ├── ToolsPage.tsx │ │ └── TroubleshootingPage.tsx │ ├── postcss.config.js │ ├── public │ │ ├── .well-known │ │ │ └── security.txt │ │ ├── 404.html │ │ ├── android-chrome-192x192.png │ │ ├── android-chrome-512x512.png │ │ ├── apple-touch-icon.png │ │ ├── explain-product-pricing-methods-no-mcp.png │ │ ├── explain-product-pricing-methods.png │ │ ├── favicon-16x16.png │ │ ├── favicon-32x32.png │ │ ├── favicon.ico │ │ ├── llms.txt │ │ ├── robots.txt │ │ ├── site.webmanifest │ │ └── sitemap.xml │ ├── README.md │ ├── scripts │ │ ├── generate-search-index.js │ │ ├── generate-sitemap.js │ │ └── search-dev.js │ ├── src │ │ └── styles │ │ ├── input.css │ │ └── prism-theme.css │ ├── tailwind.config.js │ ├── tsconfig.json │ ├── types.ts │ ├── utils │ │ ├── search.ts │ │ └── toolsData.ts │ └── vite.config.ts ├── eslint.config.js ├── jest.config.js ├── LICENSE ├── package-lock.json ├── package.json ├── README.md ├── scripts │ └── convert-docs.js ├── SECURITY.md ├── server.json ├── src │ ├── clients │ │ ├── base │ │ │ ├── http-client.ts │ │ │ ├── oauth-token.ts │ │ │ └── ocapi-auth-client.ts │ │ ├── best-practices-client.ts │ │ ├── cartridge-generation-client.ts │ │ ├── docs │ │ │ ├── class-content-parser.ts │ │ │ ├── class-name-resolver.ts │ │ │ ├── documentation-scanner.ts │ │ │ ├── index.ts │ │ │ └── referenced-types-extractor.ts │ │ ├── docs-client.ts │ │ ├── log-client.ts │ │ ├── logs │ │ │ ├── index.ts │ │ │ ├── log-analyzer.ts │ │ │ ├── log-client.ts │ │ │ ├── log-constants.ts │ │ │ ├── log-file-discovery.ts │ │ │ ├── log-file-reader.ts │ │ │ ├── log-formatter.ts │ │ │ ├── log-processor.ts │ │ │ ├── log-types.ts │ │ │ └── webdav-client-manager.ts │ │ ├── ocapi │ │ │ ├── code-versions-client.ts │ │ │ ├── site-preferences-client.ts │ │ │ └── system-objects-client.ts │ │ ├── ocapi-client.ts │ │ └── sfra-client.ts │ ├── config │ │ ├── configuration-factory.ts │ │ └── dw-json-loader.ts │ ├── core │ │ ├── handlers │ │ │ ├── abstract-log-tool-handler.ts │ │ │ ├── base-handler.ts │ │ │ ├── best-practices-handler.ts │ │ │ ├── cartridge-handler.ts │ │ │ ├── client-factory.ts │ │ │ ├── code-version-handler.ts │ │ │ ├── docs-handler.ts │ │ │ ├── job-log-handler.ts │ │ │ ├── job-log-tool-config.ts │ │ │ ├── log-handler.ts │ │ │ ├── log-tool-config.ts │ │ │ ├── sfra-handler.ts │ │ │ ├── system-object-handler.ts │ │ │ └── validation-helpers.ts │ │ ├── server.ts │ │ └── tool-definitions.ts │ ├── index.ts │ ├── main.ts │ ├── services │ │ ├── file-system-service.ts │ │ ├── index.ts │ │ └── path-service.ts │ ├── tool-configs │ │ ├── best-practices-tool-config.ts │ │ ├── cartridge-tool-config.ts │ │ ├── code-version-tool-config.ts │ │ ├── docs-tool-config.ts │ │ ├── job-log-tool-config.ts │ │ ├── log-tool-config.ts │ │ ├── sfra-tool-config.ts │ │ └── system-object-tool-config.ts │ ├── types │ │ └── types.ts │ └── utils │ ├── cache.ts │ ├── job-log-tool-config.ts │ ├── job-log-utils.ts │ ├── log-cache.ts │ ├── log-tool-config.ts │ ├── log-tool-constants.ts │ ├── log-tool-utils.ts │ ├── logger.ts │ ├── ocapi-url-builder.ts │ ├── path-resolver.ts │ ├── query-builder.ts │ ├── utils.ts │ └── validator.ts ├── tests │ ├── __mocks__ │ │ ├── docs-client.ts │ │ ├── src │ │ │ └── clients │ │ │ └── base │ │ │ └── http-client.js │ │ └── webdav.js │ ├── base-handler.test.ts │ ├── base-http-client.test.ts │ ├── best-practices-handler.test.ts │ ├── cache.test.ts │ ├── cartridge-handler.test.ts │ ├── class-content-parser.test.ts │ ├── class-name-resolver.test.ts │ ├── client-factory.test.ts │ ├── code-version-handler.test.ts │ ├── code-versions-client.test.ts │ ├── config.test.ts │ ├── configuration-factory.test.ts │ ├── docs-handler.test.ts │ ├── documentation-scanner.test.ts │ ├── file-system-service.test.ts │ ├── job-log-handler.test.ts │ ├── job-log-utils.test.ts │ ├── log-client.test.ts │ ├── log-handler.test.ts │ ├── log-processor.test.ts │ ├── logger.test.ts │ ├── mcp │ │ ├── AGENTS.md │ │ ├── node │ │ │ ├── activate-code-version-advanced.full-mode.programmatic.test.js │ │ │ ├── code-versions.full-mode.programmatic.test.js │ │ │ ├── generate-cartridge-structure.docs-only.programmatic.test.js │ │ │ ├── get-available-best-practice-guides.docs-only.programmatic.test.js │ │ │ ├── get-available-sfra-documents.programmatic.test.js │ │ │ ├── get-best-practice-guide.docs-only.programmatic.test.js │ │ │ ├── get-hook-reference.docs-only.programmatic.test.js │ │ │ ├── get-job-execution-summary.full-mode.programmatic.test.js │ │ │ ├── get-job-log-entries.full-mode.programmatic.test.js │ │ │ ├── get-latest-debug.full-mode.programmatic.test.js │ │ │ ├── get-latest-error.full-mode.programmatic.test.js │ │ │ ├── get-latest-info.full-mode.programmatic.test.js │ │ │ ├── get-latest-job-log-files.full-mode.programmatic.test.js │ │ │ ├── get-latest-warn.full-mode.programmatic.test.js │ │ │ ├── get-log-file-contents.full-mode.programmatic.test.js │ │ │ ├── get-sfcc-class-documentation.docs-only.programmatic.test.js │ │ │ ├── get-sfcc-class-info.docs-only.programmatic.test.js │ │ │ ├── get-sfra-categories.docs-only.programmatic.test.js │ │ │ ├── get-sfra-document.programmatic.test.js │ │ │ ├── get-sfra-documents-by-category.docs-only.programmatic.test.js │ │ │ ├── get-system-object-definition.full-mode.programmatic.test.js │ │ │ ├── get-system-object-definitions.docs-only.programmatic.test.js │ │ │ ├── get-system-object-definitions.full-mode.programmatic.test.js │ │ │ ├── list-log-files.full-mode.programmatic.test.js │ │ │ ├── list-sfcc-classes.docs-only.programmatic.test.js │ │ │ ├── search-best-practices.docs-only.programmatic.test.js │ │ │ ├── search-custom-object-attribute-definitions.full-mode.programmatic.test.js │ │ │ ├── search-job-logs-by-name.full-mode.programmatic.test.js │ │ │ ├── search-job-logs.full-mode.programmatic.test.js │ │ │ ├── search-logs.full-mode.programmatic.test.js │ │ │ ├── search-sfcc-classes.docs-only.programmatic.test.js │ │ │ ├── search-sfcc-methods.docs-only.programmatic.test.js │ │ │ ├── search-sfra-documentation.docs-only.programmatic.test.js │ │ │ ├── search-site-preferences.full-mode.programmatic.test.js │ │ │ ├── search-system-object-attribute-definitions.full-mode.programmatic.test.js │ │ │ ├── search-system-object-attribute-groups.full-mode.programmatic.test.js │ │ │ ├── summarize-logs.full-mode.programmatic.test.js │ │ │ ├── tools.docs-only.programmatic.test.js │ │ │ └── tools.full-mode.programmatic.test.js │ │ ├── README.md │ │ ├── test-fixtures │ │ │ └── dw.json │ │ └── yaml │ │ ├── activate-code-version.docs-only.test.mcp.yml │ │ ├── activate-code-version.full-mode.test.mcp.yml │ │ ├── get_latest_error.test.mcp.yml │ │ ├── get-available-best-practice-guides.docs-only.test.mcp.yml │ │ ├── get-available-best-practice-guides.full-mode.test.mcp.yml │ │ ├── get-available-sfra-documents.docs-only.test.mcp.yml │ │ ├── get-available-sfra-documents.full-mode.test.mcp.yml │ │ ├── get-best-practice-guide.docs-only.test.mcp.yml │ │ ├── get-best-practice-guide.full-mode.test.mcp.yml │ │ ├── get-code-versions.docs-only.test.mcp.yml │ │ ├── get-code-versions.full-mode.test.mcp.yml │ │ ├── get-hook-reference.docs-only.test.mcp.yml │ │ ├── get-hook-reference.full-mode.test.mcp.yml │ │ ├── get-job-execution-summary.full-mode.test.mcp.yml │ │ ├── get-job-log-entries.full-mode.test.mcp.yml │ │ ├── get-latest-debug.full-mode.test.mcp.yml │ │ ├── get-latest-error.full-mode.test.mcp.yml │ │ ├── get-latest-info.full-mode.test.mcp.yml │ │ ├── get-latest-job-log-files.full-mode.test.mcp.yml │ │ ├── get-latest-warn.full-mode.test.mcp.yml │ │ ├── get-log-file-contents.full-mode.test.mcp.yml │ │ ├── get-sfcc-class-documentation.docs-only.test.mcp.yml │ │ ├── get-sfcc-class-documentation.full-mode.test.mcp.yml │ │ ├── get-sfcc-class-info.docs-only.test.mcp.yml │ │ ├── get-sfcc-class-info.full-mode.test.mcp.yml │ │ ├── get-sfra-categories.docs-only.test.mcp.yml │ │ ├── get-sfra-categories.full-mode.test.mcp.yml │ │ ├── get-sfra-document.docs-only.test.mcp.yml │ │ ├── get-sfra-document.full-mode.test.mcp.yml │ │ ├── get-sfra-documents-by-category.docs-only.test.mcp.yml │ │ ├── get-sfra-documents-by-category.full-mode.test.mcp.yml │ │ ├── get-system-object-definition.docs-only.test.mcp.yml │ │ ├── get-system-object-definition.full-mode.test.mcp.yml │ │ ├── get-system-object-definitions.docs-only.test.mcp.yml │ │ ├── get-system-object-definitions.full-mode.test.mcp.yml │ │ ├── list-log-files.full-mode.test.mcp.yml │ │ ├── list-sfcc-classes.docs-only.test.mcp.yml │ │ ├── list-sfcc-classes.full-mode.test.mcp.yml │ │ ├── search-best-practices.docs-only.test.mcp.yml │ │ ├── search-best-practices.full-mode.test.mcp.yml │ │ ├── search-custom-object-attribute-definitions.docs-only.test.mcp.yml │ │ ├── search-custom-object-attribute-definitions.test.mcp.yml │ │ ├── search-job-logs-by-name.full-mode.test.mcp.yml │ │ ├── search-job-logs.full-mode.test.mcp.yml │ │ ├── search-logs.full-mode.test.mcp.yml │ │ ├── search-sfcc-classes.docs-only.test.mcp.yml │ │ ├── search-sfcc-classes.full-mode.test.mcp.yml │ │ ├── search-sfcc-methods.docs-only.test.mcp.yml │ │ ├── search-sfcc-methods.full-mode.test.mcp.yml │ │ ├── search-sfra-documentation.docs-only.test.mcp.yml │ │ ├── search-sfra-documentation.full-mode.test.mcp.yml │ │ ├── search-site-preferences.docs-only.test.mcp.yml │ │ ├── search-site-preferences.full-mode.test.mcp.yml │ │ ├── search-system-object-attribute-definitions.docs-only.test.mcp.yml │ │ ├── search-system-object-attribute-definitions.full-mode.test.mcp.yml │ │ ├── search-system-object-attribute-groups.docs-only.test.mcp.yml │ │ ├── search-system-object-attribute-groups.full-mode.test.mcp.yml │ │ ├── summarize-logs.full-mode.test.mcp.yml │ │ ├── tools.docs-only.test.mcp.yml │ │ └── tools.full-mode.test.mcp.yml │ ├── oauth-token.test.ts │ ├── ocapi-auth-client.test.ts │ ├── ocapi-client.test.ts │ ├── path-service.test.ts │ ├── query-builder.test.ts │ ├── referenced-types-extractor.test.ts │ ├── servers │ │ ├── sfcc-mock-server │ │ │ ├── mock-data │ │ │ │ └── ocapi │ │ │ │ ├── code-versions.json │ │ │ │ ├── custom-object-attributes-customapi.json │ │ │ │ ├── custom-object-attributes-globalsettings.json │ │ │ │ ├── custom-object-attributes-versionhistory.json │ │ │ │ ├── site-preferences-ccv.json │ │ │ │ ├── site-preferences-fastforward.json │ │ │ │ ├── site-preferences-sfra.json │ │ │ │ ├── site-preferences-storefront.json │ │ │ │ ├── site-preferences-system.json │ │ │ │ ├── system-object-attribute-groups-campaign.json │ │ │ │ ├── system-object-attribute-groups-category.json │ │ │ │ ├── system-object-attribute-groups-order.json │ │ │ │ ├── system-object-attribute-groups-product.json │ │ │ │ ├── system-object-attribute-groups-sitepreferences.json │ │ │ │ ├── system-object-attributes-customeraddress.json │ │ │ │ ├── system-object-attributes-product-expanded.json │ │ │ │ ├── system-object-attributes-product.json │ │ │ │ ├── system-object-definition-category.json │ │ │ │ ├── system-object-definition-customer.json │ │ │ │ ├── system-object-definition-customeraddress.json │ │ │ │ ├── system-object-definition-order.json │ │ │ │ ├── system-object-definition-product.json │ │ │ │ ├── system-object-definitions-old.json │ │ │ │ └── system-object-definitions.json │ │ │ ├── package-lock.json │ │ │ ├── package.json │ │ │ ├── README.md │ │ │ ├── scripts │ │ │ │ └── setup-logs.js │ │ │ ├── server.js │ │ │ └── src │ │ │ ├── app.js │ │ │ ├── config │ │ │ │ └── server-config.js │ │ │ ├── middleware │ │ │ │ ├── auth.js │ │ │ │ ├── cors.js │ │ │ │ └── logging.js │ │ │ ├── routes │ │ │ │ ├── ocapi │ │ │ │ │ ├── code-versions-handler.js │ │ │ │ │ ├── oauth-handler.js │ │ │ │ │ ├── ocapi-error-utils.js │ │ │ │ │ ├── ocapi-utils.js │ │ │ │ │ ├── site-preferences-handler.js │ │ │ │ │ └── system-objects-handler.js │ │ │ │ ├── ocapi.js │ │ │ │ └── webdav.js │ │ │ └── utils │ │ │ ├── mock-data-loader.js │ │ │ └── webdav-xml.js │ │ └── sfcc-mock-server-manager.ts │ ├── sfcc-mock-server.test.ts │ ├── site-preferences-client.test.ts │ ├── system-objects-client.test.ts │ ├── utils.test.ts │ ├── validation-helpers.test.ts │ └── validator.test.ts ├── tsconfig.json └── tsconfig.test.json ``` # Files -------------------------------------------------------------------------------- /tests/mcp/node/list-log-files.full-mode.programmatic.test.js: -------------------------------------------------------------------------------- ```javascript import { test, describe, before, after, beforeEach } from 'node:test'; import { strict as assert } from 'node:assert'; import { connect } from 'mcp-aegis'; describe('list_log_files - Full Mode Programmatic Tests - Optimized', () => { let client; before(async () => { client = await connect('./aegis.config.with-dw.json'); }); after(async () => { if (client?.connected) { await client.disconnect(); } }); beforeEach(() => { // CRITICAL: Clear all buffers to prevent leaking into next tests client.clearAllBuffers(); // Recommended - comprehensive protection }); // Optimized helper functions function assertValidMCPResponse(result) { assert.ok(result.content, 'Should have content'); assert.ok(Array.isArray(result.content), 'Content should be array'); assert.equal(typeof result.isError, 'boolean', 'isError should be boolean'); assert.equal(result.isError, false, 'Should not be an error response'); assert.equal(result.content[0].type, 'text'); } function parseResponseText(text) { return text.startsWith('"') && text.endsWith('"') ? JSON.parse(text) : text; } function assertCompleteLogFileFormat(result) { assertValidMCPResponse(result); const text = parseResponseText(result.content[0].text); // Header validation assert.ok(text.includes('Available log files:'), 'Should contain header'); // All log levels present with correct patterns const logTypes = ['debug', 'error', 'info', 'warn']; logTypes.forEach(logType => { assert.ok(new RegExp(`${logType}-blade-\\d{8}-\\d{6}\\.log`).test(text), `Should contain ${logType} log file pattern`); }); // File structure validation (emoji, paths, metadata) assert.ok(text.includes('📄'), 'Should contain file emoji icons'); assert.ok(/📄 \/[\w-]+\.log/.test(text), 'Should have proper file path format'); // Metadata validation (sizes and timestamps) const sizeMatches = text.match(/Size: [\d.,]+ (Bytes|KB|MB)/g); assert.ok(sizeMatches && sizeMatches.length >= 4, 'Should have size info for all files'); const timestampMatches = text.match(/Modified: [A-Za-z]{3}, \d{1,2} [A-Za-z]{3} \d{4} \d{2}:\d{2}:\d{2} GMT/g); assert.ok(timestampMatches && timestampMatches.length >= 4, 'Should have timestamps for all files'); return text; } // Core functionality tests describe('Core Functionality', () => { test('should list all log files with complete metadata and formatting', async () => { const result = await client.callTool('list_log_files', {}); const text = assertCompleteLogFileFormat(result); // Validate comprehensive structure in one test assert.ok(text.startsWith('Available log files:\n\n'), 'Should have proper header format'); assert.ok((text.match(/\n\n/g) || []).length >= 4, 'Should have proper spacing between entries'); // Validate each log type has complete structure const logTypes = ['debug', 'error', 'info', 'warn']; logTypes.forEach(logType => { const pattern = new RegExp(`📄 \\/${logType}-blade-\\d{8}-\\d{6}\\.log[\\s\\S]*?Size: [\\d.,]+ (Bytes|KB|MB)[\\s\\S]*?Modified: [A-Za-z]{3}, \\d{1,2} [A-Za-z]{3} \\d{4} \\d{2}:\\d{2}:\\d{2} GMT`); assert.ok(pattern.test(text), `Should have complete structure for ${logType} files`); }); }); test('should handle various parameter scenarios gracefully', async () => { // Test multiple parameter scenarios in one test const scenarios = [ {}, // Empty object { unknownParam: 'value', anotherParam: 123 }, // Unknown parameters { param: null }, // Null values { param: '' } // Empty strings ]; for (const params of scenarios) { const result = await client.callTool('list_log_files', params); assertValidMCPResponse(result); assert.ok(result.content[0].text.includes('Available log files:'), `Should work with params: ${JSON.stringify(params)}`); } }); }); // Advanced validation tests describe('Integration and Reliability', () => { test('should provide SFCC-compatible file information for analysis workflows', async () => { const result = await client.callTool('list_log_files', {}); const text = assertCompleteLogFileFormat(result); // SFCC-specific validation assert.ok(/blade-\d{8}-\d{6}\.log/.test(text), 'Should match SFCC blade naming convention'); // AI analysis compatibility const lines = text.split('\n'); const fileLines = lines.filter(line => line.includes('📄')); assert.ok(fileLines.length >= 4, 'Should have identifiable file entries for parsing'); // Metadata usefulness for log analysis assert.ok(/Size: [\d.,]+ (Bytes|KB|MB)/.test(text), 'Should have parseable size information'); assert.ok(/Modified: .+ GMT/.test(text), 'Should have parseable timestamp information'); }); test('should maintain consistency and reliability across multiple operations', async () => { const results = []; // Test consistency across 3 sequential calls for (let i = 0; i < 3; i++) { const result = await client.callTool('list_log_files', {}); results.push(result); assertCompleteLogFileFormat(result); } // Validate all results are structurally consistent const firstText = parseResponseText(results[0].content[0].text); results.slice(1).forEach((result, index) => { const text = parseResponseText(result.content[0].text); assert.ok(text.includes('debug-blade-'), `Call ${index + 2} should include debug logs`); assert.ok(text.includes('error-blade-'), `Call ${index + 2} should include error logs`); assert.equal(text.split('\n').length, firstText.split('\n').length, `Call ${index + 2} should have same number of lines as first call`); }); }); test('should execute without generating stderr and maintain clean state', async () => { client.clearStderr(); const result = await client.callTool('list_log_files', {}); assertValidMCPResponse(result); const stderr = client.getStderr(); assert.equal(stderr.trim(), '', 'Should not generate stderr output'); }); }); }); ``` -------------------------------------------------------------------------------- /.github/workflows/update-docs.yml: -------------------------------------------------------------------------------- ```yaml name: Update SFCC Documentation on: schedule: # Run weekly on Sundays at 3 AM UTC - cron: '0 3 * * 0' workflow_dispatch: # Allow manual triggering jobs: update-docs: runs-on: ubuntu-latest permissions: contents: write pull-requests: write steps: - name: Checkout code uses: actions/checkout@v5 with: # Use a token with write permissions for creating PRs token: ${{ secrets.GITHUB_TOKEN }} fetch-depth: 0 - name: Setup Node.js uses: actions/setup-node@v5 with: node-version: '20' cache: 'npm' - name: Install dependencies run: npm ci - name: Run lint checks run: npm run lint:check - name: Build project run: npm run build - name: Setup SFCC mock server run: | cd tests/servers/sfcc-mock-server npm install npm run setup:logs node server.js --port 3000 & SERVER_PID=$! echo "SERVER_PID=$SERVER_PID" >> $GITHUB_ENV sleep 5 - name: Run tests run: npm test - name: Install convert-docs dependencies run: | echo "Installing additional dependencies for docs conversion..." npm install axios cheerio - name: Configure Git run: | git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" - name: Create update branch run: | # Create a unique branch name with timestamp BRANCH_NAME="docs/automated-update-$(date +'%Y%m%d-%H%M%S')" echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_ENV git checkout -b "$BRANCH_NAME" - name: Run docs conversion run: | echo "Starting SFCC documentation conversion..." npm run convert-docs echo "Documentation conversion completed" - name: Check for changes id: check_changes run: | # Check if there are any changes in the docs directory if git diff --quiet HEAD -- docs/; then echo "No changes detected in documentation" echo "has_changes=false" >> $GITHUB_OUTPUT else echo "Changes detected in documentation" echo "has_changes=true" >> $GITHUB_OUTPUT # Show summary of changes echo "Changed files:" git diff --name-only HEAD -- docs/ # Count changes ADDED=$(git diff --numstat HEAD -- docs/ | awk '{sum += $1} END {print sum}') DELETED=$(git diff --numstat HEAD -- docs/ | awk '{sum += $2} END {print sum}') FILES_CHANGED=$(git diff --name-only HEAD -- docs/ | wc -l) echo "files_changed=$FILES_CHANGED" >> $GITHUB_OUTPUT echo "lines_added=$ADDED" >> $GITHUB_OUTPUT echo "lines_deleted=$DELETED" >> $GITHUB_OUTPUT fi - name: Commit changes if: steps.check_changes.outputs.has_changes == 'true' run: | git add docs/ git commit -m "docs: automated update of SFCC documentation - Updated SFCC API documentation from latest sources - Files changed: ${{ steps.check_changes.outputs.files_changed }} - Lines added: ${{ steps.check_changes.outputs.lines_added }} - Lines deleted: ${{ steps.check_changes.outputs.lines_deleted }} Generated by automated workflow on $(date -u '+%Y-%m-%d %H:%M:%S UTC')" - name: Push changes if: steps.check_changes.outputs.has_changes == 'true' run: | git push origin "$BRANCH_NAME" - name: Create Pull Request if: steps.check_changes.outputs.has_changes == 'true' run: | gh pr create \ --title "📚 Automated SFCC Documentation Update" \ --body "## 🤖 Automated Documentation Update This pull request contains automated updates to the SFCC documentation scraped from the latest Salesforce Commerce Cloud documentation sources. ### 📊 Summary - **Files changed:** ${{ steps.check_changes.outputs.files_changed }} - **Lines added:** ${{ steps.check_changes.outputs.lines_added }} - **Lines deleted:** ${{ steps.check_changes.outputs.lines_deleted }} - **Generated on:** $(date -u '+%Y-%m-%d %H:%M:%S UTC') ### 🔍 What's Updated This update includes changes to the SFCC API documentation in the \`docs/\` directory, which may include: - New or updated class documentation - Method signature changes - Property documentation updates - New API additions or deprecations ### ✅ Review Checklist - [ ] Review the changed files for accuracy - [ ] Verify that no important documentation was accidentally removed - [ ] Check that the documentation format is consistent - [ ] Ensure all links and references are working correctly ### 🚀 Auto-merge This PR can be safely merged if the documentation changes look correct and don't break any existing functionality. --- *This PR was automatically created by the \`update-docs\` GitHub Action workflow.*" \ --base develop \ --head "$BRANCH_NAME" \ --label "documentation,automated,dependencies" \ --assignee taurgis \ --reviewer taurgis env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Summary if: steps.check_changes.outputs.has_changes == 'false' run: | echo "✅ No documentation changes detected. The SFCC documentation is up to date." echo "Workflow completed successfully without creating a pull request." - name: Cleanup on failure if: failure() run: | echo "❌ Workflow failed. Cleaning up..." # Delete the branch if it was created but the workflow failed if [ -n "$BRANCH_NAME" ]; then git push origin --delete "$BRANCH_NAME" || echo "Branch cleanup failed or branch doesn't exist remotely" fi - name: Stop SFCC mock server if: always() run: | if [ -n "${SERVER_PID:-}" ]; then kill "$SERVER_PID" || true fi pkill -f "node.*tests/servers/sfcc-mock-server/server.js" || true lsof -ti :3000 | xargs kill -9 2>/dev/null || true ``` -------------------------------------------------------------------------------- /docs-site/utils/search.ts: -------------------------------------------------------------------------------- ```typescript import { GENERATED_SEARCH_INDEX, SearchableItem } from '../src/generated-search-index'; export interface SearchResult { path: string; pageTitle: string; heading: string; headingId?: string; snippet: string; // FIX: Add optional score property to be used for ranking search results. score?: number; } // Fallback search index (manually maintained for development/emergency use) const FALLBACK_SEARCH_INDEX: SearchableItem[] = [ // HomePage { path: '/', pageTitle: 'Introduction', heading: 'SFCC Development MCP Server', content: 'AI-powered Model Context Protocol server for Salesforce B2C Commerce Cloud development with comprehensive documentation, log analysis, best practices, and cartridge generation tools.' }, { path: '/', pageTitle: 'Introduction', heading: 'Quick Start', content: 'Get up and running with SFCC Development MCP Server in minutes. Install and configure to start using AI-assisted SFCC development tools.' }, { path: '/', pageTitle: 'Introduction', heading: 'Key Features', content: 'SFCC Documentation Access, Log Analysis, Best Practices Guides, Cartridge Generation, System Object Management, Code Version Control.' }, { path: '/', pageTitle: 'Introduction', heading: 'Why Choose SFCC Development MCP Server?', content: 'The comprehensive solution for AI-assisted SFCC development. Complete SFCC API Coverage, Real-time Log Analysis, Production Ready, Developer Friendly.' }, // AIInterfacesPage { path: '/ai-interfaces/', pageTitle: 'AI Assistant Setup', heading: 'AI Assistant Setup Guide', content: 'Set up the SFCC Development MCP Server with your AI assistant. Connect Claude Desktop, Cursor AI, or other MCP-compatible tools.' }, { path: '/ai-interfaces/', pageTitle: 'AI Assistant Setup', heading: 'Claude Desktop', content: 'Configure Claude Desktop to use the SFCC Development MCP Server for enhanced SFCC development assistance.' }, { path: '/ai-interfaces/', pageTitle: 'AI Assistant Setup', heading: 'Cursor AI', content: 'Set up Cursor AI editor with the MCP server for intelligent code completion and SFCC guidance.' }, // ConfigurationPage { path: '/configuration/', pageTitle: 'Configuration', heading: 'Configuration Guide', content: 'Configure SFCC Development MCP Server for your Commerce Cloud environment.' }, { path: '/configuration/', pageTitle: 'Configuration', heading: 'Operating Modes', content: 'Documentation-only mode or full mode with SFCC credentials for complete functionality.' }, // AI InterfacesPage { path: '/ai-interfaces/', pageTitle: 'AI Interfaces', heading: 'AI Interface Setup', content: 'Configure your AI assistant to work with SFCC Development MCP Server.' }, // FeaturesPage { path: '/features/', pageTitle: 'Features', heading: 'Features Overview', content: 'Comprehensive SFCC development tools powered by AI assistance.' }, // ToolsPage { path: '/tools/', pageTitle: 'Tools', heading: 'Available Tools', content: 'Complete list of available tools for SFCC development assistance.' }, // ExamplesPage { path: '/examples/', pageTitle: 'Examples', heading: 'Examples & Use Cases', content: 'Real-world examples of using SFCC Development MCP Server for various development tasks.' }, // SecurityPage { path: '/security/', pageTitle: 'Security', heading: 'Security Guidelines', content: 'Security best practices for using SFCC Development MCP Server.' }, // DevelopmentPage { path: '/development/', pageTitle: 'Development', heading: 'Development Guide', content: 'Contributing to SFCC Development MCP Server development.' }, // TroubleshootingPage { path: '/troubleshooting/', pageTitle: 'Troubleshooting', heading: 'Troubleshooting & Debugging', content: 'Common issues and solutions for SFCC Development MCP Server.' }, ]; // Use generated index if available, otherwise fall back to manual index const getSearchIndex = (): SearchableItem[] => { try { // Check if the generated index has meaningful content if (GENERATED_SEARCH_INDEX.length > 1 || (GENERATED_SEARCH_INDEX.length === 1 && GENERATED_SEARCH_INDEX[0].content !== 'AI-powered Model Context Protocol server for Salesforce B2C Commerce Cloud development.')) { return GENERATED_SEARCH_INDEX; } } catch (error) { console.warn('Failed to load generated search index, using fallback:', error); } return FALLBACK_SEARCH_INDEX; }; // Manually populated search index from all documentation pages const createSnippet = (text: string, query: string): string => { const queryLower = query.toLowerCase(); const textLower = text.toLowerCase(); const index = textLower.indexOf(queryLower); if (index === -1) { return text.length > 150 ? text.substring(0, 150) + '...' : text; } const start = Math.max(0, index - 50); const end = Math.min(text.length, index + query.length + 50); let snippet = text.substring(start, end); if (start > 0) snippet = '...' + snippet; if (end < text.length) snippet = snippet + '...'; return snippet; }; export function searchDocs(query: string): SearchResult[] { if (!query) return []; const queryLower = query.toLowerCase(); const searchIndex = getSearchIndex(); const results: SearchResult[] = []; searchIndex.forEach(item => { const contentLower = item.content.toLowerCase(); const headingLower = item.heading.toLowerCase(); const titleLower = item.pageTitle.toLowerCase(); let score = 0; if (titleLower.includes(queryLower)) score += 5; if (headingLower.includes(queryLower)) score += 3; if (contentLower.includes(queryLower)) score += 1; if (score > 0) { results.push({ path: item.path, pageTitle: item.pageTitle, heading: item.heading, headingId: item.headingId, snippet: createSnippet(item.content, query), score: score, }); } }); // Remove duplicates by path and heading, keeping the one with the highest score const uniqueResults = Array.from( results.reduce((map, item) => { const key = `${item.path}-${item.heading}`; if (!map.has(key) || (map.get(key)?.score ?? 0) < (item.score ?? 0)) { map.set(key, item); } return map; }, new Map<string, SearchResult>()).values() ); return uniqueResults .sort((a, b) => (b.score ?? 0) - (a.score ?? 0)) .slice(0, 20); } ``` -------------------------------------------------------------------------------- /docs/dw_io/Reader.md: -------------------------------------------------------------------------------- ```markdown ## Package: dw.io # Class Reader ## Inheritance Hierarchy - Object - dw.io.Reader ## Description The class supports reading characters from a stream. ## Properties ### lines **Type:** List (Read Only) The method reads the whole input stream, parses it and returns a list of strings. Using this method on large feeds is inherently unsafe and may lead to an out-of-memory condition. Instead use method readLine() and process one line at a time. ### string **Type:** String (Read Only) The method reads the whole input stream as one string and returns it. Using this method is unsafe if the length of the input stream is not known and may lead to an out-of-memory condition. Instead use method readN(Number). ## Constructor Summary Reader(source : String) Creates a reader from a string. Reader(stream : InputStream) Create a reader from a stream using UTF-8 character encoding. Reader(stream : InputStream, encoding : String) Create a reader from a stream using the specified character encoding. ## Method Summary ### close **Signature:** `close() : void` Closes the reader. ### getLines **Signature:** `getLines() : List` The method reads the whole input stream, parses it and returns a list of strings. ### getString **Signature:** `getString() : String` The method reads the whole input stream as one string and returns it. ### read **Signature:** `read() : String` Reads a single character from the stream. ### read **Signature:** `read(length : Number) : String` Reads multiple characters from the stream as string. ### readLine **Signature:** `readLine() : String` Reads the next line. ### readLines **Signature:** `readLines() : List` The method reads the whole input stream, parses it and returns a list of strings. ### readN **Signature:** `readN(n : Number) : String` Reads n characters from the stream as string. ### readString **Signature:** `readString() : String` The method reads the whole input stream as one string and returns it. ### ready **Signature:** `ready() : boolean` Identifies if this stream is ready to be read. ### skip **Signature:** `skip(n : Number) : void` Skips the specified number of characters in the stream. ## Constructor Detail ## Method Detail ## Method Details ### close **Signature:** `close() : void` **Description:** Closes the reader. --- ### getLines **Signature:** `getLines() : List` **Description:** The method reads the whole input stream, parses it and returns a list of strings. Using this method on large feeds is inherently unsafe and may lead to an out-of-memory condition. Instead use method readLine() and process one line at a time. **Deprecated:** Use readLines() **Returns:** a list of strings --- ### getString **Signature:** `getString() : String` **Description:** The method reads the whole input stream as one string and returns it. Using this method is unsafe if the length of the input stream is not known and may lead to an out-of-memory condition. Instead use method readN(Number). **Deprecated:** Use readString() **Returns:** a string, which represents the whole content of the InputStream **Throws:** IOException - if something went wrong while reading from the underlying stream --- ### read **Signature:** `read() : String` **Description:** Reads a single character from the stream. The method returns null if the end of the stream is reached. **Returns:** a single character in a string, or null if the end of the stream is reached --- ### read **Signature:** `read(length : Number) : String` **Description:** Reads multiple characters from the stream as string. The actual number of characters that were read can be determined from the length of the returned string. If the end of the stream is reached and no more characters can be read, the method exits with an exception. **Deprecated:** use readN(Number) instead which does not throw an exception if the stream is exhausted **Parameters:** - `length`: the number of characters to read. **Returns:** a string whose length is controlled by the length parameter. The actual number of characters that were read can be determined from the length of the returned string. **Throws:** an - exception if the stream is exhausted --- ### readLine **Signature:** `readLine() : String` **Description:** Reads the next line. **Returns:** A String containing the contents of the line, not including any line termination characters, or null if the end of the stream has been reached. --- ### readLines **Signature:** `readLines() : List` **Description:** The method reads the whole input stream, parses it and returns a list of strings. Using this method on large feeds is inherently unsafe and may lead to an out-of-memory condition. Instead use method readLine() and process one line at a time. **Returns:** a list of strings --- ### readN **Signature:** `readN(n : Number) : String` **Description:** Reads n characters from the stream as string. The actual number of characters that were read can be determined from the length of the returned string. If the end of the stream is reached and no more characters can be read, the method returns null. **Parameters:** - `n`: the number of characters to read **Returns:** a string whose maximum length is controlled by the n parameter, or null if the end of the stream is reached and no more characters can be read --- ### readString **Signature:** `readString() : String` **Description:** The method reads the whole input stream as one string and returns it. Using this method is unsafe if the length of the input stream is not known and may lead to an out-of-memory condition. Instead use method readN(Number). **Returns:** a string, which represents the whole content of the InputStream **Throws:** IOException - if something went wrong while reading from the underlying stream --- ### ready **Signature:** `ready() : boolean` **Description:** Identifies if this stream is ready to be read. **Returns:** true guarantees that the stream is ready to read without waiting for input. A false response means that the stream may or may not block to wait for input. Note that returning false does not guarantee that the next read() will block. --- ### skip **Signature:** `skip(n : Number) : void` **Description:** Skips the specified number of characters in the stream. **Parameters:** - `n`: the number of characters to skip. --- ``` -------------------------------------------------------------------------------- /docs/dw_order/ShipmentShippingModel.md: -------------------------------------------------------------------------------- ```markdown ## Package: dw.order # Class ShipmentShippingModel ## Inheritance Hierarchy - Object - dw.order.ShipmentShippingModel ## Description Instances of ShipmentShippingModel provide access to shipment-level shipping information, such as applicable and inapplicable shipping methods and shipping cost. Use ShippingMgr.getShipmentShippingModel(Shipment) to get the shipping model for a specific shipment. ## Properties ### applicableShippingMethods **Type:** Collection (Read Only) The active applicable shipping methods for the shipment related to this shipping model. A shipping method is applicable for a shipment if it does not exclude any of the products in the shipment, and does not exclude the shipment's shipping address, if this is set. Also checks that the the shipment customer belongs to an assigned customer group of the shipment (if any are assigned). ### inapplicableShippingMethods **Type:** Collection (Read Only) The active inapplicable shipping methods for the shipment related to this shipping model. A shipping method is inapplicable for a shipment if it is inapplicable for at least one product contained in the shipment, or the shipping address is excluded by the shipping method, or the shipping method is restricted to customer groups that the shipment customer is not a part of. ## Constructor Summary ## Method Summary ### getApplicableShippingMethods **Signature:** `getApplicableShippingMethods() : Collection` Returns the active applicable shipping methods for the shipment related to this shipping model. ### getApplicableShippingMethods **Signature:** `getApplicableShippingMethods(shippingAddressObj : Object) : Collection` Returns the active applicable shipping methods for the shipment related to this shipping model and the specified shipping address. ### getInapplicableShippingMethods **Signature:** `getInapplicableShippingMethods() : Collection` Returns the active inapplicable shipping methods for the shipment related to this shipping model. ### getInapplicableShippingMethods **Signature:** `getInapplicableShippingMethods(shippingAddressObj : Object) : Collection` Returns the active inapplicable shipping methods for the shipment related to this shipping model and the specified shipping address. ### getShippingCost **Signature:** `getShippingCost(shippingMethod : ShippingMethod) : ShipmentShippingCost` Returns the shipping cost object for the related shipment and the specified shipping method. ## Method Detail ## Method Details ### getApplicableShippingMethods **Signature:** `getApplicableShippingMethods() : Collection` **Description:** Returns the active applicable shipping methods for the shipment related to this shipping model. A shipping method is applicable for a shipment if it does not exclude any of the products in the shipment, and does not exclude the shipment's shipping address, if this is set. Also checks that the the shipment customer belongs to an assigned customer group of the shipment (if any are assigned). **Returns:** Applicable shipping methods for the shipment --- ### getApplicableShippingMethods **Signature:** `getApplicableShippingMethods(shippingAddressObj : Object) : Collection` **Description:** Returns the active applicable shipping methods for the shipment related to this shipping model and the specified shipping address. A shipping method is applicable if it does not exclude any of the products in the shipment, it does not exclude the specified shipping address, and the shipment customer belongs to an assigned customer group for the shipment (if any are assigned). The parameter shippingAddressObj must be a JavaScript literal with the same properties as an OrderAddress object, or alternatively a Map. For example: model.getApplicableShippingMethods ( { countryCode: "US", stateCode: "MA, custom { POBox : true } } ) This method is useful when it is needed to retrieve the list of applicable shipping methods for an address before the address is saved to the shipment. **Parameters:** - `shippingAddressObj`: A JavaScript object representing an order address, must not be null. **Returns:** Applicable shipping methods for the shipment --- ### getInapplicableShippingMethods **Signature:** `getInapplicableShippingMethods() : Collection` **Description:** Returns the active inapplicable shipping methods for the shipment related to this shipping model. A shipping method is inapplicable for a shipment if it is inapplicable for at least one product contained in the shipment, or the shipping address is excluded by the shipping method, or the shipping method is restricted to customer groups that the shipment customer is not a part of. **Returns:** Inapplicable shipping methods for the shipment --- ### getInapplicableShippingMethods **Signature:** `getInapplicableShippingMethods(shippingAddressObj : Object) : Collection` **Description:** Returns the active inapplicable shipping methods for the shipment related to this shipping model and the specified shipping address. A shipping method is inapplicable if it is inapplicable for at least one product contained in the shipment, or the specified shipping address is excluded by the shipping method, or the shipping method is restricted to customer groups that the shipment customer is not a part of. The parameter shippingAddressObj must be a JavaScript literal with the same properties as an OrderAddress object, or alternatively a Map. For example: model.getApplicableShippingMethods ( { countryCode: "US", stateCode: "MA, custom { POBox : true } } ) This method is useful when it is needed to retrieve the list of applicable shipping methods for an address before the address is saved to the shipment. **Parameters:** - `shippingAddressObj`: A JavaScript object representing an order address. **Returns:** Inapplicable shipping methods for the shipment --- ### getShippingCost **Signature:** `getShippingCost(shippingMethod : ShippingMethod) : ShipmentShippingCost` **Description:** Returns the shipping cost object for the related shipment and the specified shipping method. Shipping cost for shipments depended on the merchandise total of the shipment. The method uses the adjusted merchandise total after product and order discounts, and excluding products with product-level fixed-price shipping cost. **Parameters:** - `shippingMethod`: the shipping method to use. **Returns:** Product shipping cost --- ``` -------------------------------------------------------------------------------- /docs/dw_order/PaymentTransaction.md: -------------------------------------------------------------------------------- ```markdown ## Package: dw.order # Class PaymentTransaction ## Inheritance Hierarchy - Object - dw.object.PersistentObject - dw.object.ExtensibleObject - dw.order.PaymentTransaction ## Description The PaymentTransaction class represents a payment transaction. ## Constants ### TYPE_AUTH **Type:** String = "AUTH" Constant representing the authorization type of payment transaction. ### TYPE_AUTH_REVERSAL **Type:** String = "AUTH_REVERSAL" Constant representing the authorization reversal type of payment transaction. ### TYPE_CAPTURE **Type:** String = "CAPTURE" Constant representing the capture type of payment transaction. ### TYPE_CREDIT **Type:** String = "CREDIT" Constant representing the credit type of payment transaction. ## Properties ### accountID **Type:** String The payment service-specific account id. ### accountType **Type:** String The payment service-specific account type. ### amount **Type:** Money The amount of the transaction. ### paymentInstrument **Type:** OrderPaymentInstrument (Read Only) The payment instrument related to this payment transaction. ### paymentProcessor **Type:** PaymentProcessor The payment processor related to this payment transaction. ### transactionID **Type:** String The payment service-specific transaction id. ### type **Type:** EnumValue The value of the transaction type where the value is one of TYPE_AUTH, TYPE_AUTH_REVERSAL, TYPE_CAPTURE or TYPE_CREDIT. ## Constructor Summary ## Method Summary ### getAccountID **Signature:** `getAccountID() : String` Returns the payment service-specific account id. ### getAccountType **Signature:** `getAccountType() : String` Returns the payment service-specific account type. ### getAmount **Signature:** `getAmount() : Money` Returns the amount of the transaction. ### getPaymentInstrument **Signature:** `getPaymentInstrument() : OrderPaymentInstrument` Returns the payment instrument related to this payment transaction. ### getPaymentProcessor **Signature:** `getPaymentProcessor() : PaymentProcessor` Returns the payment processor related to this payment transaction. ### getTransactionID **Signature:** `getTransactionID() : String` Returns the payment service-specific transaction id. ### getType **Signature:** `getType() : EnumValue` Returns the value of the transaction type where the value is one of TYPE_AUTH, TYPE_AUTH_REVERSAL, TYPE_CAPTURE or TYPE_CREDIT. ### setAccountID **Signature:** `setAccountID(accountID : String) : void` Sets the payment service-specific account id. ### setAccountType **Signature:** `setAccountType(accountType : String) : void` Sets the payment service-specific account type. ### setAmount **Signature:** `setAmount(amount : Money) : void` Sets the amount of the transaction. ### setPaymentProcessor **Signature:** `setPaymentProcessor(paymentProcessor : PaymentProcessor) : void` Sets the payment processor related to this payment transaction. ### setTransactionID **Signature:** `setTransactionID(transactionID : String) : void` Sets the payment service-specific transaction id. ### setType **Signature:** `setType(type : String) : void` Sets the value of the transaction type where permissible values are TYPE_AUTH, TYPE_AUTH_REVERSAL, TYPE_CAPTURE or TYPE_CREDIT. ## Method Detail ## Method Details ### getAccountID **Signature:** `getAccountID() : String` **Description:** Returns the payment service-specific account id. **Returns:** the payment service-specific account id. --- ### getAccountType **Signature:** `getAccountType() : String` **Description:** Returns the payment service-specific account type. **Returns:** the payment service-specific account type. --- ### getAmount **Signature:** `getAmount() : Money` **Description:** Returns the amount of the transaction. **Returns:** the amount of the transaction. --- ### getPaymentInstrument **Signature:** `getPaymentInstrument() : OrderPaymentInstrument` **Description:** Returns the payment instrument related to this payment transaction. **Returns:** the order payment instrument related to this payment transaction. --- ### getPaymentProcessor **Signature:** `getPaymentProcessor() : PaymentProcessor` **Description:** Returns the payment processor related to this payment transaction. **Returns:** the payment processor related to this payment transaction. --- ### getTransactionID **Signature:** `getTransactionID() : String` **Description:** Returns the payment service-specific transaction id. **Returns:** the payment service-specific transaction id. --- ### getType **Signature:** `getType() : EnumValue` **Description:** Returns the value of the transaction type where the value is one of TYPE_AUTH, TYPE_AUTH_REVERSAL, TYPE_CAPTURE or TYPE_CREDIT. **Returns:** the value of the transaction type where the value is one of TYPE_AUTH, TYPE_AUTH_REVERSAL, TYPE_CAPTURE or TYPE_CREDIT. --- ### setAccountID **Signature:** `setAccountID(accountID : String) : void` **Description:** Sets the payment service-specific account id. **Parameters:** - `accountID`: the payment service-specific account id. --- ### setAccountType **Signature:** `setAccountType(accountType : String) : void` **Description:** Sets the payment service-specific account type. **Parameters:** - `accountType`: the payment service-specific account type. --- ### setAmount **Signature:** `setAmount(amount : Money) : void` **Description:** Sets the amount of the transaction. **Parameters:** - `amount`: the amount of the transaction. --- ### setPaymentProcessor **Signature:** `setPaymentProcessor(paymentProcessor : PaymentProcessor) : void` **Description:** Sets the payment processor related to this payment transaction. **Parameters:** - `paymentProcessor`: the payment processor related to this payment transaction. --- ### setTransactionID **Signature:** `setTransactionID(transactionID : String) : void` **Description:** Sets the payment service-specific transaction id. **Parameters:** - `transactionID`: the payment service-specific transaction id. --- ### setType **Signature:** `setType(type : String) : void` **Description:** Sets the value of the transaction type where permissible values are TYPE_AUTH, TYPE_AUTH_REVERSAL, TYPE_CAPTURE or TYPE_CREDIT. **Parameters:** - `type`: the value of the transaction type where the value is one of TYPE_AUTH, TYPE_AUTH_REVERSAL, TYPE_CAPTURE or TYPE_CREDIT. --- ``` -------------------------------------------------------------------------------- /docs/TopLevel/JSON.md: -------------------------------------------------------------------------------- ```markdown ## Package: TopLevel # Class JSON ## Inheritance Hierarchy - Object - JSON ## Description The JSON object is a single object that contains two functions, parse and stringify, that are used to parse and construct JSON texts. The JSON Data Interchange Format is described in RFC 4627. ## Constructor Summary JSON() ## Method Summary ### parse **Signature:** `static parse(json : String) : Object` The parse function parses a JSON text (a JSON formatted string) and produces an ECMAScript value. ### parse **Signature:** `static parse(json : String, reviver : Function) : Object` The parse function parses a JSON text (a JSON formatted string) and produces an ECMAScript value. ### stringify **Signature:** `static stringify(value : Object) : String` The stringify function produces a JSON formatted string that captures information from a JavaScript value. ### stringify **Signature:** `static stringify(value : Object, replacer : Object) : String` The stringify function produces a JSON formatted string that captures information from a JavaScript value. ### stringify **Signature:** `static stringify(value : Object, replacer : Object, space : Number) : String` The stringify function produces a JSON formatted string that captures information from a JavaScript value. ### stringify **Signature:** `static stringify(value : Object, replacer : Object, space : String) : String` The stringify function produces a JSON formatted string that captures information from a JavaScript value. ## Constructor Detail ## Method Detail ## Method Details ### parse **Signature:** `static parse(json : String) : Object` **Description:** The parse function parses a JSON text (a JSON formatted string) and produces an ECMAScript value. The JSON format is a restricted form of ECMAScript literal. JSON objects are realized as ECMAScript objects. JSON Arrays are realized as ECMAScript arrays. JSON strings, numbers, booleans, and null are realized as ECMAScript strings, numbers, booleans, and null. **Parameters:** - `json`: a JSON formatted string **Returns:** the object produced from the JSON string --- ### parse **Signature:** `static parse(json : String, reviver : Function) : Object` **Description:** The parse function parses a JSON text (a JSON formatted string) and produces an ECMAScript value. The JSON format is a restricted form of ECMAScript literal. JSON objects are realized as ECMAScript objects. JSON Arrays are realized as ECMAScript arrays. JSON strings, numbers, booleans, and null are realized as ECMAScript strings, numbers, booleans, and null. The optional reviver parameter is a function that takes two parameters, (key, value). It can filter and transform the results. It is called with each of the key/value pairs produced by the parse, and its return value is used instead of the original value. If it returns what it received, the structure is not modified. If it returns undefined then the member is deleted from the result. **Parameters:** - `json`: a JSON formatted string - `reviver`: a function, which is called with each key, value pair during parsing **Returns:** the object produced from the JSON string --- ### stringify **Signature:** `static stringify(value : Object) : String` **Description:** The stringify function produces a JSON formatted string that captures information from a JavaScript value. The value parameter is a JavaScript value is usually an object or array, although it can also be a string, boolean, number or null. Note: Stringifying API objects is not supported. **Parameters:** - `value`: the value which is stringified **Returns:** the JSON string --- ### stringify **Signature:** `static stringify(value : Object, replacer : Object) : String` **Description:** The stringify function produces a JSON formatted string that captures information from a JavaScript value. The value parameter is a JavaScript value is usually an object or array, although it can also be a string, boolean, number or null. The optional replacer parameter is either a function that alters the way objects and arrays are stringified, or an array of strings that acts as an allowlist for selecting the keys that will be stringified. Note: Stringifying API objects is not supported. **Parameters:** - `value`: the value which is stringified - `replacer`: either a function, which is called with a key and value as parameter, or an array with an allowlist **Returns:** the JSON string --- ### stringify **Signature:** `static stringify(value : Object, replacer : Object, space : Number) : String` **Description:** The stringify function produces a JSON formatted string that captures information from a JavaScript value. The value parameter is a JavaScript value is usually an object or array, although it can also be a string, boolean, number or null. The optional replacer parameter is either a function that alters the way objects and arrays are stringified, or an array of strings that acts as an allowlist for selecting the keys that will be stringified. The optional space parameter is a string or number that allows the result to have white space injected into it to improve human readability. Note: Stringifying API objects is not supported. **Parameters:** - `value`: the value which is stringified - `replacer`: either a function, which is called with a key and value as parameter, or an array with an allowlist - `space`: the number of space for indenting **Returns:** the JSON string --- ### stringify **Signature:** `static stringify(value : Object, replacer : Object, space : String) : String` **Description:** The stringify function produces a JSON formatted string that captures information from a JavaScript value. The value parameter is a JavaScript value is usually an object or array, although it can also be a string, boolean, number or null. The optional replacer parameter is either a function that alters the way objects and arrays are stringified, or an array of strings that acts as an allowlist for selecting the keys that will be stringified. The optional space parameter is a string or number that allows the result to have white space injected into it to improve human readability. Note: Stringifying API objects is not supported. **Parameters:** - `value`: the value which is stringified - `replacer`: either a function, which is called with a key and value as parameter, or an array with an allowlist - `space`: a string for indentation **Returns:** the JSON string --- ``` -------------------------------------------------------------------------------- /docs/dw_order/PaymentCard.md: -------------------------------------------------------------------------------- ```markdown ## Package: dw.order # Class PaymentCard ## Inheritance Hierarchy - Object - dw.object.PersistentObject - dw.object.ExtensibleObject - dw.order.PaymentCard ## Description Represents payment cards and provides methods to access the payment card attributes and status. Note: this class handles sensitive financial and card holder data. Pay special attention to PCI DSS v3. requirements 1, 3, 7, and 9. ## Properties ### active **Type:** boolean (Read Only) Returns 'true' if payment card is active (enabled), otherwise 'false' is returned. ### cardType **Type:** String (Read Only) The unique card type of the payment card. ### description **Type:** MarkupText (Read Only) The description of the payment card. ### image **Type:** MediaFile (Read Only) The reference to the payment card image. ### name **Type:** String (Read Only) The name of the payment card. ## Constructor Summary ## Method Summary ### getCardType **Signature:** `getCardType() : String` Returns the unique card type of the payment card. ### getDescription **Signature:** `getDescription() : MarkupText` Returns the description of the payment card. ### getImage **Signature:** `getImage() : MediaFile` Returns the reference to the payment card image. ### getName **Signature:** `getName() : String` Returns the name of the payment card. ### isActive **Signature:** `isActive() : boolean` Returns 'true' if payment card is active (enabled), otherwise 'false' is returned. ### isApplicable **Signature:** `isApplicable(customer : Customer, countryCode : String, paymentAmount : Number) : boolean` Returns 'true' if this payment card is applicable for the specified customer, country and payment amount and the session currency. ### verify **Signature:** `verify(expiresMonth : Number, expiresYear : Number, cardNumber : String) : Status` Verify the card against the provided values. ### verify **Signature:** `verify(expiresMonth : Number, expiresYear : Number, cardNumber : String, csc : String) : Status` Verify the card against the provided values. ## Method Detail ## Method Details ### getCardType **Signature:** `getCardType() : String` **Description:** Returns the unique card type of the payment card. **Returns:** cardType of the payment card. --- ### getDescription **Signature:** `getDescription() : MarkupText` **Description:** Returns the description of the payment card. **Returns:** Description of the payment card. --- ### getImage **Signature:** `getImage() : MediaFile` **Description:** Returns the reference to the payment card image. **Returns:** Image of the payment card. --- ### getName **Signature:** `getName() : String` **Description:** Returns the name of the payment card. **Returns:** Name of the payment card. --- ### isActive **Signature:** `isActive() : boolean` **Description:** Returns 'true' if payment card is active (enabled), otherwise 'false' is returned. **Returns:** true if payment card is active, otherwise false. --- ### isApplicable **Signature:** `isApplicable(customer : Customer, countryCode : String, paymentAmount : Number) : boolean` **Description:** Returns 'true' if this payment card is applicable for the specified customer, country and payment amount and the session currency. The payment card is applicable if the card is restricted by customer group, and at least one of the groups of the specified customer is assigned to the card the card is restricted by billing country, and the specified country code is assigned to the card the method is restricted by payment amount for the session currency, and the specified payment amount is within the limits of the min/max payment amount defined for the method and the session currency the method is restricted by session currency, and the session currency code is assigned to the method All parameters are optional, and if not specified, the respective restriction won't be validated. For example, if a card is restricted by billing country, but no country code is specified, this card will be returned, unless it is filtered out by customer group or payment amount. **Parameters:** - `customer`: Customer or null - `countryCode`: Billing country code or null - `paymentAmount`: Payment amount or null **Returns:** true if payment card is applicable, false otherwise --- ### verify **Signature:** `verify(expiresMonth : Number, expiresYear : Number, cardNumber : String) : Status` **Description:** Verify the card against the provided values. This method is equivalent to verify(Number, Number, String, String) but omits verification of the card security code. If the verification fails the resulting Status will hold up to 2 error items each with a code: PaymentStatusCodes.CREDITCARD_INVALID_EXPIRATION_DATE - the expiresMonth and expiresYear do not describe a month in the future, or describe an invalid month outside the range 1-12. PaymentStatusCodes.CREDITCARD_INVALID_CARD_NUMBER - the cardNumber does not verify against one or more configured checks, which may include the Luhn checksum, accepted number lengths, or accepted number prefixes. **Parameters:** - `expiresMonth`: expiration month as integer, 1 (January) to 12 (December) - `expiresYear`: expiration year as integer, e.g. 2025 - `cardNumber`: card number, a string containing digital characters **Returns:** status indicating result --- ### verify **Signature:** `verify(expiresMonth : Number, expiresYear : Number, cardNumber : String, csc : String) : Status` **Description:** Verify the card against the provided values. If the verification fails the resulting Status will hold up to 3 error items with these codes: PaymentStatusCodes.CREDITCARD_INVALID_EXPIRATION_DATE - the expiresMonth and expiresYear do not describe a month in the future, or describe an invalid month outside the range 1-12. PaymentStatusCodes.CREDITCARD_INVALID_CARD_NUMBER - the cardNumber does not verify against one or more configured checks, which may include the Luhn checksum, accepted number lengths, or accepted number prefixes. PaymentStatusCodes.CREDITCARD_INVALID_SECURITY_CODE - the card security code does not verify against the configured accepted length. **Parameters:** - `expiresMonth`: expiration month as integer, 1 (January) to 12 (December) - `expiresYear`: expiration year as integer, e.g. 2025 - `cardNumber`: card number, a string containing digital characters - `csc`: card security code, a string containing digital characters **Returns:** status indicating result --- ``` -------------------------------------------------------------------------------- /src/config/configuration-factory.ts: -------------------------------------------------------------------------------- ```typescript /** * Configuration factory for SFCC MCP Server * * Centralized configuration management with validation and defaults. * This factory creates SFCCConfig objects from various sources while * leveraging secure file loading from the config module. */ import { existsSync } from 'fs'; import { resolve } from 'path'; import { SFCCConfig, DwJsonConfig } from '../types/types.js'; import { loadSecureDwJson } from './dw-json-loader.js'; export class ConfigurationFactory { /** * Create configuration from various sources with proper validation */ static create(options: { dwJsonPath?: string; hostname?: string; username?: string; password?: string; clientId?: string; clientSecret?: string; siteId?: string; }): SFCCConfig { let config: SFCCConfig; // Load from dw.json if path provided if (options.dwJsonPath) { const dwConfig = this.loadFromDwJson(options.dwJsonPath); config = this.mapDwJsonToConfig(dwConfig); } else { // Create from provided options config = { hostname: options.hostname ?? '', username: options.username, password: options.password, clientId: options.clientId, clientSecret: options.clientSecret, siteId: options.siteId, }; } // Override with any provided options (command-line args take precedence) if (options.hostname) {config.hostname = options.hostname;} if (options.username) {config.username = options.username;} if (options.password) {config.password = options.password;} if (options.clientId) {config.clientId = options.clientId;} if (options.clientSecret) {config.clientSecret = options.clientSecret;} if (options.siteId) {config.siteId = options.siteId;} this.validate(config); return config; } /** * Load configuration from dw.json file using secure file loading * * @param dwJsonPath - Path to the dw.json file * @returns Parsed dw.json configuration * @throws Error if file cannot be loaded or is invalid */ private static loadFromDwJson(dwJsonPath: string): DwJsonConfig { const resolvedPath = resolve(dwJsonPath); if (!existsSync(resolvedPath)) { throw new Error(`dw.json file not found at: ${resolvedPath}`); } // Use the secure loading function from dw-json-loader.ts // This ensures all security validations are applied consistently return loadSecureDwJson(dwJsonPath); } /** * Map dw.json structure to SFCCConfig * * Transforms the dw.json format (with kebab-case properties) to the * internal SFCCConfig format (with camelCase properties). * * @param dwConfig - The parsed dw.json configuration * @returns Mapped SFCCConfig object */ static mapDwJsonToConfig(dwConfig: DwJsonConfig): SFCCConfig { const config: SFCCConfig = { hostname: dwConfig.hostname, username: dwConfig.username, password: dwConfig.password, }; // Map OAuth credentials if present if (dwConfig['client-id'] && dwConfig['client-secret']) { config.clientId = dwConfig['client-id']; config.clientSecret = dwConfig['client-secret']; } // Map site ID if present if (dwConfig['site-id']) { config.siteId = dwConfig['site-id']; } return config; } /** * Validate configuration for different operating modes * * This validation supports both documentation-only mode (no credentials required) * and full mode (credentials required for API access). * * @param config - The configuration to validate * @throws Error if configuration is invalid for any supported mode */ private static validate(config: SFCCConfig): void { const hasBasicAuth = config.username && config.password; const hasOAuth = config.clientId && config.clientSecret; const hasHostname = config.hostname && config.hostname.trim() !== ''; // Allow local mode if no credentials or hostname are provided if (!hasBasicAuth && !hasOAuth && !hasHostname) { // Local mode - only class documentation available return; } // If hostname is provided, require credentials if (hasHostname && !hasBasicAuth && !hasOAuth) { throw new Error( 'When hostname is provided, either username/password or OAuth credentials (clientId/clientSecret) must be provided', ); } // Additional hostname validation if provided if (hasHostname) { const trimmedHostname = config.hostname!.trim(); if (!trimmedHostname.match(/^[a-zA-Z0-9.-]+(?::[0-9]+)?$/)) { throw new Error('Invalid hostname format in configuration'); } } } /** * Check if configuration supports specific features * * This method analyzes the provided configuration to determine what * capabilities are available based on the credentials and hostname provided. * * @param config - The configuration to analyze * @returns Object describing available capabilities */ static getCapabilities(config: SFCCConfig): { canAccessLogs: boolean; canAccessOCAPI: boolean; canAccessWebDAV: boolean; canGenerateCartridges: boolean; isLocalMode: boolean; } { // WebDAV/Logs can work with either basic auth OR OAuth credentials const hasWebDAVCredentials = !!(config.username && config.password) || !!(config.clientId && config.clientSecret); // OCAPI specifically requires OAuth credentials const hasOAuthCredentials = !!(config.clientId && config.clientSecret); // Local mode when no hostname or credentials are provided const hasHostname = !!(config.hostname && config.hostname.trim() !== ''); const isLocalMode = !hasHostname && !hasWebDAVCredentials; return { canAccessLogs: hasWebDAVCredentials && hasHostname, canAccessOCAPI: hasOAuthCredentials && hasHostname, canAccessWebDAV: hasWebDAVCredentials && hasHostname, canGenerateCartridges: true, // Always available since it's a local file operation isLocalMode, }; } /** * Create a configuration for local development mode * * This creates a minimal configuration that only provides access to * documentation and best practices without requiring any SFCC credentials. * * @returns Configuration for local/documentation-only mode */ static createLocalMode(): SFCCConfig { return { hostname: '', username: undefined, password: undefined, clientId: undefined, clientSecret: undefined, siteId: undefined, }; } } ``` -------------------------------------------------------------------------------- /docs/sfra/querystring.md: -------------------------------------------------------------------------------- ```markdown # Class QueryString ## Inheritance Hierarchy - Object - sfra.models.QueryString ## Description The SFRA QueryString class is a specialized utility for parsing and managing URL query string parameters in SFCC applications. This class provides enhanced functionality beyond basic query string parsing by handling SFCC-specific parameter formats including product variants (`dwvar_`), product options (`dwopt_`), and search preferences (`pref`). The QueryString class automatically organizes these parameters into structured objects, handles URL encoding/decoding, manages duplicate parameters as arrays, and provides serialization back to query string format. It serves as the primary interface for working with URL parameters in SFRA controllers and templates. ## Properties ### variables **Type:** Object Object containing product variant information parsed from `dwvar_` parameters. ### options **Type:** Array Array of product option objects parsed from `dwopt_` parameters. ### preferences **Type:** Object Object containing search preference filters parsed from `pref` parameters. ### [parameterName] **Type:** String | Array Dynamic properties containing standard query parameters. Duplicate parameters are automatically converted to arrays. ## Constructor Summary ### QueryString **Signature:** `QueryString(raw)` Creates a new QueryString object by parsing the provided raw query string. **Parameters:** - `raw` (String) - Raw query string to parse ## Method Summary ### toString **Signature:** `toString() : String` Serializes the QueryString object back to a URL-encoded query string format. ## Constructor Detail ### QueryString **Signature:** `QueryString(raw)` **Description:** Parses a raw query string and organizes parameters into structured objects. Handles SFCC-specific parameter formats and automatically processes URL encoding. **Parameters:** - `raw` (String) - The raw query string to parse, may include the leading `?` **Processing Logic:** - Extracts and parses `dwvar_` parameters into the `variables` object - Extracts and parses `dwopt_` parameters into the `options` array - Extracts and parses `pref` parameters into the `preferences` object - Handles duplicate parameters by converting them to arrays - Performs URL decoding on all parameter values ## Method Detail ### toString **Signature:** `toString() : String` **Description:** Converts the QueryString object back to a properly formatted and URL-encoded query string. Maintains the original SFCC parameter format conventions. **Returns:** String containing the URL-encoded query string without the leading `?`. **Output Format:** - `dwvar_` parameters for product variants - `dwopt_` parameters for product options - `prefn`/`prefv`/`prefmin`/`prefmax` parameters for search preferences - Standard parameters for all other values - Results are sorted alphabetically ## Property Details ### variables **Type:** Object **Description:** Contains product variant information parsed from `dwvar_` prefixed parameters. Each variant is represented as: ```javascript { "variantAttributeName": { id: "productId", value: "selectedVariantValue" } } ``` **Example:** ```javascript // From: dwvar_123456_color=Red&dwvar_123456_size=Large variables: { "color": { id: "123456", value: "Red" }, "size": { id: "123456", value: "Large" } } ``` ### options **Type:** Array **Description:** Contains product option selections parsed from `dwopt_` prefixed parameters. Each option is represented as: ```javascript { optionId: "optionIdentifier", selectedValueId: "selectedOptionValue", productId: "associatedProductId" } ``` **Example:** ```javascript // From: dwopt_123456_warranty=extended&dwopt_123456_installation=yes options: [ { optionId: "warranty", selectedValueId: "extended", productId: "123456" }, { optionId: "installation", selectedValueId: "yes", productId: "123456" } ] ``` ### preferences **Type:** Object **Description:** Contains search refinement preferences parsed from `pref` prefixed parameters. Supports both single values and min/max ranges: **Single Value Format:** ```javascript { "attributeName": "value" } ``` **Range Value Format:** ```javascript { "attributeName": { min: "minimumValue", max: "maximumValue" } } ``` **Example:** ```javascript // From: prefn1=color&prefv1=Blue&prefn2=price&prefmin2=10&prefmax2=50 preferences: { "color": "Blue", "price": { min: "10", max: "50" } } ``` ## Parameter Handling Details ### SFCC-Specific Parameters **Product Variants (`dwvar_`):** - Format: `dwvar_{productId}_{variantAttribute}={value}` - Underscores in product IDs are encoded as double underscores (`__`) - Parsed into the `variables` object with product ID and attribute mappings **Product Options (`dwopt_`):** - Format: `dwopt_{productId}_{optionId}={selectedValueId}` - Underscores in product IDs are encoded as double underscores (`__`) - Parsed into the `options` array with structured option data **Search Preferences (`pref`):** - Single values: `prefn{index}={name}&prefv{index}={value}` - Range values: `prefn{index}={name}&prefmin{index}={min}&prefmax{index}={max}` - Parsed into the `preferences` object with appropriate structure ### Standard Parameters **Regular Query Parameters:** - Standard URL parameters are stored as properties on the QueryString object - Duplicate parameters are automatically converted to arrays - All values are URL decoded ### URL Encoding Handling **Automatic Processing:** - Input parameters are automatically URL decoded during parsing - Output via `toString()` is automatically URL encoded - Spaces are handled correctly (+ symbols converted to %20) - Special characters are properly encoded/decoded ## Usage Examples ### Basic Parsing ```javascript var qs = new QueryString('?color=red&size=large&category=shoes'); // qs.color === 'red' // qs.size === 'large' // qs.category === 'shoes' ``` ### Product Variants ```javascript var qs = new QueryString('?dwvar_123456_color=Blue&dwvar_123456_size=Medium'); // qs.variables.color.id === '123456' // qs.variables.color.value === 'Blue' ``` ### Search Preferences ```javascript var qs = new QueryString('?prefn1=color&prefv1=Red&prefn2=price&prefmin2=10&prefmax2=100'); // qs.preferences.color === 'Red' // qs.preferences.price.min === '10' // qs.preferences.price.max === '100' ``` ### Serialization ```javascript var qs = new QueryString('?color=red&size=large'); qs.brand = 'nike'; var newQuery = qs.toString(); // 'brand=nike&color=red&size=large' ``` --- ``` -------------------------------------------------------------------------------- /docs/dw_order/TaxMgr.md: -------------------------------------------------------------------------------- ```markdown ## Package: dw.order # Class TaxMgr ## Inheritance Hierarchy - Object - dw.order.TaxMgr ## Description Provides methods to access the tax table. ## Constants ### TAX_POLICY_GROSS **Type:** Number = 0 Constant representing the gross taxation policy. ### TAX_POLICY_NET **Type:** Number = 1 Constant representing the net taxation policy. ## Properties ### customRateTaxClassID **Type:** String (Read Only) The ID of the tax class that represents items with a custom tax rate. The standard order calculation process assumes that such line items are initialized with a tax rate and a being ignored during the tax rate lookup sequence of the calculation process. Note that this tax class does not appear in the Business Manager tax module. ### defaultTaxClassID **Type:** String (Read Only) The ID of the default tax class defined for the site. This class might be used in case a product or service does not define a tax class. If no default tax class is defined, the method returns null. ### defaultTaxJurisdictionID **Type:** String (Read Only) The ID of the default tax jurisdiction defined for the site. This jurisdiction might be used in case no jurisdiction is defined for a specific address. If no default tax jurisdiction is defined, this method returns null. ### taxationPolicy **Type:** Number (Read Only) The taxation policy (net/gross) configured for the current site. ### taxExemptTaxClassID **Type:** String (Read Only) The ID of the tax class that represents tax exempt items. The tax manager will return a tax rate of 0.0 for this tax class. Note that this tax class does not appear in the Business Manager tax module. ## Constructor Summary ## Method Summary ### applyExternalTax **Signature:** `static applyExternalTax(basket : Basket) : void` Applies externally set tax rates to the given Basket. ### getCustomRateTaxClassID **Signature:** `static getCustomRateTaxClassID() : String` Returns the ID of the tax class that represents items with a custom tax rate. ### getDefaultTaxClassID **Signature:** `static getDefaultTaxClassID() : String` Returns the ID of the default tax class defined for the site. ### getDefaultTaxJurisdictionID **Signature:** `static getDefaultTaxJurisdictionID() : String` Returns the ID of the default tax jurisdiction defined for the site. ### getTaxationPolicy **Signature:** `static getTaxationPolicy() : Number` Returns the taxation policy (net/gross) configured for the current site. ### getTaxExemptTaxClassID **Signature:** `static getTaxExemptTaxClassID() : String` Returns the ID of the tax class that represents tax exempt items. ### getTaxJurisdictionID **Signature:** `static getTaxJurisdictionID(location : ShippingLocation) : String` Returns the ID of the tax jurisdiction for the specified address. ### getTaxRate **Signature:** `static getTaxRate(taxClassID : String, taxJurisdictionID : String) : Number` Returns the tax rate defined for the specified combination of tax class and tax jurisdiction. ## Method Detail ## Method Details ### applyExternalTax **Signature:** `static applyExternalTax(basket : Basket) : void` **Description:** Applies externally set tax rates to the given Basket. Only use when LineItemCtnr.isExternallyTaxed() returns true. Note: a basket can only be created in EXTERNAL tax mode using SCAPI. Typical usage in tax calculation: var TaxMgr = require('dw/order/TaxMgr'); calculateTaxes: function () { Basket basket = BasketMgr.getCurrentBasket(); if ( basket.isExternallyTaxed() ) { TaxMgr.applyExternalTaxation( basket ); } else { // calculation with tax tables or customization } } **Parameters:** - `basket`: apply external taxation to this basket --- ### getCustomRateTaxClassID **Signature:** `static getCustomRateTaxClassID() : String` **Description:** Returns the ID of the tax class that represents items with a custom tax rate. The standard order calculation process assumes that such line items are initialized with a tax rate and a being ignored during the tax rate lookup sequence of the calculation process. Note that this tax class does not appear in the Business Manager tax module. --- ### getDefaultTaxClassID **Signature:** `static getDefaultTaxClassID() : String` **Description:** Returns the ID of the default tax class defined for the site. This class might be used in case a product or service does not define a tax class. If no default tax class is defined, the method returns null. **Returns:** the ID of the default tax class defined for the site or null. --- ### getDefaultTaxJurisdictionID **Signature:** `static getDefaultTaxJurisdictionID() : String` **Description:** Returns the ID of the default tax jurisdiction defined for the site. This jurisdiction might be used in case no jurisdiction is defined for a specific address. If no default tax jurisdiction is defined, this method returns null. **Returns:** the ID of the default tax jurisdiction defined for the site or null. --- ### getTaxationPolicy **Signature:** `static getTaxationPolicy() : Number` **Description:** Returns the taxation policy (net/gross) configured for the current site. **Returns:** Taxation policy configured for current site **See Also:** TAX_POLICY_GROSS TAX_POLICY_NET --- ### getTaxExemptTaxClassID **Signature:** `static getTaxExemptTaxClassID() : String` **Description:** Returns the ID of the tax class that represents tax exempt items. The tax manager will return a tax rate of 0.0 for this tax class. Note that this tax class does not appear in the Business Manager tax module. --- ### getTaxJurisdictionID **Signature:** `static getTaxJurisdictionID(location : ShippingLocation) : String` **Description:** Returns the ID of the tax jurisdiction for the specified address. If no tax jurisdiction defined for the site matches the specified address, this method returns null. **Parameters:** - `location`: The shipping location **Returns:** the ID of the tax jurisdiction for the specified address or null. --- ### getTaxRate **Signature:** `static getTaxRate(taxClassID : String, taxJurisdictionID : String) : Number` **Description:** Returns the tax rate defined for the specified combination of tax class and tax jurisdiction. Method returns null if no tax rate is defined. Method returns 0.0 of 'nontaxable' tax rate is specified (see method 'getNontaxableTaxClassID'. **Parameters:** - `taxClassID`: ID of the tax class - `taxJurisdictionID`: ID of tax jusrisdiction **Returns:** the tax rate defined for the specified combination of tax class and tax jurisdiction. --- ``` -------------------------------------------------------------------------------- /docs/dw_extensions.payments/SalesforcePaymentIntent.md: -------------------------------------------------------------------------------- ```markdown ## Package: dw.extensions.payments # Class SalesforcePaymentIntent ## Inheritance Hierarchy - Object - dw.extensions.payments.SalesforcePaymentIntent ## Description Salesforce Payments representation of a payment intent object. See Salesforce Payments documentation for how to gain access and configure it for use on your sites. A payment intent is automatically created when a shopper is ready to pay for items in their basket. It becomes confirmed when the shopper provides information to the payment provider that is acceptable to authorize payment for a given amount. Once that information has been provided it becomes available as the payment method associated with the payment intent. ## Constants ### SETUP_FUTURE_USAGE_OFF_SESSION **Type:** String = "off_session" Represents the payment method setup future usage is off session. ### SETUP_FUTURE_USAGE_ON_SESSION **Type:** String = "on_session" Represents the payment method setup future usage is on session. ## Properties ### amount **Type:** Money (Read Only) The amount of this payment intent. ### cancelable **Type:** boolean (Read Only) Returns true if this payment intent has a status which indicates it can be canceled, or false if its status does not indicate it can be canceled. ### clientSecret **Type:** String (Read Only) The client secret of this payment intent. ### confirmed **Type:** boolean (Read Only) Returns true if this payment intent has been confirmed, or false if not. ### ID **Type:** String (Read Only) The identifier of this payment intent. ### paymentMethod **Type:** SalesforcePaymentMethod (Read Only) The payment method for this payment intent, or null if none has been established. ### refundable **Type:** boolean (Read Only) Returns true if this payment intent has a status and other state which indicate it can be refunded, or false if it cannot be refunded. ### setupFutureUsage **Type:** String (Read Only) Returns SETUP_FUTURE_USAGE_OFF_SESSION or SETUP_FUTURE_USAGE_ON_SESSION to indicate how the payment intent can be used in the future or returns null if future usage is not set up. ## Constructor Summary ## Method Summary ### getAmount **Signature:** `getAmount() : Money` Returns the amount of this payment intent. ### getClientSecret **Signature:** `getClientSecret() : String` Returns the client secret of this payment intent. ### getID **Signature:** `getID() : String` Returns the identifier of this payment intent. ### getPaymentInstrument **Signature:** `getPaymentInstrument(basket : Basket) : OrderPaymentInstrument` Returns the payment instrument for this payment intent in the given basket, or null if the given basket has none. ### getPaymentInstrument **Signature:** `getPaymentInstrument(order : Order) : OrderPaymentInstrument` Returns the payment instrument for this payment intent in the given order, or null if the given order has none. ### getPaymentMethod **Signature:** `getPaymentMethod() : SalesforcePaymentMethod` Returns the payment method for this payment intent, or null if none has been established. ### getSetupFutureUsage **Signature:** `getSetupFutureUsage() : String` Returns SETUP_FUTURE_USAGE_OFF_SESSION or SETUP_FUTURE_USAGE_ON_SESSION to indicate how the payment intent can be used in the future or returns null if future usage is not set up. ### isCancelable **Signature:** `isCancelable() : boolean` Returns true if this payment intent has a status which indicates it can be canceled, or false if its status does not indicate it can be canceled. ### isConfirmed **Signature:** `isConfirmed() : boolean` Returns true if this payment intent has been confirmed, or false if not. ### isRefundable **Signature:** `isRefundable() : boolean` Returns true if this payment intent has a status and other state which indicate it can be refunded, or false if it cannot be refunded. ## Method Detail ## Method Details ### getAmount **Signature:** `getAmount() : Money` **Description:** Returns the amount of this payment intent. **Returns:** payment intent amount --- ### getClientSecret **Signature:** `getClientSecret() : String` **Description:** Returns the client secret of this payment intent. **Returns:** payment intent client secret --- ### getID **Signature:** `getID() : String` **Description:** Returns the identifier of this payment intent. **Returns:** payment intent identifier --- ### getPaymentInstrument **Signature:** `getPaymentInstrument(basket : Basket) : OrderPaymentInstrument` **Description:** Returns the payment instrument for this payment intent in the given basket, or null if the given basket has none. **Parameters:** - `basket`: basket **Returns:** basket payment instrument --- ### getPaymentInstrument **Signature:** `getPaymentInstrument(order : Order) : OrderPaymentInstrument` **Description:** Returns the payment instrument for this payment intent in the given order, or null if the given order has none. **Parameters:** - `order`: order **Returns:** order payment instrument --- ### getPaymentMethod **Signature:** `getPaymentMethod() : SalesforcePaymentMethod` **Description:** Returns the payment method for this payment intent, or null if none has been established. **Returns:** payment method --- ### getSetupFutureUsage **Signature:** `getSetupFutureUsage() : String` **Description:** Returns SETUP_FUTURE_USAGE_OFF_SESSION or SETUP_FUTURE_USAGE_ON_SESSION to indicate how the payment intent can be used in the future or returns null if future usage is not set up. **Returns:** setup future usage or null if future usage is not set up **See Also:** SalesforcePaymentRequest.setSetupFutureUsage(Boolean) SETUP_FUTURE_USAGE_OFF_SESSION SETUP_FUTURE_USAGE_ON_SESSION --- ### isCancelable **Signature:** `isCancelable() : boolean` **Description:** Returns true if this payment intent has a status which indicates it can be canceled, or false if its status does not indicate it can be canceled. **Returns:** true if this payment intent has a status which indicates it can be canceled --- ### isConfirmed **Signature:** `isConfirmed() : boolean` **Description:** Returns true if this payment intent has been confirmed, or false if not. **Returns:** true if this payment intent has been confirmed --- ### isRefundable **Signature:** `isRefundable() : boolean` **Description:** Returns true if this payment intent has a status and other state which indicate it can be refunded, or false if it cannot be refunded. **Returns:** true if this payment intent has a status and other state which indicate it can be refunded --- ``` -------------------------------------------------------------------------------- /docs/dw_catalog/ProductOptionModel.md: -------------------------------------------------------------------------------- ```markdown ## Package: dw.catalog # Class ProductOptionModel ## Inheritance Hierarchy - Object - dw.catalog.ProductOptionModel ## Description This class represents the option model of a specific product and for a specific currency. It provides accessor methods to the configured options and the values of those options. It has also methods to set a specific selection of option values. ## Properties ### options **Type:** Collection (Read Only) The collection of product options. ## Constructor Summary ## Method Summary ### getOption **Signature:** `getOption(optionID : String) : ProductOption` Returns the product option for the specified ID. ### getOptions **Signature:** `getOptions() : Collection` Returns the collection of product options. ### getOptionValue **Signature:** `getOptionValue(option : ProductOption, valueID : String) : ProductOptionValue` Returns the product option value object for the passed value id and in the context of the passed option. ### getOptionValues **Signature:** `getOptionValues(option : ProductOption) : Collection` Returns a collection of product option values for the specified product option. ### getPrice **Signature:** `getPrice(optionValue : ProductOptionValue) : Money` Returns the effective price of the specified option value. ### getSelectedOptionValue **Signature:** `getSelectedOptionValue(option : ProductOption) : ProductOptionValue` Returns the selected value for the specified product option. ### isSelectedOptionValue **Signature:** `isSelectedOptionValue(option : ProductOption, value : ProductOptionValue) : boolean` Returns true if the specified option value is the one currently selected, false otherwise. ### setSelectedOptionValue **Signature:** `setSelectedOptionValue(option : ProductOption, value : ProductOptionValue) : void` Updates the selection of the specified option based on the specified value. ### url **Signature:** `url(action : String, varOptionAndValues : Object...) : URL` Returns a URL that can be used to select one or more option values. ### urlSelectOptionValue **Signature:** `urlSelectOptionValue(action : String, option : ProductOption, value : ProductOptionValue) : String` Returns an URL that can be used to select a specific value of a specific option. ## Method Detail ## Method Details ### getOption **Signature:** `getOption(optionID : String) : ProductOption` **Description:** Returns the product option for the specified ID. **Parameters:** - `optionID`: the product option identifier. **Returns:** the product option for the specified ID. --- ### getOptions **Signature:** `getOptions() : Collection` **Description:** Returns the collection of product options. **Returns:** Collection of Product Options. --- ### getOptionValue **Signature:** `getOptionValue(option : ProductOption, valueID : String) : ProductOptionValue` **Description:** Returns the product option value object for the passed value id and in the context of the passed option. **Parameters:** - `option`: The option to get the specified value for. - `valueID`: The id of the value to retrieve **Returns:** a value for the specified product option and value id --- ### getOptionValues **Signature:** `getOptionValues(option : ProductOption) : Collection` **Description:** Returns a collection of product option values for the specified product option. **Parameters:** - `option`: the option for which we want to extract the collection of product option values. **Returns:** a collection of product option values for the specified product option. --- ### getPrice **Signature:** `getPrice(optionValue : ProductOptionValue) : Money` **Description:** Returns the effective price of the specified option value. **Parameters:** - `optionValue`: the product option value to use. **Returns:** the effective price of the specified option value. --- ### getSelectedOptionValue **Signature:** `getSelectedOptionValue(option : ProductOption) : ProductOptionValue` **Description:** Returns the selected value for the specified product option. If no option values was set as selected option explicitly, the method returns the default option value for this option. **Parameters:** - `option`: The option to get the selected value for. **Returns:** a selected value for the specified product option. --- ### isSelectedOptionValue **Signature:** `isSelectedOptionValue(option : ProductOption, value : ProductOptionValue) : boolean` **Description:** Returns true if the specified option value is the one currently selected, false otherwise. **Parameters:** - `option`: the product option. - `value`: the product option value. **Returns:** true if the specified option value is the one currently selected, false otherwise. --- ### setSelectedOptionValue **Signature:** `setSelectedOptionValue(option : ProductOption, value : ProductOptionValue) : void` **Description:** Updates the selection of the specified option based on the specified value. **Parameters:** - `option`: the option to update. - `value`: the value to use when updating the product option. --- ### url **Signature:** `url(action : String, varOptionAndValues : Object...) : URL` **Description:** Returns a URL that can be used to select one or more option values. The optional varOptionAndValues argument can be empty, or can contain one or more option / value pairs. This variable list must be even in length, with options and values alternating. If the list is odd in length, the last argument will be ignored. Options can be specified as instances of ProductOption, or String option ID. Values can be specified as instances of ProductOptionValue or as strings representing the value ID. If a parameter is invalid, then the parameter pair is not included in the generated URL. The returned URL will contain options and values already selected in the product option model, as well as options and values specified as method parameters. This includes option values explicitly selected and implicitly selected by default. **Parameters:** - `action`: The pipeline action, must not be null. - `varOptionAndValues`: Variable length list of options and values. **Returns:** The constructed URL. --- ### urlSelectOptionValue **Signature:** `urlSelectOptionValue(action : String, option : ProductOption, value : ProductOptionValue) : String` **Description:** Returns an URL that can be used to select a specific value of a specific option. **Parameters:** - `action`: the action to use. - `option`: the option to use when constructing the URL. - `value`: the value to use when constructing the URL. **Returns:** The constructed URL as string. --- ``` -------------------------------------------------------------------------------- /tests/mcp/yaml/get-system-object-definition.full-mode.test.mcp.yml: -------------------------------------------------------------------------------- ```yaml # ================================================================================== # SFCC MCP Server - get_system_object_definition Tool YAML Tests (Full Mode) # Streamlined smoke testing and declarative validation for core functionality # Complex business logic, edge cases, and workflows are covered in programmatic tests # # Quick Test Commands: # aegis "tests/mcp/yaml/get-system-object-definition.full-mode.test.mcp.yml" --config "aegis.config.with-dw.json" --verbose # aegis query get_system_object_definition '{"objectType": "Product"}' --config "aegis.config.with-dw.json" # ================================================================================== description: "get_system_object_definition tool smoke tests - Basic functionality validation" tests: # ================================================================================== # TOOL AVAILABILITY VALIDATION # ================================================================================== - it: "should have get_system_object_definition tool available with proper schema" request: jsonrpc: "2.0" id: "tool-available" method: "tools/list" params: {} expect: response: jsonrpc: "2.0" id: "tool-available" result: tools: match:arrayElements: match:partial: name: "match:type:string" description: "match:type:string" match:extractField: "tools.*.name" value: "match:arrayContains:get_system_object_definition" stderr: "toBeEmpty" # ================================================================================== # CORE FUNCTIONALITY VALIDATION # ================================================================================== - it: "should successfully retrieve Product object definition with valid structure" request: jsonrpc: "2.0" id: "product-success" method: "tools/call" params: name: "get_system_object_definition" arguments: objectType: "Product" expect: response: jsonrpc: "2.0" id: "product-success" result: content: - type: "text" text: "match:contains:Product" isError: false performance: maxResponseTime: "800ms" stderr: "toBeEmpty" - it: "should successfully retrieve Customer object definition" request: jsonrpc: "2.0" id: "customer-success" method: "tools/call" params: name: "get_system_object_definition" arguments: objectType: "Customer" expect: response: jsonrpc: "2.0" id: "customer-success" result: content: - type: "text" text: "match:contains:Customer" isError: false stderr: "toBeEmpty" - it: "should return valid JSON structure with required SFCC metadata" request: jsonrpc: "2.0" id: "valid-json" method: "tools/call" params: name: "get_system_object_definition" arguments: objectType: "Product" expect: response: jsonrpc: "2.0" id: "valid-json" result: content: - type: "text" text: "match:regex:^\\{[\\s\\S]*object_type_definition[\\s\\S]*\\}$" isError: false stderr: "toBeEmpty" # ================================================================================== # ERROR HANDLING VALIDATION # ================================================================================== - it: "should handle missing objectType parameter with clear error" request: jsonrpc: "2.0" id: "missing-param" method: "tools/call" params: name: "get_system_object_definition" arguments: {} expect: response: jsonrpc: "2.0" id: "missing-param" result: content: - type: "text" text: "match:contains:objectType must be a non-empty string" isError: true stderr: "toBeEmpty" - it: "should handle invalid parameter type gracefully" request: jsonrpc: "2.0" id: "invalid-type" method: "tools/call" params: name: "get_system_object_definition" arguments: objectType: 123 expect: response: jsonrpc: "2.0" id: "invalid-type" result: content: - type: "text" text: "match:contains:objectType must be a non-empty string" isError: true stderr: "toBeEmpty" # ================================================================================== # PERFORMANCE SMOKE TEST # ================================================================================== - it: "should respond within acceptable timeframe for unknown objects" request: jsonrpc: "2.0" id: "performance-check" method: "tools/call" params: name: "get_system_object_definition" arguments: objectType: "UnknownObject" expect: response: jsonrpc: "2.0" id: "performance-check" result: content: - type: "text" text: "match:contains:UnknownObject" isError: false performance: maxResponseTime: "600ms" stderr: "toBeEmpty" # ================================================================================== # OPTIMIZATION NOTES # ================================================================================== # This YAML test suite has been optimized to focus on declarative smoke testing. # # REMOVED from YAML (handled better in programmatic tests): # - Detailed JSON structure validation (complex regex patterns) # - Multiple object-specific tests (9 tests → 2 representative tests) # - Fallback behavior testing (3 tests → covered in programmatic) # - Case sensitivity edge cases (2 tests → covered in programmatic) # - Complex edge case testing (3 tests → covered in programmatic) # - Multiple tool discovery tests (4 tests → 1 consolidated test) # - Detailed metadata field validation (brittle regex patterns) # # KEPT in YAML (optimal for declarative validation): # - Basic tool availability (1 consolidated test) # - Core functionality smoke tests (2 key object types) # - Basic error handling (2 representative cases) # - Performance smoke test (1 test) # # TOTAL REDUCTION: 30+ tests → 7 focused tests # COMPLEX LOGIC: Now exclusively in programmatic tests where it belongs # ================================================================================== ``` -------------------------------------------------------------------------------- /tests/job-log-utils.test.ts: -------------------------------------------------------------------------------- ```typescript import { JobLogValidators, JobLogFormatters } from '../src/utils/job-log-utils.js'; describe('JobLogValidators', () => { describe('validateJobLogLevel', () => { it('should accept valid log levels', () => { const validLevels = ['error', 'warn', 'info', 'debug', 'all']; validLevels.forEach(level => { expect(() => JobLogValidators.validateJobLogLevel(level)).not.toThrow(); }); }); it('should reject invalid log levels', () => { const invalidLevels = ['trace', 'fatal', 'verbose', 'invalid', '']; invalidLevels.forEach(level => { expect(() => JobLogValidators.validateJobLogLevel(level)) .toThrow(`Invalid log level: ${level}. Must be one of: error, warn, info, debug, all`); }); }); it('should include tool name in error message when provided', () => { const toolName = 'test_tool'; const invalidLevel = 'invalid'; expect(() => JobLogValidators.validateJobLogLevel(invalidLevel, toolName)) .toThrow(`${toolName}: Invalid log level: ${invalidLevel}. Must be one of: error, warn, info, debug, all`); }); it('should handle null and undefined gracefully', () => { expect(() => JobLogValidators.validateJobLogLevel(null as any)).toThrow(); expect(() => JobLogValidators.validateJobLogLevel(undefined as any)).toThrow(); }); it('should be case sensitive', () => { expect(() => JobLogValidators.validateJobLogLevel('ERROR')).toThrow(); expect(() => JobLogValidators.validateJobLogLevel('ALL')).toThrow(); expect(() => JobLogValidators.validateJobLogLevel('Debug')).toThrow(); }); }); describe('getDefaultLimit', () => { it('should return correct default limit for search operations', () => { expect(JobLogValidators.getDefaultLimit('search')).toBe(20); }); it('should return correct default limit for entries operations', () => { expect(JobLogValidators.getDefaultLimit('entries')).toBe(10); }); it('should return correct default limit for files operations', () => { expect(JobLogValidators.getDefaultLimit('files')).toBe(10); }); it('should return default limit for unknown operations', () => { expect(JobLogValidators.getDefaultLimit('unknown' as any)).toBe(10); }); }); describe('ALLOWED_LEVELS constant', () => { it('should contain exactly the expected levels', () => { expect(JobLogValidators.ALLOWED_LEVELS).toEqual(['error', 'warn', 'info', 'debug', 'all']); }); it('should be readonly array', () => { const levels = JobLogValidators.ALLOWED_LEVELS; expect(levels).toEqual(['error', 'warn', 'info', 'debug', 'all']); // Test that it's a readonly array by checking its type/immutability intent expect(Array.isArray(levels)).toBe(true); }); }); }); describe('JobLogFormatters', () => { describe('formatJobLogMessage', () => { it('should format message with operation only', () => { const result = JobLogFormatters.formatJobLogMessage('Testing operation', {}); expect(result).toBe('Testing operation'); }); it('should format message with job name', () => { const result = JobLogFormatters.formatJobLogMessage('Testing operation', { jobName: 'TestJob', }); expect(result).toBe('Testing operation jobName=TestJob'); }); it('should format message with level', () => { const result = JobLogFormatters.formatJobLogMessage('Testing operation', { level: 'error', }); expect(result).toBe('Testing operation level=error'); }); it('should format message with limit', () => { const result = JobLogFormatters.formatJobLogMessage('Testing operation', { limit: 50, }); expect(result).toBe('Testing operation limit=50'); }); it('should format message with limit of 0', () => { const result = JobLogFormatters.formatJobLogMessage('Testing operation', { limit: 0, }); expect(result).toBe('Testing operation limit=0'); }); it('should format message with pattern', () => { const result = JobLogFormatters.formatJobLogMessage('Testing operation', { pattern: 'error-pattern', }); expect(result).toBe('Testing operation pattern="error-pattern"'); }); it('should format message with pattern containing spaces', () => { const result = JobLogFormatters.formatJobLogMessage('Testing operation', { pattern: 'error with spaces', }); expect(result).toBe('Testing operation pattern="error with spaces"'); }); it('should format message with all parameters', () => { const result = JobLogFormatters.formatJobLogMessage('Complex operation', { jobName: 'ComplexJob', level: 'debug', limit: 25, pattern: 'search-term', }); expect(result).toBe('Complex operation jobName=ComplexJob level=debug limit=25 pattern="search-term"'); }); it('should handle empty strings in parameters', () => { const result = JobLogFormatters.formatJobLogMessage('Testing operation', { jobName: '', level: '', pattern: '', }); expect(result).toBe('Testing operation'); }); it('should handle undefined limit correctly', () => { const result = JobLogFormatters.formatJobLogMessage('Testing operation', { jobName: 'TestJob', limit: undefined, }); expect(result).toBe('Testing operation jobName=TestJob'); }); it('should handle special characters in job name', () => { const result = JobLogFormatters.formatJobLogMessage('Testing operation', { jobName: 'Job-With_Special.Characters', }); expect(result).toBe('Testing operation jobName=Job-With_Special.Characters'); }); it('should handle special characters in pattern', () => { const result = JobLogFormatters.formatJobLogMessage('Testing operation', { pattern: 'pattern-with_special.chars', }); expect(result).toBe('Testing operation pattern="pattern-with_special.chars"'); }); it('should preserve order of parameters', () => { const result = JobLogFormatters.formatJobLogMessage('Operation', { pattern: 'last', jobName: 'first', level: 'second', limit: 123, }); // Should maintain the order: jobName, level, limit, pattern expect(result).toBe('Operation jobName=first level=second limit=123 pattern="last"'); }); it('should handle empty operation string', () => { const result = JobLogFormatters.formatJobLogMessage('', { jobName: 'TestJob', }); expect(result).toBe(' jobName=TestJob'); }); }); }); ``` -------------------------------------------------------------------------------- /docs/dw_crypto/WeakSignature.md: -------------------------------------------------------------------------------- ```markdown ## Package: dw.crypto # Class WeakSignature ## Inheritance Hierarchy - Object - dw.crypto.WeakSignature ## Description This API provides access to Deprecated algorithms. See Signature for full documentation. WeakSignature is simply a drop-in replacement that only supports deprecated algorithms. This is helpful when you need to deal with weak algorithms for backward compatibility purposes, but Signature should always be used for new development and for anything intended to be secure. This class allows access to signature services offered through the Java Cryptography Architecture (JCA). At this time the signature/verification implementation of the methods is based on the default RSA JCE provider of the JDK - sun.security.rsa.SunRsaSign dw.crypto.WeakSignature is an adapter to the security provider implementation and only covers one digest algorithm: SHA1withRSA Note: this class handles sensitive security-related data. Pay special attention to PCI DSS v3. requirements 2, 4, 12, and other relevant requirements. ## Constructor Summary WeakSignature() ## Method Summary ### isDigestAlgorithmSupported **Signature:** `isDigestAlgorithmSupported(digestAlgorithm : String) : boolean` Checks to see if a digest algorithm is supported ### sign **Signature:** `sign(contentToSign : String, privateKey : String, digestAlgorithm : String) : String` Signs a string and returns a string ### sign **Signature:** `sign(contentToSign : String, privateKey : KeyRef, digestAlgorithm : String) : String` Signs a string and returns a string ### signBytes **Signature:** `signBytes(contentToSign : Bytes, privateKey : String, digestAlgorithm : String) : Bytes` Signs bytes and returns bytes ### signBytes **Signature:** `signBytes(contentToSign : Bytes, privateKey : KeyRef, digestAlgorithm : String) : Bytes` Signs bytes and returns bytes ### verifyBytesSignature **Signature:** `verifyBytesSignature(signature : Bytes, contentToVerify : Bytes, publicKey : String, digestAlgorithm : String) : boolean` Verifies a signature supplied as bytes ### verifyBytesSignature **Signature:** `verifyBytesSignature(signature : Bytes, contentToVerify : Bytes, certificate : CertificateRef, digestAlgorithm : String) : boolean` Verifies a signature supplied as bytes ### verifySignature **Signature:** `verifySignature(signature : String, contentToVerify : String, publicKey : String, digestAlgorithm : String) : boolean` Verifies a signature supplied as string ### verifySignature **Signature:** `verifySignature(signature : String, contentToVerify : String, certificate : CertificateRef, digestAlgorithm : String) : boolean` Verifies a signature supplied as string ## Constructor Detail ## Method Detail ## Method Details ### isDigestAlgorithmSupported **Signature:** `isDigestAlgorithmSupported(digestAlgorithm : String) : boolean` **Description:** Checks to see if a digest algorithm is supported **Parameters:** - `digestAlgorithm`: the digest algorithm name **Returns:** a boolean indicating success (true) or failure (false) --- ### sign **Signature:** `sign(contentToSign : String, privateKey : String, digestAlgorithm : String) : String` **Description:** Signs a string and returns a string **Parameters:** - `contentToSign`: base64 encoded content to sign - `privateKey`: base64 encoded private key - `digestAlgorithm`: must be one of the currently supported ones **Returns:** the base64 encoded signature --- ### sign **Signature:** `sign(contentToSign : String, privateKey : KeyRef, digestAlgorithm : String) : String` **Description:** Signs a string and returns a string **Parameters:** - `contentToSign`: base64 encoded content to sign - `privateKey`: a reference to a private key entry in the keystore - `digestAlgorithm`: must be one of the currently supported ones **Returns:** the base64 encoded signature --- ### signBytes **Signature:** `signBytes(contentToSign : Bytes, privateKey : String, digestAlgorithm : String) : Bytes` **Description:** Signs bytes and returns bytes **Parameters:** - `contentToSign`: transformed with UTF-8 encoding into a byte stream - `privateKey`: base64 encoded private key - `digestAlgorithm`: must be one of the currently supported ones **Returns:** signature --- ### signBytes **Signature:** `signBytes(contentToSign : Bytes, privateKey : KeyRef, digestAlgorithm : String) : Bytes` **Description:** Signs bytes and returns bytes **Parameters:** - `contentToSign`: transformed with UTF-8 encoding into a byte stream - `privateKey`: a reference to a private key entry in the keystore - `digestAlgorithm`: must be one of the currently supported ones **Returns:** signature --- ### verifyBytesSignature **Signature:** `verifyBytesSignature(signature : Bytes, contentToVerify : Bytes, publicKey : String, digestAlgorithm : String) : boolean` **Description:** Verifies a signature supplied as bytes **Parameters:** - `signature`: signature to check as bytes - `contentToVerify`: as bytes - `publicKey`: base64 encoded public key - `digestAlgorithm`: must be one of the currently supported ones **Returns:** a boolean indicating success (true) or failure (false) --- ### verifyBytesSignature **Signature:** `verifyBytesSignature(signature : Bytes, contentToVerify : Bytes, certificate : CertificateRef, digestAlgorithm : String) : boolean` **Description:** Verifies a signature supplied as bytes **Parameters:** - `signature`: signature to check as bytes - `contentToVerify`: as bytes - `certificate`: a reference to a trusted certificate - `digestAlgorithm`: must be one of the currently supported ones **Returns:** a boolean indicating success (true) or failure (false) --- ### verifySignature **Signature:** `verifySignature(signature : String, contentToVerify : String, publicKey : String, digestAlgorithm : String) : boolean` **Description:** Verifies a signature supplied as string **Parameters:** - `signature`: base64 encoded signature - `contentToVerify`: base64 encoded content to verify - `publicKey`: base64 encoded public key - `digestAlgorithm`: must be one of the currently supported ones **Returns:** a boolean indicating success (true) or failure (false) --- ### verifySignature **Signature:** `verifySignature(signature : String, contentToVerify : String, certificate : CertificateRef, digestAlgorithm : String) : boolean` **Description:** Verifies a signature supplied as string **Parameters:** - `signature`: base64 encoded signature - `contentToVerify`: base64 encoded content to verify - `certificate`: a reference to a trusted certificate - `digestAlgorithm`: must be one of the currently supported ones **Returns:** a boolean indicating success (true) or failure (false) --- ``` -------------------------------------------------------------------------------- /docs/dw_util/Collection.md: -------------------------------------------------------------------------------- ```markdown ## Package: dw.util # Class Collection ## Inheritance Hierarchy - Object - dw.util.Collection ## Description Represents a collection of objects. ## Properties ### empty **Type:** boolean (Read Only) Returns true if the collection is empty. ### length **Type:** Number (Read Only) The length of the collection. This is similar to to a ECMA array of 'products.length'. ## Constructor Summary ## Method Summary ### add **Signature:** `add(values : Object...) : boolean` Adds the specified objects to the collection. ### add1 **Signature:** `add1(object : Object) : boolean` The method adds a single object to the collection. ### addAll **Signature:** `addAll(objs : Collection) : boolean` Adds the collection of objects to the collection. ### clear **Signature:** `clear() : void` Clears the collection. ### contains **Signature:** `contains(obj : Object) : boolean` Returns true if the collection contains the specified object. ### containsAll **Signature:** `containsAll(objs : Collection) : boolean` Returns true if the collection contains all of the objects in the specified collection. ### getLength **Signature:** `getLength() : Number` Returns the length of the collection. ### isEmpty **Signature:** `isEmpty() : boolean` Returns true if the collection is empty. ### iterator **Signature:** `iterator() : Iterator` Returns an iterator that can be used to access the members of the collection. ### remove **Signature:** `remove(obj : Object) : boolean` Removes the specified object from the collection. ### removeAll **Signature:** `removeAll(objs : Collection) : boolean` Removes all of object in the specified object from the collection. ### retainAll **Signature:** `retainAll(objs : Collection) : boolean` Removes all of object in the collection that are not in the specified collection. ### size **Signature:** `size() : Number` Returns the size of the collection. ### toArray **Signature:** `toArray() : Array` Returns all elements of this collection in a newly created array. ### toArray **Signature:** `toArray(start : Number, size : Number) : Array` Returns a subset of the elements of this collection in a newly created array. ## Method Detail ## Method Details ### add **Signature:** `add(values : Object...) : boolean` **Description:** Adds the specified objects to the collection. The method can also be called with an ECMA array as argument. If called with a single ECMA array as argument the individual elements of that array are added to the collection. If the array object itself should be added use the method add1(). **Parameters:** - `values`: the values to add. **Returns:** true if the values were added, false otherwise. --- ### add1 **Signature:** `add1(object : Object) : boolean` **Description:** The method adds a single object to the collection. **Parameters:** - `object`: the object to add. **Returns:** true if the object was added, false otherwise. --- ### addAll **Signature:** `addAll(objs : Collection) : boolean` **Description:** Adds the collection of objects to the collection. **Parameters:** - `objs`: the objects to add. **Returns:** true if the objects were added, false otherwise. --- ### clear **Signature:** `clear() : void` **Description:** Clears the collection. --- ### contains **Signature:** `contains(obj : Object) : boolean` **Description:** Returns true if the collection contains the specified object. **Parameters:** - `obj`: the object to locate in this collection. **Returns:** true if the collection contains the specified object, false otherwise. --- ### containsAll **Signature:** `containsAll(objs : Collection) : boolean` **Description:** Returns true if the collection contains all of the objects in the specified collection. **Parameters:** - `objs`: the collection of objects to locate in this collection. **Returns:** true if the collection contains all of the specified objects, false otherwise. --- ### getLength **Signature:** `getLength() : Number` **Description:** Returns the length of the collection. This is similar to to a ECMA array of 'products.length'. **Returns:** the length of the collection. --- ### isEmpty **Signature:** `isEmpty() : boolean` **Description:** Returns true if the collection is empty. **Returns:** true if the collection is empty, false otherwise --- ### iterator **Signature:** `iterator() : Iterator` **Description:** Returns an iterator that can be used to access the members of the collection. **Returns:** an iterator that can be used to access the members of the collection. --- ### remove **Signature:** `remove(obj : Object) : boolean` **Description:** Removes the specified object from the collection. **Parameters:** - `obj`: the object to remove. **Returns:** true if the specified object was removed, false otherwise. --- ### removeAll **Signature:** `removeAll(objs : Collection) : boolean` **Description:** Removes all of object in the specified object from the collection. **Parameters:** - `objs`: the collection of objects to remove. **Returns:** true if the all of the specified objects were removed, false otherwise. --- ### retainAll **Signature:** `retainAll(objs : Collection) : boolean` **Description:** Removes all of object in the collection that are not in the specified collection. **Parameters:** - `objs`: the collection of objects to retain in the collection. **Returns:** true if the collection retains all of the specified objects, false otherwise. --- ### size **Signature:** `size() : Number` **Description:** Returns the size of the collection. **Returns:** the size of the collection. --- ### toArray **Signature:** `toArray() : Array` **Description:** Returns all elements of this collection in a newly created array. The returned array is independent of this collection and can be modified without changing the collection. The elements in the array are in the same order as they are returned when iterating over this collection. **Returns:** a newly created array. --- ### toArray **Signature:** `toArray(start : Number, size : Number) : Array` **Description:** Returns a subset of the elements of this collection in a newly created array. The returned array is independent of this collection and can be modified without changing the collection. The elements in the array are in the same order as they are returned when iterating over this collection. **Parameters:** - `start`: the number of elements to iterate before adding elements to the array. Negative values are treated as 0. - `size`: the maximum number of elements to add to the array. Nonpositive values always result in empty array. **Returns:** a newly created array. --- ``` -------------------------------------------------------------------------------- /src/clients/ocapi-client.ts: -------------------------------------------------------------------------------- ```typescript /** * OCAPI Client for Salesforce Commerce Cloud * * This module provides a unified interface for making authenticated requests to SFCC's Open Commerce API (OCAPI). * It orchestrates specialized client modules for different domain areas while maintaining backward compatibility. */ import { OCAPIConfig } from '../types/types.js'; import { OCAPISystemObjectsClient } from './ocapi/system-objects-client.js'; import { OCAPISitePreferencesClient } from './ocapi/site-preferences-client.js'; import { OCAPICodeVersionsClient } from './ocapi/code-versions-client.js'; import { OCAPIAuthClient } from './base/ocapi-auth-client.js'; import { Logger } from '../utils/logger.js'; /** * Interface for common query parameters used across multiple endpoints */ interface BaseQueryParams { start?: number; count?: number; select?: string; } /** * Interface for search request structure used in multiple search endpoints */ interface SearchRequest { query?: { text_query?: { fields: string[]; search_phrase: string; }; term_query?: { fields: string[]; operator: string; values: any[]; }; filtered_query?: { filter: any; query: any; }; bool_query?: { must?: any[]; must_not?: any[]; should?: any[]; }; match_all_query?: {}; }; sorts?: Array<{ field: string; sort_order?: 'asc' | 'desc'; }>; start?: number; count?: number; select?: string; } /** * OCAPI Client - Unified interface for SFCC OCAPI operations * * This class serves as a facade that orchestrates specialized client modules: * - SystemObjectsClient: Handles system object definitions and attributes * - SitePreferencesClient: Manages site preference operations * - CodeVersionsClient: Manages code version operations * - AuthClient: Manages OAuth authentication and token lifecycle */ export class OCAPIClient { // Specialized client modules public readonly systemObjects: OCAPISystemObjectsClient; public readonly sitePreferences: OCAPISitePreferencesClient; public readonly codeVersions: OCAPICodeVersionsClient; private readonly authClient: OCAPIAuthClient; private logger: Logger; constructor(config: OCAPIConfig) { this.logger = Logger.getChildLogger('OCAPIClient'); this.logger.debug(`Initializing OCAPI client for hostname: ${config.hostname}`); const finalConfig = { version: 'v21_3', ...config, }; // Initialize specialized clients this.systemObjects = new OCAPISystemObjectsClient(finalConfig); this.sitePreferences = new OCAPISitePreferencesClient(finalConfig); this.codeVersions = new OCAPICodeVersionsClient(finalConfig); this.authClient = new OCAPIAuthClient(finalConfig); this.logger.debug('OCAPI client initialized with specialized modules'); } // ============================================================================= // System Objects API - Delegated to SystemObjectsClient // ============================================================================= /** * Get all system object definitions */ async getSystemObjectDefinitions(params?: BaseQueryParams): Promise<any> { return this.systemObjects.getSystemObjectDefinitions(params); } /** * Get a specific system object definition by object type */ async getSystemObjectDefinition(objectType: string): Promise<any> { return this.systemObjects.getSystemObjectDefinition(objectType); } /** * Search for system object definitions using complex queries */ async searchSystemObjectDefinitions(searchRequest: SearchRequest): Promise<any> { return this.systemObjects.searchSystemObjectDefinitions(searchRequest); } /** * Search attribute definitions for a specific system object type using complex queries */ async searchSystemObjectAttributeDefinitions( objectType: string, searchRequest: SearchRequest, ): Promise<any> { return this.systemObjects.searchSystemObjectAttributeDefinitions(objectType, searchRequest); } /** * Search attribute groups for a specific system object type */ async searchSystemObjectAttributeGroups( objectType: string, searchRequest: SearchRequest, ): Promise<any> { return this.systemObjects.searchSystemObjectAttributeGroups(objectType, searchRequest); } /** * Search attribute definitions for a specific custom object type using complex queries */ async searchCustomObjectAttributeDefinitions( objectType: string, searchRequest: SearchRequest, ): Promise<any> { return this.systemObjects.searchCustomObjectAttributeDefinitions(objectType, searchRequest); } // ============================================================================= // Site Preferences API - Delegated to SitePreferencesClient // ============================================================================= /** * Search site preferences across sites in the specified preference group and instance */ async searchSitePreferences( groupId: string, instanceType: string, searchRequest: SearchRequest, options?: { maskPasswords?: boolean; expand?: string; }, ): Promise<any> { return this.sitePreferences.searchSitePreferences(groupId, instanceType, searchRequest, options); } // ============================================================================= // Code Versions API - Delegated to CodeVersionsClient // ============================================================================= /** * Get all code versions from the SFCC instance * * @returns {Promise<any>} Code version result with data array containing version information */ async getCodeVersions(): Promise<any> { return this.codeVersions.getCodeVersions(); } /** * Activate a specific code version on the SFCC instance * * @param {string} codeVersionId - The ID of the code version to activate * @param {string} codeVersionId - The ID of the code version to activate * @returns {Promise<any>} Updated code version object */ async activateCodeVersion(codeVersionId: string): Promise<any> { return this.codeVersions.activateCodeVersion(codeVersionId); } // ============================================================================= // Authentication & Token Management - Delegated to AuthClient // ============================================================================= /** * Get current token expiration for debugging */ getTokenExpiration(): Date | null { return this.authClient.getTokenExpiration(); } /** * Force refresh the token (useful for testing) */ async refreshToken(): Promise<void> { return this.authClient.refreshToken(); } } ``` -------------------------------------------------------------------------------- /tests/mcp/yaml/get-system-object-definition.docs-only.test.mcp.yml: -------------------------------------------------------------------------------- ```yaml # ================================================================================== # SFCC MCP Server - get_system_object_definition Tool YAML Tests (Docs-Only Mode) # Tests that system object tools are NOT available in docs-only mode # This tool requires SFCC credentials and should not be available without them # However, the tool can still be called and should return authentication error # # Quick Test Commands: # aegis "tests/mcp/yaml/get-system-object-definition.docs-only.test.mcp.yml" --config "aegis.config.docs-only.json" --verbose # aegis "tests/mcp/yaml/get-system-object-definition.docs-only.test.mcp.yml" --config "aegis.config.docs-only.json" --debug --timing # aegis query --config "aegis.config.docs-only.json" # aegis query get_system_object_definition '{"objectType": "Product"}' --config "aegis.config.docs-only.json" # ================================================================================== description: "get_system_object_definition tool tests - Docs-only mode tool availability and authentication errors" # ================================================================================== # TOOL UNAVAILABILITY IN DOCS-ONLY MODE # ================================================================================== tests: - it: "should NOT list get_system_object_definition tool in docs-only mode" request: jsonrpc: "2.0" id: "tool-not-available-docs" method: "tools/list" params: {} expect: response: jsonrpc: "2.0" id: "tool-not-available-docs" result: match:extractField: "tools.*.name" value: "match:not:arrayContains:get_system_object_definition" stderr: "toBeEmpty" # ================================================================================== # AUTHENTICATION ERROR TESTS (Tool Can Be Called But Returns Error) # ================================================================================== - it: "should return authentication error when calling get_system_object_definition in docs-only mode" request: jsonrpc: "2.0" id: "auth-error-product" method: "tools/call" params: name: "get_system_object_definition" arguments: objectType: "Product" expect: response: jsonrpc: "2.0" id: "auth-error-product" result: content: - type: "text" text: "match:contains:OCAPI client not configured" isError: true performance: maxResponseTime: "500ms" stderr: "toBeEmpty" - it: "should return authentication error for Customer object type" request: jsonrpc: "2.0" id: "auth-error-customer" method: "tools/call" params: name: "get_system_object_definition" arguments: objectType: "Customer" expect: response: jsonrpc: "2.0" id: "auth-error-customer" result: content: - type: "text" text: "match:contains:credentials are provided" isError: true stderr: "toBeEmpty" - it: "should return authentication error for any object type" request: jsonrpc: "2.0" id: "auth-error-any" method: "tools/call" params: name: "get_system_object_definition" arguments: objectType: "AnyObjectType" expect: response: jsonrpc: "2.0" id: "auth-error-any" result: content: - type: "text" text: "match:contains:full mode" isError: true stderr: "toBeEmpty" - it: "should return consistent authentication error message structure" request: jsonrpc: "2.0" id: "auth-error-structure" method: "tools/call" params: name: "get_system_object_definition" arguments: objectType: "Order" expect: response: jsonrpc: "2.0" id: "auth-error-structure" result: content: - type: "text" text: "match:startsWith:Error:" isError: true stderr: "toBeEmpty" # ================================================================================== # PARAMETER VALIDATION IN DOCS-ONLY MODE # ================================================================================== - it: "should return authentication error even with missing objectType in docs-only mode" request: jsonrpc: "2.0" id: "docs-missing-param" method: "tools/call" params: name: "get_system_object_definition" arguments: {} expect: response: jsonrpc: "2.0" id: "docs-missing-param" result: content: - type: "text" text: "match:contains:OCAPI client not configured" isError: true stderr: "toBeEmpty" - it: "should return authentication error even with invalid parameter types in docs-only mode" request: jsonrpc: "2.0" id: "docs-invalid-type" method: "tools/call" params: name: "get_system_object_definition" arguments: objectType: 123 expect: response: jsonrpc: "2.0" id: "docs-invalid-type" result: content: - type: "text" text: "match:contains:OCAPI client not configured" isError: true stderr: "toBeEmpty" - it: "should return auth error for valid parameters in docs-only mode" request: jsonrpc: "2.0" id: "docs-valid-param-auth-error" method: "tools/call" params: name: "get_system_object_definition" arguments: objectType: "ValidObjectType" expect: response: jsonrpc: "2.0" id: "docs-valid-param-auth-error" result: content: - type: "text" text: "match:regex:Error:[\\s\\S]*OCAPI[\\s\\S]*configured" isError: true stderr: "toBeEmpty" # ================================================================================== # PERFORMANCE TESTS FOR ERROR RESPONSES # ================================================================================== - it: "should return authentication errors quickly" request: jsonrpc: "2.0" id: "auth-error-perf" method: "tools/call" params: name: "get_system_object_definition" arguments: objectType: "FastErrorTest" expect: response: jsonrpc: "2.0" id: "auth-error-perf" result: content: - type: "text" text: "match:contains:Error" isError: true performance: maxResponseTime: "400ms" stderr: "toBeEmpty" ``` -------------------------------------------------------------------------------- /docs/dw_value/Quantity.md: -------------------------------------------------------------------------------- ```markdown ## Package: dw.value # Class Quantity ## Inheritance Hierarchy - Object - dw.value.Quantity ## Description Represents the quantity of an item. ## Properties ### available **Type:** boolean (Read Only) Identifies if the instance contains settings for value and unit. ### decimalValue **Type:** Decimal (Read Only) The quantity as Decimal, null is returned when the quantity is not available. ### unit **Type:** String (Read Only) The value for unit which identifies the unit of measure for the quantity. Examples of unit are 'inches' or 'pounds'. ### value **Type:** Number (Read Only) The quantity value. ## Constructor Summary Quantity(value : Number, unit : String) Creates a new quantity instance with the specified value and unit. ## Method Summary ### add **Signature:** `add(value : Quantity) : Quantity` Add Quantity object to the current object. ### compareTo **Signature:** `compareTo(other : Quantity) : Number` Compares two Quantity values. ### divide **Signature:** `divide(divisor : Number) : Quantity` Divide Quantity object by specified divisor. ### equals **Signature:** `equals(other : Object) : boolean` Compares two decimal values whether they are equivalent. ### getDecimalValue **Signature:** `getDecimalValue() : Decimal` Returns the quantity as Decimal, null is returned when the quantity is not available. ### getUnit **Signature:** `getUnit() : String` Returns the value for unit which identifies the unit of measure for the quantity. ### getValue **Signature:** `getValue() : Number` Returns the quantity value. ### hashCode **Signature:** `hashCode() : Number` Calculates the hash code for a decimal. ### isAvailable **Signature:** `isAvailable() : boolean` Identifies if the instance contains settings for value and unit. ### isOfSameUnit **Signature:** `isOfSameUnit(value : Quantity) : boolean` Identifies if two Quantities have the same unit. ### multiply **Signature:** `multiply(factor : Number) : Quantity` Multiply Quantity object by specified factor. ### newQuantity **Signature:** `newQuantity(value : Decimal) : Quantity` Method returns a new instance of Quantity with the same unit but different value. ### round **Signature:** `round(precision : Number) : Quantity` Rounds the Quantity value to the number of specified decimal digits. ### subtract **Signature:** `subtract(value : Quantity) : Quantity` Subtract Quantity object from the current object. ### toString **Signature:** `toString() : String` Returns a string representation of this quantity object. ### valueOf **Signature:** `valueOf() : Object` According to the ECMA spec returns the "natural" primitive value. ## Constructor Detail ## Method Detail ## Method Details ### add **Signature:** `add(value : Quantity) : Quantity` **Description:** Add Quantity object to the current object. Only objects representing the same unit can be added. **Parameters:** - `value`: Quantity object **Returns:** Quantity object representing the sum of the operands --- ### compareTo **Signature:** `compareTo(other : Quantity) : Number` **Description:** Compares two Quantity values. An exception is thrown if the two Quantities values are of different unit. If one of the Quantity values represents the N/A value it is treated as 0.0. **Parameters:** - `other`: the other quantity to compare. **Returns:** the comparison. --- ### divide **Signature:** `divide(divisor : Number) : Quantity` **Description:** Divide Quantity object by specified divisor. **Parameters:** - `divisor`: divisor **Returns:** Quantity object representing division result --- ### equals **Signature:** `equals(other : Object) : boolean` **Description:** Compares two decimal values whether they are equivalent. **Parameters:** - `other`: the object to compare against this quantity instance. **Returns:** true if equal, false otherwise. --- ### getDecimalValue **Signature:** `getDecimalValue() : Decimal` **Description:** Returns the quantity as Decimal, null is returned when the quantity is not available. **Returns:** the quantity as Decimal --- ### getUnit **Signature:** `getUnit() : String` **Description:** Returns the value for unit which identifies the unit of measure for the quantity. Examples of unit are 'inches' or 'pounds'. **Returns:** the unit value. --- ### getValue **Signature:** `getValue() : Number` **Description:** Returns the quantity value. **Returns:** the quantity value. **See Also:** getDecimalValue() --- ### hashCode **Signature:** `hashCode() : Number` **Description:** Calculates the hash code for a decimal. **Returns:** the hash code. --- ### isAvailable **Signature:** `isAvailable() : boolean` **Description:** Identifies if the instance contains settings for value and unit. **Returns:** true if the instance is initialized with value and unit, false if the state is 'not available'. --- ### isOfSameUnit **Signature:** `isOfSameUnit(value : Quantity) : boolean` **Description:** Identifies if two Quantities have the same unit. **Parameters:** - `value`: the second quantity for the comparison. **Returns:** true if both quantities have the same unit, false otherwise. --- ### multiply **Signature:** `multiply(factor : Number) : Quantity` **Description:** Multiply Quantity object by specified factor. **Parameters:** - `factor`: multiplication factor **Returns:** Quantity object representing multiplication result --- ### newQuantity **Signature:** `newQuantity(value : Decimal) : Quantity` **Description:** Method returns a new instance of Quantity with the same unit but different value. An N/A instance is returned if value is null. **Parameters:** - `value`: as a decimal **Returns:** new Quantity instance with same unit --- ### round **Signature:** `round(precision : Number) : Quantity` **Description:** Rounds the Quantity value to the number of specified decimal digits. **Parameters:** - `precision`: number of decimal digits after the decimal point **Returns:** the new rounded Quantity value --- ### subtract **Signature:** `subtract(value : Quantity) : Quantity` **Description:** Subtract Quantity object from the current object. Only objects representing the same unit can be subtracted. **Parameters:** - `value`: Quantity object to subtract **Returns:** Quantity object representing the result of subtraction --- ### toString **Signature:** `toString() : String` **Description:** Returns a string representation of this quantity object. **Returns:** a string representation of this quantity object. --- ### valueOf **Signature:** `valueOf() : Object` **Description:** According to the ECMA spec returns the "natural" primitive value. Here the value portion of the Quantity is returned. --- ``` -------------------------------------------------------------------------------- /docs/sfra/product-full.md: -------------------------------------------------------------------------------- ```markdown # SFRA Full Product Model ## Overview The Full Product model represents a complete product with all detailed information, typically used on product detail pages (PDP). It provides comprehensive product data including pricing, images, variations, descriptions, ratings, promotions, and availability. ## Module Function ```javascript module.exports = function fullProduct(product, apiProduct, options) ``` Decorates a product object with comprehensive product information using multiple decorators. ### Parameters - `product` (Object) - Product Model to be decorated - `apiProduct` (dw.catalog.Product) - Product information returned by the script API - `options` (Object) - Options object containing: - `variationModel` (dw.catalog.ProductVariationModel) - Variation model returned by the API - `options` (Object) - Options provided on the query string - `optionModel` (dw.catalog.ProductOptionModel) - Options model returned by the API - `promotions` (dw.util.Collection) - Active promotions for the product - `quantity` (number) - Current selected quantity - `variables` (Object) - Variables passed in on the query string ### Returns Object - Decorated product model with comprehensive product information ## Applied Decorators The full product model applies the following decorators: ### base Adds fundamental product information including uuid, id, productName, productType, and brand. ### price Adds comprehensive pricing information including promotional prices, with option model integration. Sets `price` and `renderedPrice` properties. ### images Adds product images with full configuration: - **Types:** ['large', 'small'] - Multiple image sizes for different display contexts - **Quantity:** 'all' - All available images ### quantity Adds quantity information and constraints: `selectedQuantity`, `minOrderQuantity`, and `maxOrderQuantity`. ### variationAttributes Adds variation attribute information with full configuration: - **Attributes:** '*' - All variation attributes - **EndPoint:** 'Variation' - Endpoint for variation handling ### description Adds product description: `longDescription` and `shortDescription` markup properties. ### ratings Adds product rating information: `rating` value calculated from product ID. ### promotions Adds active promotion information: `promotions` array with promotion details. ### attributes Adds product attributes from the attribute model: `attributes` array with grouped attribute data. ### availability Adds availability information: `availability` object with messages and stock status based on quantity and availability model. ### options Adds product option information: `options` array including option model, variables, and quantity. ### quantitySelector Adds quantity selector information: `quantities` array with step quantity and URL options. ### sizeChart (conditional) Adds size chart information: `sizeChartId` property if the product's category has a custom sizeChartID attribute. ### currentUrl Adds current product URL: `selectedProductUrl` property with variation and option parameters. ### readyToOrder Adds order readiness status: `readyToOrder` boolean indicating if product can be ordered. ### online Adds online status: `online` boolean indicating if product is available online. ### raw Adds raw API product: `raw` property (non-enumerable) containing the original dw.catalog.Product object. ### pageMetaData Adds SEO metadata: `pageTitle`, `pageDescription`, `pageKeywords`, and `pageMetaTags` properties. ### template Adds template information: `template` property for rendering purposes. ## Usage Example ```javascript var fullProductDecorator = require('*/cartridge/models/product/fullProduct'); var productFactory = require('*/cartridge/scripts/factories/product'); // Prepare options var options = { variationModel: variationModel, optionModel: optionModel, promotions: activePromotions, quantity: 1, variables: req.querystring, options: req.httpParameterMap }; // Create and decorate product var product = {}; var fullProduct = fullProductDecorator(product, apiProduct, options); // Access comprehensive product information console.log(fullProduct.price.sales); console.log(fullProduct.images.large); console.log(fullProduct.availability.messages); console.log(fullProduct.variationAttributes); ``` ## Typical Properties After Decoration After applying all decorators, the full product object contains: - **uuid** - Product UUID - **id** - Product ID - **productName** - Product name and display information - **productType** - Product type - **brand** - Product brand - **price** - Comprehensive pricing with promotions - **renderedPrice** - HTML-rendered price for display - **images** - Large and small product images - **selectedQuantity** - Currently selected quantity - **minOrderQuantity** - Minimum order quantity - **maxOrderQuantity** - Maximum order quantity - **variationAttributes** - Complete variation attribute data - **longDescription** - Product long description markup - **shortDescription** - Product short description markup - **rating** - Product rating value - **promotions** - Active promotion information - **attributes** - Product attribute groups and values - **availability** - Availability status and messages - **options** - Product option configurations - **quantities** - Available quantity selection options - **sizeChartId** - Size chart identifier (if applicable) - **selectedProductUrl** - Current product URL with selected variations and options - **readyToOrder** - Boolean indicating if product can be ordered - **online** - Boolean indicating if product is available online - **pageTitle** - SEO page title - **pageDescription** - SEO page description - **pageKeywords** - SEO page keywords - **pageMetaTags** - SEO meta tags array - **template** - Template identifier for rendering ## Size Chart Handling The model automatically checks for size chart information: 1. Gets the product's primary category 2. For variants/variation groups, uses the master product's primary category 3. If the category has a custom `sizeChartID` attribute, applies the sizeChart decorator ## Notes - Provides the most comprehensive product information available - Optimized for product detail pages with full functionality - Handles all product types including variants, masters, and sets - Includes promotional pricing and availability calculations - Supports product options and variations - Automatically handles size chart integration - Performance-optimized for single product display ## Related Models - **Product Tile Model** - Simplified version for listings - **Product Bundle Model** - For bundled products - **Product Set Model** - For product sets - **Product Decorators** - Individual decoration functions ``` -------------------------------------------------------------------------------- /docs/dw_util/BigInteger.md: -------------------------------------------------------------------------------- ```markdown ## Package: dw.util # Class BigInteger ## Inheritance Hierarchy - Object - dw.util.BigInteger ## Description The BigInteger class is a helper class to represent an arbitrary long integer number. The Demandware framework doesn't use this class, but in some special cases web services that declare an XML element with "xsd:integer", which is by definition an arbitrary long integer number, require the use of this class. The class is designed in a way that it can be used very similar to a desktop calculator. For example: var i = new BigInteger( 10 ); var result = d.add( 2 ).sub( 3 ).get(); The above code will return 9 as result. ## Constructor Summary BigInteger() Constructs a new BigInteger with the value 0. BigInteger(value : Number) Constructs a new BigInteger using the specified Number value. BigInteger(value : String) Constructs a new BigInteger using the specified string representation of a number. ## Method Summary ### abs **Signature:** `abs() : BigInteger` Returns a new BigInteger with the absolute value of this BigInteger. ### add **Signature:** `add(value : Number) : BigInteger` Adds a Number value to this BigInteger and returns the new BigInteger. ### add **Signature:** `add(value : BigInteger) : BigInteger` Adds an BigInteger value to this BigInteger and returns the new BigInteger. ### divide **Signature:** `divide(value : Number) : BigInteger` Divides this BigInteger by the specified BigInteger and returns the new BigInteger. ### divide **Signature:** `divide(value : BigInteger) : BigInteger` Divides this BigInteger by the specified BigInteger and returns the new BigInteger. ### equals **Signature:** `equals(other : Object) : boolean` Compares two BigInteger values whether they are equivalent. ### get **Signature:** `get() : Number` Returns the value of the BigInteger as a Number. ### hashCode **Signature:** `hashCode() : Number` Calculates the hash code for this BigInteger; ### multiply **Signature:** `multiply(value : Number) : BigInteger` Multiples the specified Number value with this BigInteger and returns the new BigInteger. ### multiply **Signature:** `multiply(value : BigInteger) : BigInteger` Multiples the specified BigInteger value with this BigInteger and returns the new BigInteger. ### negate **Signature:** `negate() : BigInteger` Returns a new BigInteger with the negated value of this BigInteger. ### subtract **Signature:** `subtract(value : Number) : BigInteger` Subtracts the specified Number value from this BigInteger and returns the new BigInteger. ### subtract **Signature:** `subtract(value : BigInteger) : BigInteger` Subtracts the specified BigInteger value from this BigInteger and returns the new BigInteger. ### toString **Signature:** `toString() : String` Returns a string representation of this object. ### valueOf **Signature:** `valueOf() : Object` The valueOf() method is called by the ECMAScript interpret to return the "natural" value of an object. ## Constructor Detail ## Method Detail ## Method Details ### abs **Signature:** `abs() : BigInteger` **Description:** Returns a new BigInteger with the absolute value of this BigInteger. **Returns:** the new BigInteger --- ### add **Signature:** `add(value : Number) : BigInteger` **Description:** Adds a Number value to this BigInteger and returns the new BigInteger. **Parameters:** - `value`: the value to add to this BigInteger. **Returns:** the new BigInteger with the value added. --- ### add **Signature:** `add(value : BigInteger) : BigInteger` **Description:** Adds an BigInteger value to this BigInteger and returns the new BigInteger. **Parameters:** - `value`: the value to add to this BigInteger. **Returns:** the new BigInteger with the value added. --- ### divide **Signature:** `divide(value : Number) : BigInteger` **Description:** Divides this BigInteger by the specified BigInteger and returns the new BigInteger. **Parameters:** - `value`: the value to use to divide this BigInteger. **Returns:** the new BigInteger. --- ### divide **Signature:** `divide(value : BigInteger) : BigInteger` **Description:** Divides this BigInteger by the specified BigInteger and returns the new BigInteger. **Parameters:** - `value`: the value to use to divide this BigInteger. **Returns:** the new BigInteger. --- ### equals **Signature:** `equals(other : Object) : boolean` **Description:** Compares two BigInteger values whether they are equivalent. **Parameters:** - `other`: the object to compare against this BigInteger. --- ### get **Signature:** `get() : Number` **Description:** Returns the value of the BigInteger as a Number. **Returns:** the value of the BigInteger. --- ### hashCode **Signature:** `hashCode() : Number` **Description:** Calculates the hash code for this BigInteger; --- ### multiply **Signature:** `multiply(value : Number) : BigInteger` **Description:** Multiples the specified Number value with this BigInteger and returns the new BigInteger. **Parameters:** - `value`: the value to multiply with this BigInteger. **Returns:** the new BigInteger. --- ### multiply **Signature:** `multiply(value : BigInteger) : BigInteger` **Description:** Multiples the specified BigInteger value with this BigInteger and returns the new BigInteger. **Parameters:** - `value`: the value to multiply with this BigInteger. **Returns:** the new BigInteger. --- ### negate **Signature:** `negate() : BigInteger` **Description:** Returns a new BigInteger with the negated value of this BigInteger. **Returns:** the new BigInteger --- ### subtract **Signature:** `subtract(value : Number) : BigInteger` **Description:** Subtracts the specified Number value from this BigInteger and returns the new BigInteger. **Parameters:** - `value`: the value to add to this BigInteger. **Returns:** the new BigInteger with the value subtracted. --- ### subtract **Signature:** `subtract(value : BigInteger) : BigInteger` **Description:** Subtracts the specified BigInteger value from this BigInteger and returns the new BigInteger. **Parameters:** - `value`: the value to add to this BigInteger. **Returns:** the new BigInteger with the value subtracted. --- ### toString **Signature:** `toString() : String` **Description:** Returns a string representation of this object. **Returns:** a string representation of this object. --- ### valueOf **Signature:** `valueOf() : Object` **Description:** The valueOf() method is called by the ECMAScript interpret to return the "natural" value of an object. The BigInteger object returns its current value as number. With this behavior script snippets can be written like: var i = new BigInteger( 10 ); var x = 1 + d.add( 2 ); where x will be at the end 13. **Returns:** the value of this object. --- ``` -------------------------------------------------------------------------------- /tests/servers/sfcc-mock-server/src/routes/ocapi/code-versions-handler.js: -------------------------------------------------------------------------------- ```javascript /** * Code Versions Handler * * Handles code version listing and activation operations for OCAPI endpoints. */ const express = require('express'); class CodeVersionsHandler { constructor(config, dataLoader) { this.config = config; this.ocapiConfig = config.getOcapiConfig(); this.dataLoader = dataLoader; this.router = express.Router(); this.setupRoutes(); } setupRoutes() { // Code Versions API this.router.get(`/s/-/dw/data/${this.ocapiConfig.version}/code_versions`, this.handleGetCodeVersions.bind(this) ); this.router.patch(`/s/-/dw/data/${this.ocapiConfig.version}/code_versions/:versionId`, this.handleActivateCodeVersion.bind(this) ); } /** * Handle get code versions */ async handleGetCodeVersions(req, res) { let mockData = this.dataLoader.loadOcapiData('code-versions.json'); if (!mockData) { // Create fallback data with proper SFCC format mockData = { "_v": "23.2", "_type": "code_version_result", "count": 1, "data": [ { "_type": "code_version", "id": "SFRA_FALLBACK_VERSION", "active": true, "activation_time": new Date().toISOString(), "last_modification_time": new Date().toISOString(), "rollback": false, "compatibility_mode": "22.7", "cartridges": [ "app_storefront_base", "bm_app_storefront_base", "modules" ], "web_dav_url": "https://development-na01-sandbox.dx.commercecloud.salesforce.com/on/demandware.servlet/webdav/Sites/Cartridges/SFRA_FALLBACK_VERSION" } ], "total": 1 }; } res.json(mockData); } /** * Handle activate code version */ async handleActivateCodeVersion(req, res) { const { versionId } = req.params; // Load current mock data to find the version being activated let mockData = this.dataLoader.loadOcapiData('code-versions.json'); if (!mockData) { return res.status(404).json({ "_v": "23.2", "_type": "fault", "fault": { "type": "InvalidParameterException", "message": `Code version '${versionId}' not found` } }); } // Find the code version being activated const versionToActivate = mockData.data.find(cv => cv.id === versionId); if (!versionToActivate) { return res.status(404).json({ "_v": "23.2", "_type": "fault", "fault": { "type": "InvalidParameterException", "message": `Code version '${versionId}' not found` } }); } if (versionToActivate.active) { // For the reset version, return the current version data instead of an error // This allows tests to "activate" it reliably regardless of current state if (versionId === 'reset_version') { const activationTime = versionToActivate.activation_time || new Date().toISOString(); const activatedVersion = { "_v": "23.2", "_type": "code_version", "_resource_state": this.generateResourceState(), "activation_time": activationTime, "active": true, "cartridges": versionToActivate.cartridges || [], "compatibility_mode": versionToActivate.compatibility_mode || "22.7", "id": versionId, "last_modification_time": versionToActivate.last_modification_time || activationTime, "rollback": false, "web_dav_url": versionToActivate.web_dav_url || `https://development-na01-sandbox.dx.commercecloud.salesforce.com/on/demandware.servlet/webdav/Sites/Cartridges/${versionId}` }; return res.json(activatedVersion); } return res.status(400).json({ "_v": "23.2", "_type": "fault", "fault": { "type": "InvalidParameterException", "message": `Code version '${versionId}' is already active` } }); } // Create response matching real SFCC API behavior const activationTime = new Date().toISOString(); const activatedVersion = { "_v": "23.2", "_type": "code_version", "_resource_state": this.generateResourceState(), "activation_time": activationTime, "active": true, "cartridges": versionToActivate.cartridges || [], "compatibility_mode": versionToActivate.compatibility_mode || "22.7", "id": versionId, "last_modification_time": versionToActivate.last_modification_time || activationTime, "rollback": false, // Real API sets this to false when activating "web_dav_url": versionToActivate.web_dav_url || `https://development-na01-sandbox.dx.commercecloud.salesforce.com/on/demandware.servlet/webdav/Sites/Cartridges/${versionId}` }; // Update the mock data state (deactivate others, activate target) mockData.data.forEach(cv => { if (cv.id === versionId) { cv.active = true; cv.activation_time = activationTime; cv.rollback = false; } else if (cv.active) { cv.active = false; delete cv.activation_time; // Remove activation_time from deactivated versions } }); // Save updated state back to file (in a real scenario) // For now, just return the response res.json(activatedVersion); } /** * Generate a mock resource state hash */ generateResourceState() { // Generate a 64-character hex string similar to SFCC's resource state const chars = '0123456789abcdef'; let result = ''; for (let i = 0; i < 64; i++) { result += chars[Math.floor(Math.random() * chars.length)]; } return result; } /** * Get the configured router */ getRouter() { return this.router; } } module.exports = CodeVersionsHandler; ``` -------------------------------------------------------------------------------- /docs/sfra/product-bundle.md: -------------------------------------------------------------------------------- ```markdown # SFRA Product Bundle Model ## Overview The Product Bundle model represents bundled products in SFRA applications, where multiple products are sold together as a single unit. It provides comprehensive bundle information including individual bundled products, pricing, and bundle-specific functionality. ## Module Function ```javascript module.exports = function bundleProduct(product, apiProduct, options, factory) ``` Decorates a product object with bundle-specific information using various decorators. ### Parameters - `product` (Object) - Product Model to be decorated - `apiProduct` (dw.catalog.Product) - Product information returned by the script API - `options` (Object) - Options object containing: - `productType` (string) - Product type information - `variationModel` (dw.catalog.ProductVariationModel) - Variation model returned by the API - `options` (Object) - Options provided on the query string - `optionModel` (dw.catalog.ProductOptionModel) - Options model returned by the API - `promotions` (dw.util.Collection) - Active promotions for the product - `quantity` (number) - Current selected quantity - `variables` (Object) - Variables passed in on the query string - `factory` (Object) - Reference to product factory for creating bundled products ### Returns Object - Decorated product model with bundle-specific information ## Applied Decorators The product bundle model applies the following decorators in sequence: ### Standard Product Decorators - **base** - Fundamental product information: `uuid`, `id`, `productName`, `productType`, `brand` - **price** - Bundle pricing: `price` and `renderedPrice` with promotions - **images** - Product images: `images` with large and small sizes - **quantity** - Quantity constraints: `selectedQuantity`, `minOrderQuantity`, `maxOrderQuantity` - **description** - Product descriptions: `longDescription` and `shortDescription` markup - **ratings** - Product rating: `rating` value calculated from product ID - **promotions** - Active promotions: `promotions` array with promotion details - **attributes** - Product attributes: `attributes` array with grouped attribute data - **availability** - Availability status: `availability` object with messages and stock status - **options** - Product options: `options` array with option configurations - **quantitySelector** - Quantity selection: `quantities` array with step quantity options ### Bundle-Specific Decorators - **sizeChart** (conditional) - Size chart: `sizeChartId` if category has custom sizeChartID - **currentUrl** - Product URL: `selectedProductUrl` with variation and option parameters - **bundledProducts** - Bundle contents: `bundledProducts` array with individual product models - **bundleReadyToOrder** - Bundle readiness: `readyToOrder` boolean validation for entire bundle - **raw** - Raw API data: `raw` property (non-enumerable) with original API product - **pageMetaData** - SEO metadata: `pageTitle`, `pageDescription`, `pageKeywords`, `pageMetaTags` - **template** - Template info: `template` property for rendering ## Bundle-Specific Features ### Bundled Products Information The `bundledProducts` decorator adds: - List of individual products in the bundle - Quantities of each bundled product - Individual product pricing and availability - Product configuration options for each item ### Bundle Readiness Validation The `bundleReadyToOrder` decorator provides: - Overall bundle availability status - Validation that all required bundled products are available - Bundle-specific ordering constraints ### Bundle Pricing Bundle pricing includes: - Combined pricing of all bundled products - Bundle-level discounts and promotions - Individual product price contributions - Savings compared to individual purchases ## Usage Example ```javascript var bundleProductDecorator = require('*/cartridge/models/product/productBundle'); var productFactory = require('*/cartridge/scripts/factories/product'); // Prepare options for bundle var options = { productType: 'bundle', variationModel: variationModel, optionModel: optionModel, promotions: activePromotions, quantity: 1, variables: req.querystring, options: req.httpParameterMap }; // Create and decorate bundle product var product = {}; var bundleProduct = bundleProductDecorator(product, apiProduct, options, productFactory); // Access bundle-specific information console.log(bundleProduct.bundledProducts.length); console.log(bundleProduct.price.sales.formatted); console.log(bundleProduct.readyToOrder); // Check individual bundled products bundleProduct.bundledProducts.forEach(function(bundledProduct) { console.log(bundledProduct.productName + ' x ' + bundledProduct.quantity); }); ``` ## Bundle Structure After decoration, the bundle product contains: ### Standard Product Properties - **uuid** - Product UUID - **id** - Product ID - **productName** - Product name - **productType** - Product type - **brand** - Product brand - **price** - Comprehensive pricing with bundle discounts - **renderedPrice** - HTML-rendered price for display - **images** - Product images (large and small sizes) - **selectedQuantity** - Currently selected quantity - **minOrderQuantity** - Minimum order quantity - **maxOrderQuantity** - Maximum order quantity - **longDescription** - Product long description markup - **shortDescription** - Product short description markup - **rating** - Product rating value - **promotions** - Active promotion information - **attributes** - Product attribute groups and values - **availability** - Availability status and messages - **options** - Product option configurations - **quantities** - Available quantity selection options - **selectedProductUrl** - Current product URL with parameters ### Bundle-Specific Properties - **bundledProducts** - Array of individual product models in the bundle - **readyToOrder** - Boolean indicating if the entire bundle can be ordered - **sizeChartId** - Size chart identifier (if applicable) - **pageTitle** - SEO page title - **pageDescription** - SEO page description - **pageKeywords** - SEO page keywords - **pageMetaTags** - SEO meta tags array - **template** - Template identifier for rendering ## Notes - Handles complex bundle pricing calculations - Validates availability for all bundled products - Supports bundle-specific promotions and discounts - Maintains individual product information within the bundle - Provides comprehensive bundle readiness validation - Includes size chart support if any bundled products have size charts - Optimized for bundle product detail pages ## Related Models - **Product Factory** - Creates individual bundled product models - **Full Product Model** - Similar comprehensive decoration approach - **Product Set Model** - Alternative product grouping model - **Product Decorators** - Individual decoration functions ``` -------------------------------------------------------------------------------- /tests/servers/sfcc-mock-server-manager.ts: -------------------------------------------------------------------------------- ```typescript import { spawn, ChildProcess } from 'child_process'; import path from 'path'; /** * Manager for the unified SFCC Mock Server for testing purposes * * This class provides utilities to start, stop, and interact with the unified * SFCC mock server that combines WebDAV and OCAPI functionality. */ export class SFCCMockServerManager { private serverProcess: ChildProcess | null = null; private readonly config: SFCCMockServerConfig; private readonly serverPath: string; private startupPromise: Promise<void> | null = null; constructor(config: Partial<SFCCMockServerConfig> = {}) { this.config = { port: 3000, host: 'localhost', dev: false, autoSetup: true, timeout: 10000, webdav: true, ocapi: true, cors: true, ...config, }; this.serverPath = path.join(__dirname, 'sfcc-mock-server'); } /** * Check if the SFCC mock server is available for testing */ async isServerAvailable(): Promise<boolean> { try { const fs = await import('fs'); const serverJs = path.join(this.serverPath, 'server.js'); const packageJson = path.join(this.serverPath, 'package.json'); return fs.existsSync(serverJs) && fs.existsSync(packageJson); } catch { return false; } } /** * Start the SFCC mock server */ async start(): Promise<void> { if (this.startupPromise) { return this.startupPromise; } this.startupPromise = this._startServer(); return this.startupPromise; } private async _startServer(): Promise<void> { if (this.serverProcess) { throw new Error('Server is already running'); } const isAvailable = await this.isServerAvailable(); if (!isAvailable) { throw new Error('SFCC mock server is not available. Run setup first.'); } // Setup logs if auto-setup is enabled if (this.config.autoSetup) { await this._runSetup(); } const args = this._buildServerArgs(); return new Promise((resolve, reject) => { const timeout = setTimeout(() => { this.stop(); reject(new Error(`Server failed to start within ${this.config.timeout}ms`)); }, this.config.timeout); this.serverProcess = spawn('node', ['server.js', ...args], { cwd: this.serverPath, stdio: this.config.dev ? 'inherit' : 'pipe', }); this.serverProcess.on('error', (error) => { clearTimeout(timeout); reject(error); }); this.serverProcess.on('exit', (code, signal) => { if (code !== null && code !== 0) { clearTimeout(timeout); reject(new Error(`Server exited with code ${code}`)); } }); // Wait a bit for the server to start up setTimeout(async () => { try { // Test if server is responding using the health endpoint const response = await fetch(`${this.getServerUrl()}/health`); if (response.ok) { clearTimeout(timeout); resolve(); } else { clearTimeout(timeout); reject(new Error(`Server health check failed with status ${response.status}`)); } } catch (error) { clearTimeout(timeout); reject(new Error(`Server health check failed: ${error}`)); } }, 2000); // Give server 2 seconds to start }); } private async _runSetup(): Promise<void> { return new Promise((resolve, reject) => { const setupProcess = spawn('npm', ['run', 'setup:logs'], { cwd: this.serverPath, stdio: 'pipe', }); setupProcess.on('error', reject); setupProcess.on('exit', (code) => { if (code === 0) { resolve(); } else { reject(new Error(`Setup failed with code ${code}`)); } }); }); } private _buildServerArgs(): string[] { const args: string[] = []; args.push('--port', this.config.port.toString()); args.push('--host', this.config.host); if (this.config.dev) { args.push('--dev'); } if (!this.config.webdav) { args.push('--no-webdav'); } if (!this.config.ocapi) { args.push('--no-ocapi'); } if (!this.config.cors) { args.push('--no-cors'); } return args; } /** * Stop the SFCC mock server */ async stop(): Promise<void> { return new Promise((resolve) => { if (!this.serverProcess) { resolve(); return; } const process = this.serverProcess; this.serverProcess = null; this.startupPromise = null; const timeout = setTimeout(() => { process.kill('SIGKILL'); resolve(); }, 5000); process.on('exit', () => { clearTimeout(timeout); resolve(); }); process.kill('SIGTERM'); }); } /** * Check if the server is currently running */ isRunning(): boolean { return this.serverProcess !== null && this.serverProcess.exitCode === null; } /** * Get the base server URL */ getServerUrl(): string { return `http://${this.config.host}:${this.config.port}`; } /** * Get the WebDAV logs URL (SFCC path) */ getWebDAVLogsUrl(): string { return `${this.getServerUrl()}/on/demandware.servlet/webdav/Sites/Logs/`; } /** * Get the direct logs URL */ getDirectLogsUrl(): string { return `${this.getServerUrl()}/Logs/`; } /** * Get the OCAPI base URL */ getOCAPIUrl(): string { return `${this.getServerUrl()}/s/-/dw/data/v23_2`; } /** * Get the OCAPI OAuth URL */ getOAuthUrl(): string { return `${this.getServerUrl()}/dw/oauth2/access_token`; } } /** * Configuration interface for the SFCC mock server manager */ export interface SFCCMockServerConfig { port: number; host: string; dev: boolean; autoSetup: boolean; timeout: number; webdav: boolean; ocapi: boolean; cors: boolean; } /** * Utility function to run a test with the SFCC mock server * * @param testFn Function to run with server URLs * @param config Optional server configuration * @returns Promise resolving to the test function result */ export async function withSFCCMockServer<T>( testFn: (serverUrl: string, webdavLogsUrl: string, directLogsUrl: string, ocapiUrl: string, oauthUrl: string) => Promise<T>, config: Partial<SFCCMockServerConfig> = {} ): Promise<T> { const manager = new SFCCMockServerManager({ port: 3004, // Use different port for utility function ...config, }); if (!await manager.isServerAvailable()) { throw new Error('SFCC mock server is not available'); } try { await manager.start(); return await testFn( manager.getServerUrl(), manager.getWebDAVLogsUrl(), manager.getDirectLogsUrl(), manager.getOCAPIUrl(), manager.getOAuthUrl() ); } finally { await manager.stop(); } } ``` -------------------------------------------------------------------------------- /docs/dw_rpc/Stub.md: -------------------------------------------------------------------------------- ```markdown ## Package: dw.rpc # Class Stub ## Inheritance Hierarchy - Object - dw.rpc.Stub ## Description This is the base class for all service stubs accessible through a WebReference object. The Stub provides access to the WSDL operations. Demandware recommends a low timeout to ensure responsiveness of the site and to avoid thread exhaustion. Use the Services module in Business Manager to set timeout values, not the methods for this class. The Services module provides better analytics and timeout management. The default timeout, if not set, is 15 minutes when the web service is used in a job, and 2 minutes otherwise. If the timeout of the calling script is lower, the script timeout is used. // get WebReference var webref : WebReference = webreferences.myWSDLname; // get service stub var stub : Stub = webref.defaultService; ## Constants ### CONNECTION_TIMEOUT **Type:** String This property allows the user to set the web service connection timeout value in milliseconds. By default, the web service connection timeout is 5000 milliseconds (5 seconds). The minimum allowed value is 100 milliseconds and the maximum allowed value is 15000 milliseconds (15 seconds). Demandware recommends setting timeout values in Business Manager Services module as it provides better analytics and timeout management. ### ENDPOINT_ADDRESS_PROPERTY **Type:** String Standard property: target service endpoint address. The URI scheme for the endpoint address specification must correspond to the protocol/transport binding for this stub class. ### PASSWORD_PROPERTY **Type:** String Standard property: password for authentication. ### SESSION_MAINTAIN_PROPERTY **Type:** String Standard property: this boolean property is used by a service client to indicate whether or not it wants to participate in a session with a service endpoint. If this property is set to true, the service client indicates that it wants the session to be maintained. If set to false, the session is not maintained. The default value for this property is false. ### USERNAME_PROPERTY **Type:** String Standard property: user name for authentication. ## Properties ### password **Type:** String The password. ### timeout **Type:** Number The current read timeout value in milliseconds for this Stub. ### username **Type:** String The user name. Note: this method handles sensitive security-related data. Pay special attention to PCI DSS v3. requirements 2, 4, and 12. ## Constructor Summary Stub() ## Method Summary ### _getProperty **Signature:** `_getProperty(name : String) : Object` Gets the value of a specific configuration property. ### _setProperty **Signature:** `_setProperty(name : String, value : Object) : void` Sets the name and value of a configuration property for this Stub instance. ### getPassword **Signature:** `getPassword() : String` Returns the password. ### getTimeout **Signature:** `getTimeout() : Number` Returns the current read timeout value in milliseconds for this Stub. ### getUsername **Signature:** `getUsername() : String` Returns the user name. ### setHeader **Signature:** `setHeader(namespace : String, name : String, value : Object) : void` Sets an additional SOAP header value for the next operation. ### setPassword **Signature:** `setPassword(password : String) : void` Sets the password. ### setTimeout **Signature:** `setTimeout(timeout : Number) : void` Sets the timeout in milliseconds for the next call through this Stub. ### setUsername **Signature:** `setUsername(username : String) : void` Sets the user name. ## Constructor Detail ## Method Detail ## Method Details ### _getProperty **Signature:** `_getProperty(name : String) : Object` **Description:** Gets the value of a specific configuration property. **Deprecated:** use webreferences2 instead **Parameters:** - `name`: Name of the property whose value is to be retrieved **Returns:** Value of the configuration property --- ### _setProperty **Signature:** `_setProperty(name : String, value : Object) : void` **Description:** Sets the name and value of a configuration property for this Stub instance. If the Stub instance contains a value for the same property, the old value is replaced. Note: the _setProperty method may not perform a validity check on a configured property value. An example is the standard property for the target service endpoint address, which is not checked for validity in the _setProperty method. In this case, stub configuration errors are detected at the remote method invocation. **Deprecated:** use webreferences2 instead **Parameters:** - `name`: Name of the configuration property - `value`: Value of the property --- ### getPassword **Signature:** `getPassword() : String` **Description:** Returns the password. **Deprecated:** use webreferences2 instead **Returns:** the password. Note: this method handles sensitive security-related data. Pay special attention to PCI DSS v3. requirements 2, 4, and 12. --- ### getTimeout **Signature:** `getTimeout() : Number` **Description:** Returns the current read timeout value in milliseconds for this Stub. **Deprecated:** use webreferences2 instead **Returns:** the current timeout value for this Stub. --- ### getUsername **Signature:** `getUsername() : String` **Description:** Returns the user name. Note: this method handles sensitive security-related data. Pay special attention to PCI DSS v3. requirements 2, 4, and 12. **Deprecated:** use webreferences2 instead **Returns:** the user name. --- ### setHeader **Signature:** `setHeader(namespace : String, name : String, value : Object) : void` **Description:** Sets an additional SOAP header value for the next operation. **Deprecated:** use webreferences2 instead **Parameters:** - `namespace`: the namespace to use. - `name`: the name of the header item. - `value`: the value for the header item. --- ### setPassword **Signature:** `setPassword(password : String) : void` **Description:** Sets the password. **Deprecated:** use webreferences2 instead **Parameters:** - `password`: the password to set. --- ### setTimeout **Signature:** `setTimeout(timeout : Number) : void` **Description:** Sets the timeout in milliseconds for the next call through this Stub. This timeout value controls "read timeout" (how long, after connecting, it will wait without any data being read). To control "connection timeout" you use the _setProperty(String, Object) method where the name parameter is CONNECTION_TIMEOUT. **Deprecated:** use webreferences2 instead **Parameters:** - `timeout`: the timeout for the next call through this stub. **See Also:** _setProperty(String, Object) CONNECTION_TIMEOUT --- ### setUsername **Signature:** `setUsername(username : String) : void` **Description:** Sets the user name. **Deprecated:** use webreferences2 instead **Parameters:** - `username`: the user name to set. --- ``` -------------------------------------------------------------------------------- /tests/servers/sfcc-mock-server/mock-data/ocapi/site-preferences-sfra.json: -------------------------------------------------------------------------------- ```json { "_v": "23.2", "_type": "preference_value_search_result", "count": 4, "hits": [ { "_type": "preference_value", "attribute_definition": { "_type": "object_attribute_definition", "_resource_state": "sfra1-resource-state", "creation_date": "2024-01-01T00:00:00.000Z", "description": { "default": "Enable SFRA debug mode for development" }, "display_name": { "default": "SFRA Debug Mode" }, "effective_id": "c_sfraDebugMode", "externally_defined": false, "externally_managed": false, "id": "sfraDebugMode", "key": false, "last_modified": "2024-01-01T00:00:00.000Z", "link": "https://localhost:3000/s/-/dw/data/v23_2/system_object_definitions/SitePreferences/attribute_definitions/sfraDebugMode", "localizable": false, "mandatory": false, "multi_value_type": false, "order_required": false, "queryable": false, "read_only": false, "requires_encoding": false, "searchable": false, "set_value_type": false, "site_specific": false, "system": false, "value_type": "boolean", "visible": true }, "description": { "default": "Enable SFRA debug mode for development" }, "display_name": { "default": "SFRA Debug Mode" }, "id": "sfraDebugMode", "site_values": { "RefArch": false, "RefArchGlobal": false, "pxl_1": true, "pxl_2": false, "pxl_3": null, "pxl_4": null, "pxl_5": null, "pxl_6": null }, "value_type": "boolean" }, { "_type": "preference_value", "attribute_definition": { "_type": "object_attribute_definition", "_resource_state": "sfra2-resource-state", "creation_date": "2024-01-01T00:00:00.000Z", "description": { "default": "Custom middleware configurations for SFRA" }, "display_name": { "default": "SFRA Middleware Config" }, "effective_id": "c_sfraMiddlewareConfig", "externally_defined": false, "externally_managed": false, "field_height": 8, "id": "sfraMiddlewareConfig", "key": false, "last_modified": "2024-01-01T00:00:00.000Z", "link": "https://localhost:3000/s/-/dw/data/v23_2/system_object_definitions/SitePreferences/attribute_definitions/sfraMiddlewareConfig", "localizable": false, "mandatory": false, "multi_value_type": false, "order_required": false, "queryable": false, "read_only": false, "requires_encoding": false, "searchable": false, "set_value_type": false, "site_specific": true, "system": false, "value_type": "text", "visible": true }, "description": { "default": "Custom middleware configurations for SFRA" }, "display_name": { "default": "SFRA Middleware Config" }, "id": "sfraMiddlewareConfig", "site_values": { "RefArch": "{\"cache\": true, \"csrf\": true, \"compression\": false}", "RefArchGlobal": "{\"cache\": true, \"csrf\": true, \"compression\": true, \"logging\": \"debug\"}", "pxl_1": "", "pxl_2": "{\"cache\": false, \"csrf\": false}", "pxl_3": null, "pxl_4": null, "pxl_5": null, "pxl_6": null }, "value_type": "text" }, { "_type": "preference_value", "attribute_definition": { "_type": "object_attribute_definition", "_resource_state": "sfra3-resource-state", "creation_date": "2024-01-01T00:00:00.000Z", "description": { "default": "Maximum SFRA cache timeout in seconds" }, "display_name": { "default": "SFRA Cache Timeout" }, "effective_id": "c_sfraCacheTimeout", "externally_defined": false, "externally_managed": false, "id": "sfraCacheTimeout", "key": false, "last_modified": "2024-01-01T00:00:00.000Z", "link": "https://localhost:3000/s/-/dw/data/v23_2/system_object_definitions/SitePreferences/attribute_definitions/sfraCacheTimeout", "localizable": false, "mandatory": false, "multi_value_type": false, "order_required": false, "queryable": false, "read_only": false, "requires_encoding": false, "searchable": false, "set_value_type": false, "site_specific": true, "system": false, "value_type": "int", "visible": true }, "description": { "default": "Maximum SFRA cache timeout in seconds" }, "display_name": { "default": "SFRA Cache Timeout" }, "id": "sfraCacheTimeout", "site_values": { "RefArch": 3600, "RefArchGlobal": 7200, "pxl_1": 0, "pxl_2": 1800, "pxl_3": null, "pxl_4": null, "pxl_5": null, "pxl_6": null }, "value_type": "int" }, { "_type": "preference_value", "attribute_definition": { "_type": "object_attribute_definition", "_resource_state": "sfra4-resource-state", "creation_date": "2024-01-01T00:00:00.000Z", "description": { "default": "Configuration with null values to test edge cases" }, "display_name": { "default": "Edge Case Config" }, "effective_id": "c_edgeCaseConfig", "externally_defined": false, "externally_managed": false, "id": "edgeCaseConfig", "key": false, "last_modified": "2024-01-01T00:00:00.000Z", "link": "https://localhost:3000/s/-/dw/data/v23_2/system_object_definitions/SitePreferences/attribute_definitions/edgeCaseConfig", "localizable": false, "mandatory": false, "multi_value_type": false, "order_required": false, "queryable": false, "read_only": false, "requires_encoding": false, "searchable": false, "set_value_type": false, "site_specific": true, "system": false, "value_type": "text", "visible": false }, "description": { "default": "Configuration with null values to test edge cases" }, "display_name": { "default": "Edge Case Config" }, "id": "edgeCaseConfig", "site_values": { "RefArch": null, "RefArchGlobal": null, "pxl_1": null, "pxl_2": null, "pxl_3": null, "pxl_4": null, "pxl_5": null, "pxl_6": null }, "value_type": "text" } ], "query": { "match_all_query": { "_type": "match_all_query" } }, "select": "(**)", "start": 0, "total": 4 } ```