This is page 9 of 61. Use http://codebase.md/taurgis/sfcc-dev-mcp?lines=true&page={x} to view the full context. # Directory Structure ``` ├── .DS_Store ├── .github │ ├── dependabot.yml │ ├── instructions │ │ ├── mcp-node-tests.instructions.md │ │ └── mcp-yml-tests.instructions.md │ ├── ISSUE_TEMPLATE │ │ ├── bug_report.yml │ │ ├── config.yml │ │ ├── documentation.yml │ │ ├── feature_request.yml │ │ └── question.yml │ ├── PULL_REQUEST_TEMPLATE │ │ ├── bug_fix.md │ │ ├── documentation.md │ │ └── new_tool.md │ ├── pull_request_template.md │ └── workflows │ ├── ci.yml │ ├── deploy-pages.yml │ ├── publish.yml │ └── update-docs.yml ├── .gitignore ├── .husky │ └── pre-commit ├── aegis.config.docs-only.json ├── aegis.config.json ├── aegis.config.with-dw.json ├── AGENTS.md ├── ai-instructions │ ├── claude-desktop │ │ └── claude_custom_instructions.md │ ├── cursor │ │ └── .cursor │ │ └── rules │ │ ├── debugging-workflows.mdc │ │ ├── hooks-development.mdc │ │ ├── isml-templates.mdc │ │ ├── job-framework.mdc │ │ ├── performance-optimization.mdc │ │ ├── scapi-endpoints.mdc │ │ ├── security-patterns.mdc │ │ ├── sfcc-development.mdc │ │ ├── sfra-controllers.mdc │ │ ├── sfra-models.mdc │ │ ├── system-objects.mdc │ │ └── testing-patterns.mdc │ └── github-copilot │ └── copilot-instructions.md ├── CHANGELOG.md ├── CONTRIBUTING.md ├── docs │ ├── best-practices │ │ ├── cartridge_creation.md │ │ ├── isml_templates.md │ │ ├── job_framework.md │ │ ├── localserviceregistry.md │ │ ├── ocapi_hooks.md │ │ ├── performance.md │ │ ├── scapi_custom_endpoint.md │ │ ├── scapi_hooks.md │ │ ├── security.md │ │ ├── sfra_client_side_js.md │ │ ├── sfra_controllers.md │ │ ├── sfra_models.md │ │ └── sfra_scss.md │ ├── dw_campaign │ │ ├── ABTest.md │ │ ├── ABTestMgr.md │ │ ├── ABTestSegment.md │ │ ├── AmountDiscount.md │ │ ├── ApproachingDiscount.md │ │ ├── BonusChoiceDiscount.md │ │ ├── BonusDiscount.md │ │ ├── Campaign.md │ │ ├── CampaignMgr.md │ │ ├── CampaignStatusCodes.md │ │ ├── Coupon.md │ │ ├── CouponMgr.md │ │ ├── CouponRedemption.md │ │ ├── CouponStatusCodes.md │ │ ├── Discount.md │ │ ├── DiscountPlan.md │ │ ├── FixedPriceDiscount.md │ │ ├── FixedPriceShippingDiscount.md │ │ ├── FreeDiscount.md │ │ ├── FreeShippingDiscount.md │ │ ├── PercentageDiscount.md │ │ ├── PercentageOptionDiscount.md │ │ ├── PriceBookPriceDiscount.md │ │ ├── Promotion.md │ │ ├── PromotionMgr.md │ │ ├── PromotionPlan.md │ │ ├── SlotContent.md │ │ ├── SourceCodeGroup.md │ │ ├── SourceCodeInfo.md │ │ ├── SourceCodeStatusCodes.md │ │ └── TotalFixedPriceDiscount.md │ ├── dw_catalog │ │ ├── Catalog.md │ │ ├── CatalogMgr.md │ │ ├── Category.md │ │ ├── CategoryAssignment.md │ │ ├── CategoryLink.md │ │ ├── PriceBook.md │ │ ├── PriceBookMgr.md │ │ ├── Product.md │ │ ├── ProductActiveData.md │ │ ├── ProductAttributeModel.md │ │ ├── ProductAvailabilityLevels.md │ │ ├── ProductAvailabilityModel.md │ │ ├── ProductInventoryList.md │ │ ├── ProductInventoryMgr.md │ │ ├── ProductInventoryRecord.md │ │ ├── ProductLink.md │ │ ├── ProductMgr.md │ │ ├── ProductOption.md │ │ ├── ProductOptionModel.md │ │ ├── ProductOptionValue.md │ │ ├── ProductPriceInfo.md │ │ ├── ProductPriceModel.md │ │ ├── ProductPriceTable.md │ │ ├── ProductSearchHit.md │ │ ├── ProductSearchModel.md │ │ ├── ProductSearchRefinementDefinition.md │ │ ├── ProductSearchRefinements.md │ │ ├── ProductSearchRefinementValue.md │ │ ├── ProductVariationAttribute.md │ │ ├── ProductVariationAttributeValue.md │ │ ├── ProductVariationModel.md │ │ ├── Recommendation.md │ │ ├── SearchModel.md │ │ ├── SearchRefinementDefinition.md │ │ ├── SearchRefinements.md │ │ ├── SearchRefinementValue.md │ │ ├── SortingOption.md │ │ ├── SortingRule.md │ │ ├── Store.md │ │ ├── StoreGroup.md │ │ ├── StoreInventoryFilter.md │ │ ├── StoreInventoryFilterValue.md │ │ ├── StoreMgr.md │ │ ├── Variant.md │ │ └── VariationGroup.md │ ├── dw_content │ │ ├── Content.md │ │ ├── ContentMgr.md │ │ ├── ContentSearchModel.md │ │ ├── ContentSearchRefinementDefinition.md │ │ ├── ContentSearchRefinements.md │ │ ├── ContentSearchRefinementValue.md │ │ ├── Folder.md │ │ ├── Library.md │ │ ├── MarkupText.md │ │ └── MediaFile.md │ ├── dw_crypto │ │ ├── CertificateRef.md │ │ ├── CertificateUtils.md │ │ ├── Cipher.md │ │ ├── Encoding.md │ │ ├── JWE.md │ │ ├── JWEHeader.md │ │ ├── JWS.md │ │ ├── JWSHeader.md │ │ ├── KeyRef.md │ │ ├── Mac.md │ │ ├── MessageDigest.md │ │ ├── SecureRandom.md │ │ ├── Signature.md │ │ ├── WeakCipher.md │ │ ├── WeakMac.md │ │ ├── WeakMessageDigest.md │ │ ├── WeakSignature.md │ │ └── X509Certificate.md │ ├── dw_customer │ │ ├── AddressBook.md │ │ ├── AgentUserMgr.md │ │ ├── AgentUserStatusCodes.md │ │ ├── AuthenticationStatus.md │ │ ├── Credentials.md │ │ ├── Customer.md │ │ ├── CustomerActiveData.md │ │ ├── CustomerAddress.md │ │ ├── CustomerCDPData.md │ │ ├── CustomerContextMgr.md │ │ ├── CustomerGroup.md │ │ ├── CustomerList.md │ │ ├── CustomerMgr.md │ │ ├── CustomerPasswordConstraints.md │ │ ├── CustomerPaymentInstrument.md │ │ ├── CustomerStatusCodes.md │ │ ├── EncryptedObject.md │ │ ├── ExternalProfile.md │ │ ├── OrderHistory.md │ │ ├── ProductList.md │ │ ├── ProductListItem.md │ │ ├── ProductListItemPurchase.md │ │ ├── ProductListMgr.md │ │ ├── ProductListRegistrant.md │ │ ├── Profile.md │ │ └── Wallet.md │ ├── dw_extensions.applepay │ │ ├── ApplePayHookResult.md │ │ └── ApplePayHooks.md │ ├── dw_extensions.facebook │ │ ├── FacebookFeedHooks.md │ │ └── FacebookProduct.md │ ├── dw_extensions.paymentrequest │ │ ├── PaymentRequestHookResult.md │ │ └── PaymentRequestHooks.md │ ├── dw_extensions.payments │ │ ├── SalesforceBancontactPaymentDetails.md │ │ ├── SalesforceCardPaymentDetails.md │ │ ├── SalesforceEpsPaymentDetails.md │ │ ├── SalesforceIdealPaymentDetails.md │ │ ├── SalesforceKlarnaPaymentDetails.md │ │ ├── SalesforcePaymentDetails.md │ │ ├── SalesforcePaymentIntent.md │ │ ├── SalesforcePaymentMethod.md │ │ ├── SalesforcePaymentRequest.md │ │ ├── SalesforcePaymentsHooks.md │ │ ├── SalesforcePaymentsMgr.md │ │ ├── SalesforcePaymentsSiteConfiguration.md │ │ ├── SalesforcePayPalOrder.md │ │ ├── SalesforcePayPalOrderAddress.md │ │ ├── SalesforcePayPalOrderPayer.md │ │ ├── SalesforcePayPalPaymentDetails.md │ │ ├── SalesforceSepaDebitPaymentDetails.md │ │ └── SalesforceVenmoPaymentDetails.md │ ├── dw_extensions.pinterest │ │ ├── PinterestAvailability.md │ │ ├── PinterestFeedHooks.md │ │ ├── PinterestOrder.md │ │ ├── PinterestOrderHooks.md │ │ └── PinterestProduct.md │ ├── dw_io │ │ ├── CSVStreamReader.md │ │ ├── CSVStreamWriter.md │ │ ├── File.md │ │ ├── FileReader.md │ │ ├── FileWriter.md │ │ ├── InputStream.md │ │ ├── OutputStream.md │ │ ├── PrintWriter.md │ │ ├── RandomAccessFileReader.md │ │ ├── Reader.md │ │ ├── StringWriter.md │ │ ├── Writer.md │ │ ├── XMLIndentingStreamWriter.md │ │ ├── XMLStreamConstants.md │ │ ├── XMLStreamReader.md │ │ └── XMLStreamWriter.md │ ├── dw_job │ │ ├── JobExecution.md │ │ └── JobStepExecution.md │ ├── dw_net │ │ ├── FTPClient.md │ │ ├── FTPFileInfo.md │ │ ├── HTTPClient.md │ │ ├── HTTPRequestPart.md │ │ ├── Mail.md │ │ ├── SFTPClient.md │ │ ├── SFTPFileInfo.md │ │ ├── WebDAVClient.md │ │ └── WebDAVFileInfo.md │ ├── dw_object │ │ ├── ActiveData.md │ │ ├── CustomAttributes.md │ │ ├── CustomObject.md │ │ ├── CustomObjectMgr.md │ │ ├── Extensible.md │ │ ├── ExtensibleObject.md │ │ ├── Note.md │ │ ├── ObjectAttributeDefinition.md │ │ ├── ObjectAttributeGroup.md │ │ ├── ObjectAttributeValueDefinition.md │ │ ├── ObjectTypeDefinition.md │ │ ├── PersistentObject.md │ │ ├── SimpleExtensible.md │ │ └── SystemObjectMgr.md │ ├── dw_order │ │ ├── AbstractItem.md │ │ ├── AbstractItemCtnr.md │ │ ├── Appeasement.md │ │ ├── AppeasementItem.md │ │ ├── Basket.md │ │ ├── BasketMgr.md │ │ ├── BonusDiscountLineItem.md │ │ ├── CouponLineItem.md │ │ ├── CreateAgentBasketLimitExceededException.md │ │ ├── CreateBasketFromOrderException.md │ │ ├── CreateCouponLineItemException.md │ │ ├── CreateOrderException.md │ │ ├── CreateTemporaryBasketLimitExceededException.md │ │ ├── GiftCertificate.md │ │ ├── GiftCertificateLineItem.md │ │ ├── GiftCertificateMgr.md │ │ ├── GiftCertificateStatusCodes.md │ │ ├── Invoice.md │ │ ├── InvoiceItem.md │ │ ├── LineItem.md │ │ ├── LineItemCtnr.md │ │ ├── Order.md │ │ ├── OrderAddress.md │ │ ├── OrderItem.md │ │ ├── OrderMgr.md │ │ ├── OrderPaymentInstrument.md │ │ ├── OrderProcessStatusCodes.md │ │ ├── PaymentCard.md │ │ ├── PaymentInstrument.md │ │ ├── PaymentMethod.md │ │ ├── PaymentMgr.md │ │ ├── PaymentProcessor.md │ │ ├── PaymentStatusCodes.md │ │ ├── PaymentTransaction.md │ │ ├── PriceAdjustment.md │ │ ├── PriceAdjustmentLimitTypes.md │ │ ├── ProductLineItem.md │ │ ├── ProductShippingCost.md │ │ ├── ProductShippingLineItem.md │ │ ├── ProductShippingModel.md │ │ ├── Return.md │ │ ├── ReturnCase.md │ │ ├── ReturnCaseItem.md │ │ ├── ReturnItem.md │ │ ├── Shipment.md │ │ ├── ShipmentShippingCost.md │ │ ├── ShipmentShippingModel.md │ │ ├── ShippingLineItem.md │ │ ├── ShippingLocation.md │ │ ├── ShippingMethod.md │ │ ├── ShippingMgr.md │ │ ├── ShippingOrder.md │ │ ├── ShippingOrderItem.md │ │ ├── SumItem.md │ │ ├── TaxGroup.md │ │ ├── TaxItem.md │ │ ├── TaxMgr.md │ │ ├── TrackingInfo.md │ │ └── TrackingRef.md │ ├── dw_order.hooks │ │ ├── CalculateHooks.md │ │ ├── OrderHooks.md │ │ ├── PaymentHooks.md │ │ ├── ReturnHooks.md │ │ └── ShippingOrderHooks.md │ ├── dw_rpc │ │ ├── SOAPUtil.md │ │ ├── Stub.md │ │ └── WebReference.md │ ├── dw_suggest │ │ ├── BrandSuggestions.md │ │ ├── CategorySuggestions.md │ │ ├── ContentSuggestions.md │ │ ├── CustomSuggestions.md │ │ ├── ProductSuggestions.md │ │ ├── SearchPhraseSuggestions.md │ │ ├── SuggestedCategory.md │ │ ├── SuggestedContent.md │ │ ├── SuggestedPhrase.md │ │ ├── SuggestedProduct.md │ │ ├── SuggestedTerm.md │ │ ├── SuggestedTerms.md │ │ ├── Suggestions.md │ │ └── SuggestModel.md │ ├── dw_svc │ │ ├── FTPService.md │ │ ├── FTPServiceDefinition.md │ │ ├── HTTPFormService.md │ │ ├── HTTPFormServiceDefinition.md │ │ ├── HTTPService.md │ │ ├── HTTPServiceDefinition.md │ │ ├── LocalServiceRegistry.md │ │ ├── Result.md │ │ ├── Service.md │ │ ├── ServiceCallback.md │ │ ├── ServiceConfig.md │ │ ├── ServiceCredential.md │ │ ├── ServiceDefinition.md │ │ ├── ServiceProfile.md │ │ ├── ServiceRegistry.md │ │ ├── SOAPService.md │ │ └── SOAPServiceDefinition.md │ ├── dw_system │ │ ├── AgentUserStatusCodes.md │ │ ├── Cache.md │ │ ├── CacheMgr.md │ │ ├── HookMgr.md │ │ ├── InternalObject.md │ │ ├── JobProcessMonitor.md │ │ ├── Log.md │ │ ├── Logger.md │ │ ├── LogNDC.md │ │ ├── OrganizationPreferences.md │ │ ├── Pipeline.md │ │ ├── PipelineDictionary.md │ │ ├── RemoteInclude.md │ │ ├── Request.md │ │ ├── RequestHooks.md │ │ ├── Response.md │ │ ├── RESTErrorResponse.md │ │ ├── RESTResponseMgr.md │ │ ├── RESTSuccessResponse.md │ │ ├── SearchStatus.md │ │ ├── Session.md │ │ ├── Site.md │ │ ├── SitePreferences.md │ │ ├── Status.md │ │ ├── StatusItem.md │ │ ├── System.md │ │ └── Transaction.md │ ├── dw_util │ │ ├── ArrayList.md │ │ ├── Assert.md │ │ ├── BigInteger.md │ │ ├── Bytes.md │ │ ├── Calendar.md │ │ ├── Collection.md │ │ ├── Currency.md │ │ ├── DateUtils.md │ │ ├── Decimal.md │ │ ├── FilteringCollection.md │ │ ├── Geolocation.md │ │ ├── HashMap.md │ │ ├── HashSet.md │ │ ├── Iterator.md │ │ ├── LinkedHashMap.md │ │ ├── LinkedHashSet.md │ │ ├── List.md │ │ ├── Locale.md │ │ ├── Map.md │ │ ├── MapEntry.md │ │ ├── MappingKey.md │ │ ├── MappingMgr.md │ │ ├── PropertyComparator.md │ │ ├── SecureEncoder.md │ │ ├── SecureFilter.md │ │ ├── SeekableIterator.md │ │ ├── Set.md │ │ ├── SortedMap.md │ │ ├── SortedSet.md │ │ ├── StringUtils.md │ │ ├── Template.md │ │ └── UUIDUtils.md │ ├── dw_value │ │ ├── EnumValue.md │ │ ├── MimeEncodedText.md │ │ ├── Money.md │ │ └── Quantity.md │ ├── dw_web │ │ ├── ClickStream.md │ │ ├── ClickStreamEntry.md │ │ ├── Cookie.md │ │ ├── Cookies.md │ │ ├── CSRFProtection.md │ │ ├── Form.md │ │ ├── FormAction.md │ │ ├── FormElement.md │ │ ├── FormElementValidationResult.md │ │ ├── FormField.md │ │ ├── FormFieldOption.md │ │ ├── FormFieldOptions.md │ │ ├── FormGroup.md │ │ ├── FormList.md │ │ ├── FormListItem.md │ │ ├── Forms.md │ │ ├── HttpParameter.md │ │ ├── HttpParameterMap.md │ │ ├── LoopIterator.md │ │ ├── PageMetaData.md │ │ ├── PageMetaTag.md │ │ ├── PagingModel.md │ │ ├── Resource.md │ │ ├── URL.md │ │ ├── URLAction.md │ │ ├── URLParameter.md │ │ ├── URLRedirect.md │ │ ├── URLRedirectMgr.md │ │ └── URLUtils.md │ ├── sfra │ │ ├── account.md │ │ ├── address.md │ │ ├── billing.md │ │ ├── cart.md │ │ ├── categories.md │ │ ├── content.md │ │ ├── locale.md │ │ ├── order.md │ │ ├── payment.md │ │ ├── price-default.md │ │ ├── price-range.md │ │ ├── price-tiered.md │ │ ├── product-bundle.md │ │ ├── product-full.md │ │ ├── product-line-items.md │ │ ├── product-search.md │ │ ├── product-tile.md │ │ ├── querystring.md │ │ ├── render.md │ │ ├── request.md │ │ ├── response.md │ │ ├── server.md │ │ ├── shipping.md │ │ ├── store.md │ │ ├── stores.md │ │ └── totals.md │ └── TopLevel │ ├── APIException.md │ ├── arguments.md │ ├── Array.md │ ├── ArrayBuffer.md │ ├── BigInt.md │ ├── Boolean.md │ ├── ConversionError.md │ ├── DataView.md │ ├── Date.md │ ├── Error.md │ ├── ES6Iterator.md │ ├── EvalError.md │ ├── Fault.md │ ├── Float32Array.md │ ├── Float64Array.md │ ├── Function.md │ ├── Generator.md │ ├── global.md │ ├── Int16Array.md │ ├── Int32Array.md │ ├── Int8Array.md │ ├── InternalError.md │ ├── IOError.md │ ├── Iterable.md │ ├── Iterator.md │ ├── JSON.md │ ├── Map.md │ ├── Math.md │ ├── Module.md │ ├── Namespace.md │ ├── Number.md │ ├── Object.md │ ├── QName.md │ ├── RangeError.md │ ├── ReferenceError.md │ ├── RegExp.md │ ├── Set.md │ ├── StopIteration.md │ ├── String.md │ ├── Symbol.md │ ├── SyntaxError.md │ ├── SystemError.md │ ├── TypeError.md │ ├── Uint16Array.md │ ├── Uint32Array.md │ ├── Uint8Array.md │ ├── Uint8ClampedArray.md │ ├── URIError.md │ ├── WeakMap.md │ ├── WeakSet.md │ ├── XML.md │ ├── XMLList.md │ └── XMLStreamError.md ├── docs-site │ ├── .gitignore │ ├── App.tsx │ ├── components │ │ ├── Badge.tsx │ │ ├── BreadcrumbSchema.tsx │ │ ├── CodeBlock.tsx │ │ ├── Collapsible.tsx │ │ ├── ConfigBuilder.tsx │ │ ├── ConfigHero.tsx │ │ ├── ConfigModeTabs.tsx │ │ ├── icons.tsx │ │ ├── Layout.tsx │ │ ├── LightCodeContainer.tsx │ │ ├── NewcomerCTA.tsx │ │ ├── NextStepsStrip.tsx │ │ ├── OnThisPage.tsx │ │ ├── Search.tsx │ │ ├── SEO.tsx │ │ ├── Sidebar.tsx │ │ ├── StructuredData.tsx │ │ ├── ToolCard.tsx │ │ ├── ToolFilters.tsx │ │ ├── Typography.tsx │ │ └── VersionBadge.tsx │ ├── constants.tsx │ ├── index.html │ ├── main.tsx │ ├── metadata.json │ ├── package-lock.json │ ├── package.json │ ├── pages │ │ ├── AIInterfacesPage.tsx │ │ ├── ConfigurationPage.tsx │ │ ├── DevelopmentPage.tsx │ │ ├── ExamplesPage.tsx │ │ ├── FeaturesPage.tsx │ │ ├── HomePage.tsx │ │ ├── SecurityPage.tsx │ │ ├── ToolsPage.tsx │ │ └── TroubleshootingPage.tsx │ ├── postcss.config.js │ ├── public │ │ ├── .well-known │ │ │ └── security.txt │ │ ├── 404.html │ │ ├── android-chrome-192x192.png │ │ ├── android-chrome-512x512.png │ │ ├── apple-touch-icon.png │ │ ├── explain-product-pricing-methods-no-mcp.png │ │ ├── explain-product-pricing-methods.png │ │ ├── favicon-16x16.png │ │ ├── favicon-32x32.png │ │ ├── favicon.ico │ │ ├── llms.txt │ │ ├── robots.txt │ │ ├── site.webmanifest │ │ └── sitemap.xml │ ├── README.md │ ├── scripts │ │ ├── generate-search-index.js │ │ ├── generate-sitemap.js │ │ └── search-dev.js │ ├── src │ │ └── styles │ │ ├── input.css │ │ └── prism-theme.css │ ├── tailwind.config.js │ ├── tsconfig.json │ ├── types.ts │ ├── utils │ │ ├── search.ts │ │ └── toolsData.ts │ └── vite.config.ts ├── eslint.config.js ├── jest.config.js ├── LICENSE ├── package-lock.json ├── package.json ├── README.md ├── scripts │ └── convert-docs.js ├── SECURITY.md ├── server.json ├── src │ ├── clients │ │ ├── base │ │ │ ├── http-client.ts │ │ │ ├── oauth-token.ts │ │ │ └── ocapi-auth-client.ts │ │ ├── best-practices-client.ts │ │ ├── cartridge-generation-client.ts │ │ ├── docs │ │ │ ├── class-content-parser.ts │ │ │ ├── class-name-resolver.ts │ │ │ ├── documentation-scanner.ts │ │ │ ├── index.ts │ │ │ └── referenced-types-extractor.ts │ │ ├── docs-client.ts │ │ ├── log-client.ts │ │ ├── logs │ │ │ ├── index.ts │ │ │ ├── log-analyzer.ts │ │ │ ├── log-client.ts │ │ │ ├── log-constants.ts │ │ │ ├── log-file-discovery.ts │ │ │ ├── log-file-reader.ts │ │ │ ├── log-formatter.ts │ │ │ ├── log-processor.ts │ │ │ ├── log-types.ts │ │ │ └── webdav-client-manager.ts │ │ ├── ocapi │ │ │ ├── code-versions-client.ts │ │ │ ├── site-preferences-client.ts │ │ │ └── system-objects-client.ts │ │ ├── ocapi-client.ts │ │ └── sfra-client.ts │ ├── config │ │ ├── configuration-factory.ts │ │ └── dw-json-loader.ts │ ├── core │ │ ├── handlers │ │ │ ├── abstract-log-tool-handler.ts │ │ │ ├── base-handler.ts │ │ │ ├── best-practices-handler.ts │ │ │ ├── cartridge-handler.ts │ │ │ ├── client-factory.ts │ │ │ ├── code-version-handler.ts │ │ │ ├── docs-handler.ts │ │ │ ├── job-log-handler.ts │ │ │ ├── job-log-tool-config.ts │ │ │ ├── log-handler.ts │ │ │ ├── log-tool-config.ts │ │ │ ├── sfra-handler.ts │ │ │ ├── system-object-handler.ts │ │ │ └── validation-helpers.ts │ │ ├── server.ts │ │ └── tool-definitions.ts │ ├── index.ts │ ├── main.ts │ ├── services │ │ ├── file-system-service.ts │ │ ├── index.ts │ │ └── path-service.ts │ ├── tool-configs │ │ ├── best-practices-tool-config.ts │ │ ├── cartridge-tool-config.ts │ │ ├── code-version-tool-config.ts │ │ ├── docs-tool-config.ts │ │ ├── job-log-tool-config.ts │ │ ├── log-tool-config.ts │ │ ├── sfra-tool-config.ts │ │ └── system-object-tool-config.ts │ ├── types │ │ └── types.ts │ └── utils │ ├── cache.ts │ ├── job-log-tool-config.ts │ ├── job-log-utils.ts │ ├── log-cache.ts │ ├── log-tool-config.ts │ ├── log-tool-constants.ts │ ├── log-tool-utils.ts │ ├── logger.ts │ ├── ocapi-url-builder.ts │ ├── path-resolver.ts │ ├── query-builder.ts │ ├── utils.ts │ └── validator.ts ├── tests │ ├── __mocks__ │ │ ├── docs-client.ts │ │ ├── src │ │ │ └── clients │ │ │ └── base │ │ │ └── http-client.js │ │ └── webdav.js │ ├── base-handler.test.ts │ ├── base-http-client.test.ts │ ├── best-practices-handler.test.ts │ ├── cache.test.ts │ ├── cartridge-handler.test.ts │ ├── class-content-parser.test.ts │ ├── class-name-resolver.test.ts │ ├── client-factory.test.ts │ ├── code-version-handler.test.ts │ ├── code-versions-client.test.ts │ ├── config.test.ts │ ├── configuration-factory.test.ts │ ├── docs-handler.test.ts │ ├── documentation-scanner.test.ts │ ├── file-system-service.test.ts │ ├── job-log-handler.test.ts │ ├── job-log-utils.test.ts │ ├── log-client.test.ts │ ├── log-handler.test.ts │ ├── log-processor.test.ts │ ├── logger.test.ts │ ├── mcp │ │ ├── AGENTS.md │ │ ├── node │ │ │ ├── activate-code-version-advanced.full-mode.programmatic.test.js │ │ │ ├── code-versions.full-mode.programmatic.test.js │ │ │ ├── generate-cartridge-structure.docs-only.programmatic.test.js │ │ │ ├── get-available-best-practice-guides.docs-only.programmatic.test.js │ │ │ ├── get-available-sfra-documents.programmatic.test.js │ │ │ ├── get-best-practice-guide.docs-only.programmatic.test.js │ │ │ ├── get-hook-reference.docs-only.programmatic.test.js │ │ │ ├── get-job-execution-summary.full-mode.programmatic.test.js │ │ │ ├── get-job-log-entries.full-mode.programmatic.test.js │ │ │ ├── get-latest-debug.full-mode.programmatic.test.js │ │ │ ├── get-latest-error.full-mode.programmatic.test.js │ │ │ ├── get-latest-info.full-mode.programmatic.test.js │ │ │ ├── get-latest-job-log-files.full-mode.programmatic.test.js │ │ │ ├── get-latest-warn.full-mode.programmatic.test.js │ │ │ ├── get-log-file-contents.full-mode.programmatic.test.js │ │ │ ├── get-sfcc-class-documentation.docs-only.programmatic.test.js │ │ │ ├── get-sfcc-class-info.docs-only.programmatic.test.js │ │ │ ├── get-sfra-categories.docs-only.programmatic.test.js │ │ │ ├── get-sfra-document.programmatic.test.js │ │ │ ├── get-sfra-documents-by-category.docs-only.programmatic.test.js │ │ │ ├── get-system-object-definition.full-mode.programmatic.test.js │ │ │ ├── get-system-object-definitions.docs-only.programmatic.test.js │ │ │ ├── get-system-object-definitions.full-mode.programmatic.test.js │ │ │ ├── list-log-files.full-mode.programmatic.test.js │ │ │ ├── list-sfcc-classes.docs-only.programmatic.test.js │ │ │ ├── search-best-practices.docs-only.programmatic.test.js │ │ │ ├── search-custom-object-attribute-definitions.full-mode.programmatic.test.js │ │ │ ├── search-job-logs-by-name.full-mode.programmatic.test.js │ │ │ ├── search-job-logs.full-mode.programmatic.test.js │ │ │ ├── search-logs.full-mode.programmatic.test.js │ │ │ ├── search-sfcc-classes.docs-only.programmatic.test.js │ │ │ ├── search-sfcc-methods.docs-only.programmatic.test.js │ │ │ ├── search-sfra-documentation.docs-only.programmatic.test.js │ │ │ ├── search-site-preferences.full-mode.programmatic.test.js │ │ │ ├── search-system-object-attribute-definitions.full-mode.programmatic.test.js │ │ │ ├── search-system-object-attribute-groups.full-mode.programmatic.test.js │ │ │ ├── summarize-logs.full-mode.programmatic.test.js │ │ │ ├── tools.docs-only.programmatic.test.js │ │ │ └── tools.full-mode.programmatic.test.js │ │ ├── README.md │ │ ├── test-fixtures │ │ │ └── dw.json │ │ └── yaml │ │ ├── activate-code-version.docs-only.test.mcp.yml │ │ ├── activate-code-version.full-mode.test.mcp.yml │ │ ├── get_latest_error.test.mcp.yml │ │ ├── get-available-best-practice-guides.docs-only.test.mcp.yml │ │ ├── get-available-best-practice-guides.full-mode.test.mcp.yml │ │ ├── get-available-sfra-documents.docs-only.test.mcp.yml │ │ ├── get-available-sfra-documents.full-mode.test.mcp.yml │ │ ├── get-best-practice-guide.docs-only.test.mcp.yml │ │ ├── get-best-practice-guide.full-mode.test.mcp.yml │ │ ├── get-code-versions.docs-only.test.mcp.yml │ │ ├── get-code-versions.full-mode.test.mcp.yml │ │ ├── get-hook-reference.docs-only.test.mcp.yml │ │ ├── get-hook-reference.full-mode.test.mcp.yml │ │ ├── get-job-execution-summary.full-mode.test.mcp.yml │ │ ├── get-job-log-entries.full-mode.test.mcp.yml │ │ ├── get-latest-debug.full-mode.test.mcp.yml │ │ ├── get-latest-error.full-mode.test.mcp.yml │ │ ├── get-latest-info.full-mode.test.mcp.yml │ │ ├── get-latest-job-log-files.full-mode.test.mcp.yml │ │ ├── get-latest-warn.full-mode.test.mcp.yml │ │ ├── get-log-file-contents.full-mode.test.mcp.yml │ │ ├── get-sfcc-class-documentation.docs-only.test.mcp.yml │ │ ├── get-sfcc-class-documentation.full-mode.test.mcp.yml │ │ ├── get-sfcc-class-info.docs-only.test.mcp.yml │ │ ├── get-sfcc-class-info.full-mode.test.mcp.yml │ │ ├── get-sfra-categories.docs-only.test.mcp.yml │ │ ├── get-sfra-categories.full-mode.test.mcp.yml │ │ ├── get-sfra-document.docs-only.test.mcp.yml │ │ ├── get-sfra-document.full-mode.test.mcp.yml │ │ ├── get-sfra-documents-by-category.docs-only.test.mcp.yml │ │ ├── get-sfra-documents-by-category.full-mode.test.mcp.yml │ │ ├── get-system-object-definition.docs-only.test.mcp.yml │ │ ├── get-system-object-definition.full-mode.test.mcp.yml │ │ ├── get-system-object-definitions.docs-only.test.mcp.yml │ │ ├── get-system-object-definitions.full-mode.test.mcp.yml │ │ ├── list-log-files.full-mode.test.mcp.yml │ │ ├── list-sfcc-classes.docs-only.test.mcp.yml │ │ ├── list-sfcc-classes.full-mode.test.mcp.yml │ │ ├── search-best-practices.docs-only.test.mcp.yml │ │ ├── search-best-practices.full-mode.test.mcp.yml │ │ ├── search-custom-object-attribute-definitions.docs-only.test.mcp.yml │ │ ├── search-custom-object-attribute-definitions.test.mcp.yml │ │ ├── search-job-logs-by-name.full-mode.test.mcp.yml │ │ ├── search-job-logs.full-mode.test.mcp.yml │ │ ├── search-logs.full-mode.test.mcp.yml │ │ ├── search-sfcc-classes.docs-only.test.mcp.yml │ │ ├── search-sfcc-classes.full-mode.test.mcp.yml │ │ ├── search-sfcc-methods.docs-only.test.mcp.yml │ │ ├── search-sfcc-methods.full-mode.test.mcp.yml │ │ ├── search-sfra-documentation.docs-only.test.mcp.yml │ │ ├── search-sfra-documentation.full-mode.test.mcp.yml │ │ ├── search-site-preferences.docs-only.test.mcp.yml │ │ ├── search-site-preferences.full-mode.test.mcp.yml │ │ ├── search-system-object-attribute-definitions.docs-only.test.mcp.yml │ │ ├── search-system-object-attribute-definitions.full-mode.test.mcp.yml │ │ ├── search-system-object-attribute-groups.docs-only.test.mcp.yml │ │ ├── search-system-object-attribute-groups.full-mode.test.mcp.yml │ │ ├── summarize-logs.full-mode.test.mcp.yml │ │ ├── tools.docs-only.test.mcp.yml │ │ └── tools.full-mode.test.mcp.yml │ ├── oauth-token.test.ts │ ├── ocapi-auth-client.test.ts │ ├── ocapi-client.test.ts │ ├── path-service.test.ts │ ├── query-builder.test.ts │ ├── referenced-types-extractor.test.ts │ ├── servers │ │ ├── sfcc-mock-server │ │ │ ├── mock-data │ │ │ │ └── ocapi │ │ │ │ ├── code-versions.json │ │ │ │ ├── custom-object-attributes-customapi.json │ │ │ │ ├── custom-object-attributes-globalsettings.json │ │ │ │ ├── custom-object-attributes-versionhistory.json │ │ │ │ ├── site-preferences-ccv.json │ │ │ │ ├── site-preferences-fastforward.json │ │ │ │ ├── site-preferences-sfra.json │ │ │ │ ├── site-preferences-storefront.json │ │ │ │ ├── site-preferences-system.json │ │ │ │ ├── system-object-attribute-groups-campaign.json │ │ │ │ ├── system-object-attribute-groups-category.json │ │ │ │ ├── system-object-attribute-groups-order.json │ │ │ │ ├── system-object-attribute-groups-product.json │ │ │ │ ├── system-object-attribute-groups-sitepreferences.json │ │ │ │ ├── system-object-attributes-customeraddress.json │ │ │ │ ├── system-object-attributes-product-expanded.json │ │ │ │ ├── system-object-attributes-product.json │ │ │ │ ├── system-object-definition-category.json │ │ │ │ ├── system-object-definition-customer.json │ │ │ │ ├── system-object-definition-customeraddress.json │ │ │ │ ├── system-object-definition-order.json │ │ │ │ ├── system-object-definition-product.json │ │ │ │ ├── system-object-definitions-old.json │ │ │ │ └── system-object-definitions.json │ │ │ ├── package-lock.json │ │ │ ├── package.json │ │ │ ├── README.md │ │ │ ├── scripts │ │ │ │ └── setup-logs.js │ │ │ ├── server.js │ │ │ └── src │ │ │ ├── app.js │ │ │ ├── config │ │ │ │ └── server-config.js │ │ │ ├── middleware │ │ │ │ ├── auth.js │ │ │ │ ├── cors.js │ │ │ │ └── logging.js │ │ │ ├── routes │ │ │ │ ├── ocapi │ │ │ │ │ ├── code-versions-handler.js │ │ │ │ │ ├── oauth-handler.js │ │ │ │ │ ├── ocapi-error-utils.js │ │ │ │ │ ├── ocapi-utils.js │ │ │ │ │ ├── site-preferences-handler.js │ │ │ │ │ └── system-objects-handler.js │ │ │ │ ├── ocapi.js │ │ │ │ └── webdav.js │ │ │ └── utils │ │ │ ├── mock-data-loader.js │ │ │ └── webdav-xml.js │ │ └── sfcc-mock-server-manager.ts │ ├── sfcc-mock-server.test.ts │ ├── site-preferences-client.test.ts │ ├── system-objects-client.test.ts │ ├── utils.test.ts │ ├── validation-helpers.test.ts │ └── validator.test.ts ├── tsconfig.json └── tsconfig.test.json ``` # Files -------------------------------------------------------------------------------- /src/clients/base/ocapi-auth-client.ts: -------------------------------------------------------------------------------- ```typescript 1 | /** 2 | * OCAPI Authentication Client 3 | * 4 | * This module handles OAuth 2.0 authentication specifically for SFCC OCAPI requests. 5 | * It extends the base HTTP client with OCAPI-specific authentication logic. 6 | */ 7 | 8 | import { OCAPIConfig, OAuthTokenResponse } from '../../types/types.js'; 9 | import { TokenManager } from './oauth-token.js'; 10 | import { BaseHttpClient } from './http-client.js'; 11 | import { buildOCAPIAuthUrl } from '../../utils/ocapi-url-builder.js'; 12 | 13 | // OCAPI authentication constants 14 | const OCAPI_AUTH_CONSTANTS = { 15 | DEFAULT_AUTH_URL: 'https://account.demandware.com/dwsso/oauth2/access_token', 16 | GRANT_TYPE: 'client_credentials', 17 | FORM_CONTENT_TYPE: 'application/x-www-form-urlencoded', 18 | } as const; 19 | 20 | /** 21 | * OCAPI Authentication Client 22 | * Handles OAuth 2.0 Client Credentials flow for OCAPI access 23 | */ 24 | export class OCAPIAuthClient extends BaseHttpClient { 25 | private config: OCAPIConfig; 26 | private tokenManager: TokenManager; 27 | 28 | constructor(config: OCAPIConfig) { 29 | super('', 'OCAPIAuthClient'); // Initialize BaseHttpClient with logger 30 | this.config = config; 31 | this.tokenManager = TokenManager.getInstance(); 32 | } 33 | 34 | /** 35 | * Get authentication headers for OCAPI requests 36 | */ 37 | protected async getAuthHeaders(): Promise<Record<string, string>> { 38 | const accessToken = await this.getAccessToken(); 39 | return { 40 | 'Authorization': `Bearer ${accessToken}`, 41 | }; 42 | } 43 | 44 | /** 45 | * Handle authentication errors by clearing the stored token 46 | */ 47 | protected async handleAuthError(): Promise<void> { 48 | this.logger.debug('Clearing token due to authentication error'); 49 | this.tokenManager.clearToken(this.config.hostname, this.config.clientId); 50 | } 51 | 52 | /** 53 | * Get the appropriate auth URL based on the hostname 54 | * Uses localhost-based auth for mock servers, production auth otherwise 55 | */ 56 | private getAuthUrl(): string { 57 | return buildOCAPIAuthUrl(this.config); 58 | } 59 | 60 | /** 61 | * Get a valid OAuth access token 62 | */ 63 | private async getAccessToken(): Promise<string> { 64 | this.logger.debug('Attempting to get access token'); 65 | 66 | // Check if we have a valid token first 67 | const existingToken = this.tokenManager.getValidToken(this.config.hostname, this.config.clientId); 68 | if (existingToken) { 69 | this.logger.debug('Using existing valid token'); 70 | return existingToken; 71 | } 72 | 73 | this.logger.debug('No valid token found, requesting new token'); 74 | return this.requestNewToken(); 75 | } 76 | 77 | /** 78 | * Request a new OAuth token from SFCC 79 | */ 80 | private async requestNewToken(): Promise<string> { 81 | // Create Basic Auth header using client credentials 82 | const credentials = `${this.config.clientId}:${this.config.clientSecret}`; 83 | const encodedCredentials = Buffer.from(credentials).toString('base64'); 84 | 85 | // Get the appropriate auth URL (localhost for mock, production for real SFCC) 86 | const authUrl = this.getAuthUrl(); 87 | this.logger.debug(`Requesting token from: ${authUrl}`); 88 | 89 | try { 90 | const response = await fetch(authUrl, { 91 | method: 'POST', 92 | headers: { 93 | 'Authorization': `Basic ${encodedCredentials}`, 94 | 'Content-Type': OCAPI_AUTH_CONSTANTS.FORM_CONTENT_TYPE, 95 | }, 96 | body: `grant_type=${OCAPI_AUTH_CONSTANTS.GRANT_TYPE}`, 97 | }); 98 | 99 | if (!response.ok) { 100 | const errorText = await response.text(); 101 | throw new Error(`OAuth authentication failed: ${response.status} ${response.statusText} - ${errorText}`); 102 | } 103 | 104 | const tokenResponse: OAuthTokenResponse = await response.json(); 105 | this.logger.debug('Successfully obtained new access token'); 106 | 107 | // Store the token for future use 108 | this.tokenManager.storeToken(this.config.hostname, this.config.clientId, tokenResponse); 109 | 110 | return tokenResponse.access_token; 111 | } catch (error) { 112 | this.logger.error(`Failed to get access token: ${error}`); 113 | throw new Error(`Failed to get access token: ${error}`); 114 | } 115 | } 116 | 117 | /** 118 | * Get current token expiration for debugging 119 | */ 120 | getTokenExpiration(): Date | null { 121 | return this.tokenManager.getTokenExpiration(this.config.hostname, this.config.clientId); 122 | } 123 | 124 | /** 125 | * Force refresh the token 126 | */ 127 | async refreshToken(): Promise<void> { 128 | this.logger.debug('Forcing token refresh'); 129 | this.tokenManager.clearToken(this.config.hostname, this.config.clientId); 130 | await this.getAccessToken(); 131 | this.logger.debug('Token refresh completed'); 132 | } 133 | } 134 | ``` -------------------------------------------------------------------------------- /docs/dw_web/ClickStreamEntry.md: -------------------------------------------------------------------------------- ```markdown 1 | ## Package: dw.web 2 | 3 | # Class ClickStreamEntry 4 | 5 | ## Inheritance Hierarchy 6 | 7 | - Object 8 | - dw.web.ClickStreamEntry 9 | 10 | ## Description 11 | 12 | Represent an entry in the click stream. 13 | 14 | ## Properties 15 | 16 | ### host 17 | 18 | **Type:** String (Read Only) 19 | 20 | The host. 21 | 22 | ### locale 23 | 24 | **Type:** String (Read Only) 25 | 26 | The locale sent from the user agent. 27 | 28 | ### path 29 | 30 | **Type:** String (Read Only) 31 | 32 | The path. 33 | 34 | ### pipelineName 35 | 36 | **Type:** String (Read Only) 37 | 38 | The name of the called pipeline. In most cases the 39 | name can be derived from the path, but not in all cases. If with 40 | URL rewritting a special landing page is defined for a DNS name, than 41 | the system internally might use a specific pipeline associated with 42 | this landing page. 43 | 44 | ### queryString 45 | 46 | **Type:** String (Read Only) 47 | 48 | The query string. 49 | 50 | ### referer 51 | 52 | **Type:** String (Read Only) 53 | 54 | The referer. 55 | 56 | ### remoteAddress 57 | 58 | **Type:** String (Read Only) 59 | 60 | The remote address. 61 | 62 | ### timestamp 63 | 64 | **Type:** Number (Read Only) 65 | 66 | The entry's timestamp. 67 | 68 | ### url 69 | 70 | **Type:** String (Read Only) 71 | 72 | The full URL for this click. The URL is returned as relative 73 | URL. 74 | 75 | ### userAgent 76 | 77 | **Type:** String (Read Only) 78 | 79 | The user agent. 80 | 81 | ## Constructor Summary 82 | 83 | ## Method Summary 84 | 85 | ### getHost 86 | 87 | **Signature:** `getHost() : String` 88 | 89 | Returns the host. 90 | 91 | ### getLocale 92 | 93 | **Signature:** `getLocale() : String` 94 | 95 | Returns the locale sent from the user agent. 96 | 97 | ### getParameter 98 | 99 | **Signature:** `getParameter(name : String) : String` 100 | 101 | Returns a specific parameter value from the stored query string. 102 | 103 | ### getPath 104 | 105 | **Signature:** `getPath() : String` 106 | 107 | Returns the path. 108 | 109 | ### getPipelineName 110 | 111 | **Signature:** `getPipelineName() : String` 112 | 113 | Returns the name of the called pipeline. 114 | 115 | ### getQueryString 116 | 117 | **Signature:** `getQueryString() : String` 118 | 119 | Returns the query string. 120 | 121 | ### getReferer 122 | 123 | **Signature:** `getReferer() : String` 124 | 125 | Returns the referer. 126 | 127 | ### getRemoteAddress 128 | 129 | **Signature:** `getRemoteAddress() : String` 130 | 131 | Returns the remote address. 132 | 133 | ### getTimestamp 134 | 135 | **Signature:** `getTimestamp() : Number` 136 | 137 | Returns the entry's timestamp. 138 | 139 | ### getUrl 140 | 141 | **Signature:** `getUrl() : String` 142 | 143 | Returns the full URL for this click. 144 | 145 | ### getUserAgent 146 | 147 | **Signature:** `getUserAgent() : String` 148 | 149 | Returns the user agent. 150 | 151 | ## Method Detail 152 | 153 | ## Method Details 154 | 155 | ### getHost 156 | 157 | **Signature:** `getHost() : String` 158 | 159 | **Description:** Returns the host. 160 | 161 | **Returns:** 162 | 163 | the host. 164 | 165 | --- 166 | 167 | ### getLocale 168 | 169 | **Signature:** `getLocale() : String` 170 | 171 | **Description:** Returns the locale sent from the user agent. 172 | 173 | **Returns:** 174 | 175 | the locale sent from the user agent. 176 | 177 | --- 178 | 179 | ### getParameter 180 | 181 | **Signature:** `getParameter(name : String) : String` 182 | 183 | **Description:** Returns a specific parameter value from the stored query string. The method can be used to extract a source code or affiliate id out of the URLs in the click stream. The method returns null if there is no parameter with the given name. 184 | 185 | **Parameters:** 186 | 187 | - `name`: the name of the parameter. 188 | 189 | **Returns:** 190 | 191 | the value associated with the specified parameter, or null. 192 | 193 | --- 194 | 195 | ### getPath 196 | 197 | **Signature:** `getPath() : String` 198 | 199 | **Description:** Returns the path. 200 | 201 | **Returns:** 202 | 203 | the path. 204 | 205 | --- 206 | 207 | ### getPipelineName 208 | 209 | **Signature:** `getPipelineName() : String` 210 | 211 | **Description:** Returns the name of the called pipeline. In most cases the name can be derived from the path, but not in all cases. If with URL rewritting a special landing page is defined for a DNS name, than the system internally might use a specific pipeline associated with this landing page. 212 | 213 | **Returns:** 214 | 215 | the name of the called pipeline. 216 | 217 | --- 218 | 219 | ### getQueryString 220 | 221 | **Signature:** `getQueryString() : String` 222 | 223 | **Description:** Returns the query string. 224 | 225 | **Returns:** 226 | 227 | the query string. 228 | 229 | --- 230 | 231 | ### getReferer 232 | 233 | **Signature:** `getReferer() : String` 234 | 235 | **Description:** Returns the referer. 236 | 237 | **Returns:** 238 | 239 | the referer. 240 | 241 | --- 242 | 243 | ### getRemoteAddress 244 | 245 | **Signature:** `getRemoteAddress() : String` 246 | 247 | **Description:** Returns the remote address. 248 | 249 | **Returns:** 250 | 251 | the remote address. 252 | 253 | --- 254 | 255 | ### getTimestamp 256 | 257 | **Signature:** `getTimestamp() : Number` 258 | 259 | **Description:** Returns the entry's timestamp. 260 | 261 | **Returns:** 262 | 263 | the entry's timestamp. 264 | 265 | --- 266 | 267 | ### getUrl 268 | 269 | **Signature:** `getUrl() : String` 270 | 271 | **Description:** Returns the full URL for this click. The URL is returned as relative URL. 272 | 273 | **Returns:** 274 | 275 | the full URL for this click. 276 | 277 | --- 278 | 279 | ### getUserAgent 280 | 281 | **Signature:** `getUserAgent() : String` 282 | 283 | **Description:** Returns the user agent. 284 | 285 | **Returns:** 286 | 287 | the user agent. 288 | 289 | --- ``` -------------------------------------------------------------------------------- /tests/code-versions-client.test.ts: -------------------------------------------------------------------------------- ```typescript 1 | /** 2 | * Tests for OCAPICodeVersionsClient 3 | * Tests code version management functionality 4 | */ 5 | 6 | import { OCAPICodeVersionsClient } from '../src/clients/ocapi/code-versions-client.js'; 7 | import { TokenManager } from '../src/clients/base/oauth-token.js'; 8 | import { OCAPIConfig } from '../src/types/types.js'; 9 | 10 | // Mock fetch globally 11 | global.fetch = jest.fn(); 12 | 13 | // Mock TokenManager 14 | jest.mock('../src/clients/base/oauth-token.js'); 15 | 16 | // Mock Logger 17 | jest.mock('../src/utils/logger.js', () => ({ 18 | Logger: { 19 | initialize: jest.fn(), 20 | getInstance: jest.fn(() => ({ 21 | methodEntry: jest.fn(), 22 | methodExit: jest.fn(), 23 | debug: jest.fn(), 24 | warn: jest.fn(), 25 | error: jest.fn(), 26 | timing: jest.fn(), 27 | log: jest.fn(), 28 | info: jest.fn(), 29 | })), 30 | getChildLogger: jest.fn(() => ({ 31 | methodEntry: jest.fn(), 32 | methodExit: jest.fn(), 33 | debug: jest.fn(), 34 | warn: jest.fn(), 35 | error: jest.fn(), 36 | timing: jest.fn(), 37 | log: jest.fn(), 38 | info: jest.fn(), 39 | })), 40 | }, 41 | })); 42 | 43 | // Mock BaseHttpClient 44 | jest.mock('../src/clients/base/http-client.js'); 45 | 46 | // Mock Validator 47 | jest.mock('../src/utils/validator.js'); 48 | 49 | describe('OCAPICodeVersionsClient', () => { 50 | let client: OCAPICodeVersionsClient; 51 | let mockTokenManager: jest.Mocked<TokenManager>; 52 | 53 | const mockConfig: OCAPIConfig = { 54 | hostname: 'test-instance.demandware.net', 55 | clientId: 'test-client-id', 56 | clientSecret: 'test-client-secret', 57 | version: 'v21_3', 58 | }; 59 | 60 | beforeEach(() => { 61 | jest.clearAllMocks(); 62 | 63 | // Setup TokenManager mock 64 | mockTokenManager = { 65 | getValidToken: jest.fn(), 66 | storeToken: jest.fn(), 67 | clearToken: jest.fn(), 68 | getTokenExpiration: jest.fn(), 69 | isTokenValid: jest.fn(), 70 | clearAllTokens: jest.fn(), 71 | } as any; 72 | 73 | (TokenManager.getInstance as jest.Mock).mockReturnValue(mockTokenManager); 74 | 75 | client = new OCAPICodeVersionsClient(mockConfig); 76 | }); 77 | 78 | describe('getCodeVersions', () => { 79 | it('should make GET request to /code_versions endpoint', async () => { 80 | const mockCodeVersions = { 81 | _v: '23.2', 82 | _type: 'code_version_result', 83 | count: 1, 84 | data: [ 85 | { 86 | _type: 'code_version', 87 | id: 'version1', 88 | active: true, 89 | cartridges: 'app_storefront_base', 90 | compatibility_mode: '23.2', 91 | activation_time: '2024-01-01T00:00:00Z', 92 | total_size: '1024 KB', 93 | }, 94 | ], 95 | total: 1, 96 | }; 97 | 98 | // Mock the get method from BaseHttpClient 99 | const mockGet = jest.fn().mockResolvedValue(mockCodeVersions); 100 | (client as any).get = mockGet; 101 | 102 | const result = await client.getCodeVersions(); 103 | 104 | expect(mockGet).toHaveBeenCalledWith('/code_versions'); 105 | expect(result).toBe(mockCodeVersions); 106 | }); 107 | }); 108 | 109 | describe('activateCodeVersion', () => { 110 | it('should make PATCH request to activate code version', async () => { 111 | const mockActivatedVersion = { 112 | _v: '23.2', 113 | _type: 'code_version', 114 | _resource_state: 'new-resource-state-12345', 115 | id: 'version2', 116 | active: true, 117 | cartridges: 'app_storefront_base', 118 | compatibility_mode: '23.2', 119 | activation_time: '2024-01-15T10:30:00Z', 120 | total_size: '1024 KB', 121 | }; 122 | 123 | // Mock the patch method from BaseHttpClient 124 | const mockPatch = jest.fn().mockResolvedValue(mockActivatedVersion); 125 | (client as any).patch = mockPatch; 126 | 127 | const codeVersionId = 'version2'; 128 | const result = await client.activateCodeVersion(codeVersionId); 129 | 130 | expect(mockPatch).toHaveBeenCalledWith('/code_versions/version2', { 131 | active: true, 132 | }); 133 | expect(result).toBe(mockActivatedVersion); 134 | }); 135 | 136 | it('should validate required parameters', async () => { 137 | // Import the actual validator to test parameter validation 138 | const { Validator } = await import('../src/utils/validator.js'); 139 | const mockValidateRequired = jest.fn(); 140 | (Validator as any).validateRequired = mockValidateRequired; 141 | 142 | const codeVersionId = 'version2'; 143 | 144 | // Mock the patch method 145 | const mockPatch = jest.fn().mockResolvedValue({}); 146 | (client as any).patch = mockPatch; 147 | 148 | await client.activateCodeVersion(codeVersionId); 149 | 150 | expect(mockValidateRequired).toHaveBeenCalledWith( 151 | { codeVersionId }, 152 | ['codeVersionId'], 153 | ); 154 | }); 155 | }); 156 | }); 157 | ``` -------------------------------------------------------------------------------- /docs/dw_content/MarkupText.md: -------------------------------------------------------------------------------- ```markdown 1 | ## Package: dw.content 2 | 3 | # Class MarkupText 4 | 5 | ## Inheritance Hierarchy 6 | 7 | - Object 8 | - dw.content.MarkupText 9 | 10 | ## Description 11 | 12 | The class represents a content snippet with markup. This is typically a HTML content snippet. The class also processes the special links from Commerce Cloud Digital content management and automatically rewrites them into links for use in the storefront. The following special links can be used inside of a MarkupText: $url('<pipeline>' [, '<key1>', '<value1>', '<key2>', '<value2>', ...])$ Description: The $url()$ function creates and absolute URL and retains the protocol incoming request. Example: MarkupText: $url('MyLinkPipeline-Start', 'key1', 'value1', 'key2', 'value2')$ is rewritten to: http://<host>:<port>/on/demandware.store/<current site>/default/MyLinkPipeline-Start?key1=value1&key2=value2 Note that the incoming protocol was http in the example above. $httpUrl('<pipeline>' [, '<key1>', '<value1>', '<key2>', '<value2>', ...])$ Description: The $httpUrl()$ function creates an absolute URL but always with the fix protocol "http". The protocol type of the incomming request is ignored. Example: MarkupText: $httpUrl('MyLinkPipeline-Start', 'key1', 'value1', 'key2', 'value2')$ is rewritten to: http://<host>:'<port>/on/demandware.store/<current site>/default/MyLinkPipeline-Start?key1=value1&key2=value2 $httpsUrl('<pipeline>' [, '<key1>', '<value1>', '<key2>', '<value2>', ...])$ Description: The $httpsUrl()$ function creates an absolute URL but always with the fix protocol "https". The protocol type of the incomming request is ignored. Example: MarkupText: $httpsUrl('MyLinkPipeline-Start', 'key1', 'value1', 'key2', 'value2')$ is rewritten to: https://<host>:<port>/on/demandware.store/<current site>/default/MyLinkPipeline-Start?key1=value1&key2=value2 $include('<pipeline>' [, '<key1>', '<value1>', '<key2>', '<value2>', ...])$ Description: The $include()$ function creates a relative URL which is post processed by the Commerce Cloud Digital Webadapter. The result is the content generated by the given pipeline call. Example: MarkupText: $include('MyIncludePipeline-Start','key1', 'value1', 'key2' ,'value2')$ results in the content delivered by the 'MyIncludePipeline-Start' pipeline. ...?$staticlink$ Description: The $staticlink$ function can be used to create a URL to a static resource (such as an image). The URL being generated depends on the owner of the MarkupText instance. For example, a product's long description (which is a MarkupText) will generate links to static resources within the catalog. Possible URL targets are catalogs (for catalog related objects like products and categories), the content library (for library related objects like folders and assets) or the organization (for all objects that are not catalog or library related). Example: MarkupText: (owned by a content asset) <img src="demo/content/bullet.gif?$staticlink$"> is rewritten to: <img src="/on/demandware.static/<current site>/<library>/default/v1178201405900/demo/content/bullet.gif"> Note: The comma symbol , is not supported in parameter values for the link functions. 13 | 14 | ## Properties 15 | 16 | ### markup 17 | 18 | **Type:** String (Read Only) 19 | 20 | The content with all links rewritten for storefront use. 21 | 22 | ### source 23 | 24 | **Type:** String (Read Only) 25 | 26 | The original content source, without any links re-written. 27 | 28 | ## Constructor Summary 29 | 30 | ## Method Summary 31 | 32 | ### getMarkup 33 | 34 | **Signature:** `getMarkup() : String` 35 | 36 | Returns the content with all links rewritten for storefront use. 37 | 38 | ### getSource 39 | 40 | **Signature:** `getSource() : String` 41 | 42 | Returns the original content source, without any links re-written. 43 | 44 | ### toString 45 | 46 | **Signature:** `toString() : String` 47 | 48 | Returns a string representation of this class, the same as getMarkup(). 49 | 50 | ## Method Detail 51 | 52 | ## Method Details 53 | 54 | ### getMarkup 55 | 56 | **Signature:** `getMarkup() : String` 57 | 58 | **Description:** Returns the content with all links rewritten for storefront use. 59 | 60 | **Returns:** 61 | 62 | the content with all links rewritten for storefront use. 63 | 64 | --- 65 | 66 | ### getSource 67 | 68 | **Signature:** `getSource() : String` 69 | 70 | **Description:** Returns the original content source, without any links re-written. 71 | 72 | **Returns:** 73 | 74 | the original content source, without any links re-written. 75 | 76 | --- 77 | 78 | ### toString 79 | 80 | **Signature:** `toString() : String` 81 | 82 | **Description:** Returns a string representation of this class, the same as getMarkup(). 83 | 84 | **Returns:** 85 | 86 | a string representation of this class, the same as getMarkup(). 87 | 88 | --- ``` -------------------------------------------------------------------------------- /docs-site/src/styles/input.css: -------------------------------------------------------------------------------- ```css 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | /* Custom Prism.js theme for SFCC Development MCP Server docs */ 6 | /* Override default Prism styles with a clean, modern theme */ 7 | 8 | pre[class*="language-"] { 9 | background: transparent !important; 10 | margin: 0 !important; 11 | padding: 1rem !important; /* Force proper padding */ 12 | overflow: visible; 13 | } 14 | 15 | code[class*="language-"] { 16 | background: transparent !important; 17 | text-shadow: none; 18 | font-family: ui-monospace, SFMono-Regular, "SF Mono", Monaco, Consolas, "Liberation Mono", "Courier New", monospace; 19 | font-size: 0.875rem; 20 | line-height: 1.5; 21 | color: #374151; /* slate-700 */ 22 | padding: 0 !important; /* Remove any inherited padding from code element */ 23 | } 24 | 25 | /* Tokens */ 26 | .token.comment, 27 | .token.prolog, 28 | .token.doctype, 29 | .token.cdata { 30 | color: #6b7280; /* slate-500 */ 31 | font-style: italic; 32 | } 33 | 34 | .token.punctuation { 35 | color: #6b7280; /* slate-500 */ 36 | } 37 | 38 | .token.property, 39 | .token.tag, 40 | .token.boolean, 41 | .token.number, 42 | .token.constant, 43 | .token.symbol, 44 | .token.deleted { 45 | color: #dc2626; /* red-600 */ 46 | } 47 | 48 | .token.selector, 49 | .token.attr-name, 50 | .token.string, 51 | .token.char, 52 | .token.builtin, 53 | .token.inserted { 54 | color: #059669; /* emerald-600 */ 55 | } 56 | 57 | .token.operator, 58 | .token.entity, 59 | .token.url, 60 | .language-css .token.string, 61 | .style .token.string { 62 | color: #7c3aed; /* violet-600 */ 63 | } 64 | 65 | .token.atrule, 66 | .token.attr-value, 67 | .token.keyword { 68 | color: #2563eb; /* blue-600 */ 69 | } 70 | 71 | .token.function, 72 | .token.class-name { 73 | color: #ea580c; /* orange-600 */ 74 | } 75 | 76 | .token.regex, 77 | .token.important, 78 | .token.variable { 79 | color: #dc2626; /* red-600 */ 80 | } 81 | 82 | .token.important, 83 | .token.bold { 84 | font-weight: bold; 85 | } 86 | 87 | .token.italic { 88 | font-style: italic; 89 | } 90 | 91 | .token.entity { 92 | cursor: help; 93 | } 94 | 95 | /* JSON specific */ 96 | .token.key { 97 | color: #2563eb; /* blue-600 */ 98 | } 99 | 100 | /* YAML specific */ 101 | .token.title { 102 | color: #2563eb; /* blue-600 */ 103 | } 104 | 105 | /* Bash/Shell specific */ 106 | .token.command { 107 | color: #059669; /* emerald-600 */ 108 | } 109 | 110 | .token.parameter { 111 | color: #dc2626; /* red-600 */ 112 | } 113 | 114 | /* JSX/TSX specific */ 115 | .token.tag .token.punctuation { 116 | color: #6b7280; /* slate-500 */ 117 | } 118 | 119 | .token.tag .token.script-punctuation { 120 | color: #6b7280; /* slate-500 */ 121 | } 122 | 123 | .token.attr-value .token.punctuation { 124 | color: #059669; /* emerald-600 */ 125 | } 126 | 127 | .token.attr-value .token.punctuation:first-child { 128 | color: #059669; /* emerald-600 */ 129 | } 130 | 131 | /* Mobile responsiveness and text overflow fixes */ 132 | * { 133 | box-sizing: border-box; 134 | } 135 | 136 | html { 137 | overflow-x: hidden; 138 | } 139 | 140 | body { 141 | overflow-x: hidden; 142 | width: 100vw; 143 | max-width: 100vw; 144 | } 145 | 146 | /* Ensure all text content can break appropriately */ 147 | .prose { 148 | word-wrap: break-word; 149 | overflow-wrap: break-word; 150 | word-break: break-word; 151 | } 152 | 153 | /* Force long words and URLs to break */ 154 | .prose p, 155 | .prose li, 156 | .prose td, 157 | .prose th { 158 | word-wrap: break-word; 159 | overflow-wrap: break-word; 160 | hyphens: auto; 161 | } 162 | 163 | /* Ensure code blocks don't overflow */ 164 | .prose pre { 165 | max-width: 100%; 166 | overflow-x: auto; 167 | white-space: pre; 168 | word-break: normal; 169 | } 170 | 171 | .prose code { 172 | white-space: pre; 173 | word-break: normal; 174 | } 175 | 176 | /* Allow horizontal scroll specifically in code blocks */ 177 | .prose pre code { 178 | white-space: pre; 179 | word-break: normal; 180 | overflow-wrap: normal; 181 | } 182 | 183 | /* Inline code should break words */ 184 | .prose p code, 185 | .prose li code, 186 | .prose td code, 187 | .prose th code, 188 | .prose h1 code, 189 | .prose h2 code, 190 | .prose h3 code, 191 | .prose h4 code, 192 | .prose h5 code, 193 | .prose h6 code { 194 | word-break: break-word !important; 195 | overflow-wrap: break-word !important; 196 | white-space: normal !important; 197 | } 198 | 199 | /* Tables should be responsive */ 200 | .prose table { 201 | width: 100%; 202 | table-layout: fixed; 203 | word-break: break-word; 204 | } 205 | 206 | /* Prevent horizontal scrolling on mobile */ 207 | @media (max-width: 768px) { 208 | html, body { 209 | overflow-x: hidden !important; 210 | max-width: 100vw !important; 211 | width: 100% !important; 212 | } 213 | 214 | * { 215 | max-width: 100% !important; 216 | } 217 | 218 | .prose { 219 | max-width: none; 220 | width: 100%; 221 | } 222 | 223 | .prose pre { 224 | max-width: calc(100vw - 3rem) !important; 225 | overflow-x: auto; 226 | white-space: pre; 227 | word-break: normal; 228 | } 229 | 230 | .prose pre code { 231 | white-space: pre !important; 232 | word-break: normal !important; 233 | overflow-wrap: normal !important; 234 | } 235 | 236 | .prose table { 237 | max-width: calc(100vw - 3rem) !important; 238 | overflow-x: auto; 239 | display: block; 240 | white-space: nowrap; 241 | } 242 | 243 | /* Ensure no element can be wider than viewport */ 244 | #root, .min-h-screen, main, .prose { 245 | max-width: 100vw !important; 246 | overflow-x: hidden !important; 247 | } 248 | } 249 | ``` -------------------------------------------------------------------------------- /docs/dw_web/FormFieldOption.md: -------------------------------------------------------------------------------- ```markdown 1 | ## Package: dw.web 2 | 3 | # Class FormFieldOption 4 | 5 | ## Inheritance Hierarchy 6 | 7 | - Object 8 | - dw.web.FormFieldOption 9 | 10 | ## Description 11 | 12 | Represents an option for a form field. 13 | 14 | ## Properties 15 | 16 | ### checked 17 | 18 | **Type:** boolean (Read Only) 19 | 20 | Identifies if this option is checked. 21 | 22 | ### htmlValue 23 | 24 | **Type:** String (Read Only) 25 | 26 | The value for the HTML value attribute of a HTML option element. 27 | 28 | ### label 29 | 30 | **Type:** String 31 | 32 | The value for the HTML label attribute of the HTML option element. 33 | If not specified in the form option definition the label is identical with 34 | the string representation of option value (see getValue()). 35 | 36 | ### object 37 | 38 | **Type:** Object (Read Only) 39 | 40 | The object that was bound to this option value. 41 | 42 | ### optionId 43 | 44 | **Type:** String (Read Only) 45 | 46 | The ID of the option. This is an internal ID used to uniquely 47 | reference this option. If not specified in the form option definition 48 | the ID is identical with the string representation of the option value 49 | (see getValue()). 50 | 51 | ### parent 52 | 53 | **Type:** FormField (Read Only) 54 | 55 | The parent, which is a field element. 56 | 57 | ### selected 58 | 59 | **Type:** boolean (Read Only) 60 | 61 | Identifies if this option is selected. 62 | 63 | ### value 64 | 65 | **Type:** Object (Read Only) 66 | 67 | The actual value associated with this option. This value is formatted 68 | and than returned as HTML value with the method getHtmlValue(). 69 | 70 | ## Constructor Summary 71 | 72 | ## Method Summary 73 | 74 | ### getHtmlValue 75 | 76 | **Signature:** `getHtmlValue() : String` 77 | 78 | Returns the value for the HTML value attribute of a HTML option element. 79 | 80 | ### getLabel 81 | 82 | **Signature:** `getLabel() : String` 83 | 84 | Returns the value for the HTML label attribute of the HTML option element. 85 | 86 | ### getObject 87 | 88 | **Signature:** `getObject() : Object` 89 | 90 | Returns the object that was bound to this option value. 91 | 92 | ### getOptionId 93 | 94 | **Signature:** `getOptionId() : String` 95 | 96 | Returns the ID of the option. 97 | 98 | ### getParent 99 | 100 | **Signature:** `getParent() : FormField` 101 | 102 | The parent, which is a field element. 103 | 104 | ### getValue 105 | 106 | **Signature:** `getValue() : Object` 107 | 108 | The actual value associated with this option. 109 | 110 | ### isChecked 111 | 112 | **Signature:** `isChecked() : boolean` 113 | 114 | Identifies if this option is checked. 115 | 116 | ### isSelected 117 | 118 | **Signature:** `isSelected() : boolean` 119 | 120 | Identifies if this option is selected. 121 | 122 | ### setLabel 123 | 124 | **Signature:** `setLabel(label : String) : void` 125 | 126 | Sets the label attribute for this option. 127 | 128 | ## Method Detail 129 | 130 | ## Method Details 131 | 132 | ### getHtmlValue 133 | 134 | **Signature:** `getHtmlValue() : String` 135 | 136 | **Description:** Returns the value for the HTML value attribute of a HTML option element. 137 | 138 | **Returns:** 139 | 140 | the value for the HTML value attribute of a HTML option element. 141 | 142 | --- 143 | 144 | ### getLabel 145 | 146 | **Signature:** `getLabel() : String` 147 | 148 | **Description:** Returns the value for the HTML label attribute of the HTML option element. If not specified in the form option definition the label is identical with the string representation of option value (see getValue()). 149 | 150 | **Returns:** 151 | 152 | the value for the HTML label attribute of the HTML option element. 153 | 154 | --- 155 | 156 | ### getObject 157 | 158 | **Signature:** `getObject() : Object` 159 | 160 | **Description:** Returns the object that was bound to this option value. 161 | 162 | **Returns:** 163 | 164 | the object that was bound to this option value. 165 | 166 | --- 167 | 168 | ### getOptionId 169 | 170 | **Signature:** `getOptionId() : String` 171 | 172 | **Description:** Returns the ID of the option. This is an internal ID used to uniquely reference this option. If not specified in the form option definition the ID is identical with the string representation of the option value (see getValue()). 173 | 174 | **Returns:** 175 | 176 | the ID of the option. 177 | 178 | --- 179 | 180 | ### getParent 181 | 182 | **Signature:** `getParent() : FormField` 183 | 184 | **Description:** The parent, which is a field element. 185 | 186 | **Returns:** 187 | 188 | the parent form field. 189 | 190 | --- 191 | 192 | ### getValue 193 | 194 | **Signature:** `getValue() : Object` 195 | 196 | **Description:** The actual value associated with this option. This value is formatted and than returned as HTML value with the method getHtmlValue(). 197 | 198 | **Returns:** 199 | 200 | the value associated with this option 201 | 202 | --- 203 | 204 | ### isChecked 205 | 206 | **Signature:** `isChecked() : boolean` 207 | 208 | **Description:** Identifies if this option is checked. 209 | 210 | **Returns:** 211 | 212 | true if this option is checked, false otherwise. 213 | 214 | --- 215 | 216 | ### isSelected 217 | 218 | **Signature:** `isSelected() : boolean` 219 | 220 | **Description:** Identifies if this option is selected. 221 | 222 | **Returns:** 223 | 224 | true if this option is selected, false otherwise. 225 | 226 | --- 227 | 228 | ### setLabel 229 | 230 | **Signature:** `setLabel(label : String) : void` 231 | 232 | **Description:** Sets the label attribute for this option. 233 | 234 | **Parameters:** 235 | 236 | - `label`: the label value. 237 | 238 | --- ``` -------------------------------------------------------------------------------- /docs/dw_extensions.applepay/ApplePayHookResult.md: -------------------------------------------------------------------------------- ```markdown 1 | ## Package: dw.extensions.applepay 2 | 3 | # Class ApplePayHookResult 4 | 5 | ## Inheritance Hierarchy 6 | 7 | - Object 8 | - dw.extensions.applepay.ApplePayHookResult 9 | 10 | ## Description 11 | 12 | Result of a hook handling an Apple Pay request. Use the constants in this type to indicate specific error reasons to be provided to Apple Pay JS. For example, the following code creates a Status that indicates the shipping contact information provided by Apple Pay is invalid: var ApplePayHookResult = require('dw/extensions/applepay/ApplePayHookResult'); var Status = require('dw/system/Status'); var error = new Status(Status.ERROR); error.addDetail(ApplePayHookResult.STATUS_REASON_DETAIL_KEY, ApplePayHookResult.REASON_SHIPPING_CONTACT); If a specific error reason is not provided, the generic Apple Pay STATUS_FAILURE reason will be used when necessary. 13 | 14 | ## Constants 15 | 16 | ### REASON_BILLING_ADDRESS 17 | 18 | **Type:** String = "InvalidBillingPostalAddress" 19 | 20 | Error reason code representing an invalid billing address. 21 | 22 | ### REASON_FAILURE 23 | 24 | **Type:** String = "Failure" 25 | 26 | Error reason code representing an error or failure not otherwise specified. 27 | 28 | ### REASON_PIN_INCORRECT 29 | 30 | **Type:** String = "PINIncorrect" 31 | 32 | Error reason code representing the PIN is incorrect. 33 | 34 | ### REASON_PIN_LOCKOUT 35 | 36 | **Type:** String = "PINLockout" 37 | 38 | Error reason code representing a PIN lockout. 39 | 40 | ### REASON_PIN_REQUIRED 41 | 42 | **Type:** String = "PINRequired" 43 | 44 | Error reason code representing a PIN is required. 45 | 46 | ### REASON_SHIPPING_ADDRESS 47 | 48 | **Type:** String = "InvalidShippingPostalAddress" 49 | 50 | Error reason code representing an invalid shipping address. 51 | 52 | ### REASON_SHIPPING_CONTACT 53 | 54 | **Type:** String = "InvalidShippingContact" 55 | 56 | Error reason code representing invalid shipping contact information. 57 | 58 | ### STATUS_REASON_DETAIL_KEY 59 | 60 | **Type:** String = "reason" 61 | 62 | Key for the detail to be used in Status objects to indicate the reason to communicate to Apple Pay for errors. 63 | 64 | ## Properties 65 | 66 | ### eventDetail 67 | 68 | **Type:** Object (Read Only) 69 | 70 | Detail to the JS custom event to dispatch in response to this result. 71 | 72 | ### eventName 73 | 74 | **Type:** String (Read Only) 75 | 76 | Name of the JS custom event to dispatch in response to this result. 77 | 78 | ### redirect 79 | 80 | **Type:** URL (Read Only) 81 | 82 | URL to navigate to in response to this result. 83 | 84 | ### status 85 | 86 | **Type:** Status (Read Only) 87 | 88 | Status describing the outcome of this result. 89 | 90 | ## Constructor Summary 91 | 92 | ApplePayHookResult(status : Status, redirect : URL) Constructs a result with the given outcome information. 93 | 94 | ## Method Summary 95 | 96 | ### getEventDetail 97 | 98 | **Signature:** `getEventDetail() : Object` 99 | 100 | Detail to the JS custom event to dispatch in response to this result. 101 | 102 | ### getEventName 103 | 104 | **Signature:** `getEventName() : String` 105 | 106 | Name of the JS custom event to dispatch in response to this result. 107 | 108 | ### getRedirect 109 | 110 | **Signature:** `getRedirect() : URL` 111 | 112 | URL to navigate to in response to this result. 113 | 114 | ### getStatus 115 | 116 | **Signature:** `getStatus() : Status` 117 | 118 | Status describing the outcome of this result. 119 | 120 | ### setEvent 121 | 122 | **Signature:** `setEvent(name : String) : void` 123 | 124 | Sets the name of the JS custom event to dispatch in response to this result. 125 | 126 | ### setEvent 127 | 128 | **Signature:** `setEvent(name : String, detail : Object) : void` 129 | 130 | Sets the name and detail of the JS custom event to dispatch in response to this result. 131 | 132 | ## Constructor Detail 133 | 134 | ## Method Detail 135 | 136 | ## Method Details 137 | 138 | ### getEventDetail 139 | 140 | **Signature:** `getEventDetail() : Object` 141 | 142 | **Description:** Detail to the JS custom event to dispatch in response to this result. 143 | 144 | **Returns:** 145 | 146 | event detail 147 | 148 | --- 149 | 150 | ### getEventName 151 | 152 | **Signature:** `getEventName() : String` 153 | 154 | **Description:** Name of the JS custom event to dispatch in response to this result. 155 | 156 | **Returns:** 157 | 158 | event name 159 | 160 | --- 161 | 162 | ### getRedirect 163 | 164 | **Signature:** `getRedirect() : URL` 165 | 166 | **Description:** URL to navigate to in response to this result. 167 | 168 | **Returns:** 169 | 170 | redirect URL 171 | 172 | --- 173 | 174 | ### getStatus 175 | 176 | **Signature:** `getStatus() : Status` 177 | 178 | **Description:** Status describing the outcome of this result. 179 | 180 | **Returns:** 181 | 182 | status of this result 183 | 184 | --- 185 | 186 | ### setEvent 187 | 188 | **Signature:** `setEvent(name : String) : void` 189 | 190 | **Description:** Sets the name of the JS custom event to dispatch in response to this result. 191 | 192 | **Parameters:** 193 | 194 | - `name`: JS custom event name 195 | 196 | --- 197 | 198 | ### setEvent 199 | 200 | **Signature:** `setEvent(name : String, detail : Object) : void` 201 | 202 | **Description:** Sets the name and detail of the JS custom event to dispatch in response to this result. 203 | 204 | **Parameters:** 205 | 206 | - `name`: JS custom event name 207 | - `detail`: JS custom event detail 208 | 209 | --- ``` -------------------------------------------------------------------------------- /docs-site/components/CodeBlock.tsx: -------------------------------------------------------------------------------- ```typescript 1 | 2 | import React, { useState, useEffect, useRef } from 'react'; 3 | import { CopyIcon, CheckIcon } from './icons'; 4 | 5 | // Dynamic Prism import to prevent SSR issues 6 | let Prism: any = null; 7 | 8 | interface CodeBlockProps { 9 | code: string; 10 | language: string; 11 | } 12 | 13 | const CodeBlock: React.FC<CodeBlockProps> = ({ code, language }) => { 14 | const [copied, setCopied] = useState(false); 15 | const [isMounted, setIsMounted] = useState(false); 16 | const codeRef = useRef<HTMLElement>(null); 17 | 18 | const handleCopy = () => { 19 | if (typeof window !== 'undefined' && navigator.clipboard) { 20 | navigator.clipboard.writeText(code.trim()); 21 | setCopied(true); 22 | setTimeout(() => setCopied(false), 2000); 23 | } 24 | }; 25 | 26 | // Map common language aliases to Prism language identifiers 27 | const getPrismLanguage = (lang: string): string => { 28 | const langMap: { [key: string]: string } = { 29 | 'js': 'javascript', 30 | 'ts': 'typescript', 31 | 'jsx': 'jsx', 32 | 'tsx': 'tsx', 33 | 'json': 'json', 34 | 'yml': 'yaml', 35 | 'yaml': 'yaml', 36 | 'sh': 'bash', 37 | 'shell': 'bash', 38 | 'bash': 'bash', 39 | 'zsh': 'bash', 40 | 'md': 'markdown', 41 | 'markdown': 'markdown', 42 | 'css': 'css', 43 | 'scss': 'scss', 44 | 'sass': 'scss', 45 | }; 46 | return langMap[lang.toLowerCase()] || lang.toLowerCase(); 47 | }; 48 | 49 | const prismLanguage = getPrismLanguage(language); 50 | 51 | // Apply syntax highlighting after component mounts (client-side only) 52 | useEffect(() => { 53 | setIsMounted(true); 54 | 55 | // Load Prism dynamically on client side only 56 | const loadPrismAndHighlight = async () => { 57 | if (typeof window !== 'undefined' && !Prism) { 58 | try { 59 | // Dynamically import Prism and language components 60 | const prismModule = await import('prismjs'); 61 | await import('prismjs/components/prism-javascript'); 62 | await import('prismjs/components/prism-typescript'); 63 | await import('prismjs/components/prism-jsx'); 64 | await import('prismjs/components/prism-tsx'); 65 | await import('prismjs/components/prism-json'); 66 | await import('prismjs/components/prism-yaml'); 67 | await import('prismjs/components/prism-bash'); 68 | await import('prismjs/components/prism-shell-session'); 69 | await import('prismjs/components/prism-markdown'); 70 | await import('prismjs/components/prism-css'); 71 | await import('prismjs/components/prism-scss'); 72 | 73 | Prism = prismModule.default; 74 | } catch (error) { 75 | console.warn('Failed to load Prism:', error); 76 | return; 77 | } 78 | } 79 | 80 | // Apply highlighting after a small delay to ensure hydration is complete 81 | setTimeout(() => { 82 | if (Prism && codeRef.current && Prism.languages[prismLanguage]) { 83 | const highlighted = Prism.highlight(code.trim(), Prism.languages[prismLanguage], prismLanguage); 84 | codeRef.current.innerHTML = highlighted; 85 | } 86 | }, 100); 87 | }; 88 | 89 | loadPrismAndHighlight(); 90 | }, [code, language, prismLanguage]); 91 | 92 | return ( 93 | <div className="my-6 rounded-xl border border-slate-200 bg-slate-50 not-prose overflow-hidden max-w-full"> 94 | <div className="flex justify-between items-center px-3 sm:px-4 py-2 border-b border-slate-200"> 95 | <span className="text-xs font-semibold text-slate-500 uppercase truncate">{language}</span> 96 | <button 97 | onClick={handleCopy} 98 | className="flex items-center gap-1 sm:gap-1.5 text-xs sm:text-sm text-slate-500 hover:text-slate-800 transition-colors flex-shrink-0 ml-2" 99 | > 100 | {copied ? ( 101 | <> 102 | <CheckIcon className="w-4 h-4 text-green-500" /> 103 | <span className="hidden xs:inline">Copied!</span> 104 | </> 105 | ) : ( 106 | <> 107 | <CopyIcon className="w-4 h-4" /> 108 | <span className="hidden xs:inline">Copy</span> 109 | </> 110 | )} 111 | </button> 112 | </div> 113 | <div className="overflow-x-auto max-w-full"> 114 | <pre className="p-3 sm:p-4 text-xs sm:text-sm min-w-0 m-0"> 115 | <code 116 | ref={codeRef} 117 | className={`block whitespace-pre language-${prismLanguage}`} 118 | > 119 | {code.trim()} 120 | </code> 121 | </pre> 122 | </div> 123 | </div> 124 | ); 125 | }; 126 | 127 | export const InlineCode: React.FC<{children: React.ReactNode}> = ({ children }) => ( 128 | <code className="text-sm font-mono bg-rose-100 text-rose-800 rounded-md px-1 py-0.5">{children}</code> 129 | ); 130 | 131 | 132 | export default CodeBlock; 133 | ``` -------------------------------------------------------------------------------- /docs/dw_web/URL.md: -------------------------------------------------------------------------------- ```markdown 1 | ## Package: dw.web 2 | 3 | # Class URL 4 | 5 | ## Inheritance Hierarchy 6 | 7 | - Object 8 | - dw.web.URL 9 | 10 | ## Description 11 | 12 | Represents a URL in Commerce Cloud Digital. 13 | 14 | ## Constructor Summary 15 | 16 | ## Method Summary 17 | 18 | ### abs 19 | 20 | **Signature:** `abs() : URL` 21 | 22 | Makes the URL absolute and ensures that the protocol of the request is used or http in a mail context. 23 | 24 | ### append 25 | 26 | **Signature:** `append(name : String, value : String) : URL` 27 | 28 | Append a request parameter to this URL. 29 | 30 | ### appendCSRFTokenBM 31 | 32 | **Signature:** `appendCSRFTokenBM() : URL` 33 | 34 | Appends, if applicable, a CSRF protection token to this URL. 35 | 36 | ### host 37 | 38 | **Signature:** `host(host : String) : URL` 39 | 40 | Updates the URL with the specified host name Note: This method is not applicable for static content or image transformation URLs. 41 | 42 | ### http 43 | 44 | **Signature:** `http() : URL` 45 | 46 | Makes the URL absolute and ensures that the protocol http is used. 47 | 48 | ### https 49 | 50 | **Signature:** `https() : URL` 51 | 52 | Makes the URL absolute and ensures that the protocol https is used. 53 | 54 | ### relative 55 | 56 | **Signature:** `relative() : URL` 57 | 58 | Makes the URL relative. 59 | 60 | ### remove 61 | 62 | **Signature:** `remove(name : String) : URL` 63 | 64 | Remove a request parameter from this URL. 65 | 66 | ### siteHost 67 | 68 | **Signature:** `siteHost() : URL` 69 | 70 | Updates the URL with the site host name Note: This method is not applicable for static content or image transformation URLs. 71 | 72 | ### toString 73 | 74 | **Signature:** `toString() : String` 75 | 76 | Return String representation of the URL. 77 | 78 | ## Method Detail 79 | 80 | ## Method Details 81 | 82 | ### abs 83 | 84 | **Signature:** `abs() : URL` 85 | 86 | **Description:** Makes the URL absolute and ensures that the protocol of the request is used or http in a mail context. Note: This method is not applicable for static content or image transformation URLs. In this case a runtime exception is thrown. 87 | 88 | **Returns:** 89 | 90 | A new URL instance. 91 | 92 | --- 93 | 94 | ### append 95 | 96 | **Signature:** `append(name : String, value : String) : URL` 97 | 98 | **Description:** Append a request parameter to this URL. 99 | 100 | **Parameters:** 101 | 102 | - `name`: The parameter name. Must not be null. 103 | - `value`: The parameter value. If null, then treated as empty value. 104 | 105 | **Returns:** 106 | 107 | A reference to this URL. 108 | 109 | --- 110 | 111 | ### appendCSRFTokenBM 112 | 113 | **Signature:** `appendCSRFTokenBM() : URL` 114 | 115 | **Description:** Appends, if applicable, a CSRF protection token to this URL. The CSRF token will only be appended under the following conditions: the URL is a pipeline URL the URL is for Business Manager If a CSRF token already exists in the URL, it will be replaced with a newly generated one. 116 | 117 | **Returns:** 118 | 119 | a reference to this URL, with a CSRF token appended if applicable. 120 | 121 | --- 122 | 123 | ### host 124 | 125 | **Signature:** `host(host : String) : URL` 126 | 127 | **Description:** Updates the URL with the specified host name Note: This method is not applicable for static content or image transformation URLs. In this case a runtime exception is thrown. 128 | 129 | **Parameters:** 130 | 131 | - `host`: The host name that is used to update the URL. 132 | 133 | **Returns:** 134 | 135 | A new URL instance. 136 | 137 | --- 138 | 139 | ### http 140 | 141 | **Signature:** `http() : URL` 142 | 143 | **Description:** Makes the URL absolute and ensures that the protocol http is used. Note: This method is not applicable for static content or image transformation URLs. In this case a runtime exception is thrown. 144 | 145 | **Returns:** 146 | 147 | A new URL instance. 148 | 149 | --- 150 | 151 | ### https 152 | 153 | **Signature:** `https() : URL` 154 | 155 | **Description:** Makes the URL absolute and ensures that the protocol https is used. Note: This method is not applicable for static content or image transformation URLs. In this case a runtime exception is thrown. 156 | 157 | **Returns:** 158 | 159 | A new URL instance. 160 | 161 | --- 162 | 163 | ### relative 164 | 165 | **Signature:** `relative() : URL` 166 | 167 | **Description:** Makes the URL relative. Note: This method is not applicable for static content or image transformation URLs. In this case a runtime exception is thrown. 168 | 169 | **Returns:** 170 | 171 | A new URL instance. 172 | 173 | --- 174 | 175 | ### remove 176 | 177 | **Signature:** `remove(name : String) : URL` 178 | 179 | **Description:** Remove a request parameter from this URL. If the parameter is not part of the URL, nothing is done. 180 | 181 | **Parameters:** 182 | 183 | - `name`: The parameter name. Must not be null. 184 | 185 | **Returns:** 186 | 187 | A reference to this URL. 188 | 189 | --- 190 | 191 | ### siteHost 192 | 193 | **Signature:** `siteHost() : URL` 194 | 195 | **Description:** Updates the URL with the site host name Note: This method is not applicable for static content or image transformation URLs. In this case a runtime exception is thrown. 196 | 197 | **Returns:** 198 | 199 | A new URL instance. 200 | 201 | --- 202 | 203 | ### toString 204 | 205 | **Signature:** `toString() : String` 206 | 207 | **Description:** Return String representation of the URL. 208 | 209 | **Returns:** 210 | 211 | the URL as a string. 212 | 213 | --- ``` -------------------------------------------------------------------------------- /docs/dw_crypto/SecureRandom.md: -------------------------------------------------------------------------------- ```markdown 1 | ## Package: dw.crypto 2 | 3 | # Class SecureRandom 4 | 5 | ## Inheritance Hierarchy 6 | 7 | - Object 8 | - dw.crypto.SecureRandom 9 | 10 | ## Description 11 | 12 | The SecureRandom class provides a cryptographically strong random number generator (RNG). See the Internet Engineering Task Force (IETF) RFC 1750: Randomness Recommendations for Security for more information. Typical callers of SecureRandom invoke the following methods to retrieve random bytes: Bytes bytes... SecureRandom random = new SecureRandom(); Bytes nextBytes = random.nextBytes(bytes); or more convenient to get a Bytes with the demanded length int length = 32; SecureRandom random = new SecureRandom(); Bytes nextBytes = random.nextBytes(length); dw.crypto.SecureRandom is intentionally an adapter for generating cryptographic hard random numbers. 13 | 14 | ## Constructor Summary 15 | 16 | SecureRandom() Instantiates a new secure random. 17 | 18 | ## Method Summary 19 | 20 | ### generateSeed 21 | 22 | **Signature:** `generateSeed(numBytes : Number) : Bytes` 23 | 24 | Returns the given number of seed bytes, computed using the seed generation algorithm that this class uses to seed itself. 25 | 26 | ### nextBytes 27 | 28 | **Signature:** `nextBytes(numBits : Number) : Bytes` 29 | 30 | Generates a user-specified number of random bytes. 31 | 32 | ### nextInt 33 | 34 | **Signature:** `nextInt() : Number` 35 | 36 | Returns the next pseudorandom, uniformly distributed int value from this random number generator's sequence. 37 | 38 | ### nextInt 39 | 40 | **Signature:** `nextInt(upperBound : Number) : Number` 41 | 42 | Returns a pseudorandom, uniformly distributed int value between 0 (inclusive) and the specified value (exclusive), drawn from this random number generator's sequence. 43 | 44 | ### nextNumber 45 | 46 | **Signature:** `nextNumber() : Number` 47 | 48 | Returns the next pseudorandom, uniformly distributed Number value between 0.0 (inclusive) and 1.0 (exclusive) from this random number generator's sequence. 49 | 50 | ### setSeed 51 | 52 | **Signature:** `setSeed(seed : Bytes) : void` 53 | 54 | Reseeds this random object. 55 | 56 | ## Constructor Detail 57 | 58 | ## Method Detail 59 | 60 | ## Method Details 61 | 62 | ### generateSeed 63 | 64 | **Signature:** `generateSeed(numBytes : Number) : Bytes` 65 | 66 | **Description:** Returns the given number of seed bytes, computed using the seed generation algorithm that this class uses to seed itself. This call may be used to seed other random number generators. 67 | 68 | **Parameters:** 69 | 70 | - `numBytes`: the number of seed bytes to generate. 71 | 72 | **Returns:** 73 | 74 | the seed bytes. 75 | 76 | --- 77 | 78 | ### nextBytes 79 | 80 | **Signature:** `nextBytes(numBits : Number) : Bytes` 81 | 82 | **Description:** Generates a user-specified number of random bytes. If a call to setSeed had not occurred previously, the first call to this method forces this SecureRandom object to seed itself. This self-seeding will not occur if setSeed was previously called. 83 | 84 | **Parameters:** 85 | 86 | - `numBits`: the demanded number of bits 87 | 88 | **Returns:** 89 | 90 | a randomly filled Bytes 91 | 92 | --- 93 | 94 | ### nextInt 95 | 96 | **Signature:** `nextInt() : Number` 97 | 98 | **Description:** Returns the next pseudorandom, uniformly distributed int value from this random number generator's sequence. The general contract of nextInt is that one int value is pseudorandomly generated and returned. All 2^32 possible int values are produced with (approximately) equal probability. 99 | 100 | **Returns:** 101 | 102 | the next pseudorandom, uniformly distributed int value from this random number generator's sequence 103 | 104 | --- 105 | 106 | ### nextInt 107 | 108 | **Signature:** `nextInt(upperBound : Number) : Number` 109 | 110 | **Description:** Returns a pseudorandom, uniformly distributed int value between 0 (inclusive) and the specified value (exclusive), drawn from this random number generator's sequence. 111 | 112 | **Parameters:** 113 | 114 | - `upperBound`: the bound on the random number to be returned. Must be positive. 115 | 116 | **Returns:** 117 | 118 | the next pseudorandom, uniformly distributed int value between 0 (inclusive) and upperBound (exclusive) from this random number generator's sequence 119 | 120 | **Throws:** 121 | 122 | IllegalArgumentException - if n is not positive 123 | 124 | --- 125 | 126 | ### nextNumber 127 | 128 | **Signature:** `nextNumber() : Number` 129 | 130 | **Description:** Returns the next pseudorandom, uniformly distributed Number value between 0.0 (inclusive) and 1.0 (exclusive) from this random number generator's sequence. 131 | 132 | **Returns:** 133 | 134 | the next pseudorandom, uniformly distributed Number value between 0.0 and 1.0 from this random number generator's sequence 135 | 136 | --- 137 | 138 | ### setSeed 139 | 140 | **Signature:** `setSeed(seed : Bytes) : void` 141 | 142 | **Description:** Reseeds this random object. The given seed supplements, rather than replaces, the existing seed. Thus, repeated calls are guaranteed never to reduce randomness. 143 | 144 | **Parameters:** 145 | 146 | - `seed`: the seed. 147 | 148 | --- ``` -------------------------------------------------------------------------------- /docs/dw_customer/AddressBook.md: -------------------------------------------------------------------------------- ```markdown 1 | ## Package: dw.customer 2 | 3 | # Class AddressBook 4 | 5 | ## Inheritance Hierarchy 6 | 7 | - Object 8 | - dw.customer.AddressBook 9 | 10 | ## Description 11 | 12 | Represents a set of addresses associated with a specific customer. The AddressBook object gets its data from the Profile object for the customer. When scripting, this class allows AddressBook to be treated as a separate object from the Profile. However, data is only stored in the platform in the Profile object and there is no separate AddressBook object. For this reason, the AddressBook ID is always the customer profile ID. Note: this class allows access to sensitive personal and private information. Pay attention to appropriate legal and regulatory requirements when developing. 13 | 14 | ## Properties 15 | 16 | ### addresses 17 | 18 | **Type:** List (Read Only) 19 | 20 | A sorted list of addresses in the address book. The addresses 21 | are sorted so that the preferred address is always sorted first. The 22 | remaining addresses are sorted alphabetically by ID. 23 | 24 | ### preferredAddress 25 | 26 | **Type:** CustomerAddress 27 | 28 | The address that has been defined as the customer's preferred 29 | address. 30 | 31 | ## Constructor Summary 32 | 33 | ## Method Summary 34 | 35 | ### createAddress 36 | 37 | **Signature:** `createAddress(name : String) : CustomerAddress` 38 | 39 | Creates a new, empty address object with the specified name. 40 | 41 | ### getAddress 42 | 43 | **Signature:** `getAddress(id : String) : CustomerAddress` 44 | 45 | Returns the address with the given name from the address book. 46 | 47 | ### getAddresses 48 | 49 | **Signature:** `getAddresses() : List` 50 | 51 | Returns a sorted list of addresses in the address book. 52 | 53 | ### getPreferredAddress 54 | 55 | **Signature:** `getPreferredAddress() : CustomerAddress` 56 | 57 | Returns the address that has been defined as the customer's preferred address. 58 | 59 | ### removeAddress 60 | 61 | **Signature:** `removeAddress(address : CustomerAddress) : void` 62 | 63 | Removes the specified address from the address book. 64 | 65 | ### setPreferredAddress 66 | 67 | **Signature:** `setPreferredAddress(anAddress : CustomerAddress) : void` 68 | 69 | Sets the specified address as the customer's preferred address. 70 | 71 | ## Method Detail 72 | 73 | ## Method Details 74 | 75 | ### createAddress 76 | 77 | **Signature:** `createAddress(name : String) : CustomerAddress` 78 | 79 | **Description:** Creates a new, empty address object with the specified name. 80 | 81 | **Parameters:** 82 | 83 | - `name`: the ID of the address to create, must not be null. 84 | 85 | **Returns:** 86 | 87 | the new address object or null if an address with the given name already exists in the address book. 88 | 89 | **Throws:** 90 | 91 | NullArgumentException - If passed 'name' is null. 92 | IllegalArgumentException - If passed 'name' is not null, but an empty string. 93 | 94 | --- 95 | 96 | ### getAddress 97 | 98 | **Signature:** `getAddress(id : String) : CustomerAddress` 99 | 100 | **Description:** Returns the address with the given name from the address book. The name is a unique identifier of the address within the address book. 101 | 102 | **Parameters:** 103 | 104 | - `id`: An address ID, must not be null. 105 | 106 | **Returns:** 107 | 108 | The Address object or null if the address does not exist. 109 | 110 | **Throws:** 111 | 112 | NullArgumentException - If passed 'id' is null. 113 | IllegalArgumentException - If passed 'id' is not null, but an empty string. 114 | 115 | --- 116 | 117 | ### getAddresses 118 | 119 | **Signature:** `getAddresses() : List` 120 | 121 | **Description:** Returns a sorted list of addresses in the address book. The addresses are sorted so that the preferred address is always sorted first. The remaining addresses are sorted alphabetically by ID. 122 | 123 | **Returns:** 124 | 125 | Sorted List of customer addresses in the address book. 126 | 127 | --- 128 | 129 | ### getPreferredAddress 130 | 131 | **Signature:** `getPreferredAddress() : CustomerAddress` 132 | 133 | **Description:** Returns the address that has been defined as the customer's preferred address. 134 | 135 | **Returns:** 136 | 137 | the default CustomerAddress object, or null if there is no preferred address. 138 | 139 | --- 140 | 141 | ### removeAddress 142 | 143 | **Signature:** `removeAddress(address : CustomerAddress) : void` 144 | 145 | **Description:** Removes the specified address from the address book. Because an address can be associated with a product list, you may want to verify if the address is being used by a product list. See ProductListMgr.findAddress(). 146 | 147 | **Parameters:** 148 | 149 | - `address`: the address to remove, must not be null. 150 | 151 | --- 152 | 153 | ### setPreferredAddress 154 | 155 | **Signature:** `setPreferredAddress(anAddress : CustomerAddress) : void` 156 | 157 | **Description:** Sets the specified address as the customer's preferred address. If null is passed, and there is an existing preferred address, then the address book will have no preferred address. 158 | 159 | **Parameters:** 160 | 161 | - `anAddress`: the address to be set as preferred, or null if the goal is to unset the existing preferred address. 162 | 163 | --- ``` -------------------------------------------------------------------------------- /src/core/handlers/validation-helpers.ts: -------------------------------------------------------------------------------- ```typescript 1 | /** 2 | * Validation helpers for handler arguments 3 | */ 4 | 5 | import { HandlerError, ToolArguments } from './base-handler.js'; 6 | 7 | export interface ValidationRule<T = any> { 8 | field: string; 9 | required?: boolean; 10 | type?: 'string' | 'number' | 'boolean' | 'object' | 'array'; 11 | validator?: (value: T) => boolean; 12 | errorMessage?: string; 13 | } 14 | 15 | export class ValidationHelpers { 16 | /** 17 | * Validate arguments against a set of rules 18 | */ 19 | static validateArguments( 20 | args: ToolArguments, 21 | rules: ValidationRule[], 22 | toolName: string, 23 | ): void { 24 | for (const rule of rules) { 25 | const value = args?.[rule.field]; 26 | 27 | // Check required fields 28 | if (rule.required && (value === undefined || value === null || value === '')) { 29 | throw new HandlerError( 30 | rule.errorMessage ?? `${rule.field} is required`, 31 | toolName, 32 | 'MISSING_ARGUMENT', 33 | { field: rule.field, rules }, 34 | ); 35 | } 36 | 37 | // Skip type and custom validation if value is not present and not required 38 | if (!rule.required && (value === undefined || value === null)) { 39 | continue; 40 | } 41 | 42 | // Check type (including for required fields that have values) 43 | if (rule.type && value !== undefined && value !== null && !this.validateType(value, rule.type)) { 44 | throw new HandlerError( 45 | rule.errorMessage ?? `${rule.field} must be of type ${rule.type}`, 46 | toolName, 47 | 'INVALID_TYPE', 48 | { field: rule.field, expectedType: rule.type, actualType: typeof value }, 49 | ); 50 | } 51 | 52 | // Custom validation 53 | if (rule.validator && !rule.validator(value)) { 54 | throw new HandlerError( 55 | rule.errorMessage ?? `${rule.field} validation failed`, 56 | toolName, 57 | 'VALIDATION_FAILED', 58 | { field: rule.field, value }, 59 | ); 60 | } 61 | } 62 | } 63 | 64 | /** 65 | * Quick validation for required string fields 66 | * @deprecated Use CommonValidations.requiredString() with validateArguments() instead 67 | * @example 68 | * // Old way 69 | * ValidationHelpers.requireStrings(args, ['fieldName'], 'tool_name'); 70 | * 71 | * // New way 72 | * ValidationHelpers.validateArguments(args, CommonValidations.requiredString('fieldName'), 'tool_name'); 73 | */ 74 | static requireStrings(args: ToolArguments, fields: string[], toolName: string): void { 75 | const rules: ValidationRule[] = fields.map(field => ({ 76 | field, 77 | required: true, 78 | type: 'string' as const, 79 | errorMessage: `${field} is required for ${toolName}`, 80 | })); 81 | this.validateArguments(args, rules, toolName); 82 | } 83 | 84 | /** 85 | * Validate a single field with custom validator 86 | */ 87 | static validateField<T>( 88 | args: ToolArguments, 89 | field: string, 90 | validator: (value: T) => boolean, 91 | errorMessage: string, 92 | toolName: string, 93 | ): void { 94 | const rules: ValidationRule[] = [{ 95 | field, 96 | validator, 97 | errorMessage, 98 | }]; 99 | this.validateArguments(args, rules, toolName); 100 | } 101 | 102 | private static validateType(value: any, type: ValidationRule['type']): boolean { 103 | switch (type) { 104 | case 'string': 105 | return typeof value === 'string'; 106 | case 'number': 107 | return typeof value === 'number' && !isNaN(value); 108 | case 'boolean': 109 | return typeof value === 'boolean'; 110 | case 'object': 111 | return typeof value === 'object' && value !== null && !Array.isArray(value); 112 | case 'array': 113 | return Array.isArray(value); 114 | default: 115 | return true; 116 | } 117 | } 118 | } 119 | 120 | /** 121 | * Common validation rules factory 122 | */ 123 | export const CommonValidations = { 124 | /** 125 | * Create a required string field validation 126 | */ 127 | requiredString: (field: string, customMessage?: string): ValidationRule[] => [{ 128 | field, 129 | required: true, 130 | type: 'string', 131 | validator: (value: string) => value.trim().length > 0, 132 | errorMessage: customMessage ?? `${field} must be a non-empty string`, 133 | }], 134 | 135 | /** 136 | * Create a required field validation with custom validator 137 | */ 138 | requiredField: ( 139 | field: string, 140 | type: ValidationRule['type'], 141 | validator: (value: any) => boolean, 142 | errorMessage: string, 143 | ): ValidationRule[] => [{ 144 | field, 145 | required: true, 146 | type, 147 | validator, 148 | errorMessage, 149 | }], 150 | 151 | /** 152 | * Create an optional field validation 153 | */ 154 | optionalField: ( 155 | field: string, 156 | type: ValidationRule['type'], 157 | validator: (value: any) => boolean, 158 | errorMessage: string, 159 | ): ValidationRule[] => [{ 160 | field, 161 | required: false, 162 | type, 163 | validator, 164 | errorMessage, 165 | }], 166 | }; 167 | ``` -------------------------------------------------------------------------------- /docs/dw_web/LoopIterator.md: -------------------------------------------------------------------------------- ```markdown 1 | ## Package: dw.web 2 | 3 | # Class LoopIterator 4 | 5 | ## Inheritance Hierarchy 6 | 7 | - Object 8 | - dw.util.Iterator 9 | - dw.web.LoopIterator 10 | 11 | ## Description 12 | 13 | Iterator used in <ISLOOP> implementation. It defines properties used to determine loop status. LoopIterator object is assigned to variable declared in "status" attribute of the <ISLOOP> tag. 14 | 15 | ## Properties 16 | 17 | ### begin 18 | 19 | **Type:** Number (Read Only) 20 | 21 | Return begin iteration index. By default begin index is 0. 22 | 23 | ### count 24 | 25 | **Type:** Number (Read Only) 26 | 27 | Return iteration count, starting with 1. 28 | 29 | ### end 30 | 31 | **Type:** Number (Read Only) 32 | 33 | Return end iteration index. By default end index equals 'length - 1', provided that length is determined. 34 | If length cannot be determined end index is -1. 35 | 36 | ### even 37 | 38 | **Type:** boolean (Read Only) 39 | 40 | Identifies if count is an even value. 41 | 42 | ### first 43 | 44 | **Type:** boolean (Read Only) 45 | 46 | Identifies if the iterator is positioned at first iteratable item. 47 | 48 | ### index 49 | 50 | **Type:** Number (Read Only) 51 | 52 | Return iteration index, which is the position of the iterator in the underlying iteratable object. 53 | Index is 0-based and is calculated according the following formula: Index = (Count - 1) * Step. 54 | 55 | ### last 56 | 57 | **Type:** boolean (Read Only) 58 | 59 | Identifies if the iterator is positioned at last iteratable item. 60 | 61 | ### length 62 | 63 | **Type:** Number (Read Only) 64 | 65 | Return the length of the object. If length cannot be determined, -1 is returned. 66 | 67 | ### odd 68 | 69 | **Type:** boolean (Read Only) 70 | 71 | Identifies if count is an odd value. 72 | 73 | ### step 74 | 75 | **Type:** Number (Read Only) 76 | 77 | Return iterator step. 78 | 79 | ## Constructor Summary 80 | 81 | ## Method Summary 82 | 83 | ### getBegin 84 | 85 | **Signature:** `getBegin() : Number` 86 | 87 | Return begin iteration index. 88 | 89 | ### getCount 90 | 91 | **Signature:** `getCount() : Number` 92 | 93 | Return iteration count, starting with 1. 94 | 95 | ### getEnd 96 | 97 | **Signature:** `getEnd() : Number` 98 | 99 | Return end iteration index. 100 | 101 | ### getIndex 102 | 103 | **Signature:** `getIndex() : Number` 104 | 105 | Return iteration index, which is the position of the iterator in the underlying iteratable object. 106 | 107 | ### getLength 108 | 109 | **Signature:** `getLength() : Number` 110 | 111 | Return the length of the object. 112 | 113 | ### getStep 114 | 115 | **Signature:** `getStep() : Number` 116 | 117 | Return iterator step. 118 | 119 | ### isEven 120 | 121 | **Signature:** `isEven() : boolean` 122 | 123 | Identifies if count is an even value. 124 | 125 | ### isFirst 126 | 127 | **Signature:** `isFirst() : boolean` 128 | 129 | Identifies if the iterator is positioned at first iteratable item. 130 | 131 | ### isLast 132 | 133 | **Signature:** `isLast() : boolean` 134 | 135 | Identifies if the iterator is positioned at last iteratable item. 136 | 137 | ### isOdd 138 | 139 | **Signature:** `isOdd() : boolean` 140 | 141 | Identifies if count is an odd value. 142 | 143 | ## Method Detail 144 | 145 | ## Method Details 146 | 147 | ### getBegin 148 | 149 | **Signature:** `getBegin() : Number` 150 | 151 | **Description:** Return begin iteration index. By default begin index is 0. 152 | 153 | **Returns:** 154 | 155 | the begin iteration index. 156 | 157 | --- 158 | 159 | ### getCount 160 | 161 | **Signature:** `getCount() : Number` 162 | 163 | **Description:** Return iteration count, starting with 1. 164 | 165 | **Returns:** 166 | 167 | the iteration count. 168 | 169 | --- 170 | 171 | ### getEnd 172 | 173 | **Signature:** `getEnd() : Number` 174 | 175 | **Description:** Return end iteration index. By default end index equals 'length - 1', provided that length is determined. If length cannot be determined end index is -1. 176 | 177 | --- 178 | 179 | ### getIndex 180 | 181 | **Signature:** `getIndex() : Number` 182 | 183 | **Description:** Return iteration index, which is the position of the iterator in the underlying iteratable object. Index is 0-based and is calculated according the following formula: Index = (Count - 1) * Step. 184 | 185 | **Returns:** 186 | 187 | the iteration index. 188 | 189 | --- 190 | 191 | ### getLength 192 | 193 | **Signature:** `getLength() : Number` 194 | 195 | **Description:** Return the length of the object. If length cannot be determined, -1 is returned. 196 | 197 | **Returns:** 198 | 199 | the length of the object 200 | 201 | --- 202 | 203 | ### getStep 204 | 205 | **Signature:** `getStep() : Number` 206 | 207 | **Description:** Return iterator step. 208 | 209 | **Returns:** 210 | 211 | the iterator step. 212 | 213 | --- 214 | 215 | ### isEven 216 | 217 | **Signature:** `isEven() : boolean` 218 | 219 | **Description:** Identifies if count is an even value. 220 | 221 | **Returns:** 222 | 223 | true if count is even, false otherwise. 224 | 225 | --- 226 | 227 | ### isFirst 228 | 229 | **Signature:** `isFirst() : boolean` 230 | 231 | **Description:** Identifies if the iterator is positioned at first iteratable item. 232 | 233 | **Returns:** 234 | 235 | true if the iterator is at first item, false otherwise. 236 | 237 | --- 238 | 239 | ### isLast 240 | 241 | **Signature:** `isLast() : boolean` 242 | 243 | **Description:** Identifies if the iterator is positioned at last iteratable item. 244 | 245 | **Returns:** 246 | 247 | true if iterator is at last item, false otherwise. 248 | 249 | --- 250 | 251 | ### isOdd 252 | 253 | **Signature:** `isOdd() : boolean` 254 | 255 | **Description:** Identifies if count is an odd value. 256 | 257 | **Returns:** 258 | 259 | true if count is odd, false otherwise. 260 | 261 | --- ``` -------------------------------------------------------------------------------- /tests/mcp/yaml/search-job-logs.full-mode.test.mcp.yml: -------------------------------------------------------------------------------- ```yaml 1 | --- 2 | description: "Optimized search_job_logs tool tests for aegis framework validation" 3 | tests: 4 | # Essential functionality tests - focus on MCP protocol and aegis pattern matching 5 | - it: "should search for patterns with basic functionality" 6 | request: 7 | jsonrpc: "2.0" 8 | id: "search-basic" 9 | method: "tools/call" 10 | params: 11 | name: "search_job_logs" 12 | arguments: 13 | pattern: "INFO" 14 | limit: 3 15 | expect: 16 | response: 17 | jsonrpc: "2.0" 18 | id: "search-basic" 19 | result: 20 | content: 21 | match:arrayElements: 22 | type: "text" 23 | text: "match:contains:Found" 24 | isError: false 25 | stderr: "toBeEmpty" 26 | performance: 27 | maxResponseTime: "2000ms" 28 | 29 | - it: "should combine all parameters effectively" 30 | request: 31 | jsonrpc: "2.0" 32 | id: "search-combined" 33 | method: "tools/call" 34 | params: 35 | name: "search_job_logs" 36 | arguments: 37 | pattern: "job" 38 | level: "info" 39 | limit: 2 40 | jobName: "ImportCatalog" 41 | expect: 42 | response: 43 | jsonrpc: "2.0" 44 | id: "search-combined" 45 | result: 46 | content: 47 | match:arrayElements: 48 | match:partial: 49 | type: "text" 50 | isError: false 51 | stderr: "toBeEmpty" 52 | performance: 53 | maxResponseTime: "2000ms" 54 | 55 | # Content validation - test response structure and format 56 | - it: "should return properly formatted job log entries with timestamps" 57 | request: 58 | jsonrpc: "2.0" 59 | id: "search-format" 60 | method: "tools/call" 61 | params: 62 | name: "search_job_logs" 63 | arguments: 64 | pattern: "Executing" 65 | limit: 1 66 | expect: 67 | response: 68 | jsonrpc: "2.0" 69 | id: "search-format" 70 | result: 71 | content: 72 | match:arrayElements: 73 | type: "text" 74 | text: "match:regex:\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}\\.\\d{3} GMT" 75 | isError: false 76 | stderr: "toBeEmpty" 77 | performance: 78 | maxResponseTime: "2000ms" 79 | 80 | # Edge cases - essential for aegis testing 81 | - it: "should handle no matches gracefully" 82 | request: 83 | jsonrpc: "2.0" 84 | id: "search-no-matches" 85 | method: "tools/call" 86 | params: 87 | name: "search_job_logs" 88 | arguments: 89 | pattern: "ZZZNOTHINGFOUND" 90 | expect: 91 | response: 92 | jsonrpc: "2.0" 93 | id: "search-no-matches" 94 | result: 95 | content: 96 | match:arrayElements: 97 | type: "text" 98 | text: "match:contains:No matches found" 99 | isError: false 100 | stderr: "toBeEmpty" 101 | performance: 102 | maxResponseTime: "2000ms" 103 | 104 | # Critical error handling - test MCP error responses 105 | - it: "should handle missing pattern parameter" 106 | request: 107 | jsonrpc: "2.0" 108 | id: "search-missing-pattern" 109 | method: "tools/call" 110 | params: 111 | name: "search_job_logs" 112 | arguments: {} 113 | expect: 114 | response: 115 | jsonrpc: "2.0" 116 | id: "search-missing-pattern" 117 | result: 118 | content: 119 | match:arrayElements: 120 | type: "text" 121 | text: "match:contains:pattern must be a non-empty string" 122 | isError: true 123 | stderr: "toBeEmpty" 124 | performance: 125 | maxResponseTime: "1000ms" 126 | 127 | - it: "should validate parameter types" 128 | request: 129 | jsonrpc: "2.0" 130 | id: "search-invalid-limit" 131 | method: "tools/call" 132 | params: 133 | name: "search_job_logs" 134 | arguments: 135 | pattern: "INFO" 136 | limit: "invalid" 137 | expect: 138 | response: 139 | jsonrpc: "2.0" 140 | id: "search-invalid-limit" 141 | result: 142 | content: 143 | match:arrayElements: 144 | type: "text" 145 | text: "match:contains:Invalid limit" 146 | isError: true 147 | stderr: "toBeEmpty" 148 | performance: 149 | maxResponseTime: "1000ms" 150 | 151 | # Performance validation for aegis 152 | - it: "should handle large search operations efficiently" 153 | request: 154 | jsonrpc: "2.0" 155 | id: "search-performance" 156 | method: "tools/call" 157 | params: 158 | name: "search_job_logs" 159 | arguments: 160 | pattern: "step" 161 | limit: 50 162 | expect: 163 | response: 164 | jsonrpc: "2.0" 165 | id: "search-performance" 166 | result: 167 | content: 168 | match:arrayElements: 169 | match:partial: 170 | type: "text" 171 | isError: false 172 | stderr: "toBeEmpty" 173 | performance: 174 | maxResponseTime: "3000ms" 175 | ``` -------------------------------------------------------------------------------- /docs/dw_web/ClickStream.md: -------------------------------------------------------------------------------- ```markdown 1 | ## Package: dw.web 2 | 3 | # Class ClickStream 4 | 5 | ## Inheritance Hierarchy 6 | 7 | - Object 8 | - dw.web.ClickStream 9 | 10 | ## Description 11 | 12 | Represents the click stream in the session. A maximum number of 50 clicks is recorded per session. After the maximum is reached, each time the customer clicks on a new link, the oldest click stream entry is purged. The ClickStream always remembers the first click. The click stream is consulted when the GetLastVisitedProducts pipelet is called to retrieve the products that the customer has recently visited. 13 | 14 | ## Properties 15 | 16 | ### clicks 17 | 18 | **Type:** List (Read Only) 19 | 20 | A collection with all clicks. The first entry is the oldest 21 | entry. The last entry is the latest entry. The method returns a copy of 22 | the click stream, which makes it safe to work with the click stream, 23 | while it might be modified. 24 | 25 | ### enabled 26 | 27 | **Type:** Session.isTrackingAllowed() (Read Only) 28 | 29 | Identifies if the clickstream recording is enabled or not. 30 | It is considered enabled if either: 31 | the method Session.isTrackingAllowed() returns true 32 | or if the above method returns false but the preference 'ClickstreamHonorDNT' is set to false. 33 | 34 | When clickstream tracking is not enabled the getFirst() method still operates as expected 35 | but the rest of the clicks are not collected. 36 | 37 | ### first 38 | 39 | **Type:** ClickStreamEntry (Read Only) 40 | 41 | The first click within this session. This first click 42 | is stored independent of whether entries are purged. 43 | 44 | ### last 45 | 46 | **Type:** ClickStreamEntry (Read Only) 47 | 48 | The last recorded click stream, which is also typically 49 | the current click. In where rare cases (e.g. RedirectURL pipeline) this 50 | is not the current click, but instead the last recorded click. 51 | 52 | ### partial 53 | 54 | **Type:** boolean (Read Only) 55 | 56 | Identifies if this is only a partial click stream. If the maximum number 57 | of clicks (50) is recorded, the oldest entry is automatically purged with 58 | each additional click. In this case, this flag indicates that the click 59 | stream is only partial. 60 | 61 | ## Constructor Summary 62 | 63 | ## Method Summary 64 | 65 | ### getClicks 66 | 67 | **Signature:** `getClicks() : List` 68 | 69 | Returns a collection with all clicks. 70 | 71 | ### getFirst 72 | 73 | **Signature:** `getFirst() : ClickStreamEntry` 74 | 75 | Returns the first click within this session. 76 | 77 | ### getLast 78 | 79 | **Signature:** `getLast() : ClickStreamEntry` 80 | 81 | Returns the last recorded click stream, which is also typically the current click. 82 | 83 | ### isEnabled 84 | 85 | **Signature:** `isEnabled() : boolean` 86 | 87 | Identifies if the clickstream recording is enabled or not. 88 | 89 | ### isPartial 90 | 91 | **Signature:** `isPartial() : boolean` 92 | 93 | Identifies if this is only a partial click stream. 94 | 95 | ## Method Detail 96 | 97 | ## Method Details 98 | 99 | ### getClicks 100 | 101 | **Signature:** `getClicks() : List` 102 | 103 | **Description:** Returns a collection with all clicks. The first entry is the oldest entry. The last entry is the latest entry. The method returns a copy of the click stream, which makes it safe to work with the click stream, while it might be modified. 104 | 105 | **Returns:** 106 | 107 | a collection of ClickStreamEntry instances, sorted chronologically. 108 | 109 | --- 110 | 111 | ### getFirst 112 | 113 | **Signature:** `getFirst() : ClickStreamEntry` 114 | 115 | **Description:** Returns the first click within this session. This first click is stored independent of whether entries are purged. 116 | 117 | **Returns:** 118 | 119 | the first click within this session. 120 | 121 | --- 122 | 123 | ### getLast 124 | 125 | **Signature:** `getLast() : ClickStreamEntry` 126 | 127 | **Description:** Returns the last recorded click stream, which is also typically the current click. In where rare cases (e.g. RedirectURL pipeline) this is not the current click, but instead the last recorded click. 128 | 129 | **Returns:** 130 | 131 | the last recorded click stream, which is also typically the current click. 132 | 133 | --- 134 | 135 | ### isEnabled 136 | 137 | **Signature:** `isEnabled() : boolean` 138 | 139 | **Description:** Identifies if the clickstream recording is enabled or not. It is considered enabled if either: the method Session.isTrackingAllowed() returns true or if the above method returns false but the preference 'ClickstreamHonorDNT' is set to false. When clickstream tracking is not enabled the getFirst() method still operates as expected but the rest of the clicks are not collected. 140 | 141 | **Returns:** 142 | 143 | whether clickstream tracking is enabled 144 | 145 | --- 146 | 147 | ### isPartial 148 | 149 | **Signature:** `isPartial() : boolean` 150 | 151 | **Description:** Identifies if this is only a partial click stream. If the maximum number of clicks (50) is recorded, the oldest entry is automatically purged with each additional click. In this case, this flag indicates that the click stream is only partial. 152 | 153 | **Returns:** 154 | 155 | true if this click stream is partial, false otherwise. 156 | 157 | --- ``` -------------------------------------------------------------------------------- /docs/dw_order/ProductShippingModel.md: -------------------------------------------------------------------------------- ```markdown 1 | ## Package: dw.order 2 | 3 | # Class ProductShippingModel 4 | 5 | ## Inheritance Hierarchy 6 | 7 | - Object 8 | - dw.order.ProductShippingModel 9 | 10 | ## Description 11 | 12 | Instances of ProductShippingModel provide access to product-level shipping information, such as applicable or inapplicable shipping methods and shipping cost defined for the product for a specified shipping method. Use ShippingMgr.getProductShippingModel(Product) to get the shipping model for a specific product. 13 | 14 | ## Properties 15 | 16 | ### applicableShippingMethods 17 | 18 | **Type:** Collection (Read Only) 19 | 20 | The active applicable shipping methods for the product related 21 | to this shipping model, i.e. shipping methods the product can be shipped 22 | with. A product can be shipping with a shipping methods if the shipping 23 | method is not explicitely marked as inapplicable for this product. 24 | 25 | ### inapplicableShippingMethods 26 | 27 | **Type:** Collection (Read Only) 28 | 29 | The active inapplicable shipping methods for the product related 30 | to this shipping model, i.e. shipping methods the product cannot be 31 | shipped with. A product cannot be shipping with a shipping methods if the 32 | shipping method is explicitely marked as inapplicable for this product. 33 | 34 | ### shippingMethodsWithShippingCost 35 | 36 | **Type:** Collection (Read Only) 37 | 38 | The active shipping methods for which either any fixed-price or 39 | surcharge product-level shipping cost is defined for the specified product. 40 | Note that this can include inapplicable shipping methods 41 | (see getInapplicableShippingMethods()). 42 | 43 | ## Constructor Summary 44 | 45 | ## Method Summary 46 | 47 | ### getApplicableShippingMethods 48 | 49 | **Signature:** `getApplicableShippingMethods() : Collection` 50 | 51 | Returns the active applicable shipping methods for the product related to this shipping model, i.e. 52 | 53 | ### getInapplicableShippingMethods 54 | 55 | **Signature:** `getInapplicableShippingMethods() : Collection` 56 | 57 | Returns the active inapplicable shipping methods for the product related to this shipping model, i.e. 58 | 59 | ### getShippingCost 60 | 61 | **Signature:** `getShippingCost(shippingMethod : ShippingMethod) : ProductShippingCost` 62 | 63 | Returns the shipping cost object for the related product and the specified shipping method, or null if no product-level fixed-price or surcharge shipping cost are defined for the specified product. 64 | 65 | ### getShippingMethodsWithShippingCost 66 | 67 | **Signature:** `getShippingMethodsWithShippingCost() : Collection` 68 | 69 | Returns the active shipping methods for which either any fixed-price or surcharge product-level shipping cost is defined for the specified product. 70 | 71 | ## Method Detail 72 | 73 | ## Method Details 74 | 75 | ### getApplicableShippingMethods 76 | 77 | **Signature:** `getApplicableShippingMethods() : Collection` 78 | 79 | **Description:** Returns the active applicable shipping methods for the product related to this shipping model, i.e. shipping methods the product can be shipped with. A product can be shipping with a shipping methods if the shipping method is not explicitely marked as inapplicable for this product. 80 | 81 | **Returns:** 82 | 83 | Applicable shipping methods for the product 84 | 85 | --- 86 | 87 | ### getInapplicableShippingMethods 88 | 89 | **Signature:** `getInapplicableShippingMethods() : Collection` 90 | 91 | **Description:** Returns the active inapplicable shipping methods for the product related to this shipping model, i.e. shipping methods the product cannot be shipped with. A product cannot be shipping with a shipping methods if the shipping method is explicitely marked as inapplicable for this product. 92 | 93 | **Returns:** 94 | 95 | Inapplicable shipping methods for the product 96 | 97 | --- 98 | 99 | ### getShippingCost 100 | 101 | **Signature:** `getShippingCost(shippingMethod : ShippingMethod) : ProductShippingCost` 102 | 103 | **Description:** Returns the shipping cost object for the related product and the specified shipping method, or null if no product-level fixed-price or surcharge shipping cost are defined for the specified product. The following rules apply: if fixed and surcharge shipping cost is defined for a product, the fixed cost takes precedence if a product is member of multiple shipping cost groups, the lowest shipping cost takes precedence 104 | 105 | **Parameters:** 106 | 107 | - `shippingMethod`: the shipping method to use. 108 | 109 | **Returns:** 110 | 111 | Product shipping cost 112 | 113 | --- 114 | 115 | ### getShippingMethodsWithShippingCost 116 | 117 | **Signature:** `getShippingMethodsWithShippingCost() : Collection` 118 | 119 | **Description:** Returns the active shipping methods for which either any fixed-price or surcharge product-level shipping cost is defined for the specified product. Note that this can include inapplicable shipping methods (see getInapplicableShippingMethods()). 120 | 121 | **Returns:** 122 | 123 | Shipping methods with shipping cost 124 | 125 | --- ``` -------------------------------------------------------------------------------- /tests/servers/sfcc-mock-server/mock-data/ocapi/site-preferences-fastforward.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "_v": "23.2", 3 | "_type": "preference_value_search_result", 4 | "count": 2, 5 | "hits": [ 6 | { 7 | "_type": "preference_value", 8 | "attribute_definition": { 9 | "_type": "object_attribute_definition", 10 | "_resource_state": "3a0e7b1f995f68fb1ad3a0a15ab3e1d744879da35d819fab7725ac56de0bac12", 11 | "creation_date": "2024-02-26T19:35:27.000Z", 12 | "description": { 13 | "default": "The custom attributes that are searchable in the FastForward Business Manager modules." 14 | }, 15 | "display_name": { 16 | "default": "FastForward: Category Search Custom Attributes" 17 | }, 18 | "effective_id": "c_fastforward_categorySearchCustomAttributes", 19 | "externally_defined": false, 20 | "externally_managed": false, 21 | "field_height": 10, 22 | "id": "fastforward_categorySearchCustomAttributes", 23 | "key": false, 24 | "last_modified": "2024-02-26T19:35:27.000Z", 25 | "link": "https://localhost:3000/s/-/dw/data/v23_2/system_object_definitions/SitePreferences/attribute_definitions/fastforward_categorySearchCustomAttributes", 26 | "localizable": false, 27 | "mandatory": false, 28 | "min_length": 0, 29 | "multi_value_type": false, 30 | "order_required": false, 31 | "queryable": false, 32 | "read_only": false, 33 | "requires_encoding": false, 34 | "searchable": false, 35 | "set_value_type": false, 36 | "site_specific": false, 37 | "system": false, 38 | "value_type": "text", 39 | "visible": false 40 | }, 41 | "description": { 42 | "default": "The custom attributes that are searchable in the FastForward Business Manager modules." 43 | }, 44 | "display_name": { 45 | "default": "FastForward: Category Search Custom Attributes" 46 | }, 47 | "id": "fastforward_categorySearchCustomAttributes", 48 | "site_values": { 49 | "RefArch": null, 50 | "RefArchGlobal": "[{\"id\":\"catBannerID\",\"type\":\"string\"},{\"id\":\"customCSSFile\",\"type\":\"image\"},{\"id\":\"enableCompare\",\"type\":\"boolean\"},{\"id\":\"alternativeUrl\",\"type\":\"html\"}]", 51 | "pxl_1": null, 52 | "pxl_2": null, 53 | "pxl_3": null, 54 | "pxl_4": null, 55 | "pxl_5": null, 56 | "pxl_6": null 57 | }, 58 | "value_type": "text" 59 | }, 60 | { 61 | "_type": "preference_value", 62 | "attribute_definition": { 63 | "_type": "object_attribute_definition", 64 | "_resource_state": "a8fe5c4af162e8019daab09c5a0f32c1f57bf46db00a3cb4ba4f7d930a8c9121", 65 | "creation_date": "2024-02-26T19:35:27.000Z", 66 | "description": { 67 | "default": "The custom attributes that are searchable in the FastForward Business Manager modules." 68 | }, 69 | "display_name": { 70 | "default": "FastForward: Product Search Custom Attributes" 71 | }, 72 | "effective_id": "c_fastforward_productSearchCustomAttributes", 73 | "externally_defined": false, 74 | "externally_managed": false, 75 | "field_height": 10, 76 | "id": "fastforward_productSearchCustomAttributes", 77 | "key": false, 78 | "last_modified": "2024-02-26T19:35:27.000Z", 79 | "link": "https://localhost:3000/s/-/dw/data/v23_2/system_object_definitions/SitePreferences/attribute_definitions/fastforward_productSearchCustomAttributes", 80 | "localizable": false, 81 | "mandatory": false, 82 | "min_length": 0, 83 | "multi_value_type": false, 84 | "order_required": false, 85 | "queryable": false, 86 | "read_only": false, 87 | "requires_encoding": false, 88 | "searchable": false, 89 | "set_value_type": false, 90 | "site_specific": false, 91 | "system": false, 92 | "value_type": "text", 93 | "visible": false 94 | }, 95 | "description": { 96 | "default": "The custom attributes that are searchable in the FastForward Business Manager modules." 97 | }, 98 | "display_name": { 99 | "default": "FastForward: Product Search Custom Attributes" 100 | }, 101 | "id": "fastforward_productSearchCustomAttributes", 102 | "site_values": { 103 | "RefArch": null, 104 | "RefArchGlobal": "[{\"id\":\"batteryType\",\"type\":\"string\"},{\"id\":\"bootType\",\"type\":\"enum_of_string\"},{\"id\":\"batteryLife\",\"type\":\"string\"},{\"id\":\"Wool\",\"type\":\"string\"}]", 105 | "pxl_1": null, 106 | "pxl_2": null, 107 | "pxl_3": null, 108 | "pxl_4": null, 109 | "pxl_5": null, 110 | "pxl_6": null 111 | }, 112 | "value_type": "text" 113 | } 114 | ], 115 | "query": { 116 | "match_all_query": { 117 | "_type": "match_all_query" 118 | } 119 | }, 120 | "select": "(**)", 121 | "start": 0, 122 | "total": 2 123 | } ``` -------------------------------------------------------------------------------- /tests/mcp/yaml/search-job-logs-by-name.full-mode.test.mcp.yml: -------------------------------------------------------------------------------- ```yaml 1 | --- 2 | description: "Test search_job_logs_by_name tool in full mode - focused on aegis framework validation" 3 | tests: 4 | # Basic functionality - test aegis with simple patterns 5 | - it: "should search for job logs and validate basic structure" 6 | request: 7 | jsonrpc: "2.0" 8 | id: "search-job-basic" 9 | method: "tools/call" 10 | params: 11 | name: "search_job_logs_by_name" 12 | arguments: 13 | jobName: "Import" 14 | expect: 15 | response: 16 | jsonrpc: "2.0" 17 | id: "search-job-basic" 18 | result: 19 | content: 20 | match:arrayElements: 21 | type: "text" 22 | text: "match:regex:\"(?:Found \\d+ job logs|No job logs found)" 23 | isError: false 24 | stderr: "toBeEmpty" 25 | performance: 26 | maxResponseTime: "2000ms" 27 | 28 | - it: "should return exact empty result format for non-existent job" 29 | request: 30 | jsonrpc: "2.0" 31 | id: "search-job-empty-result" 32 | method: "tools/call" 33 | params: 34 | name: "search_job_logs_by_name" 35 | arguments: 36 | jobName: "NonExistentJobXYZ" 37 | expect: 38 | response: 39 | jsonrpc: "2.0" 40 | id: "search-job-empty-result" 41 | result: 42 | content: 43 | match:arrayElements: 44 | type: "text" 45 | text: "\"No job logs found.\"" 46 | isError: false 47 | stderr: "toBeEmpty" 48 | performance: 49 | maxResponseTime: "1500ms" 50 | 51 | - it: "should include job emoji and basic details when found" 52 | request: 53 | jsonrpc: "2.0" 54 | id: "search-job-details" 55 | method: "tools/call" 56 | params: 57 | name: "search_job_logs_by_name" 58 | arguments: 59 | jobName: "Import" 60 | limit: 1 61 | expect: 62 | response: 63 | jsonrpc: "2.0" 64 | id: "search-job-details" 65 | result: 66 | content: 67 | match:arrayElements: 68 | type: "text" 69 | # Test for job emoji presence 70 | text: "match:contains:🔧 Job:" 71 | isError: false 72 | stderr: "toBeEmpty" 73 | performance: 74 | maxResponseTime: "2000ms" 75 | 76 | # Error validation - test exact error messages 77 | - it: "should reject empty job name with exact error message" 78 | request: 79 | jsonrpc: "2.0" 80 | id: "search-job-empty-name" 81 | method: "tools/call" 82 | params: 83 | name: "search_job_logs_by_name" 84 | arguments: 85 | jobName: "" 86 | expect: 87 | response: 88 | jsonrpc: "2.0" 89 | id: "search-job-empty-name" 90 | result: 91 | content: 92 | match:arrayElements: 93 | type: "text" 94 | text: "Error: jobName must be a non-empty string" 95 | isError: true 96 | stderr: "toBeEmpty" 97 | performance: 98 | maxResponseTime: "800ms" 99 | 100 | - it: "should reject invalid limit with specific error format" 101 | request: 102 | jsonrpc: "2.0" 103 | id: "search-job-invalid-limit" 104 | method: "tools/call" 105 | params: 106 | name: "search_job_logs_by_name" 107 | arguments: 108 | jobName: "Import" 109 | limit: -1 110 | expect: 111 | response: 112 | jsonrpc: "2.0" 113 | id: "search-job-invalid-limit" 114 | result: 115 | content: 116 | match:arrayElements: 117 | type: "text" 118 | text: "Error: Invalid limit '-1' for tool. Must be between 1 and 1000" 119 | isError: true 120 | stderr: "toBeEmpty" 121 | performance: 122 | maxResponseTime: "800ms" 123 | 124 | # Parameter handling - test limit behavior 125 | - it: "should respect custom limit parameter" 126 | request: 127 | jsonrpc: "2.0" 128 | id: "search-job-custom-limit" 129 | method: "tools/call" 130 | params: 131 | name: "search_job_logs_by_name" 132 | arguments: 133 | jobName: "Import" 134 | limit: 5 135 | expect: 136 | response: 137 | jsonrpc: "2.0" 138 | id: "search-job-custom-limit" 139 | result: 140 | content: 141 | match:arrayElements: 142 | type: "text" 143 | text: "match:type:string" 144 | isError: false 145 | stderr: "toBeEmpty" 146 | performance: 147 | maxResponseTime: "2000ms" 148 | 149 | # Response structure validation 150 | - it: "should maintain consistent MCP response structure" 151 | request: 152 | jsonrpc: "2.0" 153 | id: "search-job-structure" 154 | method: "tools/call" 155 | params: 156 | name: "search_job_logs_by_name" 157 | arguments: 158 | jobName: "Import" 159 | expect: 160 | response: 161 | jsonrpc: "2.0" 162 | id: "search-job-structure" 163 | result: 164 | match:partial: 165 | content: "match:arrayLength:1" 166 | isError: "match:type:boolean" 167 | stderr: "toBeEmpty" 168 | performance: 169 | maxResponseTime: "2000ms" 170 | ``` -------------------------------------------------------------------------------- /docs/TopLevel/Map.md: -------------------------------------------------------------------------------- ```markdown 1 | ## Package: TopLevel 2 | 3 | # Class Map 4 | 5 | ## Inheritance Hierarchy 6 | 7 | - Object 8 | - Map 9 | 10 | ## Description 11 | 12 | Map objects are collections of key/value pairs where both the keys and values may be arbitrary ECMAScript language values. A distinct key value may only occur in one key/value pair within the Map's collection. Key/value pairs are stored and iterated in insertion order. 13 | 14 | ## Properties 15 | 16 | ### size 17 | 18 | **Type:** Number 19 | 20 | Number of key/value pairs stored in this map. 21 | 22 | ## Constructor Summary 23 | 24 | Map() Creates an empty map. 25 | 26 | Map(values : Iterable) If the passed value is null or undefined then an empty map is constructed. 27 | 28 | ## Method Summary 29 | 30 | ### clear 31 | 32 | **Signature:** `clear() : void` 33 | 34 | Removes all key/value pairs from this map. 35 | 36 | ### delete 37 | 38 | **Signature:** `delete(key : Object) : boolean` 39 | 40 | Removes the entry for the given key. 41 | 42 | ### entries 43 | 44 | **Signature:** `entries() : ES6Iterator` 45 | 46 | Returns an iterator containing all key/value pairs of this map. 47 | 48 | ### forEach 49 | 50 | **Signature:** `forEach(callback : Function) : void` 51 | 52 | Runs the provided callback function once for each key/value pair present in this map. 53 | 54 | ### forEach 55 | 56 | **Signature:** `forEach(callback : Function, thisObject : Object) : void` 57 | 58 | Runs the provided callback function once for each key/value pair present in this map. 59 | 60 | ### get 61 | 62 | **Signature:** `get(key : Object) : Object` 63 | 64 | Returns the value associated with the given key. 65 | 66 | ### has 67 | 68 | **Signature:** `has(key : Object) : boolean` 69 | 70 | Returns if this map has value associated with the given key. 71 | 72 | ### keys 73 | 74 | **Signature:** `keys() : ES6Iterator` 75 | 76 | Returns an iterator containing all keys of this map. 77 | 78 | ### set 79 | 80 | **Signature:** `set(key : Object, value : Object) : Map` 81 | 82 | Adds or updates a key/value pair to the map. 83 | 84 | ### values 85 | 86 | **Signature:** `values() : ES6Iterator` 87 | 88 | Returns an iterator containing all values of this map. 89 | 90 | ## Constructor Detail 91 | 92 | ## Method Detail 93 | 94 | ## Method Details 95 | 96 | ### clear 97 | 98 | **Signature:** `clear() : void` 99 | 100 | **Description:** Removes all key/value pairs from this map. 101 | 102 | --- 103 | 104 | ### delete 105 | 106 | **Signature:** `delete(key : Object) : boolean` 107 | 108 | **Description:** Removes the entry for the given key. 109 | 110 | **Parameters:** 111 | 112 | - `key`: The key of the key/value pair to be removed from the map. 113 | 114 | **Returns:** 115 | 116 | true if the map contained an entry for the passed key that was removed. Else false is returned. 117 | 118 | --- 119 | 120 | ### entries 121 | 122 | **Signature:** `entries() : ES6Iterator` 123 | 124 | **Description:** Returns an iterator containing all key/value pairs of this map. The iterator produces a series of two-element arrays with the first element as the key and the second element as the value. 125 | 126 | --- 127 | 128 | ### forEach 129 | 130 | **Signature:** `forEach(callback : Function) : void` 131 | 132 | **Description:** Runs the provided callback function once for each key/value pair present in this map. 133 | 134 | **Parameters:** 135 | 136 | - `callback`: The function to call, which is invoked with three arguments: the value of the element, the key of the element, and the Map object being iterated. 137 | 138 | --- 139 | 140 | ### forEach 141 | 142 | **Signature:** `forEach(callback : Function, thisObject : Object) : void` 143 | 144 | **Description:** Runs the provided callback function once for each key/value pair present in this map. 145 | 146 | **Parameters:** 147 | 148 | - `callback`: The function to call, which is invoked with three arguments: the value of the element, the key of the element, and the Map object being iterated. 149 | - `thisObject`: The Object to use as 'this' when executing callback. 150 | 151 | --- 152 | 153 | ### get 154 | 155 | **Signature:** `get(key : Object) : Object` 156 | 157 | **Description:** Returns the value associated with the given key. 158 | 159 | **Parameters:** 160 | 161 | - `key`: The key to look for. 162 | 163 | **Returns:** 164 | 165 | The value associated with the given key if an entry with the key exists else undefined is returned. 166 | 167 | --- 168 | 169 | ### has 170 | 171 | **Signature:** `has(key : Object) : boolean` 172 | 173 | **Description:** Returns if this map has value associated with the given key. 174 | 175 | **Parameters:** 176 | 177 | - `key`: The key to look for. 178 | 179 | **Returns:** 180 | 181 | true if an entry with the key exists else false is returned. 182 | 183 | --- 184 | 185 | ### keys 186 | 187 | **Signature:** `keys() : ES6Iterator` 188 | 189 | **Description:** Returns an iterator containing all keys of this map. 190 | 191 | --- 192 | 193 | ### set 194 | 195 | **Signature:** `set(key : Object, value : Object) : Map` 196 | 197 | **Description:** Adds or updates a key/value pair to the map. You can't use JavaScript bracket notation to access map entries. JavaScript bracket notation accesses only properties for Map objects, not map entries. 198 | 199 | **Parameters:** 200 | 201 | - `key`: The key object. 202 | - `value`: The value to be associated with the key. 203 | 204 | **Returns:** 205 | 206 | This map object. 207 | 208 | --- 209 | 210 | ### values 211 | 212 | **Signature:** `values() : ES6Iterator` 213 | 214 | **Description:** Returns an iterator containing all values of this map. 215 | 216 | --- ``` -------------------------------------------------------------------------------- /src/tool-configs/docs-tool-config.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { GenericToolSpec, ToolExecutionContext } from '../core/handlers/base-handler.js'; 2 | import { ToolArguments } from '../core/handlers/base-handler.js'; 3 | import { ValidationHelpers, CommonValidations } from '../core/handlers/validation-helpers.js'; 4 | import { SFCCDocumentationClient } from '../clients/docs-client.js'; 5 | 6 | export const DOC_TOOL_NAMES = [ 7 | 'get_sfcc_class_info', 8 | 'search_sfcc_classes', 9 | 'search_sfcc_methods', 10 | 'list_sfcc_classes', 11 | 'get_sfcc_class_documentation', 12 | ] as const; 13 | 14 | export type DocToolName = typeof DOC_TOOL_NAMES[number]; 15 | export const DOC_TOOL_NAMES_SET = new Set<DocToolName>(DOC_TOOL_NAMES); 16 | 17 | /** 18 | * Configuration for SFCC documentation tools 19 | * Maps each tool to its validation, execution, and messaging logic 20 | */ 21 | export const DOCS_TOOL_CONFIG: Record<DocToolName, GenericToolSpec<ToolArguments, any>> = { 22 | get_sfcc_class_info: { 23 | defaults: (args: ToolArguments) => ({ 24 | ...args, 25 | expand: args.expand ?? false, 26 | includeDescription: args.includeDescription ?? true, 27 | includeConstants: args.includeConstants ?? true, 28 | includeProperties: args.includeProperties ?? true, 29 | includeMethods: args.includeMethods ?? true, 30 | includeInheritance: args.includeInheritance ?? true, 31 | search: args.search ?? undefined, 32 | }), 33 | validate: (args: ToolArguments, toolName: string) => { 34 | ValidationHelpers.validateArguments(args, CommonValidations.requiredString('className'), toolName); 35 | }, 36 | exec: async (args: ToolArguments, context: ToolExecutionContext) => { 37 | const client = context.docsClient as SFCCDocumentationClient; 38 | const result = await client.getClassDetailsExpanded( 39 | args.className as string, 40 | args.expand as boolean, 41 | { 42 | includeDescription: args.includeDescription as boolean, 43 | includeConstants: args.includeConstants as boolean, 44 | includeProperties: args.includeProperties as boolean, 45 | includeMethods: args.includeMethods as boolean, 46 | includeInheritance: args.includeInheritance as boolean, 47 | search: args.search as string | undefined, 48 | }, 49 | ); 50 | if (!result) { 51 | throw new Error(`Class "${args.className}" not found`); 52 | } 53 | return result; 54 | }, 55 | logMessage: (args: ToolArguments) => 56 | `Class info ${args.className} expand=${args.expand ?? false} ${args.search ? `search="${args.search}"` : ''}`, 57 | }, 58 | 59 | search_sfcc_classes: { 60 | defaults: (args: ToolArguments) => args, 61 | validate: (args: ToolArguments, toolName: string) => { 62 | ValidationHelpers.validateArguments(args, CommonValidations.requiredString('query'), toolName); 63 | }, 64 | exec: async (args: ToolArguments, context: ToolExecutionContext) => { 65 | const client = context.docsClient as SFCCDocumentationClient; 66 | return client.searchClasses(args.query as string); 67 | }, 68 | logMessage: (args: ToolArguments) => `Search classes ${args.query}`, 69 | }, 70 | 71 | search_sfcc_methods: { 72 | defaults: (args: ToolArguments) => args, 73 | validate: (args: ToolArguments, toolName: string) => { 74 | ValidationHelpers.validateArguments(args, CommonValidations.requiredString('methodName'), toolName); 75 | }, 76 | exec: async (args: ToolArguments, context: ToolExecutionContext) => { 77 | const client = context.docsClient as SFCCDocumentationClient; 78 | return client.searchMethods(args.methodName as string); 79 | }, 80 | logMessage: (args: ToolArguments) => `Search methods ${args.methodName}`, 81 | }, 82 | 83 | list_sfcc_classes: { 84 | defaults: (args: ToolArguments) => args, 85 | validate: (_args: ToolArguments, _toolName: string) => { 86 | // No validation needed for list operation 87 | }, 88 | exec: async (args: ToolArguments, context: ToolExecutionContext) => { 89 | const client = context.docsClient as SFCCDocumentationClient; 90 | return client.getAvailableClasses(); 91 | }, 92 | logMessage: (_args: ToolArguments) => 'List classes', 93 | }, 94 | 95 | get_sfcc_class_documentation: { 96 | defaults: (args: ToolArguments) => args, 97 | validate: (args: ToolArguments, toolName: string) => { 98 | ValidationHelpers.validateArguments(args, CommonValidations.requiredString('className'), toolName); 99 | }, 100 | exec: async (args: ToolArguments, context: ToolExecutionContext) => { 101 | const client = context.docsClient as SFCCDocumentationClient; 102 | const result = await client.getClassDocumentation(args.className as string); 103 | if (!result) { 104 | throw new Error(`Documentation for class "${args.className}" not found`); 105 | } 106 | return result; 107 | }, 108 | logMessage: (args: ToolArguments) => `Raw doc ${args.className}`, 109 | }, 110 | }; 111 | ``` -------------------------------------------------------------------------------- /docs/dw_system/System.md: -------------------------------------------------------------------------------- ```markdown 1 | ## Package: dw.system 2 | 3 | # Class System 4 | 5 | ## Inheritance Hierarchy 6 | 7 | - Object 8 | - dw.system.System 9 | 10 | ## Description 11 | 12 | Represents the Commerce Cloud Digital server instance. An application server instance is configured to be of one of three types, "development system", "staging system" or "production system". 13 | 14 | ## Constants 15 | 16 | ### DEVELOPMENT_SYSTEM 17 | 18 | **Type:** Number = 0 19 | 20 | Represents the development system. 21 | 22 | ### PRODUCTION_SYSTEM 23 | 24 | **Type:** Number = 2 25 | 26 | Represents the production system. 27 | 28 | ### STAGING_SYSTEM 29 | 30 | **Type:** Number = 1 31 | 32 | Represents the staging system. 33 | 34 | ## Properties 35 | 36 | ### calendar 37 | 38 | **Type:** Calendar (Read Only) 39 | 40 | A new Calendar object in the time zone of the 41 | current instance. 42 | 43 | ### compatibilityMode 44 | 45 | **Type:** Number (Read Only) 46 | 47 | The compatibility mode of the custom code version that is currently active. The compatibility mode is 48 | returned as a number, e.g. compatibility mode "15.5" is returned as 1505. 49 | 50 | ### instanceHostname 51 | 52 | **Type:** String (Read Only) 53 | 54 | Returns instance hostname. 55 | 56 | ### instanceTimeZone 57 | 58 | **Type:** String (Read Only) 59 | 60 | The instance time zone. The instance time zone is the time zone in which global actions like jobs or 61 | reporting are specified in the system. Keep in mind that the instance time zone is cached at the current session. 62 | Changes will affect only new sessions. 63 | 64 | ### instanceType 65 | 66 | **Type:** Number (Read Only) 67 | 68 | The type of the instance. An application server instance is configured to be of one of three types, 69 | "development system", "staging system" or "production system". 70 | This method returns a constant representing the instance type of this 71 | application server. 72 | 73 | ### preferences 74 | 75 | **Type:** OrganizationPreferences (Read Only) 76 | 77 | This method returns a container of all global preferences of this 78 | organization (instance). 79 | 80 | ## Constructor Summary 81 | 82 | ## Method Summary 83 | 84 | ### getCalendar 85 | 86 | **Signature:** `static getCalendar() : Calendar` 87 | 88 | Returns a new Calendar object in the time zone of the current instance. 89 | 90 | ### getCompatibilityMode 91 | 92 | **Signature:** `static getCompatibilityMode() : Number` 93 | 94 | Returns the compatibility mode of the custom code version that is currently active. 95 | 96 | ### getInstanceHostname 97 | 98 | **Signature:** `static getInstanceHostname() : String` 99 | 100 | Returns instance hostname. 101 | 102 | ### getInstanceTimeZone 103 | 104 | **Signature:** `static getInstanceTimeZone() : String` 105 | 106 | Returns the instance time zone. 107 | 108 | ### getInstanceType 109 | 110 | **Signature:** `static getInstanceType() : Number` 111 | 112 | Returns the type of the instance. 113 | 114 | ### getPreferences 115 | 116 | **Signature:** `static getPreferences() : OrganizationPreferences` 117 | 118 | This method returns a container of all global preferences of this organization (instance). 119 | 120 | ## Method Detail 121 | 122 | ## Method Details 123 | 124 | ### getCalendar 125 | 126 | **Signature:** `static getCalendar() : Calendar` 127 | 128 | **Description:** Returns a new Calendar object in the time zone of the current instance. 129 | 130 | **Returns:** 131 | 132 | a Calendar object in the time zone of the instance. 133 | 134 | --- 135 | 136 | ### getCompatibilityMode 137 | 138 | **Signature:** `static getCompatibilityMode() : Number` 139 | 140 | **Description:** Returns the compatibility mode of the custom code version that is currently active. The compatibility mode is returned as a number, e.g. compatibility mode "15.5" is returned as 1505. 141 | 142 | **Returns:** 143 | 144 | The currently active compatibility mode. 145 | 146 | --- 147 | 148 | ### getInstanceHostname 149 | 150 | **Signature:** `static getInstanceHostname() : String` 151 | 152 | **Description:** Returns instance hostname. 153 | 154 | **Returns:** 155 | 156 | instance hostname. 157 | 158 | --- 159 | 160 | ### getInstanceTimeZone 161 | 162 | **Signature:** `static getInstanceTimeZone() : String` 163 | 164 | **Description:** Returns the instance time zone. The instance time zone is the time zone in which global actions like jobs or reporting are specified in the system. Keep in mind that the instance time zone is cached at the current session. Changes will affect only new sessions. 165 | 166 | **Returns:** 167 | 168 | the instance time zone. 169 | 170 | --- 171 | 172 | ### getInstanceType 173 | 174 | **Signature:** `static getInstanceType() : Number` 175 | 176 | **Description:** Returns the type of the instance. An application server instance is configured to be of one of three types, "development system", "staging system" or "production system". This method returns a constant representing the instance type of this application server. 177 | 178 | **Returns:** 179 | 180 | the instance type of the application server where this method was called. 181 | 182 | **See Also:** 183 | 184 | DEVELOPMENT_SYSTEM 185 | PRODUCTION_SYSTEM 186 | STAGING_SYSTEM 187 | 188 | --- 189 | 190 | ### getPreferences 191 | 192 | **Signature:** `static getPreferences() : OrganizationPreferences` 193 | 194 | **Description:** This method returns a container of all global preferences of this organization (instance). 195 | 196 | **Returns:** 197 | 198 | a preferences object containing all global system and custom preferences of this instance 199 | 200 | --- ``` -------------------------------------------------------------------------------- /docs/sfra/payment.md: -------------------------------------------------------------------------------- ```markdown 1 | # SFRA Payment Model 2 | 3 | ## Overview 4 | 5 | The Payment model represents payment information for the current basket in SFRA applications. It provides comprehensive payment method options, applicable payment cards, and selected payment instruments for checkout processing. 6 | 7 | ## Constructor 8 | 9 | ```javascript 10 | function Payment(currentBasket, currentCustomer, countryCode) 11 | ``` 12 | 13 | Creates a Payment model instance with applicable payment methods and current payment selections. 14 | 15 | ### Parameters 16 | 17 | - `currentBasket` (dw.order.Basket) - The target Basket object 18 | - `currentCustomer` (dw.customer.Customer) - The associated Customer object 19 | - `countryCode` (string) - The associated Site country code 20 | 21 | ## Properties 22 | 23 | ### applicablePaymentMethods 24 | **Type:** Array<Object> | null 25 | 26 | Array of payment methods available for the current basket and customer. Each method object contains: 27 | - `ID` (string) - Payment method ID 28 | - `name` (string) - Display name of the payment method 29 | 30 | ### applicablePaymentCards 31 | **Type:** Array<Object> | null 32 | 33 | Array of credit card types available for the current customer and basket. Each card object contains: 34 | - `cardType` (string) - Credit card type identifier 35 | - `name` (string) - Display name of the card type 36 | 37 | ### selectedPaymentInstruments 38 | **Type:** Array<Object> | null 39 | 40 | Array of currently selected payment instruments for the basket. Each instrument object contains: 41 | - `paymentMethod` (string) - Payment method type 42 | - `amount` (number) - Payment amount value 43 | 44 | #### Credit Card Instruments 45 | For credit card payments, additional properties include: 46 | - `lastFour` (string) - Last four digits of the card number 47 | - `owner` (string) - Cardholder name 48 | - `expirationYear` (number) - Card expiration year 49 | - `type` (string) - Credit card type 50 | - `maskedCreditCardNumber` (string) - Masked card number 51 | - `expirationMonth` (number) - Card expiration month 52 | 53 | #### Gift Certificate Instruments 54 | For gift certificate payments, additional properties include: 55 | - `giftCertificateCode` (string) - Full gift certificate code 56 | - `maskedGiftCertificateCode` (string) - Masked gift certificate code 57 | 58 | ## Helper Functions 59 | 60 | ### applicablePaymentMethods(paymentMethods) 61 | Creates an array of applicable payment method objects. 62 | 63 | **Parameters:** 64 | - `paymentMethods` (dw.util.ArrayList<dw.order.PaymentMethod>) - Available payment methods 65 | 66 | **Returns:** Array<Object> - Formatted payment methods array 67 | 68 | ### applicablePaymentCards(paymentCards) 69 | Creates an array of applicable credit card objects. 70 | 71 | **Parameters:** 72 | - `paymentCards` (dw.util.Collection<dw.order.PaymentCard>) - Available payment cards 73 | 74 | **Returns:** Array<Object> - Formatted payment cards array 75 | 76 | ### getSelectedPaymentInstruments(selectedPaymentInstruments) 77 | Creates an array of selected payment instrument objects with method-specific properties. 78 | 79 | **Parameters:** 80 | - `selectedPaymentInstruments` (dw.util.ArrayList<dw.order.PaymentInstrument>) - Selected payment instruments 81 | 82 | **Returns:** Array<Object> - Formatted payment instruments array 83 | 84 | ## Usage Example 85 | 86 | ```javascript 87 | var PaymentModel = require('*/cartridge/models/payment'); 88 | var BasketMgr = require('dw/order/BasketMgr'); 89 | 90 | var currentBasket = BasketMgr.getCurrentBasket(); 91 | var currentCustomer = req.currentCustomer.raw; 92 | var countryCode = 'US'; 93 | 94 | var payment = new PaymentModel(currentBasket, currentCustomer, countryCode); 95 | 96 | // Access payment methods 97 | console.log(payment.applicablePaymentMethods); 98 | // [{ ID: 'CREDIT_CARD', name: 'Credit Card' }, { ID: 'PayPal', name: 'PayPal' }] 99 | 100 | // Access applicable cards 101 | console.log(payment.applicablePaymentCards); 102 | // [{ cardType: 'Visa', name: 'Visa' }, { cardType: 'MasterCard', name: 'MasterCard' }] 103 | 104 | // Check selected instruments 105 | if (payment.selectedPaymentInstruments) { 106 | payment.selectedPaymentInstruments.forEach(function(instrument) { 107 | console.log(instrument.paymentMethod + ': $' + instrument.amount); 108 | }); 109 | } 110 | ``` 111 | 112 | ## Payment Method Support 113 | 114 | The model supports various payment methods including: 115 | - **Credit Cards** - With full card details and masking 116 | - **Gift Certificates** - With code masking 117 | - **Other Methods** - Basic method and amount information 118 | 119 | ## Notes 120 | 121 | - Payment methods are filtered based on customer, country, and basket amount 122 | - Credit card information is automatically masked for security 123 | - Supports multiple payment instruments per basket 124 | - All monetary amounts are in the basket's currency 125 | - Payment method availability depends on site configuration and customer eligibility 126 | 127 | ## Related Models 128 | 129 | - **BillingModel** - Uses payment model for billing information 130 | - **OrderModel** - Includes payment information in order data 131 | - **Cart Model** - May include payment selection during checkout 132 | ``` -------------------------------------------------------------------------------- /docs/dw_crypto/MessageDigest.md: -------------------------------------------------------------------------------- ```markdown 1 | ## Package: dw.crypto 2 | 3 | # Class MessageDigest 4 | 5 | ## Inheritance Hierarchy 6 | 7 | - Object 8 | - dw.crypto.MessageDigest 9 | 10 | ## Description 11 | 12 | This class provides the functionality of a message digest algorithm, such as MD5 or SHA. Message digests are secure one-way hash functions that take arbitrary-sized data and output a fixed-length hash value. This implementation offers only stateless digest() methods. A Bytes object or String is passed to a digest() method and the computed hash is returned. Note: this class handles sensitive security-related data. Pay special attention to PCI DSS v3. requirements 2, 4, and 12. 13 | 14 | ## Constants 15 | 16 | ### DIGEST_MD2 17 | 18 | **Type:** String = "MD2" 19 | 20 | Constant representing the MD2 algorithm. 21 | 22 | ### DIGEST_MD5 23 | 24 | **Type:** String = "MD5" 25 | 26 | Constant representing the MD5 algorithm. 27 | 28 | ### DIGEST_SHA 29 | 30 | **Type:** String = "SHA" 31 | 32 | Constant representing the SHA algorithm. 33 | 34 | ### DIGEST_SHA_1 35 | 36 | **Type:** String = "SHA-1" 37 | 38 | Constant representing the SHA 1 algorithm. 39 | 40 | ### DIGEST_SHA_256 41 | 42 | **Type:** String = "SHA-256" 43 | 44 | Constant representing the SHA 256 algorithm 45 | 46 | ### DIGEST_SHA_512 47 | 48 | **Type:** String = "SHA-512" 49 | 50 | Constant representing the SHA 512 algorithm 51 | 52 | ## Properties 53 | 54 | ## Constructor Summary 55 | 56 | MessageDigest(algorithm : String) Construct a MessageDigest with the specified algorithm name. 57 | 58 | ## Method Summary 59 | 60 | ### digest 61 | 62 | **Signature:** `digest(input : String) : String` 63 | 64 | Digests the passed string and returns a computed hash value as a string. 65 | 66 | ### digest 67 | 68 | **Signature:** `digest(algorithm : String, input : Bytes) : Bytes` 69 | 70 | Computes the hash value for the passed array of bytes. 71 | 72 | ### digest 73 | 74 | **Signature:** `digest() : Bytes` 75 | 76 | Completes the hash computation by performing final operations such as padding. 77 | 78 | ### digestBytes 79 | 80 | **Signature:** `digestBytes(input : Bytes) : Bytes` 81 | 82 | Computes the hash value for the passed Bytes. 83 | 84 | ### updateBytes 85 | 86 | **Signature:** `updateBytes(input : Bytes) : void` 87 | 88 | Updates the digest using the passed Bytes. 89 | 90 | ## Constructor Detail 91 | 92 | ## Method Detail 93 | 94 | ## Method Details 95 | 96 | ### digest 97 | 98 | **Signature:** `digest(input : String) : String` 99 | 100 | **Description:** Digests the passed string and returns a computed hash value as a string. The passed String is first encoded into a sequence of bytes using the platform's default encoding. The digest then performs any prerequisite padding, before computing the hash value. The hash is then converted into a string by converting all digits to hexadecimal. 101 | 102 | **Deprecated:** 103 | 104 | Deprecated because the conversion of the input to bytes using the default platform encoding and the hex-encoded return value are not generally appropriate. 105 | 106 | **Parameters:** 107 | 108 | - `input`: The value to hash as String, must not be null. 109 | 110 | **Returns:** 111 | 112 | The resulting hash value as hex-encoded string. 113 | 114 | --- 115 | 116 | ### digest 117 | 118 | **Signature:** `digest(algorithm : String, input : Bytes) : Bytes` 119 | 120 | **Description:** Computes the hash value for the passed array of bytes. The algorithm argument is optional. If null, then the algorithm established at construction time is used. The binary representation of the message is typically derived from a string and the resulting hash is typically converted with base64 back into a string. Example: Encoding.toBase64( digest( "MD5", new Bytes( "my password", "UTF-8" ) ) ); 121 | 122 | **Deprecated:** 123 | 124 | Deprecated because the digest algorithm should be the one set in the constructor. 125 | 126 | **Parameters:** 127 | 128 | - `algorithm`: The standard name of the digest algorithm, or null if the algorithm passed at construction time is to be used. The algorithm must be a supported algorithm. 129 | - `input`: The value to hash, must not be null. 130 | 131 | **Returns:** 132 | 133 | The resulting hash value. 134 | 135 | --- 136 | 137 | ### digest 138 | 139 | **Signature:** `digest() : Bytes` 140 | 141 | **Description:** Completes the hash computation by performing final operations such as padding. The binary representation of the message is typically derived from a string and the resulting hash is typically converted with base64 back into a string. Example: Encoding.toBase64( digest() ); 142 | 143 | **Returns:** 144 | 145 | The resulting hash value. 146 | 147 | --- 148 | 149 | ### digestBytes 150 | 151 | **Signature:** `digestBytes(input : Bytes) : Bytes` 152 | 153 | **Description:** Computes the hash value for the passed Bytes. The binary representation of the message is typically derived from a string and the resulting hash is typically converted with base64 back into a string. Example: Encoding.toBase64( digest( new Bytes( "my password", "UTF-8" ) ) ); 154 | 155 | **Parameters:** 156 | 157 | - `input`: The value to hash, must not be null. 158 | 159 | **Returns:** 160 | 161 | The resulting hash value. 162 | 163 | --- 164 | 165 | ### updateBytes 166 | 167 | **Signature:** `updateBytes(input : Bytes) : void` 168 | 169 | **Description:** Updates the digest using the passed Bytes. 170 | 171 | **Parameters:** 172 | 173 | - `input`: The value to hash, must not be null. 174 | 175 | --- ``` -------------------------------------------------------------------------------- /docs-site/components/ToolCard.tsx: -------------------------------------------------------------------------------- ```typescript 1 | import React from 'react'; 2 | import { ToolMeta } from '../utils/toolsData'; 3 | import { InlineCode } from './CodeBlock'; 4 | 5 | interface ToolCardProps { 6 | tool: ToolMeta; 7 | } 8 | 9 | const ModeBadge: React.FC<{ mode: ToolMeta['mode'] }> = ({ mode }) => { 10 | if (mode === 'both') return <span className="text-[10px] font-semibold bg-gradient-to-r from-blue-600 to-purple-600 text-white px-2 py-0.5 rounded-full tracking-wide">Docs + Full</span>; 11 | if (mode === 'docs') return <span className="text-[10px] font-semibold bg-green-100 text-green-700 px-2 py-0.5 rounded-full tracking-wide">Docs</span>; 12 | return <span className="text-[10px] font-semibold bg-blue-100 text-blue-700 px-2 py-0.5 rounded-full tracking-wide">Full</span>; 13 | }; 14 | 15 | const ToolCard: React.FC<ToolCardProps> = ({ tool }) => { 16 | const [open, setOpen] = React.useState(false); 17 | return ( 18 | <div id={tool.id} className="group rounded-xl border border-gray-200 bg-white/90 backdrop-blur-sm p-4 shadow-sm hover:shadow transition relative"> 19 | <div className="flex items-start justify-between gap-4"> 20 | <div className="flex-1 min-w-0"> 21 | <div className="flex items-center gap-2 mb-2 flex-wrap"> 22 | <ModeBadge mode={tool.mode} /> 23 | {tool.popular && <span className="text-[10px] bg-yellow-100 text-yellow-700 px-1.5 py-0.5 rounded">Popular</span>} 24 | {tool.tags?.slice(0,3).map(tag => ( 25 | <span key={tag} className="text-[10px] bg-gray-100 text-gray-600 px-1.5 py-0.5 rounded">{tag}</span> 26 | ))} 27 | </div> 28 | <h4 className="font-mono text-sm font-semibold text-gray-900 break-all mb-1">{tool.name}</h4> 29 | <p className="text-xs text-gray-600 leading-relaxed line-clamp-2 group-hover:line-clamp-none transition-all">{tool.description}</p> 30 | </div> 31 | <button aria-label="Toggle details" onClick={() => setOpen(o=>!o)} className="shrink-0 rounded-lg border border-gray-200 p-2 hover:bg-gray-50 text-gray-500 hover:text-gray-700 transition" aria-expanded={open}> 32 | <svg className={`w-4 h-4 transform transition ${open ? 'rotate-180' : ''}`} fill="none" stroke="currentColor" strokeWidth="2" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" d="M19 9l-7 7-7-7" /></svg> 33 | </button> 34 | </div> 35 | {open && ( 36 | <div className="mt-4 space-y-3 animate-fade-in"> 37 | {tool.params && tool.params.length > 0 && ( 38 | <div> 39 | <p className="text-[11px] font-semibold text-gray-700 mb-1">Parameters</p> 40 | <div className="border border-gray-200 rounded-lg overflow-hidden bg-white/60"> 41 | <div className="divide-y divide-gray-200"> 42 | {tool.params.map(p => ( 43 | <div key={p.name} className="p-2 hover:bg-gray-50 transition flex gap-4 items-start"> 44 | {/* Name column */} 45 | <div className="flex-shrink-0 min-w-[100px]"> 46 | <InlineCode> 47 | <span className="text-[10px] font-medium">{p.name}</span> 48 | </InlineCode> 49 | </div> 50 | {/* Optional badge column (fixed width) */} 51 | <div className="w-[50px] flex justify-start"> 52 | {p.required === false ? ( 53 | <span className="text-[10px] leading-none px-1 py-0.5 rounded bg-gray-100 text-gray-500 border border-gray-200 whitespace-nowrap">optional</span> 54 | ) : ( 55 | <span className="text-[10px] text-transparent select-none">req</span> 56 | )} 57 | </div> 58 | {/* Description column */} 59 | <div className="text-[11px] text-gray-600 leading-relaxed flex-1 min-w-0">{p.description}</div> 60 | </div> 61 | ))} 62 | </div> 63 | </div> 64 | </div> 65 | )} 66 | {tool.examples && tool.examples.length > 0 && ( 67 | <div> 68 | <p className="text-[11px] font-semibold text-gray-700 mb-1">Example Prompts</p> 69 | <ul className="list-disc pl-5 space-y-0.5 text-[11px] text-gray-600"> 70 | {tool.examples.map(ex => ( 71 | <li key={ex} className="flex items-start gap-2"><span className="flex-1">{ex}</span> 72 | <button onClick={() => navigator.clipboard.writeText(ex)} className="ml-2 text-[10px] bg-gray-100 hover:bg-gray-200 text-gray-700 px-2 py-0.5 rounded transition">Copy</button> 73 | </li> 74 | ))} 75 | </ul> 76 | </div> 77 | )} 78 | </div> 79 | )} 80 | </div> 81 | ); 82 | }; 83 | 84 | export default ToolCard; 85 | ``` -------------------------------------------------------------------------------- /docs/dw_crypto/WeakMessageDigest.md: -------------------------------------------------------------------------------- ```markdown 1 | ## Package: dw.crypto 2 | 3 | # Class WeakMessageDigest 4 | 5 | ## Inheritance Hierarchy 6 | 7 | - Object 8 | - dw.crypto.WeakMessageDigest 9 | 10 | ## Description 11 | 12 | This API provides access to Deprecated algorithms. See MessageDigest for full documentation. WeakMessageDigest 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 MessageDigest should always be used for new development and for anything intended to be secure. Note: this class handles sensitive security-related data. Pay special attention to PCI DSS v3. requirements 2, 4, and 12. 13 | 14 | ## Constants 15 | 16 | ### DIGEST_MD2 17 | 18 | **Type:** String = "MD2" 19 | 20 | Constant representing the MD2 algorithm. This algorithm is obsolete. Do not use it for any sensitive data 21 | 22 | ### DIGEST_MD5 23 | 24 | **Type:** String = "MD5" 25 | 26 | Constant representing the MD5 algorithm. This algorithm is obsolete. Do not use it for any sensitive data 27 | 28 | ### DIGEST_SHA 29 | 30 | **Type:** String = "SHA" 31 | 32 | Constant representing the SHA algorithm. This algorithm is obsolete. Do not use it for any sensitive data 33 | 34 | ### DIGEST_SHA_1 35 | 36 | **Type:** String = "SHA-1" 37 | 38 | Constant representing the SHA 1 algorithm. This algorithm is obsolete. Do not use it for any sensitive data 39 | 40 | ## Properties 41 | 42 | ## Constructor Summary 43 | 44 | WeakMessageDigest(algorithm : String) Construct a MessageDigest with the specified algorithm name. 45 | 46 | ## Method Summary 47 | 48 | ### digest 49 | 50 | **Signature:** `digest(input : String) : String` 51 | 52 | Digests the passed string and returns a computed hash value as a string. 53 | 54 | ### digest 55 | 56 | **Signature:** `digest(algorithm : String, input : Bytes) : Bytes` 57 | 58 | Computes the hash value for the passed array of bytes. 59 | 60 | ### digest 61 | 62 | **Signature:** `digest() : Bytes` 63 | 64 | Completes the hash computation by performing final operations such as padding. 65 | 66 | ### digestBytes 67 | 68 | **Signature:** `digestBytes(input : Bytes) : Bytes` 69 | 70 | Computes the hash value for the passed Bytes. 71 | 72 | ### updateBytes 73 | 74 | **Signature:** `updateBytes(input : Bytes) : void` 75 | 76 | Updates the digest using the passed Bytes. 77 | 78 | ## Constructor Detail 79 | 80 | ## Method Detail 81 | 82 | ## Method Details 83 | 84 | ### digest 85 | 86 | **Signature:** `digest(input : String) : String` 87 | 88 | **Description:** Digests the passed string and returns a computed hash value as a string. The passed String is first encoded into a sequence of bytes using the platform's default encoding. The digest then performs any prerequisite padding, before computing the hash value. The hash is then converted into a string by converting all digits to hexadecimal. 89 | 90 | **Deprecated:** 91 | 92 | Deprecated because the conversion of the input to bytes using the default platform encoding and the hex-encoded return value are not generally appropriate. 93 | 94 | **Parameters:** 95 | 96 | - `input`: The value to hash as String, must not be null. 97 | 98 | **Returns:** 99 | 100 | The resulting hash value as hex-encoded string. 101 | 102 | --- 103 | 104 | ### digest 105 | 106 | **Signature:** `digest(algorithm : String, input : Bytes) : Bytes` 107 | 108 | **Description:** Computes the hash value for the passed array of bytes. The algorithm argument is optional. If null, then the algorithm established at construction time is used. The binary representation of the message is typically derived from a string and the resulting hash is typically converted with base64 back into a string. Example: Encoding.toBase64( digest( "MD5", new Bytes( "my password", "UTF-8" ) ) ); 109 | 110 | **Deprecated:** 111 | 112 | Deprecated because the digest algorithm should be the one set in the constructor. 113 | 114 | **Parameters:** 115 | 116 | - `algorithm`: The standard name of the digest algorithm, or null if the algorithm passed at construction time is to be used. The algorithm must be a supported algorithm. 117 | - `input`: The value to hash, must not be null. 118 | 119 | **Returns:** 120 | 121 | The resulting hash value. 122 | 123 | --- 124 | 125 | ### digest 126 | 127 | **Signature:** `digest() : Bytes` 128 | 129 | **Description:** Completes the hash computation by performing final operations such as padding. The binary representation of the message is typically derived from a string and the resulting hash is typically converted with base64 back into a string. Example: Encoding.toBase64( digest() ); 130 | 131 | **Returns:** 132 | 133 | The resulting hash value. 134 | 135 | --- 136 | 137 | ### digestBytes 138 | 139 | **Signature:** `digestBytes(input : Bytes) : Bytes` 140 | 141 | **Description:** Computes the hash value for the passed Bytes. The binary representation of the message is typically derived from a string and the resulting hash is typically converted with base64 back into a string. Example: Encoding.toBase64( digest( new Bytes( "my password", "UTF-8" ) ) ); 142 | 143 | **Parameters:** 144 | 145 | - `input`: The value to hash, must not be null. 146 | 147 | **Returns:** 148 | 149 | The resulting hash value. 150 | 151 | --- 152 | 153 | ### updateBytes 154 | 155 | **Signature:** `updateBytes(input : Bytes) : void` 156 | 157 | **Description:** Updates the digest using the passed Bytes. 158 | 159 | **Parameters:** 160 | 161 | - `input`: The value to hash, must not be null. 162 | 163 | --- ``` -------------------------------------------------------------------------------- /docs/sfra/product-line-items.md: -------------------------------------------------------------------------------- ```markdown 1 | # SFRA Product Line Items Model 2 | 3 | ## Overview 4 | 5 | The Product Line Items model represents a collection of product line items in a basket or order. It provides comprehensive information about each product in the cart including quantities, options, bonus products, and pricing details. 6 | 7 | ## Constructor 8 | 9 | ```javascript 10 | function ProductLineItems(productLineItems, view) 11 | ``` 12 | 13 | Creates a Product Line Items model with formatted line item information. 14 | 15 | ### Parameters 16 | 17 | - `productLineItems` (dw.util.Collection<dw.order.ProductLineItem>) - Collection of product line items from basket or order 18 | - `view` (string) - View context ('basket' or 'order') 19 | 20 | ## Properties 21 | 22 | ### items 23 | **Type:** Array<Object> 24 | 25 | Array of formatted product line items. Each item contains: 26 | 27 | #### Standard Product Items 28 | - `id` (string) - Product ID 29 | - `productName` (string) - Product display name 30 | - `quantity` (number) - Item quantity 31 | - `UUID` (string) - Line item UUID 32 | - `product` (Object) - Full product model with pricing, images, attributes 33 | - `options` (Array) - Product options if applicable 34 | - `bonusProducts` (Array) - Associated bonus products if applicable 35 | 36 | #### Items Without Product (Unassigned Categories) 37 | - `id` (string) - Product ID 38 | - `productName` (string) - Product name 39 | - `quantity` (number) - Item quantity 40 | - `UUID` (string) - Line item UUID 41 | - `noProduct` (boolean) - Flag indicating missing product (true) 42 | - `images` (Object) - Default "no image" placeholder 43 | 44 | ### totalQuantity 45 | **Type:** number 46 | 47 | Total quantity of all items in the collection. 48 | 49 | ## Helper Functions 50 | 51 | ### createProductLineItemsObject(allLineItems, view) 52 | Creates an array of formatted product line items with comprehensive product information. 53 | 54 | **Parameters:** 55 | - `allLineItems` (dw.util.Collection<dw.order.ProductLineItem>) - All product line items 56 | - `view` (string) - View context ('basket' or 'order') 57 | 58 | **Returns:** Array<Object> - Formatted line items array 59 | 60 | ## Product Line Item Structure 61 | 62 | Each product line item in the items array contains: 63 | 64 | ### Product Information 65 | - Complete product model created via ProductFactory 66 | - Includes pricing, images, availability, and attributes 67 | - Product options mapped with option IDs and selected values 68 | 69 | ### Bonus Products 70 | - Automatically detected and included for qualifying items 71 | - Each bonus product includes full product information 72 | - Linked via custom attributes (bonusProductLineItemUUID, preOrderUUID) 73 | 74 | ### Quantity and Identification 75 | - Line item quantity and UUID for cart operations 76 | - Product ID for catalog operations 77 | - Product name for display purposes 78 | 79 | ## Usage Example 80 | 81 | ```javascript 82 | var ProductLineItems = require('*/cartridge/models/productLineItems'); 83 | var BasketMgr = require('dw/order/BasketMgr'); 84 | 85 | var currentBasket = BasketMgr.getCurrentBasket(); 86 | var lineItemsModel = new ProductLineItems( 87 | currentBasket.productLineItems, 88 | 'basket' 89 | ); 90 | 91 | // Access line items 92 | console.log('Total items: ' + lineItemsModel.totalQuantity); 93 | 94 | lineItemsModel.items.forEach(function(item) { 95 | if (item.noProduct) { 96 | console.log('Missing product: ' + item.productName); 97 | } else { 98 | console.log(item.product.productName + ' x ' + item.quantity); 99 | 100 | // Check for options 101 | if (item.options && item.options.length > 0) { 102 | console.log('Options: ', item.options); 103 | } 104 | 105 | // Check for bonus products 106 | if (item.bonusProducts && item.bonusProducts.length > 0) { 107 | console.log('Bonus products: ' + item.bonusProducts.length); 108 | } 109 | } 110 | }); 111 | ``` 112 | 113 | ## Special Handling 114 | 115 | ### Missing Products 116 | When a product is no longer available or unassigned: 117 | - `noProduct` flag is set to true 118 | - Limited product information is available 119 | - Default "no image" placeholder is used 120 | - Product name and basic details are preserved 121 | 122 | ### Bonus Products 123 | - Automatically detected based on custom attributes 124 | - Each bonus product gets full ProductFactory treatment 125 | - Maintains relationship to parent product line item 126 | - Includes all product options and configurations 127 | 128 | ### Product Options 129 | - Maps option product line items to option configurations 130 | - Includes option ID and selected value ID for each option 131 | - Used for product configuration and pricing 132 | 133 | ## Notes 134 | 135 | - Handles both basket and order contexts 136 | - Gracefully handles missing or invalid products 137 | - Includes comprehensive product information via ProductFactory 138 | - Supports complex product relationships (bundles, sets, bonuses) 139 | - Maintains line item UUIDs for cart operations 140 | - Provides fallback handling for catalog issues 141 | 142 | ## Related Models 143 | 144 | - **Cart Model** - Uses product line items for cart display 145 | - **Order Model** - Uses product line items for order information 146 | - **Product Models** - Created via ProductFactory for each line item 147 | - **Totals Model** - Calculates totals based on line items 148 | ```