This is page 8 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 -------------------------------------------------------------------------------- /docs/dw_web/FormAction.md: -------------------------------------------------------------------------------- ```markdown 1 | ## Package: dw.web 2 | 3 | # Class FormAction 4 | 5 | ## Inheritance Hierarchy 6 | 7 | - Object 8 | - dw.web.FormElement 9 | - dw.web.FormAction 10 | 11 | ## Description 12 | 13 | The FormAction class represents the action in form instance hierarchy. 14 | 15 | ## Properties 16 | 17 | ### description 18 | 19 | **Type:** String (Read Only) 20 | 21 | The optional description for the action. The description could be used 22 | as tooltip for the action. 23 | 24 | ### label 25 | 26 | **Type:** String (Read Only) 27 | 28 | The optional label for the action. The label would be typically used 29 | as button text. 30 | 31 | ### object 32 | 33 | **Type:** Object (Read Only) 34 | 35 | The object that was bound to the form in which the action 36 | is contained. The method is a convenience method for getParent().getObject(). 37 | In most cases this is actually the object for which 38 | the specific action is triggered. 39 | 40 | ### submitted 41 | 42 | **Type:** boolean (Read Only) 43 | 44 | Identifies if the form action was submitted from 45 | the client to the server. 46 | 47 | ### triggered 48 | 49 | **Type:** boolean (Read Only) 50 | 51 | Identifies that this action is triggerd. An 52 | action is only triggered if it was submitted and the constraints, regarding 53 | a valid form, are met. 54 | 55 | ### x 56 | 57 | **Type:** Number (Read Only) 58 | 59 | In case of an image button, returns the x coordinate of the last click. 60 | 61 | ### y 62 | 63 | **Type:** Number (Read Only) 64 | 65 | In case of an image button, returns the y coordinate of the last click. 66 | 67 | ## Constructor Summary 68 | 69 | ## Method Summary 70 | 71 | ### getDescription 72 | 73 | **Signature:** `getDescription() : String` 74 | 75 | Returns the optional description for the action. 76 | 77 | ### getLabel 78 | 79 | **Signature:** `getLabel() : String` 80 | 81 | Returns the optional label for the action. 82 | 83 | ### getObject 84 | 85 | **Signature:** `getObject() : Object` 86 | 87 | Returns the object that was bound to the form in which the action is contained. 88 | 89 | ### getX 90 | 91 | **Signature:** `getX() : Number` 92 | 93 | In case of an image button, returns the x coordinate of the last click. 94 | 95 | ### getY 96 | 97 | **Signature:** `getY() : Number` 98 | 99 | In case of an image button, returns the y coordinate of the last click. 100 | 101 | ### isSubmitted 102 | 103 | **Signature:** `isSubmitted() : boolean` 104 | 105 | Identifies if the form action was submitted from the client to the server. 106 | 107 | ### isTriggered 108 | 109 | **Signature:** `isTriggered() : boolean` 110 | 111 | Identifies that this action is triggerd. 112 | 113 | ## Method Detail 114 | 115 | ## Method Details 116 | 117 | ### getDescription 118 | 119 | **Signature:** `getDescription() : String` 120 | 121 | **Description:** Returns the optional description for the action. The description could be used as tooltip for the action. 122 | 123 | **Returns:** 124 | 125 | the optional description for the action. 126 | 127 | --- 128 | 129 | ### getLabel 130 | 131 | **Signature:** `getLabel() : String` 132 | 133 | **Description:** Returns the optional label for the action. The label would be typically used as button text. 134 | 135 | **Returns:** 136 | 137 | the optional label for the action. 138 | 139 | --- 140 | 141 | ### getObject 142 | 143 | **Signature:** `getObject() : Object` 144 | 145 | **Description:** Returns the object that was bound to the form in which the action is contained. The method is a convenience method for getParent().getObject(). In most cases this is actually the object for which the specific action is triggered. 146 | 147 | **Returns:** 148 | 149 | the object that was bound to the form in which the action is contained. 150 | 151 | --- 152 | 153 | ### getX 154 | 155 | **Signature:** `getX() : Number` 156 | 157 | **Description:** In case of an image button, returns the x coordinate of the last click. 158 | 159 | **Returns:** 160 | 161 | the x coordinate of the last click. 162 | 163 | --- 164 | 165 | ### getY 166 | 167 | **Signature:** `getY() : Number` 168 | 169 | **Description:** In case of an image button, returns the y coordinate of the last click. 170 | 171 | **Returns:** 172 | 173 | the y coordinate of the last click. 174 | 175 | --- 176 | 177 | ### isSubmitted 178 | 179 | **Signature:** `isSubmitted() : boolean` 180 | 181 | **Description:** Identifies if the form action was submitted from the client to the server. 182 | 183 | **Returns:** 184 | 185 | true if the form action was submitted, false otherwise. 186 | 187 | --- 188 | 189 | ### isTriggered 190 | 191 | **Signature:** `isTriggered() : boolean` 192 | 193 | **Description:** Identifies that this action is triggerd. An action is only triggered if it was submitted and the constraints, regarding a valid form, are met. 194 | 195 | **Returns:** 196 | 197 | true if the action is triggered, false otherwise. 198 | 199 | --- ``` -------------------------------------------------------------------------------- /docs/dw_web/PageMetaData.md: -------------------------------------------------------------------------------- ```markdown 1 | ## Package: dw.web 2 | 3 | # Class PageMetaData 4 | 5 | ## Inheritance Hierarchy 6 | 7 | - Object 8 | - dw.web.PageMetaData 9 | 10 | ## Description 11 | 12 | Contains meta data about the page. For each request an instance of this class will be placed in the pipeline dictionary under the key "CurrentPageMetaData". The information stored in CurrentPageMetaData can be referenced in templates and rendered in an HTML head section: for example: <head> <title>${pdict.CurrentPageMetaData.title}</title> <meta name="description" content="${pdict.CurrentPageMetaData.description}"/> . . . </head> To update the CurrentPageMetaData there is the pipelet UpdatePageMetaData provided. 13 | 14 | ## Properties 15 | 16 | ### description 17 | 18 | **Type:** String 19 | 20 | The page's description. 21 | 22 | ### keywords 23 | 24 | **Type:** String 25 | 26 | The page's key words. 27 | 28 | ### pageMetaTags 29 | 30 | **Type:** Array (Read Only) 31 | 32 | All page meta tags added to this container. 33 | 34 | ### title 35 | 36 | **Type:** String 37 | 38 | The page's title. 39 | 40 | ## Constructor Summary 41 | 42 | ## Method Summary 43 | 44 | ### addPageMetaTag 45 | 46 | **Signature:** `addPageMetaTag(pageMetaTag : PageMetaTag) : void` 47 | 48 | Adds a page meta tag to this container. 49 | 50 | ### addPageMetaTags 51 | 52 | **Signature:** `addPageMetaTags(pageMetaTags : Array) : void` 53 | 54 | Adds a page meta tags list to this container. 55 | 56 | ### getDescription 57 | 58 | **Signature:** `getDescription() : String` 59 | 60 | Returns the page's description. 61 | 62 | ### getKeywords 63 | 64 | **Signature:** `getKeywords() : String` 65 | 66 | Returns the page's key words. 67 | 68 | ### getPageMetaTags 69 | 70 | **Signature:** `getPageMetaTags() : Array` 71 | 72 | Returns all page meta tags added to this container. 73 | 74 | ### getTitle 75 | 76 | **Signature:** `getTitle() : String` 77 | 78 | Returns the page's title. 79 | 80 | ### isPageMetaTagSet 81 | 82 | **Signature:** `isPageMetaTagSet(id : String) : boolean` 83 | 84 | Returns true if a page meta tag with the given ID is set, false otherwise. 85 | 86 | ### setDescription 87 | 88 | **Signature:** `setDescription(description : String) : void` 89 | 90 | Sets the page's description. 91 | 92 | ### setKeywords 93 | 94 | **Signature:** `setKeywords(keywords : String) : void` 95 | 96 | Sets the page's key words. 97 | 98 | ### setTitle 99 | 100 | **Signature:** `setTitle(title : String) : void` 101 | 102 | Sets the page's title. 103 | 104 | ## Method Detail 105 | 106 | ## Method Details 107 | 108 | ### addPageMetaTag 109 | 110 | **Signature:** `addPageMetaTag(pageMetaTag : PageMetaTag) : void` 111 | 112 | **Description:** Adds a page meta tag to this container. 113 | 114 | **Parameters:** 115 | 116 | - `pageMetaTag`: the page meta tag to be added 117 | 118 | --- 119 | 120 | ### addPageMetaTags 121 | 122 | **Signature:** `addPageMetaTags(pageMetaTags : Array) : void` 123 | 124 | **Description:** Adds a page meta tags list to this container. 125 | 126 | **Parameters:** 127 | 128 | - `pageMetaTags`: the page meta tags list to be added 129 | 130 | --- 131 | 132 | ### getDescription 133 | 134 | **Signature:** `getDescription() : String` 135 | 136 | **Description:** Returns the page's description. 137 | 138 | **Returns:** 139 | 140 | the page's description. 141 | 142 | --- 143 | 144 | ### getKeywords 145 | 146 | **Signature:** `getKeywords() : String` 147 | 148 | **Description:** Returns the page's key words. 149 | 150 | **Returns:** 151 | 152 | the page's key words. 153 | 154 | --- 155 | 156 | ### getPageMetaTags 157 | 158 | **Signature:** `getPageMetaTags() : Array` 159 | 160 | **Description:** Returns all page meta tags added to this container. 161 | 162 | **Returns:** 163 | 164 | page meta tags 165 | 166 | --- 167 | 168 | ### getTitle 169 | 170 | **Signature:** `getTitle() : String` 171 | 172 | **Description:** Returns the page's title. 173 | 174 | **Returns:** 175 | 176 | the page's title. 177 | 178 | --- 179 | 180 | ### isPageMetaTagSet 181 | 182 | **Signature:** `isPageMetaTagSet(id : String) : boolean` 183 | 184 | **Description:** Returns true if a page meta tag with the given ID is set, false otherwise. 185 | 186 | **Parameters:** 187 | 188 | - `id`: the ID to be check if a page meta tag is set 189 | 190 | **Returns:** 191 | 192 | true if a page meta tag with the given ID is set, false otherwise 193 | 194 | --- 195 | 196 | ### setDescription 197 | 198 | **Signature:** `setDescription(description : String) : void` 199 | 200 | **Description:** Sets the page's description. 201 | 202 | **Parameters:** 203 | 204 | - `description`: the page's description. 205 | 206 | --- 207 | 208 | ### setKeywords 209 | 210 | **Signature:** `setKeywords(keywords : String) : void` 211 | 212 | **Description:** Sets the page's key words. 213 | 214 | **Parameters:** 215 | 216 | - `keywords`: the page's key words. 217 | 218 | --- 219 | 220 | ### setTitle 221 | 222 | **Signature:** `setTitle(title : String) : void` 223 | 224 | **Description:** Sets the page's title. 225 | 226 | **Parameters:** 227 | 228 | - `title`: the page's title. 229 | 230 | --- ``` -------------------------------------------------------------------------------- /src/utils/log-tool-config.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { ToolSpec, LogToolValidators, LogMessageFormatter } from './log-tool-utils.js'; 2 | import { ValidationHelpers, CommonValidations } from '../core/handlers/validation-helpers.js'; 3 | import { LogToolName, getLimit } from './log-tool-constants.js'; 4 | 5 | /** 6 | * Configuration for standard log tools 7 | * Maps each tool to its validation, execution, and messaging logic 8 | */ 9 | export const LOG_TOOL_CONFIG: Record<LogToolName, ToolSpec> = { 10 | get_latest_error: { 11 | defaults: (args) => ({ 12 | limit: getLimit(args.limit as number, 'latest'), 13 | }), 14 | validate: (args) => LogToolValidators.validateLimit(args.limit as number, 'get_latest_error'), 15 | exec: async (args, client) => client.getLatestLogs('error', args.limit as number, args.date as string), 16 | logMessage: (args) => LogMessageFormatter.formatLatestLogs('error', args.limit as number, args.date as string), 17 | }, 18 | 19 | get_latest_warn: { 20 | defaults: (args) => ({ 21 | limit: getLimit(args.limit as number, 'latest'), 22 | }), 23 | validate: (args) => LogToolValidators.validateLimit(args.limit as number, 'get_latest_warn'), 24 | exec: async (args, client) => client.getLatestLogs('warn', args.limit as number, args.date as string), 25 | logMessage: (args) => LogMessageFormatter.formatLatestLogs('warn', args.limit as number, args.date as string), 26 | }, 27 | 28 | get_latest_info: { 29 | defaults: (args) => ({ 30 | limit: getLimit(args.limit as number, 'latest'), 31 | }), 32 | validate: (args) => LogToolValidators.validateLimit(args.limit as number, 'get_latest_info'), 33 | exec: async (args, client) => client.getLatestLogs('info', args.limit as number, args.date as string), 34 | logMessage: (args) => LogMessageFormatter.formatLatestLogs('info', args.limit as number, args.date as string), 35 | }, 36 | 37 | get_latest_debug: { 38 | defaults: (args) => ({ 39 | limit: getLimit(args.limit as number, 'latest'), 40 | }), 41 | validate: (args) => LogToolValidators.validateLimit(args.limit as number, 'get_latest_debug'), 42 | exec: async (args, client) => client.getLatestLogs('debug', args.limit as number, args.date as string), 43 | logMessage: (args) => LogMessageFormatter.formatLatestLogs('debug', args.limit as number, args.date as string), 44 | }, 45 | 46 | summarize_logs: { 47 | exec: async (args, client) => client.summarizeLogs(args.date as string), 48 | logMessage: (args) => LogMessageFormatter.formatSummarizeLogs(args.date as string), 49 | }, 50 | 51 | search_logs: { 52 | defaults: (args) => ({ 53 | limit: getLimit(args.limit as number, 'search'), 54 | }), 55 | validate: (args, toolName) => { 56 | ValidationHelpers.validateArguments(args, CommonValidations.requiredString('pattern'), toolName); 57 | LogToolValidators.validateLimit(args.limit as number, toolName); 58 | if (args.logLevel) { 59 | LogToolValidators.validateLogLevel(args.logLevel as string, toolName); 60 | } 61 | }, 62 | exec: async (args, client) => client.searchLogs( 63 | args.pattern as string, 64 | args.logLevel as any, 65 | args.limit as number, 66 | args.date as string, 67 | ), 68 | logMessage: (args) => LogMessageFormatter.formatSearchLogs( 69 | args.pattern as string, 70 | args.logLevel as string, 71 | args.limit as number, 72 | args.date as string, 73 | ), 74 | }, 75 | 76 | list_log_files: { 77 | exec: async (args, client) => client.listLogFiles(), 78 | logMessage: () => LogMessageFormatter.formatListLogFiles(), 79 | }, 80 | 81 | get_log_file_contents: { 82 | validate: (args, toolName) => { 83 | ValidationHelpers.validateArguments(args, CommonValidations.requiredString('filename'), toolName); 84 | LogToolValidators.validateFilename(args.filename as string, toolName); 85 | LogToolValidators.validateMaxBytes(args.maxBytes as number, toolName); 86 | }, 87 | exec: async (args, client) => client.getLogFileContents( 88 | args.filename as string, 89 | args.maxBytes as number, 90 | args.tailOnly as boolean, 91 | ), 92 | logMessage: (args) => LogMessageFormatter.formatGetLogFileContents( 93 | args.filename as string, 94 | args.maxBytes as number, 95 | args.tailOnly as boolean, 96 | ), 97 | }, 98 | }; 99 | ``` -------------------------------------------------------------------------------- /src/core/handlers/log-tool-config.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { ToolSpec, LogToolValidators, LogMessageFormatter } from '../../utils/log-tool-utils.js'; 2 | import { ValidationHelpers, CommonValidations } from './validation-helpers.js'; 3 | import { LogToolName, getLimit } from '../../utils/log-tool-constants.js'; 4 | 5 | /** 6 | * Configuration for standard log tools 7 | * Maps each tool to its validation, execution, and messaging logic 8 | */ 9 | export const LOG_TOOL_CONFIG: Record<LogToolName, ToolSpec> = { 10 | get_latest_error: { 11 | defaults: (args) => ({ 12 | limit: getLimit(args.limit as number, 'latest'), 13 | }), 14 | validate: (args) => LogToolValidators.validateLimit(args.limit as number, 'get_latest_error'), 15 | exec: async (args, client) => client.getLatestLogs('error', args.limit as number, args.date as string), 16 | logMessage: (args) => LogMessageFormatter.formatLatestLogs('error', args.limit as number, args.date as string), 17 | }, 18 | 19 | get_latest_warn: { 20 | defaults: (args) => ({ 21 | limit: getLimit(args.limit as number, 'latest'), 22 | }), 23 | validate: (args) => LogToolValidators.validateLimit(args.limit as number, 'get_latest_warn'), 24 | exec: async (args, client) => client.getLatestLogs('warn', args.limit as number, args.date as string), 25 | logMessage: (args) => LogMessageFormatter.formatLatestLogs('warn', args.limit as number, args.date as string), 26 | }, 27 | 28 | get_latest_info: { 29 | defaults: (args) => ({ 30 | limit: getLimit(args.limit as number, 'latest'), 31 | }), 32 | validate: (args) => LogToolValidators.validateLimit(args.limit as number, 'get_latest_info'), 33 | exec: async (args, client) => client.getLatestLogs('info', args.limit as number, args.date as string), 34 | logMessage: (args) => LogMessageFormatter.formatLatestLogs('info', args.limit as number, args.date as string), 35 | }, 36 | 37 | get_latest_debug: { 38 | defaults: (args) => ({ 39 | limit: getLimit(args.limit as number, 'latest'), 40 | }), 41 | validate: (args) => LogToolValidators.validateLimit(args.limit as number, 'get_latest_debug'), 42 | exec: async (args, client) => client.getLatestLogs('debug', args.limit as number, args.date as string), 43 | logMessage: (args) => LogMessageFormatter.formatLatestLogs('debug', args.limit as number, args.date as string), 44 | }, 45 | 46 | summarize_logs: { 47 | exec: async (args, client) => client.summarizeLogs(args.date as string), 48 | logMessage: (args) => LogMessageFormatter.formatSummarizeLogs(args.date as string), 49 | }, 50 | 51 | search_logs: { 52 | defaults: (args) => ({ 53 | limit: getLimit(args.limit as number, 'search'), 54 | }), 55 | validate: (args, toolName) => { 56 | ValidationHelpers.validateArguments(args, CommonValidations.requiredString('pattern'), toolName); 57 | LogToolValidators.validateLimit(args.limit as number, toolName); 58 | if (args.logLevel) { 59 | LogToolValidators.validateLogLevel(args.logLevel as string, toolName); 60 | } 61 | }, 62 | exec: async (args, client) => client.searchLogs( 63 | args.pattern as string, 64 | args.logLevel as any, 65 | args.limit as number, 66 | args.date as string, 67 | ), 68 | logMessage: (args) => LogMessageFormatter.formatSearchLogs( 69 | args.pattern as string, 70 | args.logLevel as string, 71 | args.limit as number, 72 | args.date as string, 73 | ), 74 | }, 75 | 76 | list_log_files: { 77 | exec: async (args, client) => client.listLogFiles(), 78 | logMessage: () => LogMessageFormatter.formatListLogFiles(), 79 | }, 80 | 81 | get_log_file_contents: { 82 | validate: (args, toolName) => { 83 | ValidationHelpers.validateArguments(args, CommonValidations.requiredString('filename'), toolName); 84 | LogToolValidators.validateFilename(args.filename as string, toolName); 85 | LogToolValidators.validateMaxBytes(args.maxBytes as number, toolName); 86 | }, 87 | exec: async (args, client) => client.getLogFileContents( 88 | args.filename as string, 89 | args.maxBytes as number, 90 | args.tailOnly as boolean, 91 | ), 92 | logMessage: (args) => LogMessageFormatter.formatGetLogFileContents( 93 | args.filename as string, 94 | args.maxBytes as number, 95 | args.tailOnly as boolean, 96 | ), 97 | }, 98 | }; 99 | ``` -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- ```typescript 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * Main entry point for the SFCC Development MCP Server 5 | */ 6 | 7 | import { SFCCDevServer } from './core/server.js'; 8 | import { ConfigurationFactory } from './config/configuration-factory.js'; 9 | import { Logger } from './utils/logger.js'; 10 | import { existsSync } from 'fs'; 11 | import { resolve } from 'path'; 12 | 13 | /** 14 | * Parse command line arguments to extract configuration options 15 | */ 16 | function parseCommandLineArgs(): { dwJsonPath?: string; debug?: boolean } { 17 | const args = process.argv.slice(2); 18 | const options: { dwJsonPath?: string; debug?: boolean } = {}; 19 | 20 | for (let i = 0; i < args.length; i++) { 21 | const arg = args[i]; 22 | 23 | if (arg === '--dw-json' && i + 1 < args.length) { 24 | options.dwJsonPath = args[i + 1]; 25 | i++; // Skip the next argument since we consumed it 26 | } else if (arg === '--debug' && i + 1 < args.length) { 27 | const debugValue = args[i + 1].toLowerCase(); 28 | options.debug = debugValue === 'true' || debugValue === '1' || debugValue === 'yes'; 29 | i++; // Skip the next argument since we consumed it 30 | } else if (arg === '--debug') { 31 | // Allow --debug without a value to default to true 32 | options.debug = true; 33 | } 34 | } 35 | 36 | return options; 37 | } 38 | 39 | /** 40 | * Find dw.json file in common locations 41 | */ 42 | function findDwJsonFile(): string | undefined { 43 | const commonPaths = [ 44 | './dw.json', 45 | '../dw.json', 46 | '../../dw.json', 47 | process.env.HOME ? resolve(process.env.HOME, 'dw.json') : null, 48 | ].filter(Boolean) as string[]; 49 | 50 | for (const path of commonPaths) { 51 | if (existsSync(path)) { 52 | const logger = Logger.getInstance(); 53 | logger.debug(`Found dw.json at: ${path}`); 54 | return path; 55 | } 56 | } 57 | 58 | return undefined; 59 | } 60 | 61 | /** 62 | * Main application entry point 63 | */ 64 | async function main(): Promise<void> { 65 | try { 66 | const options = parseCommandLineArgs(); 67 | const debug = options.debug ?? false; 68 | 69 | // Initialize the global logger with debug setting 70 | Logger.initialize('SFCC-MCP-Server', true, debug); 71 | const logger = Logger.getInstance(); 72 | 73 | logger.log('Starting SFCC Development MCP Server...'); 74 | if (debug) { 75 | logger.log('Debug mode enabled'); 76 | } 77 | 78 | // Try to find dw.json if not explicitly provided 79 | const dwJsonPath = options.dwJsonPath ?? findDwJsonFile(); 80 | 81 | // Create configuration using the factory 82 | const config = ConfigurationFactory.create({ 83 | dwJsonPath, 84 | // Add support for environment variables as fallback 85 | hostname: process.env.SFCC_HOSTNAME, 86 | username: process.env.SFCC_USERNAME, 87 | password: process.env.SFCC_PASSWORD, 88 | clientId: process.env.SFCC_CLIENT_ID, 89 | clientSecret: process.env.SFCC_CLIENT_SECRET, 90 | }); 91 | 92 | // Log configuration summary (without sensitive data) 93 | const capabilities = ConfigurationFactory.getCapabilities(config); 94 | 95 | if (capabilities.isLocalMode) { 96 | logger.log('Running in Local Mode - SFCC class documentation only'); 97 | logger.log('To access SFCC logs and OCAPI, provide hostname and credentials'); 98 | } else { 99 | logger.log(`Configuration loaded - Hostname: ${config.hostname}`); 100 | logger.log(`Available features: Logs=${capabilities.canAccessLogs}, OCAPI=${capabilities.canAccessOCAPI}, WebDAV=${capabilities.canAccessWebDAV}`); 101 | } 102 | 103 | // Create and start the server 104 | const server = new SFCCDevServer(config); 105 | await server.run(); 106 | } catch (error) { 107 | const logger = Logger.getInstance(); 108 | logger.error('Failed to start SFCC Development MCP Server:', error); 109 | 110 | if (error instanceof Error) { 111 | if (error.message.includes('not found')) { 112 | logger.log('\nConfiguration Help:'); 113 | logger.log('1. Create a dw.json file with your SFCC credentials'); 114 | logger.log('2. Use --dw-json /path/to/dw.json'); 115 | logger.log('3. Set environment variables: SFCC_HOSTNAME, SFCC_USERNAME, SFCC_PASSWORD'); 116 | } 117 | } 118 | 119 | process.exit(1); 120 | } 121 | } 122 | 123 | // Run the main function 124 | main().catch((error) => { 125 | const logger = Logger.getInstance(); 126 | logger.error('Unhandled error:', error); 127 | process.exit(1); 128 | }); 129 | ``` -------------------------------------------------------------------------------- /docs-site/public/llms.txt: -------------------------------------------------------------------------------- ``` 1 | # SFCC Development MCP Server 2 | 3 | > A comprehensive Model Context Protocol (MCP) server that provides AI assistants with direct access to Salesforce B2C Commerce Cloud development tools, documentation, best practices, and real-time debugging capabilities. 4 | 5 | This server bridges the gap between AI assistants and SFCC development workflows, offering both documentation-only mode (no credentials required) and full mode (with live SFCC instance access). It provides 36 tools across 8 categories including complete SFCC API documentation, curated best practices guides, enhanced SFRA documentation, real-time log analysis, system object exploration, and automated cartridge generation. 6 | 7 | Key architectural principles: 8 | - **Capability-gated**: Tools requiring SFCC credentials are only exposed when valid configuration is provided 9 | - **Modular handlers**: Clean separation between tool routing and domain logic 10 | - **Dependency injection**: Testable architecture with service abstractions 11 | - **Performance optimized**: Efficient caching and range request optimization for log analysis 12 | 13 | ## Core Documentation 14 | 15 | - [Installation Guide](https://sfcc-mcp-dev.rhino-inquisitor.com/#/installation): Step-by-step setup instructions for different AI interfaces (Claude Desktop, Cursor, GitHub Copilot) 16 | - [Configuration Guide](https://sfcc-mcp-dev.rhino-inquisitor.com/#/configuration): Detailed configuration options for both documentation-only and full modes 17 | - [Available Tools](https://sfcc-mcp-dev.rhino-inquisitor.com/#/tools): Comprehensive list of all 36 tools organized by category with usage examples 18 | - [Features Overview](https://sfcc-mcp-dev.rhino-inquisitor.com/#/features): Complete feature breakdown including operating modes and capabilities 19 | 20 | ## Development Resources 21 | 22 | - [Development Guide](https://sfcc-mcp-dev.rhino-inquisitor.com/#/development): Architecture overview, adding new tools, testing guidelines, and contribution workflow 23 | - [Examples & Use Cases](https://sfcc-mcp-dev.rhino-inquisitor.com/#/examples): Practical examples for documentation access, log analysis, cartridge generation, and debugging workflows 24 | - [AI Interface Setup](https://sfcc-mcp-dev.rhino-inquisitor.com/#/ai-interfaces): Platform-specific setup guides for Claude Desktop, Cursor IDE, and GitHub Copilot integration 25 | 26 | ## Security & Best Practices 27 | 28 | - [Security Considerations](https://sfcc-mcp-dev.rhino-inquisitor.com/#/security): Credential management, local security practices, and network security guidelines 29 | - [Troubleshooting Guide](https://sfcc-mcp-dev.rhino-inquisitor.com/#/troubleshooting): Common issues, debugging steps, and configuration validation 30 | 31 | ## Tool Categories 32 | 33 | - **SFCC Documentation Tools (5 tools)**: Complete API class information, method search, and namespace exploration 34 | - **Best Practices Guides (4 tools)**: Curated development guidelines for cartridges, hooks, controllers, security, and performance 35 | - **SFRA Documentation Tools (5 tools)**: Enhanced Storefront Reference Architecture documentation with dynamic discovery 36 | - **Log Analysis Tools (8 tools)**: Real-time error monitoring, pattern matching, and system health analysis 37 | - **Job Log Tools (5 tools)**: Specialized job log analysis, execution summaries, and custom job step debugging 38 | - **System Object Tools (6 tools)**: Custom attribute discovery, site preference management, and schema exploration 39 | - **Cartridge Generation Tools (1 tool)**: Automated cartridge structure creation with complete project setup 40 | - **Code Version Tools (2 tools)**: Code version management and deployment activation 41 | 42 | ## Optional 43 | 44 | - [GitHub Repository](https://github.com/taurgis/sfcc-dev-mcp): Source code, issues, and contribution guidelines 45 | - [NPM Package](https://www.npmjs.com/package/sfcc-dev-mcp): Package installation and version information 46 | - [CHANGELOG](https://github.com/taurgis/sfcc-dev-mcp/blob/main/CHANGELOG.md): Release notes and version history 47 | - [Contributing Guidelines](https://github.com/taurgis/sfcc-dev-mcp/blob/main/CONTRIBUTING.md): Development setup and contribution workflow ``` -------------------------------------------------------------------------------- /docs/dw_io/RandomAccessFileReader.md: -------------------------------------------------------------------------------- ```markdown 1 | ## Package: dw.io 2 | 3 | # Class RandomAccessFileReader 4 | 5 | ## Inheritance Hierarchy 6 | 7 | - Object 8 | - dw.io.RandomAccessFileReader 9 | 10 | ## Description 11 | 12 | Instances of this class support reading from a random access file. A random access file behaves like a large array of bytes stored in the file system. There is a kind of cursor, or index into the implied array, called the file pointer. Read operations read bytes starting at the file pointer and advance the file pointer past the bytes read. The file pointer can be read by the getPosition method and set by the setPosition method. 13 | 14 | ## Constants 15 | 16 | ### MAX_READ_BYTES 17 | 18 | **Type:** Number = 10240L 19 | 20 | The maximum number of bytes that a single call to readBytes(Number) can return == 10KB 21 | 22 | ## Properties 23 | 24 | ### position 25 | 26 | **Type:** Number 27 | 28 | The current offset in this file. 29 | 30 | ## Constructor Summary 31 | 32 | RandomAccessFileReader(file : File) Construct a reader for random read access to the provided file. 33 | 34 | ## Method Summary 35 | 36 | ### close 37 | 38 | **Signature:** `close() : void` 39 | 40 | Closes this random access file reader and releases any system resources associated with the stream. 41 | 42 | ### getPosition 43 | 44 | **Signature:** `getPosition() : Number` 45 | 46 | Returns the current offset in this file. 47 | 48 | ### length 49 | 50 | **Signature:** `length() : Number` 51 | 52 | Returns the length of this file. 53 | 54 | ### readByte 55 | 56 | **Signature:** `readByte() : Number` 57 | 58 | Reads a signed eight-bit value from the file starting from the current file pointer. 59 | 60 | ### readBytes 61 | 62 | **Signature:** `readBytes(numBytes : Number) : Bytes` 63 | 64 | Reads up to n bytes from the file starting at the current file pointer. 65 | 66 | ### setPosition 67 | 68 | **Signature:** `setPosition(position : Number) : void` 69 | 70 | Sets the file-pointer offset, measured from the beginning of this file, at which the next read occurs. 71 | 72 | ## Constructor Detail 73 | 74 | ## Method Detail 75 | 76 | ## Method Details 77 | 78 | ### close 79 | 80 | **Signature:** `close() : void` 81 | 82 | **Description:** Closes this random access file reader and releases any system resources associated with the stream. 83 | 84 | **Throws:** 85 | 86 | IOException - if an I/O error occurs. 87 | 88 | --- 89 | 90 | ### getPosition 91 | 92 | **Signature:** `getPosition() : Number` 93 | 94 | **Description:** Returns the current offset in this file. 95 | 96 | **Returns:** 97 | 98 | the offset from the beginning of the file, in bytes, at which the next read occurs. 99 | 100 | **Throws:** 101 | 102 | IOException - if an I/O error occurs. 103 | 104 | --- 105 | 106 | ### length 107 | 108 | **Signature:** `length() : Number` 109 | 110 | **Description:** Returns the length of this file. 111 | 112 | **Returns:** 113 | 114 | the length of this file, measured in bytes. 115 | 116 | **Throws:** 117 | 118 | IOException - if an I/O error occurs. 119 | 120 | --- 121 | 122 | ### readByte 123 | 124 | **Signature:** `readByte() : Number` 125 | 126 | **Description:** Reads a signed eight-bit value from the file starting from the current file pointer. Since the byte is interpreted as signed, the value returned will always be between -128 and +127. 127 | 128 | **Returns:** 129 | 130 | the next byte of this file as a signed eight-bit byte. 131 | 132 | **Throws:** 133 | 134 | IOException - if an I/O error occurs or if this file has reached the end. 135 | 136 | --- 137 | 138 | ### readBytes 139 | 140 | **Signature:** `readBytes(numBytes : Number) : Bytes` 141 | 142 | **Description:** Reads up to n bytes from the file starting at the current file pointer. If there are fewer than n bytes remaining in the file, then as many bytes as possible are read. If no bytes remain in the file, then null is returned. 143 | 144 | **Parameters:** 145 | 146 | - `numBytes`: The number of bytes to read. Must be non-negative and smaller than MAX_READ_BYTES or an exception will be thrown. 147 | 148 | **Returns:** 149 | 150 | A Bytes object representing the read bytes or null if no bytes were read. 151 | 152 | **Throws:** 153 | 154 | IOException - if an I/O error occurs. 155 | IllegalArgumentException - if numBytes< 0 or numBytes > MAX_READ_BYTES. 156 | 157 | --- 158 | 159 | ### setPosition 160 | 161 | **Signature:** `setPosition(position : Number) : void` 162 | 163 | **Description:** Sets the file-pointer offset, measured from the beginning of this file, at which the next read occurs. The offset may be set beyond the end of the file. 164 | 165 | **Parameters:** 166 | 167 | - `position`: the offset position, measured in bytes from the beginning of the file, at which to set the file pointer 168 | 169 | **Throws:** 170 | 171 | IOException - if position is less than 0 or if an I/O error occurs. 172 | 173 | --- ``` -------------------------------------------------------------------------------- /docs/dw_customer/OrderHistory.md: -------------------------------------------------------------------------------- ```markdown 1 | ## Package: dw.customer 2 | 3 | # Class OrderHistory 4 | 5 | ## Inheritance Hierarchy 6 | 7 | - Object 8 | - dw.customer.OrderHistory 9 | 10 | ## Description 11 | 12 | The class provides access to past orders of the customer. Note: This class allows access to sensitive financial and cardholder data. Pay special attention to PCI DSS v3. requirements 1, 3, 7, and 9. It also allows access to sensitive personal and private information. Pay attention to appropriate legal and regulatory requirements related to this data. Note: The following methods do not work with Salesforce Order Management orders. 13 | 14 | ## Properties 15 | 16 | ### orderCount 17 | 18 | **Type:** Number (Read Only) 19 | 20 | The number of orders the customer has placed in the store. 21 | 22 | If the customer is anonymous, this method always returns zero. If an active data record is available for this 23 | customer, the orders count is retrieved from that record, otherwise a real-time query is used to get the count. 24 | 25 | ### orders 26 | 27 | **Type:** SeekableIterator (Read Only) 28 | 29 | Retrieves the order history for the customer in the current storefront site. 30 | 31 | If the result exceeds 1000 orders, only the first 1000 orders are retrieved. Same as 32 | 33 | orderHistory.getOrders( null, "creationDate DESC" ) 34 | 35 | 36 | 37 | It is strongly recommended to call SeekableIterator.close() on the returned 38 | SeekableIterator if not all of its elements are being retrieved. This will ensure the proper cleanup of system 39 | resources. 40 | 41 | ## Constructor Summary 42 | 43 | ## Method Summary 44 | 45 | ### getOrderCount 46 | 47 | **Signature:** `getOrderCount() : Number` 48 | 49 | Returns the number of orders the customer has placed in the store. 50 | 51 | ### getOrders 52 | 53 | **Signature:** `getOrders() : SeekableIterator` 54 | 55 | Retrieves the order history for the customer in the current storefront site. 56 | 57 | ### getOrders 58 | 59 | **Signature:** `getOrders(query : String, sortString : String, params : Object...) : SeekableIterator` 60 | 61 | Retrieves the order history for the customer in the current storefront site. 62 | 63 | ## Method Detail 64 | 65 | ## Method Details 66 | 67 | ### getOrderCount 68 | 69 | **Signature:** `getOrderCount() : Number` 70 | 71 | **Description:** Returns the number of orders the customer has placed in the store. If the customer is anonymous, this method always returns zero. If an active data record is available for this customer, the orders count is retrieved from that record, otherwise a real-time query is used to get the count. 72 | 73 | **Returns:** 74 | 75 | the number of orders the customer has placed in the store. 76 | 77 | --- 78 | 79 | ### getOrders 80 | 81 | **Signature:** `getOrders() : SeekableIterator` 82 | 83 | **Description:** Retrieves the order history for the customer in the current storefront site. If the result exceeds 1000 orders, only the first 1000 orders are retrieved. Same as orderHistory.getOrders( null, "creationDate DESC" ) It is strongly recommended to call SeekableIterator.close() on the returned SeekableIterator if not all of its elements are being retrieved. This will ensure the proper cleanup of system resources. 84 | 85 | **Returns:** 86 | 87 | the orders 88 | 89 | **See Also:** 90 | 91 | getOrders(String, String, Object...) 92 | 93 | --- 94 | 95 | ### getOrders 96 | 97 | **Signature:** `getOrders(query : String, sortString : String, params : Object...) : SeekableIterator` 98 | 99 | **Description:** Retrieves the order history for the customer in the current storefront site. If the result exceeds 1000 orders, only the first 1000 orders are retrieved. Optionally, you can retrieve a subset of the orders by specifying a query. At maximum 3 expressions are allowed to be specified and no custom attribute expressions are allowed. It is strongly recommended to call SeekableIterator.close() on the returned SeekableIterator if not all of its elements are being retrieved. This will ensure the proper cleanup of system resources. Example: var orderHistory : dw.customer.OrderHistory = customer.getOrderHistory(); var orders = orderHistory.getOrders("status = {0}", "creationDate DESC", dw.order.Order.ORDER_STATUS_NEW); for each (var order : dw.order.Order in orders) { // ... process orders } orders.close(); 100 | 101 | **Parameters:** 102 | 103 | - `query`: optional query 104 | - `sortString`: optional sort string 105 | - `params`: optional parameters for the query 106 | 107 | **Returns:** 108 | 109 | the orders 110 | 111 | --- ``` -------------------------------------------------------------------------------- /docs/dw_catalog/ProductPriceInfo.md: -------------------------------------------------------------------------------- ```markdown 1 | ## Package: dw.catalog 2 | 3 | # Class ProductPriceInfo 4 | 5 | ## Inheritance Hierarchy 6 | 7 | - Object 8 | - dw.catalog.ProductPriceInfo 9 | 10 | ## Description 11 | 12 | Simple class representing a product price point. This class is useful because it provides additional information beyond just the price. Since the system calculates sales prices based on applicable price books, it is sometimes useful to know additional information such as which price book defined a price point, what percentage discount off the base price this value represents, and the date range for which this price point is active. 13 | 14 | ## Properties 15 | 16 | ### onlineFrom 17 | 18 | **Type:** Date (Read Only) 19 | 20 | The date from which the associated price point is valid. If such a date doesn't exist, e.g. as in the 21 | case of a continuous price point, null will be returned. 22 | 23 | ### onlineTo 24 | 25 | **Type:** Date (Read Only) 26 | 27 | The date until which the associated price point is valid. If such a date doesn't exist, e.g. as in the case 28 | of a continuous price point, null will be returned. 29 | 30 | ### percentage 31 | 32 | **Type:** Number (Read Only) 33 | 34 | The percentage off value of this price point related to the base 35 | price for the product's minimum order quantity. 36 | 37 | ### price 38 | 39 | **Type:** Money (Read Only) 40 | 41 | The monetary price for this price point. 42 | 43 | ### priceBook 44 | 45 | **Type:** PriceBook (Read Only) 46 | 47 | The price book which defined this price point. 48 | 49 | ### priceInfo 50 | 51 | **Type:** String (Read Only) 52 | 53 | The price info associated with this price point. This is an 54 | arbitrary string which a merchant can associate with a price entry. This 55 | can be used for example, to track which back-end system the price is 56 | derived from. 57 | 58 | ## Constructor Summary 59 | 60 | ## Method Summary 61 | 62 | ### getOnlineFrom 63 | 64 | **Signature:** `getOnlineFrom() : Date` 65 | 66 | Returns the date from which the associated price point is valid. 67 | 68 | ### getOnlineTo 69 | 70 | **Signature:** `getOnlineTo() : Date` 71 | 72 | Returns the date until which the associated price point is valid. 73 | 74 | ### getPercentage 75 | 76 | **Signature:** `getPercentage() : Number` 77 | 78 | Returns the percentage off value of this price point related to the base price for the product's minimum order quantity. 79 | 80 | ### getPrice 81 | 82 | **Signature:** `getPrice() : Money` 83 | 84 | Returns the monetary price for this price point. 85 | 86 | ### getPriceBook 87 | 88 | **Signature:** `getPriceBook() : PriceBook` 89 | 90 | Returns the price book which defined this price point. 91 | 92 | ### getPriceInfo 93 | 94 | **Signature:** `getPriceInfo() : String` 95 | 96 | Returns the price info associated with this price point. 97 | 98 | ## Method Detail 99 | 100 | ## Method Details 101 | 102 | ### getOnlineFrom 103 | 104 | **Signature:** `getOnlineFrom() : Date` 105 | 106 | **Description:** Returns the date from which the associated price point is valid. If such a date doesn't exist, e.g. as in the case of a continuous price point, null will be returned. 107 | 108 | **Returns:** 109 | 110 | the date from which the associated price point is valid 111 | 112 | --- 113 | 114 | ### getOnlineTo 115 | 116 | **Signature:** `getOnlineTo() : Date` 117 | 118 | **Description:** Returns the date until which the associated price point is valid. If such a date doesn't exist, e.g. as in the case of a continuous price point, null will be returned. 119 | 120 | **Returns:** 121 | 122 | the date to which the associated price point is valid 123 | 124 | --- 125 | 126 | ### getPercentage 127 | 128 | **Signature:** `getPercentage() : Number` 129 | 130 | **Description:** Returns the percentage off value of this price point related to the base price for the product's minimum order quantity. 131 | 132 | **Returns:** 133 | 134 | the percentage off value of this price point 135 | 136 | --- 137 | 138 | ### getPrice 139 | 140 | **Signature:** `getPrice() : Money` 141 | 142 | **Description:** Returns the monetary price for this price point. 143 | 144 | **Returns:** 145 | 146 | the price amount 147 | 148 | --- 149 | 150 | ### getPriceBook 151 | 152 | **Signature:** `getPriceBook() : PriceBook` 153 | 154 | **Description:** Returns the price book which defined this price point. 155 | 156 | **Returns:** 157 | 158 | the price book defining this price 159 | 160 | --- 161 | 162 | ### getPriceInfo 163 | 164 | **Signature:** `getPriceInfo() : String` 165 | 166 | **Description:** Returns the price info associated with this price point. This is an arbitrary string which a merchant can associate with a price entry. This can be used for example, to track which back-end system the price is derived from. 167 | 168 | **Returns:** 169 | 170 | the price info associated with this price point. 171 | 172 | --- ``` -------------------------------------------------------------------------------- /docs/sfra/categories.md: -------------------------------------------------------------------------------- ```markdown 1 | # SFRA Categories Model 2 | 3 | ## Overview 4 | 5 | The Categories model represents a hierarchical structure of categories for navigation menus and category displays in SFRA applications. It provides formatted category information with URLs, subcategories, and menu display logic. 6 | 7 | ## Constructor 8 | 9 | ```javascript 10 | function categories(items) 11 | ``` 12 | 13 | Creates a Categories model instance from a collection of top-level categories. 14 | 15 | ### Parameters 16 | 17 | - `items` (dw.util.ArrayList<dw.catalog.Category>) - Top level categories collection 18 | 19 | ## Properties 20 | 21 | ### categories 22 | **Type:** Array<Object> 23 | 24 | Array of formatted category objects that should be shown in menus. Each category contains: 25 | - `name` (string) - Category display name 26 | - `url` (string) - Category URL (custom alternative URL or search URL) 27 | - `id` (string) - Category ID 28 | - `subCategories` (Array<Object>) - Array of subcategory objects (if any) 29 | - `complexSubCategories` (boolean) - True if any subcategories have their own subcategories 30 | 31 | ## Helper Functions 32 | 33 | ### getCategoryUrl(category) 34 | Generates the appropriate URL for a category, preferring custom alternative URLs. 35 | 36 | **Parameters:** 37 | - `category` (dw.catalog.Category) - Category object 38 | 39 | **Returns:** string - Category URL (custom alternative URL or search URL) 40 | 41 | ### categoryToObject(category) 42 | Converts a catalog category to a plain object with menu-appropriate formatting. 43 | 44 | **Parameters:** 45 | - `category` (dw.catalog.Category) - Single category to convert 46 | 47 | **Returns:** Object | null - Formatted category object or null if not shown in menu 48 | 49 | ## Category Structure 50 | 51 | Each category object in the categories array contains: 52 | 53 | ### Basic Properties 54 | - **name** - Category display name for menu labels 55 | - **url** - Properly formatted URL for category navigation 56 | - **id** - Category identifier for tracking and CSS classes 57 | 58 | ### Hierarchical Properties 59 | - **subCategories** - Nested array of subcategory objects (same structure) 60 | - **complexSubCategories** - Boolean flag indicating multi-level nesting 61 | 62 | ## Menu Display Logic 63 | 64 | Categories are included in the menu only if: 65 | 1. Category has `custom.showInMenu` set to true 66 | 2. Category has online products OR online subcategories 67 | 3. Category meets the same criteria recursively for subcategories 68 | 69 | ## URL Handling 70 | 71 | The model provides flexible URL generation: 72 | - **Custom URLs**: Uses `category.custom.alternativeUrl` if available 73 | - **Standard URLs**: Falls back to Search-Show with category ID parameter 74 | - **URL Cleaning**: Removes HTML entities (& becomes &) 75 | 76 | ## Usage Example 77 | 78 | ```javascript 79 | var CategoriesModel = require('*/cartridge/models/categories'); 80 | var CatalogMgr = require('dw/catalog/CatalogMgr'); 81 | 82 | // Get site catalog and root categories 83 | var siteCatalog = CatalogMgr.getSiteCatalog(); 84 | var topLevelCategories = siteCatalog.getRoot().getOnlineSubCategories(); 85 | 86 | var categoriesModel = new CategoriesModel(topLevelCategories); 87 | 88 | // Access menu categories 89 | categoriesModel.categories.forEach(function(category) { 90 | console.log(category.name + ' -> ' + category.url); 91 | 92 | if (category.subCategories) { 93 | category.subCategories.forEach(function(subcat) { 94 | console.log(' ' + subcat.name + ' -> ' + subcat.url); 95 | }); 96 | } 97 | 98 | if (category.complexSubCategories) { 99 | console.log('Category has multi-level navigation'); 100 | } 101 | }); 102 | ``` 103 | 104 | ## Recursive Structure 105 | 106 | The model handles deep category hierarchies: 107 | - Subcategories are processed recursively with the same logic 108 | - Each level maintains the same object structure 109 | - The `complexSubCategories` flag helps with menu rendering decisions 110 | 111 | ## Notes 112 | 113 | - Only processes categories marked for menu display (`showInMenu`) 114 | - Filters out empty categories with no products or subcategories 115 | - Maintains hierarchical relationships for multi-level navigation 116 | - Provides clean URLs with proper entity handling 117 | - Supports both custom and standard URL patterns 118 | - Optimized for navigation menu rendering 119 | 120 | ## Related Models 121 | 122 | - **Search Models** - Categories link to search results 123 | - **Product Models** - Categories contain products 124 | - **Content Models** - May reference category information 125 | ``` -------------------------------------------------------------------------------- /tests/servers/sfcc-mock-server/mock-data/ocapi/custom-object-attributes-customapi.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "_v": "23.2", 3 | "_type": "object_attribute_definition_search_result", 4 | "count": 4, 5 | "hits": [ 6 | { 7 | "_type": "object_attribute_definition", 8 | "_resource_state": "99fb446a1b38712210cb5572b2a2c5acde8a414f3b70d3fbd887d5239c3902ec", 9 | "creation_date": "2025-03-06T07:14:22.000Z", 10 | "effective_id": "c_ID", 11 | "externally_defined": false, 12 | "externally_managed": false, 13 | "id": "ID", 14 | "key": true, 15 | "last_modified": "2025-03-06T07:14:22.000Z", 16 | "link": "https://localhost:3000/s/-/dw/data/v23_2/custom_object_definitions/CustomApi/attribute_definitions/ID", 17 | "localizable": false, 18 | "mandatory": true, 19 | "min_length": 0, 20 | "multi_value_type": false, 21 | "order_required": false, 22 | "queryable": true, 23 | "read_only": false, 24 | "requires_encoding": false, 25 | "searchable": false, 26 | "set_value_type": false, 27 | "site_specific": false, 28 | "system": false, 29 | "value_type": "string", 30 | "visible": false 31 | }, 32 | { 33 | "_type": "object_attribute_definition", 34 | "_resource_state": "a2d9fadb3bca35c9dc4d71365ca24ed5e8e98514fa9fd7ece48c5a1214d7b8a4", 35 | "creation_date": "2025-03-06T07:14:22.000Z", 36 | "display_name": { 37 | "default": "UUID" 38 | }, 39 | "effective_id": "UUID", 40 | "externally_defined": false, 41 | "externally_managed": false, 42 | "field_length": 28, 43 | "id": "UUID", 44 | "key": false, 45 | "last_modified": "2025-03-06T07:14:22.000Z", 46 | "link": "https://localhost:3000/s/-/dw/data/v23_2/custom_object_definitions/CustomApi/attribute_definitions/UUID", 47 | "localizable": false, 48 | "mandatory": true, 49 | "min_length": 0, 50 | "multi_value_type": false, 51 | "order_required": false, 52 | "queryable": true, 53 | "read_only": true, 54 | "requires_encoding": false, 55 | "searchable": false, 56 | "set_value_type": false, 57 | "site_specific": false, 58 | "system": true, 59 | "value_type": "string", 60 | "visible": false 61 | }, 62 | { 63 | "_type": "object_attribute_definition", 64 | "_resource_state": "e79f6e1fc72a3b162e732bf0b04798d623e4ca23a2ad86311a1b2fdf76d70f0b", 65 | "creation_date": "2025-03-06T07:14:22.000Z", 66 | "display_name": { 67 | "default": "Creation Date" 68 | }, 69 | "effective_id": "creationDate", 70 | "externally_defined": false, 71 | "externally_managed": false, 72 | "id": "creationDate", 73 | "key": false, 74 | "last_modified": "2025-03-06T07:14:22.000Z", 75 | "link": "https://localhost:3000/s/-/dw/data/v23_2/custom_object_definitions/CustomApi/attribute_definitions/creationDate", 76 | "localizable": false, 77 | "mandatory": true, 78 | "min_length": 0, 79 | "multi_value_type": false, 80 | "order_required": false, 81 | "queryable": true, 82 | "read_only": true, 83 | "requires_encoding": false, 84 | "searchable": false, 85 | "set_value_type": false, 86 | "site_specific": false, 87 | "system": true, 88 | "value_type": "datetime", 89 | "visible": false 90 | }, 91 | { 92 | "_type": "object_attribute_definition", 93 | "_resource_state": "236466300ffa270a07b8fc8b1c8bc0eea8ddacfc0a7d29eeba5279c438b19655", 94 | "creation_date": "2025-03-06T07:14:22.000Z", 95 | "display_name": { 96 | "default": "Last Modified" 97 | }, 98 | "effective_id": "lastModified", 99 | "externally_defined": false, 100 | "externally_managed": false, 101 | "id": "lastModified", 102 | "key": false, 103 | "last_modified": "2025-03-06T07:14:22.000Z", 104 | "link": "https://localhost:3000/s/-/dw/data/v23_2/custom_object_definitions/CustomApi/attribute_definitions/lastModified", 105 | "localizable": false, 106 | "mandatory": true, 107 | "min_length": 0, 108 | "multi_value_type": false, 109 | "order_required": false, 110 | "queryable": true, 111 | "read_only": true, 112 | "requires_encoding": false, 113 | "searchable": false, 114 | "set_value_type": false, 115 | "site_specific": false, 116 | "system": true, 117 | "value_type": "datetime", 118 | "visible": false 119 | } 120 | ], 121 | "query": { 122 | "match_all_query": { 123 | "_type": "match_all_query" 124 | } 125 | }, 126 | "start": 0, 127 | "total": 4 128 | } ``` -------------------------------------------------------------------------------- /docs/dw_net/HTTPRequestPart.md: -------------------------------------------------------------------------------- ```markdown 1 | ## Package: dw.net 2 | 3 | # Class HTTPRequestPart 4 | 5 | ## Inheritance Hierarchy 6 | 7 | - Object 8 | - dw.net.HTTPRequestPart 9 | 10 | ## Description 11 | 12 | This represents a part in a multi-part HTTP POST request. A part always has a name and value. The value may be a String, Bytes, or the contents of a File. A character encoding may be specified for any of these, and the content type and a file name may additionally be specified for the Bytes and File types. Note: when this class is used with sensitive data, be careful in persisting sensitive information. 13 | 14 | ## Properties 15 | 16 | ### bytesValue 17 | 18 | **Type:** Bytes (Read Only) 19 | 20 | Get the Bytes value of the part. 21 | 22 | ### contentType 23 | 24 | **Type:** String (Read Only) 25 | 26 | The content type of this part. 27 | 28 | ### encoding 29 | 30 | **Type:** String (Read Only) 31 | 32 | Get the charset to be used to encode the string. 33 | 34 | ### fileName 35 | 36 | **Type:** String (Read Only) 37 | 38 | Get the file name to use when sending a file part. 39 | 40 | ### fileValue 41 | 42 | **Type:** File (Read Only) 43 | 44 | Get the file value of the part. 45 | 46 | ### name 47 | 48 | **Type:** String (Read Only) 49 | 50 | Get the name of the part. 51 | 52 | ### stringValue 53 | 54 | **Type:** String (Read Only) 55 | 56 | Get the string value of the part. 57 | 58 | ## Constructor Summary 59 | 60 | HTTPRequestPart(name : String, value : String) Construct a part representing a simple string name/value pair. 61 | 62 | HTTPRequestPart(name : String, value : String, encoding : String) Construct a part representing a simple string name/value pair. 63 | 64 | HTTPRequestPart(name : String, file : File) Construct a part representing a name/File pair. 65 | 66 | HTTPRequestPart(name : String, data : Bytes) Construct a part representing a name/bytes pair. 67 | 68 | HTTPRequestPart(name : String, data : Bytes, contentType : String, encoding : String, fileName : String) Construct a part representing a name/File pair. 69 | 70 | HTTPRequestPart(name : String, file : File, contentType : String, encoding : String) Construct a part representing a name/File pair. 71 | 72 | HTTPRequestPart(name : String, file : File, contentType : String, encoding : String, fileName : String) Construct a part representing a name/File pair. 73 | 74 | ## Method Summary 75 | 76 | ### getBytesValue 77 | 78 | **Signature:** `getBytesValue() : Bytes` 79 | 80 | Get the Bytes value of the part. 81 | 82 | ### getContentType 83 | 84 | **Signature:** `getContentType() : String` 85 | 86 | Returns the content type of this part. 87 | 88 | ### getEncoding 89 | 90 | **Signature:** `getEncoding() : String` 91 | 92 | Get the charset to be used to encode the string. 93 | 94 | ### getFileName 95 | 96 | **Signature:** `getFileName() : String` 97 | 98 | Get the file name to use when sending a file part. 99 | 100 | ### getFileValue 101 | 102 | **Signature:** `getFileValue() : File` 103 | 104 | Get the file value of the part. 105 | 106 | ### getName 107 | 108 | **Signature:** `getName() : String` 109 | 110 | Get the name of the part. 111 | 112 | ### getStringValue 113 | 114 | **Signature:** `getStringValue() : String` 115 | 116 | Get the string value of the part. 117 | 118 | ## Constructor Detail 119 | 120 | ## Method Detail 121 | 122 | ## Method Details 123 | 124 | ### getBytesValue 125 | 126 | **Signature:** `getBytesValue() : Bytes` 127 | 128 | **Description:** Get the Bytes value of the part. 129 | 130 | **Returns:** 131 | 132 | The Bytes value, or null if this part is not a Bytes part. 133 | 134 | --- 135 | 136 | ### getContentType 137 | 138 | **Signature:** `getContentType() : String` 139 | 140 | **Description:** Returns the content type of this part. 141 | 142 | **Returns:** 143 | 144 | The content type, or null if content type was not specified. 145 | 146 | --- 147 | 148 | ### getEncoding 149 | 150 | **Signature:** `getEncoding() : String` 151 | 152 | **Description:** Get the charset to be used to encode the string. 153 | 154 | **Returns:** 155 | 156 | The charset, or null if charset was not specified. 157 | 158 | --- 159 | 160 | ### getFileName 161 | 162 | **Signature:** `getFileName() : String` 163 | 164 | **Description:** Get the file name to use when sending a file part. 165 | 166 | **Returns:** 167 | 168 | File name to use in the Mime header, or null for default behavior. 169 | 170 | --- 171 | 172 | ### getFileValue 173 | 174 | **Signature:** `getFileValue() : File` 175 | 176 | **Description:** Get the file value of the part. 177 | 178 | **Returns:** 179 | 180 | The file value, or null if this part is not a file part. 181 | 182 | --- 183 | 184 | ### getName 185 | 186 | **Signature:** `getName() : String` 187 | 188 | **Description:** Get the name of the part. 189 | 190 | **Returns:** 191 | 192 | The part name, never null. 193 | 194 | --- 195 | 196 | ### getStringValue 197 | 198 | **Signature:** `getStringValue() : String` 199 | 200 | **Description:** Get the string value of the part. 201 | 202 | **Returns:** 203 | 204 | The string value, or null if this part is not a string part. 205 | 206 | --- ``` -------------------------------------------------------------------------------- /src/clients/ocapi/system-objects-client.ts: -------------------------------------------------------------------------------- ```typescript 1 | /** 2 | * OCAPI System Objects Client 3 | * 4 | * This module handles all SFCC system object related operations including 5 | * object definitions, attribute definitions, and attribute groups. 6 | */ 7 | 8 | import { OCAPIConfig } from '../../types/types.js'; 9 | import { OCAPIAuthClient } from '../base/ocapi-auth-client.js'; 10 | import { QueryBuilder } from '../../utils/query-builder.js'; 11 | import { Validator } from '../../utils/validator.js'; 12 | import { buildOCAPIBaseUrl } from '../../utils/ocapi-url-builder.js'; 13 | 14 | /** 15 | * Interface for common query parameters 16 | */ 17 | interface BaseQueryParams { 18 | start?: number; 19 | count?: number; 20 | select?: string; 21 | } 22 | 23 | /** 24 | * Interface for search request structure 25 | */ 26 | interface SearchRequest { 27 | query?: { 28 | text_query?: { 29 | fields: string[]; 30 | search_phrase: string; 31 | }; 32 | term_query?: { 33 | fields: string[]; 34 | operator: string; 35 | values: any[]; 36 | }; 37 | filtered_query?: { 38 | filter: any; 39 | query: any; 40 | }; 41 | bool_query?: { 42 | must?: any[]; 43 | must_not?: any[]; 44 | should?: any[]; 45 | }; 46 | match_all_query?: {}; 47 | }; 48 | sorts?: Array<{ 49 | field: string; 50 | sort_order?: 'asc' | 'desc'; 51 | }>; 52 | start?: number; 53 | count?: number; 54 | select?: string; 55 | } 56 | 57 | /** 58 | * OCAPI System Objects Client 59 | * Specialized client for system object operations 60 | */ 61 | export class OCAPISystemObjectsClient extends OCAPIAuthClient { 62 | constructor(config: OCAPIConfig) { 63 | super(config); 64 | // Override the baseUrl for this specialized client 65 | this.baseUrl = buildOCAPIBaseUrl(config); 66 | } 67 | 68 | /** 69 | * Get all system object definitions 70 | */ 71 | async getSystemObjectDefinitions(params?: BaseQueryParams): Promise<any> { 72 | let endpoint = '/system_object_definitions'; 73 | 74 | if (params) { 75 | const queryString = QueryBuilder.fromObject(params); 76 | if (queryString) { 77 | endpoint += `?${queryString}`; 78 | } 79 | } 80 | 81 | return this.get(endpoint); 82 | } 83 | 84 | /** 85 | * Get a specific system object definition by object type 86 | */ 87 | async getSystemObjectDefinition(objectType: string): Promise<any> { 88 | Validator.validateRequired({ objectType }, ['objectType']); 89 | Validator.validateObjectType(objectType); 90 | 91 | const endpoint = `/system_object_definitions/${encodeURIComponent(objectType)}`; 92 | return this.get(endpoint); 93 | } 94 | 95 | /** 96 | * Search for system object definitions using complex queries 97 | */ 98 | async searchSystemObjectDefinitions(searchRequest: SearchRequest): Promise<any> { 99 | Validator.validateSearchRequest(searchRequest); 100 | 101 | const endpoint = '/system_object_definition_search'; 102 | return this.post(endpoint, searchRequest); 103 | } 104 | 105 | /** 106 | * Search attribute definitions for a specific system object type 107 | */ 108 | async searchSystemObjectAttributeDefinitions( 109 | objectType: string, 110 | searchRequest: SearchRequest, 111 | ): Promise<any> { 112 | Validator.validateRequired({ objectType }, ['objectType']); 113 | Validator.validateObjectType(objectType); 114 | Validator.validateSearchRequest(searchRequest); 115 | 116 | const endpoint = `/system_object_definitions/${encodeURIComponent(objectType)}/attribute_definition_search`; 117 | return this.post(endpoint, searchRequest); 118 | } 119 | 120 | /** 121 | * Search attribute groups for a specific system object type 122 | */ 123 | async searchSystemObjectAttributeGroups( 124 | objectType: string, 125 | searchRequest: SearchRequest, 126 | ): Promise<any> { 127 | Validator.validateRequired({ objectType }, ['objectType']); 128 | Validator.validateObjectType(objectType); 129 | Validator.validateSearchRequest(searchRequest); 130 | 131 | const endpoint = `/system_object_definitions/${encodeURIComponent(objectType)}/attribute_group_search`; 132 | return this.post(endpoint, searchRequest); 133 | } 134 | 135 | /** 136 | * Search attribute definitions for a specific custom object type 137 | */ 138 | async searchCustomObjectAttributeDefinitions( 139 | objectType: string, 140 | searchRequest: SearchRequest, 141 | ): Promise<any> { 142 | Validator.validateRequired({ objectType }, ['objectType']); 143 | Validator.validateSearchRequest(searchRequest); 144 | 145 | const endpoint = `/custom_object_definitions/${encodeURIComponent(objectType)}/attribute_definition_search`; 146 | return this.post(endpoint, searchRequest); 147 | } 148 | } 149 | ``` -------------------------------------------------------------------------------- /src/utils/log-tool-utils.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { ToolArguments } from '../core/handlers/base-handler.js'; 2 | import { SFCCLogClient } from '../clients/log-client.js'; 3 | import { LogLevel, isValidLogLevel } from './log-tool-constants.js'; 4 | 5 | /** 6 | * Configuration interface for tool dispatch 7 | */ 8 | export interface ToolSpec<T = any> { 9 | validate?: (args: ToolArguments, toolName: string) => void; 10 | defaults?: (args: ToolArguments) => Record<string, any>; 11 | exec: (args: ToolArguments, client: SFCCLogClient) => Promise<T>; 12 | logMessage: (args: ToolArguments) => string; 13 | } 14 | 15 | /** 16 | * Validation utilities for log tools 17 | */ 18 | export class LogToolValidators { 19 | static validateLogLevel(level: string, toolName: string): void { 20 | if (!isValidLogLevel(level)) { 21 | throw new Error(`Invalid log level '${level}' for ${toolName}. Valid levels: ${Object.values(LogLevel).join(', ')}`); 22 | } 23 | } 24 | 25 | static validateLimit(limit: number | undefined, toolName: string): void { 26 | if (limit !== undefined) { 27 | // Validate type first 28 | if (typeof limit !== 'number' || isNaN(limit)) { 29 | throw new Error(`Invalid limit '${limit}' for ${toolName}. Must be a valid number`); 30 | } 31 | // Then validate range 32 | if (limit <= 0 || limit > 1000) { 33 | throw new Error(`Invalid limit '${limit}' for ${toolName}. Must be between 1 and 1000`); 34 | } 35 | } 36 | } 37 | 38 | static validateMaxBytes(maxBytes: number | undefined, toolName: string): void { 39 | if (maxBytes !== undefined) { 40 | // Validate type first 41 | if (typeof maxBytes !== 'number' || isNaN(maxBytes)) { 42 | throw new Error(`Invalid maxBytes '${maxBytes}' for ${toolName}. Must be a valid number`); 43 | } 44 | // Then validate range 45 | if (maxBytes <= 0 || maxBytes > 10_000_000) { // 10MB limit 46 | throw new Error(`Invalid maxBytes '${maxBytes}' for ${toolName}. Must be between 1 and 10,000,000`); 47 | } 48 | } 49 | } 50 | 51 | static validateFilename(filename: string, toolName: string): void { 52 | if (!filename || filename.trim().length === 0) { 53 | throw new Error(`Filename is required for ${toolName}`); 54 | } 55 | 56 | // Prevent path traversal 57 | if (filename.includes('..') || filename.includes('\\')) { 58 | throw new Error(`Invalid filename '${filename}' for ${toolName}. Path traversal not allowed`); 59 | } 60 | } 61 | } 62 | 63 | /** 64 | * Message formatting utilities for log tools 65 | */ 66 | export class LogMessageFormatter { 67 | static formatLatestLogs(level: string, limit: number, date?: string): string { 68 | return `Fetching latest ${level} logs limit=${limit} date=${date ?? 'today'}`; 69 | } 70 | 71 | static formatSummarizeLogs(date?: string): string { 72 | return `Summarizing logs for date ${date ?? 'today'}`; 73 | } 74 | 75 | static formatSearchLogs(pattern: string, logLevel?: string, limit?: number, _date?: string): string { 76 | // For backward compatibility with existing tests, don't include date in message 77 | return `Searching logs pattern="${pattern}" level=${logLevel ?? 'all'} limit=${limit ?? 20}`; 78 | } 79 | 80 | static formatListLogFiles(): string { 81 | return 'Listing log files'; 82 | } 83 | 84 | static formatGetLogFileContents(filename: string, maxBytes?: number, tailOnly?: boolean): string { 85 | return `Reading log file contents: ${filename} (maxBytes=${maxBytes ?? 'default'}, tailOnly=${tailOnly ?? false})`; 86 | } 87 | 88 | static formatJobLogMessage(operation: string, params: Record<string, any>): string { 89 | const paramStr = Object.entries(params) 90 | .filter(([_, value]) => value !== undefined) 91 | .map(([key, value]) => `${key}=${value}`) 92 | .join(' '); 93 | 94 | return paramStr ? `${operation} ${paramStr}` : operation; 95 | } 96 | } 97 | 98 | /** 99 | * Utility functions for argument processing 100 | */ 101 | export class LogToolUtils { 102 | static applyDefaults(spec: ToolSpec, args: ToolArguments): ToolArguments { 103 | if (!spec.defaults) { 104 | return args; 105 | } 106 | 107 | const defaults = spec.defaults(args); 108 | return { ...args, ...defaults }; 109 | } 110 | 111 | static createValidatedArgs(spec: ToolSpec, args: ToolArguments, toolName: string): ToolArguments { 112 | // Apply defaults first 113 | const processedArgs = LogToolUtils.applyDefaults(spec, args); 114 | 115 | // Validate if validator exists 116 | if (spec.validate) { 117 | spec.validate(processedArgs, toolName); 118 | } 119 | 120 | return processedArgs; 121 | } 122 | } 123 | ``` -------------------------------------------------------------------------------- /docs/dw_order/AbstractItem.md: -------------------------------------------------------------------------------- ```markdown 1 | ## Package: dw.order 2 | 3 | # Class AbstractItem 4 | 5 | ## Inheritance Hierarchy 6 | 7 | - Object 8 | - dw.object.Extensible 9 | - dw.order.AbstractItem 10 | 11 | ## Description 12 | 13 | An item which references, or in other words is based upon, an OrderItem. Provides methods to access the OrderItem, the order LineItem which has been extended, and the Order. In addition it defines methods to access item level prices and the item id. Supports custom-properties. 14 | 15 | ## Properties 16 | 17 | ### grossPrice 18 | 19 | **Type:** Money (Read Only) 20 | 21 | Gross price of item. 22 | 23 | ### itemID 24 | 25 | **Type:** String (Read Only) 26 | 27 | The item-id used for referencing between items 28 | 29 | ### lineItem 30 | 31 | **Type:** LineItem (Read Only) 32 | 33 | The Order Product- or Shipping- LineItem associated with this item. Should never return null. 34 | 35 | ### netPrice 36 | 37 | **Type:** Money (Read Only) 38 | 39 | Net price of item. 40 | 41 | ### orderItem 42 | 43 | **Type:** OrderItem (Read Only) 44 | 45 | The order item extensions related to this item. Should never return null. 46 | 47 | ### orderItemID 48 | 49 | **Type:** String (Read Only) 50 | 51 | The order-item-id used for referencing the OrderItem 52 | 53 | ### tax 54 | 55 | **Type:** Money (Read Only) 56 | 57 | Total tax for item. 58 | 59 | ### taxBasis 60 | 61 | **Type:** Money (Read Only) 62 | 63 | Price of entire item on which tax calculation is based. Same as getNetPrice() 64 | or getGrossPrice() depending on whether the order is based on net or gross prices. 65 | 66 | ### taxItems 67 | 68 | **Type:** Collection (Read Only) 69 | 70 | Tax items representing a tax breakdown 71 | 72 | ## Constructor Summary 73 | 74 | ## Method Summary 75 | 76 | ### getGrossPrice 77 | 78 | **Signature:** `getGrossPrice() : Money` 79 | 80 | Gross price of item. 81 | 82 | ### getItemID 83 | 84 | **Signature:** `getItemID() : String` 85 | 86 | The item-id used for referencing between items 87 | 88 | ### getLineItem 89 | 90 | **Signature:** `getLineItem() : LineItem` 91 | 92 | Returns the Order Product- or Shipping- LineItem associated with this item. 93 | 94 | ### getNetPrice 95 | 96 | **Signature:** `getNetPrice() : Money` 97 | 98 | Net price of item. 99 | 100 | ### getOrderItem 101 | 102 | **Signature:** `getOrderItem() : OrderItem` 103 | 104 | Returns the order item extensions related to this item. 105 | 106 | ### getOrderItemID 107 | 108 | **Signature:** `getOrderItemID() : String` 109 | 110 | The order-item-id used for referencing the OrderItem 111 | 112 | ### getTax 113 | 114 | **Signature:** `getTax() : Money` 115 | 116 | Total tax for item. 117 | 118 | ### getTaxBasis 119 | 120 | **Signature:** `getTaxBasis() : Money` 121 | 122 | Price of entire item on which tax calculation is based. 123 | 124 | ### getTaxItems 125 | 126 | **Signature:** `getTaxItems() : Collection` 127 | 128 | Tax items representing a tax breakdown 129 | 130 | ## Method Detail 131 | 132 | ## Method Details 133 | 134 | ### getGrossPrice 135 | 136 | **Signature:** `getGrossPrice() : Money` 137 | 138 | **Description:** Gross price of item. 139 | 140 | **Returns:** 141 | 142 | Gross price of item. 143 | 144 | --- 145 | 146 | ### getItemID 147 | 148 | **Signature:** `getItemID() : String` 149 | 150 | **Description:** The item-id used for referencing between items 151 | 152 | **Returns:** 153 | 154 | the item-id used for referencing between items 155 | 156 | --- 157 | 158 | ### getLineItem 159 | 160 | **Signature:** `getLineItem() : LineItem` 161 | 162 | **Description:** Returns the Order Product- or Shipping- LineItem associated with this item. Should never return null. 163 | 164 | **Returns:** 165 | 166 | the Order Product- or Shipping- LineItem associated with this item 167 | 168 | --- 169 | 170 | ### getNetPrice 171 | 172 | **Signature:** `getNetPrice() : Money` 173 | 174 | **Description:** Net price of item. 175 | 176 | **Returns:** 177 | 178 | Net price of item. 179 | 180 | --- 181 | 182 | ### getOrderItem 183 | 184 | **Signature:** `getOrderItem() : OrderItem` 185 | 186 | **Description:** Returns the order item extensions related to this item. Should never return null. 187 | 188 | **Returns:** 189 | 190 | the order item extensions related to this item 191 | 192 | --- 193 | 194 | ### getOrderItemID 195 | 196 | **Signature:** `getOrderItemID() : String` 197 | 198 | **Description:** The order-item-id used for referencing the OrderItem 199 | 200 | **Returns:** 201 | 202 | the order-item-id used for referencing the OrderItem 203 | 204 | --- 205 | 206 | ### getTax 207 | 208 | **Signature:** `getTax() : Money` 209 | 210 | **Description:** Total tax for item. 211 | 212 | **Returns:** 213 | 214 | Total tax for item. 215 | 216 | --- 217 | 218 | ### getTaxBasis 219 | 220 | **Signature:** `getTaxBasis() : Money` 221 | 222 | **Description:** Price of entire item on which tax calculation is based. Same as getNetPrice() or getGrossPrice() depending on whether the order is based on net or gross prices. 223 | 224 | **Returns:** 225 | 226 | Price of entire item on which tax calculation is based 227 | 228 | --- 229 | 230 | ### getTaxItems 231 | 232 | **Signature:** `getTaxItems() : Collection` 233 | 234 | **Description:** Tax items representing a tax breakdown 235 | 236 | **Returns:** 237 | 238 | tax items representing a tax breakdown 239 | 240 | **See Also:** 241 | 242 | TaxItem 243 | 244 | --- ``` -------------------------------------------------------------------------------- /docs/dw_crypto/JWE.md: -------------------------------------------------------------------------------- ```markdown 1 | ## Package: dw.crypto 2 | 3 | # Class JWE 4 | 5 | ## Inheritance Hierarchy 6 | 7 | - Object 8 | - dw.crypto.JWE 9 | 10 | ## Description 11 | 12 | This class represents a JSON Web Encryption (JWE) object. Note: this class handles sensitive security-related data. Pay special attention to PCI DSS v3 requirements 2, 4, and 12. 13 | 14 | ## Properties 15 | 16 | ### algorithm 17 | 18 | **Type:** String (Read Only) 19 | 20 | Get the algorithm (alg) from the header. 21 | 22 | ### encryptionMethod 23 | 24 | **Type:** String (Read Only) 25 | 26 | Get the encryption method (enc) from the header. 27 | 28 | ### headerMap 29 | 30 | **Type:** Map (Read Only) 31 | 32 | Get a copy of the JWE headers as a Map. 33 | 34 | ### keyID 35 | 36 | **Type:** String (Read Only) 37 | 38 | Get the key id (kid) from the header. 39 | 40 | ### payload 41 | 42 | **Type:** String (Read Only) 43 | 44 | Get the decrypted payload. 45 | 46 | ## Constructor Summary 47 | 48 | JWE(header : JWEHeader, payload : String) Construct a new JWE for encryption. 49 | 50 | JWE(header : JWEHeader, payload : Bytes) Construct a new JWE for encryption. 51 | 52 | ## Method Summary 53 | 54 | ### decrypt 55 | 56 | **Signature:** `decrypt(privateKey : KeyRef) : void` 57 | 58 | Decrypt the payload of this JWE object. 59 | 60 | ### encrypt 61 | 62 | **Signature:** `encrypt(publicKey : CertificateRef) : void` 63 | 64 | Encrypt the payload of this JWE object. 65 | 66 | ### getAlgorithm 67 | 68 | **Signature:** `getAlgorithm() : String` 69 | 70 | Get the algorithm (alg) from the header. 71 | 72 | ### getEncryptionMethod 73 | 74 | **Signature:** `getEncryptionMethod() : String` 75 | 76 | Get the encryption method (enc) from the header. 77 | 78 | ### getHeaderMap 79 | 80 | **Signature:** `getHeaderMap() : Map` 81 | 82 | Get a copy of the JWE headers as a Map. 83 | 84 | ### getKeyID 85 | 86 | **Signature:** `getKeyID() : String` 87 | 88 | Get the key id (kid) from the header. 89 | 90 | ### getPayload 91 | 92 | **Signature:** `getPayload() : String` 93 | 94 | Get the decrypted payload. 95 | 96 | ### parse 97 | 98 | **Signature:** `static parse(jwe : String) : JWE` 99 | 100 | Parse a JSON Web Encryption (JWE) object from its compact serialization format. 101 | 102 | ### serialize 103 | 104 | **Signature:** `serialize() : String` 105 | 106 | Get this JWE in compact serialization form. 107 | 108 | ## Constructor Detail 109 | 110 | ## Method Detail 111 | 112 | ## Method Details 113 | 114 | ### decrypt 115 | 116 | **Signature:** `decrypt(privateKey : KeyRef) : void` 117 | 118 | **Description:** Decrypt the payload of this JWE object. Elliptic Curve (EC) and RSA keys are both supported. Supported EC key management algorithms: ECDH-ES ECDH-ES+A128KW ECDH-ES+A192KW ECDH-ES+A256KW Supported EC curves: P-256 P-384 P-521 Supported RSA key management algorithms: RSA-OAEP-256 RSA-OAEP-384 RSA-OAEP-512 Supported content encryption algorithms: A128CBC-HS256 A128CBC-HS384 A128CBC-HS512 A128GCM A192GCM A256GCM 119 | 120 | **Parameters:** 121 | 122 | - `privateKey`: Reference to private RSA or EC key to use for decryption. 123 | 124 | --- 125 | 126 | ### encrypt 127 | 128 | **Signature:** `encrypt(publicKey : CertificateRef) : void` 129 | 130 | **Description:** Encrypt the payload of this JWE object. Elliptic Curve (EC) and RSA keys are both supported. See decrypt(KeyRef) for the list of supported algorithms and encryption methods. 131 | 132 | **Parameters:** 133 | 134 | - `publicKey`: Reference to public RSA or EC key to use for decryption. 135 | 136 | --- 137 | 138 | ### getAlgorithm 139 | 140 | **Signature:** `getAlgorithm() : String` 141 | 142 | **Description:** Get the algorithm (alg) from the header. 143 | 144 | **Returns:** 145 | 146 | Value of the algorithm or null if missing. 147 | 148 | --- 149 | 150 | ### getEncryptionMethod 151 | 152 | **Signature:** `getEncryptionMethod() : String` 153 | 154 | **Description:** Get the encryption method (enc) from the header. 155 | 156 | **Returns:** 157 | 158 | Value of the encryption method or null if missing. 159 | 160 | --- 161 | 162 | ### getHeaderMap 163 | 164 | **Signature:** `getHeaderMap() : Map` 165 | 166 | **Description:** Get a copy of the JWE headers as a Map. 167 | 168 | **Returns:** 169 | 170 | Copy of the JWE headers. 171 | 172 | --- 173 | 174 | ### getKeyID 175 | 176 | **Signature:** `getKeyID() : String` 177 | 178 | **Description:** Get the key id (kid) from the header. 179 | 180 | **Returns:** 181 | 182 | Value of the key id or null if missing. 183 | 184 | --- 185 | 186 | ### getPayload 187 | 188 | **Signature:** `getPayload() : String` 189 | 190 | **Description:** Get the decrypted payload. 191 | 192 | **Returns:** 193 | 194 | Payload or null if the payload is encrypted. 195 | 196 | --- 197 | 198 | ### parse 199 | 200 | **Signature:** `static parse(jwe : String) : JWE` 201 | 202 | **Description:** Parse a JSON Web Encryption (JWE) object from its compact serialization format. 203 | 204 | **Parameters:** 205 | 206 | - `jwe`: JWE in compact serialization format. 207 | 208 | **Returns:** 209 | 210 | JWE object. 211 | 212 | --- 213 | 214 | ### serialize 215 | 216 | **Signature:** `serialize() : String` 217 | 218 | **Description:** Get this JWE in compact serialization form. 219 | 220 | **Returns:** 221 | 222 | Compact serialized object. 223 | 224 | --- ``` -------------------------------------------------------------------------------- /docs/dw_order/AbstractItemCtnr.md: -------------------------------------------------------------------------------- ```markdown 1 | ## Package: dw.order 2 | 3 | # Class AbstractItemCtnr 4 | 5 | ## Inheritance Hierarchy 6 | 7 | - Object 8 | - dw.object.Extensible 9 | - dw.order.AbstractItemCtnr 10 | 11 | ## Description 12 | 13 | Basis for item-based objects stemming from a single Order, with these common properties (Invoice is used as an example): The object has been created from an Order accessible using getOrder() Contains a collection of items, each item related to exactly one OrderItem which in turn represents an extension to one of the order ProductLineItem or one ShippingLineItem. Example: an Invoice has InvoiceItems The items hold various prices which are summed, resulting in a product-subtotal, a service-subtotal and a grand-total, each represented by a SumItem. The object is customizable using custom properties 14 | 15 | ## Properties 16 | 17 | ### createdBy 18 | 19 | **Type:** String (Read Only) 20 | 21 | Created by this user. 22 | 23 | ### creationDate 24 | 25 | **Type:** Date (Read Only) 26 | 27 | The time of creation. 28 | 29 | ### grandTotal 30 | 31 | **Type:** SumItem (Read Only) 32 | 33 | The sum-item representing the grandtotal for all items. 34 | 35 | ### items 36 | 37 | **Type:** FilteringCollection (Read Only) 38 | 39 | The unsorted collection of items 40 | 41 | ### lastModified 42 | 43 | **Type:** Date (Read Only) 44 | 45 | The last modification time. 46 | 47 | ### modifiedBy 48 | 49 | **Type:** String (Read Only) 50 | 51 | Last modified by this user. 52 | 53 | ### order 54 | 55 | **Type:** Order (Read Only) 56 | 57 | The Order this object was created for. 58 | 59 | ### productSubtotal 60 | 61 | **Type:** SumItem (Read Only) 62 | 63 | The sum-item representing the subtotal for product items. 64 | 65 | ### serviceSubtotal 66 | 67 | **Type:** SumItem (Read Only) 68 | 69 | The sum-item representing the subtotal for service items such as 70 | shipping. 71 | 72 | ## Constructor Summary 73 | 74 | ## Method Summary 75 | 76 | ### getCreatedBy 77 | 78 | **Signature:** `getCreatedBy() : String` 79 | 80 | Created by this user. 81 | 82 | ### getCreationDate 83 | 84 | **Signature:** `getCreationDate() : Date` 85 | 86 | The time of creation. 87 | 88 | ### getGrandTotal 89 | 90 | **Signature:** `getGrandTotal() : SumItem` 91 | 92 | Returns the sum-item representing the grandtotal for all items. 93 | 94 | ### getItems 95 | 96 | **Signature:** `getItems() : FilteringCollection` 97 | 98 | Returns the unsorted collection of items 99 | 100 | ### getLastModified 101 | 102 | **Signature:** `getLastModified() : Date` 103 | 104 | The last modification time. 105 | 106 | ### getModifiedBy 107 | 108 | **Signature:** `getModifiedBy() : String` 109 | 110 | Last modified by this user. 111 | 112 | ### getOrder 113 | 114 | **Signature:** `getOrder() : Order` 115 | 116 | Returns the Order this object was created for. 117 | 118 | ### getProductSubtotal 119 | 120 | **Signature:** `getProductSubtotal() : SumItem` 121 | 122 | Returns the sum-item representing the subtotal for product items. 123 | 124 | ### getServiceSubtotal 125 | 126 | **Signature:** `getServiceSubtotal() : SumItem` 127 | 128 | Returns the sum-item representing the subtotal for service items such as shipping. 129 | 130 | ## Method Detail 131 | 132 | ## Method Details 133 | 134 | ### getCreatedBy 135 | 136 | **Signature:** `getCreatedBy() : String` 137 | 138 | **Description:** Created by this user. 139 | 140 | **Returns:** 141 | 142 | Created by this user 143 | 144 | --- 145 | 146 | ### getCreationDate 147 | 148 | **Signature:** `getCreationDate() : Date` 149 | 150 | **Description:** The time of creation. 151 | 152 | **Returns:** 153 | 154 | time of creation. 155 | 156 | --- 157 | 158 | ### getGrandTotal 159 | 160 | **Signature:** `getGrandTotal() : SumItem` 161 | 162 | **Description:** Returns the sum-item representing the grandtotal for all items. 163 | 164 | **Returns:** 165 | 166 | sum-item for all items 167 | 168 | --- 169 | 170 | ### getItems 171 | 172 | **Signature:** `getItems() : FilteringCollection` 173 | 174 | **Description:** Returns the unsorted collection of items 175 | 176 | **Returns:** 177 | 178 | the unsorted collection of items 179 | 180 | --- 181 | 182 | ### getLastModified 183 | 184 | **Signature:** `getLastModified() : Date` 185 | 186 | **Description:** The last modification time. 187 | 188 | **Returns:** 189 | 190 | last modification time.. 191 | 192 | --- 193 | 194 | ### getModifiedBy 195 | 196 | **Signature:** `getModifiedBy() : String` 197 | 198 | **Description:** Last modified by this user. 199 | 200 | **Returns:** 201 | 202 | Last modified by this user 203 | 204 | --- 205 | 206 | ### getOrder 207 | 208 | **Signature:** `getOrder() : Order` 209 | 210 | **Description:** Returns the Order this object was created for. 211 | 212 | **Returns:** 213 | 214 | the Order this object was created for. 215 | 216 | --- 217 | 218 | ### getProductSubtotal 219 | 220 | **Signature:** `getProductSubtotal() : SumItem` 221 | 222 | **Description:** Returns the sum-item representing the subtotal for product items. 223 | 224 | **Returns:** 225 | 226 | sum-item for product items 227 | 228 | --- 229 | 230 | ### getServiceSubtotal 231 | 232 | **Signature:** `getServiceSubtotal() : SumItem` 233 | 234 | **Description:** Returns the sum-item representing the subtotal for service items such as shipping. 235 | 236 | **Returns:** 237 | 238 | sum-item for service items such as shipping 239 | 240 | --- ``` -------------------------------------------------------------------------------- /src/utils/utils.ts: -------------------------------------------------------------------------------- ```typescript 1 | /** 2 | * Utility functions for SFCC MCP Server 3 | * 4 | * This module contains helper functions for date formatting, file size conversion, 5 | * and other common operations used throughout the application. 6 | */ 7 | 8 | /** 9 | * Get current date in YYYYMMDD format 10 | * Used for filtering log files by date 11 | * 12 | * @returns Current date string in YYYYMMDD format 13 | */ 14 | export function getCurrentDate(): string { 15 | const now = new Date(); 16 | const year = now.getFullYear(); 17 | const month = String(now.getMonth() + 1).padStart(2, '0'); 18 | const day = String(now.getDate()).padStart(2, '0'); 19 | return `${year}${month}${day}`; 20 | } 21 | 22 | /** 23 | * Convert bytes to human-readable format 24 | * 25 | * @param bytes - Number of bytes to format 26 | * @returns Formatted string with appropriate unit (Bytes, KB, MB, GB) 27 | */ 28 | export function formatBytes(bytes: number): string { 29 | if (bytes === 0) {return '0 Bytes';} 30 | const k = 1024; 31 | const sizes = ['Bytes', 'KB', 'MB', 'GB']; 32 | const i = Math.floor(Math.log(bytes) / Math.log(k)); 33 | return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2)) } ${ sizes[i]}`; 34 | } 35 | 36 | /** 37 | * Parse log content into individual entries based on log level 38 | * Handles multi-line log entries properly by grouping lines that belong together 39 | * 40 | * @param content - Raw log file content 41 | * @param level - Log level to filter for (ERROR, WARN, INFO) 42 | * @returns Array of complete log entries 43 | */ 44 | export function parseLogEntries(content: string, level: string): string[] { 45 | const lines = content.split('\n'); 46 | const entries: string[] = []; 47 | let currentEntry = ''; 48 | 49 | for (const line of lines) { 50 | // Check if this line starts a new log entry for the specified level 51 | if (line.includes(`] ${level} `) && line.includes('GMT]')) { 52 | // Save the previous entry if it exists 53 | if (currentEntry) { 54 | entries.push(currentEntry.trim()); 55 | } 56 | // Start a new entry 57 | currentEntry = line; 58 | } else if (currentEntry && line.trim()) { 59 | // Add continuation lines to the current entry 60 | currentEntry += `\n${ line}`; 61 | } 62 | } 63 | 64 | // Don't forget the last entry 65 | if (currentEntry) { 66 | entries.push(currentEntry.trim()); 67 | } 68 | 69 | return entries; 70 | } 71 | 72 | /** 73 | * Extract timestamp from a log entry 74 | * @param logEntry - Complete log entry string 75 | * @returns Date object or null if timestamp cannot be parsed 76 | */ 77 | export function extractTimestampFromLogEntry(logEntry: string): Date | null { 78 | // Match pattern: [2025-08-19T10:30:00.000 GMT] or [2025-09-19 20:47:32.324 GMT] 79 | const timestampMatch = logEntry.match(/^\[(\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}\.\d{3}) GMT\]/); 80 | 81 | if (!timestampMatch) { 82 | return null; 83 | } 84 | 85 | try { 86 | // Normalize the timestamp format for parsing 87 | let timestampStr = timestampMatch[1]; 88 | 89 | // Convert space format to ISO format if needed 90 | if (timestampStr.includes(' ')) { 91 | timestampStr = timestampStr.replace(' ', 'T'); 92 | } 93 | 94 | // Parse the ISO timestamp (adding 'Z' for UTC) 95 | const date = new Date(`${timestampStr}Z`); 96 | 97 | // Check if the date is valid 98 | if (isNaN(date.getTime())) { 99 | return null; 100 | } 101 | 102 | return date; 103 | } catch { 104 | return null; 105 | } 106 | } 107 | 108 | /** 109 | * Extract unique error patterns from error log entries 110 | * Removes timestamps and common formatting to identify core error messages 111 | * 112 | * @param errors - Array of error log entries 113 | * @returns Array of unique error patterns (limited to top 10) 114 | */ 115 | export function extractUniqueErrors(errors: string[]): string[] { 116 | const patterns = new Set<string>(); 117 | 118 | for (const error of errors) { 119 | // Extract main error message after the class name 120 | // Pattern: [timestamp] ERROR ClassName - ErrorMessage 121 | const match = error.match(/] ERROR [^-]+ - (.+?)(?:\n|$)/); 122 | if (match) { 123 | patterns.add(match[1].trim()); 124 | } 125 | } 126 | 127 | return Array.from(patterns).slice(0, 10); // Limit to top 10 unique errors 128 | } 129 | 130 | /** 131 | * Normalize file path by removing leading slash if present 132 | * SFCC WebDAV sometimes returns paths with leading slashes that need to be handled 133 | * 134 | * @param filePath - File path that may have a leading slash 135 | * @returns Normalized file path without leading slash 136 | */ 137 | export function normalizeFilePath(filePath: string): string { 138 | return filePath.startsWith('/') ? filePath.substring(1) : filePath; 139 | } 140 | ``` -------------------------------------------------------------------------------- /src/clients/base/http-client.ts: -------------------------------------------------------------------------------- ```typescript 1 | /** 2 | * Base HTTP Client for SFCC API requests 3 | * 4 | * This module provides a foundation for making authenticated HTTP requests to SFCC APIs. 5 | * It handles common concerns like authentication, request/response formatting, and error handling. 6 | */ 7 | 8 | import { Logger } from '../../utils/logger.js'; 9 | 10 | /** 11 | * HTTP request options interface 12 | */ 13 | export interface HttpRequestOptions extends RequestInit { 14 | headers?: Record<string, string>; 15 | } 16 | 17 | /** 18 | * Base HTTP client for SFCC API communication 19 | */ 20 | export abstract class BaseHttpClient { 21 | protected baseUrl: string; 22 | protected logger: Logger; 23 | 24 | constructor(baseUrl: string, loggerContext: string) { 25 | this.baseUrl = baseUrl; 26 | this.logger = Logger.getChildLogger(loggerContext); 27 | } 28 | 29 | /** 30 | * Get authentication headers - must be implemented by subclasses 31 | */ 32 | protected abstract getAuthHeaders(): Promise<Record<string, string>>; 33 | 34 | /** 35 | * Handle authentication errors - can be overridden by subclasses 36 | */ 37 | protected async handleAuthError(): Promise<void> { 38 | // Default implementation does nothing 39 | // Subclasses can override to clear tokens, retry, etc. 40 | } 41 | 42 | /** 43 | * Make an authenticated HTTP request 44 | */ 45 | protected async makeRequest<T>( 46 | endpoint: string, 47 | options: HttpRequestOptions = {}, 48 | ): Promise<T> { 49 | const url = `${this.baseUrl}${endpoint}`; 50 | const method = options.method ?? 'GET'; 51 | 52 | this.logger.debug(`Making ${method} request to: ${endpoint}`); 53 | 54 | // Get authentication headers 55 | const authHeaders = await this.getAuthHeaders(); 56 | 57 | const requestOptions: RequestInit = { 58 | ...options, 59 | headers: { 60 | 'Content-Type': 'application/json', 61 | ...authHeaders, 62 | ...options.headers, 63 | }, 64 | }; 65 | 66 | try { 67 | const response = await fetch(url, requestOptions); 68 | 69 | if (!response.ok) { 70 | // Handle authentication errors 71 | if (response.status === 401) { 72 | this.logger.debug('Received 401, attempting to handle auth error'); 73 | await this.handleAuthError(); 74 | 75 | // Retry with fresh authentication 76 | const newAuthHeaders = await this.getAuthHeaders(); 77 | requestOptions.headers = { 78 | ...requestOptions.headers, 79 | ...newAuthHeaders, 80 | }; 81 | 82 | const retryResponse = await fetch(url, requestOptions); 83 | if (!retryResponse.ok) { 84 | const errorText = await retryResponse.text(); 85 | throw new Error( 86 | `Request failed after retry: ${retryResponse.status} ${retryResponse.statusText} - ${errorText}`, 87 | ); 88 | } 89 | 90 | this.logger.debug('Retry request successful'); 91 | return retryResponse.json(); 92 | } 93 | 94 | const errorText = await response.text(); 95 | throw new Error(`Request failed: ${response.status} ${response.statusText} - ${errorText}`); 96 | } 97 | 98 | this.logger.debug(`Request to ${endpoint} completed successfully`); 99 | return response.json(); 100 | } catch (error) { 101 | this.logger.error(`Network error during request to ${endpoint}: ${error}`); 102 | throw error; 103 | } 104 | } 105 | 106 | /** 107 | * GET request 108 | */ 109 | protected async get<T>(endpoint: string): Promise<T> { 110 | return this.makeRequest<T>(endpoint, { method: 'GET' }); 111 | } 112 | 113 | /** 114 | * POST request 115 | */ 116 | protected async post<T>(endpoint: string, data?: any): Promise<T> { 117 | const options: HttpRequestOptions = { method: 'POST' }; 118 | if (data) { 119 | options.body = JSON.stringify(data); 120 | } 121 | return this.makeRequest<T>(endpoint, options); 122 | } 123 | 124 | /** 125 | * PUT request 126 | */ 127 | protected async put<T>(endpoint: string, data?: any): Promise<T> { 128 | const options: HttpRequestOptions = { method: 'PUT' }; 129 | if (data) { 130 | options.body = JSON.stringify(data); 131 | } 132 | return this.makeRequest<T>(endpoint, options); 133 | } 134 | 135 | /** 136 | * PATCH request 137 | */ 138 | protected async patch<T>(endpoint: string, data?: any): Promise<T> { 139 | const options: HttpRequestOptions = { method: 'PATCH' }; 140 | if (data) { 141 | options.body = JSON.stringify(data); 142 | } 143 | return this.makeRequest<T>(endpoint, options); 144 | } 145 | 146 | /** 147 | * DELETE request 148 | */ 149 | protected async delete<T>(endpoint: string): Promise<T> { 150 | return this.makeRequest<T>(endpoint, { method: 'DELETE' }); 151 | } 152 | } 153 | ``` -------------------------------------------------------------------------------- /docs/dw_extensions.pinterest/PinterestOrder.md: -------------------------------------------------------------------------------- ```markdown 1 | ## Package: dw.extensions.pinterest 2 | 3 | # Class PinterestOrder 4 | 5 | ## Inheritance Hierarchy 6 | 7 | - Object 8 | - dw.extensions.pinterest.PinterestOrder 9 | 10 | ## Description 11 | 12 | An order that was placed through Pinterest. 13 | 14 | ## Constants 15 | 16 | ### PAYMENT_STATUS_NOT_PAID 17 | 18 | **Type:** String = "NOT_PAID" 19 | 20 | Indicates that payment has not been made. 21 | 22 | ### PAYMENT_STATUS_PAID 23 | 24 | **Type:** String = "PAID" 25 | 26 | Indicates that payment is complete. 27 | 28 | ### PAYMENT_STATUS_PART_PAID 29 | 30 | **Type:** String = "PART_PAID" 31 | 32 | Indicates that payment is incomplete. 33 | 34 | ### STATUS_BACKORDER 35 | 36 | **Type:** String = "BACKORDER" 37 | 38 | Indicates an order on backorder. 39 | 40 | ### STATUS_CANCELLED 41 | 42 | **Type:** String = "CANCELLED" 43 | 44 | Indicates an order that has been canceled. 45 | 46 | ### STATUS_DELIVERED 47 | 48 | **Type:** String = "DELIVERED" 49 | 50 | Indicates an order that has been delivered. 51 | 52 | ### STATUS_IN_PROGRESS 53 | 54 | **Type:** String = "IN_PROGRESS" 55 | 56 | Indicates an order in progress. 57 | 58 | ### STATUS_NEW 59 | 60 | **Type:** String = "NEW" 61 | 62 | Indicates a new order. 63 | 64 | ### STATUS_RETURNED 65 | 66 | **Type:** String = "RETURNED" 67 | 68 | Indicates an order that has been returned. 69 | 70 | ### STATUS_SHIPPED 71 | 72 | **Type:** String = "SHIPPED" 73 | 74 | Indicates an order that has shipped. 75 | 76 | ## Properties 77 | 78 | ### itemId 79 | 80 | **Type:** String 81 | 82 | The item ID for this Pinterest order. 83 | 84 | ### orderNo 85 | 86 | **Type:** String (Read Only) 87 | 88 | The order number for this Pinterest order. This is the same as the order number of the Demandware order. 89 | 90 | ### paymentStatus 91 | 92 | **Type:** String 93 | 94 | The status of this Pinterest order. Possible values are 95 | PAYMENT_STATUS_PAID, 96 | PAYMENT_STATUS_NOT_PAID, 97 | or PAYMENT_STATUS_PART_PAID. 98 | 99 | ### status 100 | 101 | **Type:** String 102 | 103 | The status of this Pinterest order. Possible values are 104 | STATUS_NEW, 105 | STATUS_IN_PROGRESS, 106 | STATUS_SHIPPED, 107 | STATUS_BACKORDER, 108 | STATUS_CANCELLED, 109 | STATUS_DELIVERED, 110 | or STATUS_RETURNED. 111 | 112 | ## Constructor Summary 113 | 114 | ## Method Summary 115 | 116 | ### getItemId 117 | 118 | **Signature:** `getItemId() : String` 119 | 120 | Returns the item ID for this Pinterest order. 121 | 122 | ### getOrderNo 123 | 124 | **Signature:** `getOrderNo() : String` 125 | 126 | Returns the order number for this Pinterest order. 127 | 128 | ### getPaymentStatus 129 | 130 | **Signature:** `getPaymentStatus() : String` 131 | 132 | Returns the status of this Pinterest order. 133 | 134 | ### getStatus 135 | 136 | **Signature:** `getStatus() : String` 137 | 138 | Returns the status of this Pinterest order. 139 | 140 | ### setItemId 141 | 142 | **Signature:** `setItemId(itemId : String) : void` 143 | 144 | Sets the item ID for this Pinterest order. 145 | 146 | ### setPaymentStatus 147 | 148 | **Signature:** `setPaymentStatus(status : String) : void` 149 | 150 | Sets the status of this Pinterest order. 151 | 152 | ### setStatus 153 | 154 | **Signature:** `setStatus(status : String) : void` 155 | 156 | Sets the status of this Pinterest order. 157 | 158 | ## Method Detail 159 | 160 | ## Method Details 161 | 162 | ### getItemId 163 | 164 | **Signature:** `getItemId() : String` 165 | 166 | **Description:** Returns the item ID for this Pinterest order. 167 | 168 | --- 169 | 170 | ### getOrderNo 171 | 172 | **Signature:** `getOrderNo() : String` 173 | 174 | **Description:** Returns the order number for this Pinterest order. This is the same as the order number of the Demandware order. 175 | 176 | **Returns:** 177 | 178 | order number 179 | 180 | --- 181 | 182 | ### getPaymentStatus 183 | 184 | **Signature:** `getPaymentStatus() : String` 185 | 186 | **Description:** Returns the status of this Pinterest order. Possible values are PAYMENT_STATUS_PAID, PAYMENT_STATUS_NOT_PAID, or PAYMENT_STATUS_PART_PAID. 187 | 188 | --- 189 | 190 | ### getStatus 191 | 192 | **Signature:** `getStatus() : String` 193 | 194 | **Description:** Returns the status of this Pinterest order. Possible values are STATUS_NEW, STATUS_IN_PROGRESS, STATUS_SHIPPED, STATUS_BACKORDER, STATUS_CANCELLED, STATUS_DELIVERED, or STATUS_RETURNED. 195 | 196 | --- 197 | 198 | ### setItemId 199 | 200 | **Signature:** `setItemId(itemId : String) : void` 201 | 202 | **Description:** Sets the item ID for this Pinterest order. 203 | 204 | **Parameters:** 205 | 206 | - `itemId`: item ID 207 | 208 | --- 209 | 210 | ### setPaymentStatus 211 | 212 | **Signature:** `setPaymentStatus(status : String) : void` 213 | 214 | **Description:** Sets the status of this Pinterest order. Possible values are PAYMENT_STATUS_PAID, PAYMENT_STATUS_NOT_PAID, or PAYMENT_STATUS_PART_PAID. 215 | 216 | **Parameters:** 217 | 218 | - `status`: the status to set for this order 219 | 220 | --- 221 | 222 | ### setStatus 223 | 224 | **Signature:** `setStatus(status : String) : void` 225 | 226 | **Description:** Sets the status of this Pinterest order. Possible values are STATUS_NEW, STATUS_IN_PROGRESS, STATUS_SHIPPED, STATUS_BACKORDER, STATUS_CANCELLED, STATUS_DELIVERED, or STATUS_RETURNED. 227 | 228 | **Parameters:** 229 | 230 | - `status`: the status to set for this order 231 | 232 | --- ``` -------------------------------------------------------------------------------- /docs/dw_campaign/ApproachingDiscount.md: -------------------------------------------------------------------------------- ```markdown 1 | ## Package: dw.campaign 2 | 3 | # Class ApproachingDiscount 4 | 5 | ## Inheritance Hierarchy 6 | 7 | - Object 8 | - dw.campaign.ApproachingDiscount 9 | 10 | ## Description 11 | 12 | Transient class representing a discount that a LineItemCtnr "almost" qualifies for based on the amount of merchandise in it. Storefronts can display information about approaching discounts to customers in order to entice them to buy more merchandise. Approaching discounts are calculated on the basis of a DiscountPlan instead of a LineItemCtnr itself. When one of PromotionMgr.getDiscounts(LineItemCtnr) or PromotionMgr.getDiscounts(LineItemCtnr, PromotionPlan) is called, the promotions engine calculates the discounts the LineItemCtnr receives based on the promotions in context, and also tries to determine the discounts the LineItemCtnr would receive if additional merchandise were added. DiscountPlan provides different methods to retrieve this approaching discount info. Merchants can use these fine-grained methods to display information about approaching order discounts on the cart page, and approaching shipping discounts on the shipping method page during checkout, for example. The merchant may include or exclude individual promotions from being included in this list, and define distance thresholds when configuring their promotions. 13 | 14 | ## Properties 15 | 16 | ### conditionThreshold 17 | 18 | **Type:** Money (Read Only) 19 | 20 | The amount of merchandise required in the cart in order to receive the 21 | discount. For an order promotion "Get 15% off orders of $100 or more", 22 | the condition threshold is $100.00. 23 | 24 | ### discount 25 | 26 | **Type:** Discount (Read Only) 27 | 28 | The discount that the customer will receive if he adds more merchandise 29 | to the cart. For an order promotion "Get 15% off orders of $100 or more", 30 | the discount is a PercentageDiscount object. 31 | 32 | ### distanceFromConditionThreshold 33 | 34 | **Type:** Money (Read Only) 35 | 36 | Convenience method that returns 37 | getConditionThreshold().subtract(getMerchandiseValue()) 38 | 39 | ### merchandiseTotal 40 | 41 | **Type:** Money (Read Only) 42 | 43 | The amount of merchandise in the cart contributing towards the condition 44 | threshold. This will always be less than the condition threshold. 45 | 46 | ## Constructor Summary 47 | 48 | ## Method Summary 49 | 50 | ### getConditionThreshold 51 | 52 | **Signature:** `getConditionThreshold() : Money` 53 | 54 | The amount of merchandise required in the cart in order to receive the discount. 55 | 56 | ### getDiscount 57 | 58 | **Signature:** `getDiscount() : Discount` 59 | 60 | The discount that the customer will receive if he adds more merchandise to the cart. 61 | 62 | ### getDistanceFromConditionThreshold 63 | 64 | **Signature:** `getDistanceFromConditionThreshold() : Money` 65 | 66 | Convenience method that returns getConditionThreshold().subtract(getMerchandiseValue()) 67 | 68 | ### getMerchandiseTotal 69 | 70 | **Signature:** `getMerchandiseTotal() : Money` 71 | 72 | The amount of merchandise in the cart contributing towards the condition threshold. 73 | 74 | ## Method Detail 75 | 76 | ## Method Details 77 | 78 | ### getConditionThreshold 79 | 80 | **Signature:** `getConditionThreshold() : Money` 81 | 82 | **Description:** The amount of merchandise required in the cart in order to receive the discount. For an order promotion "Get 15% off orders of $100 or more", the condition threshold is $100.00. 83 | 84 | **Returns:** 85 | 86 | The amount of merchandise required in the cart in order to receive the discount. 87 | 88 | --- 89 | 90 | ### getDiscount 91 | 92 | **Signature:** `getDiscount() : Discount` 93 | 94 | **Description:** The discount that the customer will receive if he adds more merchandise to the cart. For an order promotion "Get 15% off orders of $100 or more", the discount is a PercentageDiscount object. 95 | 96 | **Returns:** 97 | 98 | The discount that the customer will receive if he adds more merchandise to the cart. 99 | 100 | --- 101 | 102 | ### getDistanceFromConditionThreshold 103 | 104 | **Signature:** `getDistanceFromConditionThreshold() : Money` 105 | 106 | **Description:** Convenience method that returns getConditionThreshold().subtract(getMerchandiseValue()) 107 | 108 | **Returns:** 109 | 110 | The amount of money needed to add to the order or shipment in order to receive the discount. 111 | 112 | --- 113 | 114 | ### getMerchandiseTotal 115 | 116 | **Signature:** `getMerchandiseTotal() : Money` 117 | 118 | **Description:** The amount of merchandise in the cart contributing towards the condition threshold. This will always be less than the condition threshold. 119 | 120 | **Returns:** 121 | 122 | The amount of merchandise in the cart contributing towards the condition threshold. 123 | 124 | --- ``` -------------------------------------------------------------------------------- /tests/mcp/yaml/get-job-execution-summary.full-mode.test.mcp.yml: -------------------------------------------------------------------------------- ```yaml 1 | --- 2 | description: "Test get_job_execution_summary tool in full mode (YAML/Aegis framework validation)" 3 | tests: 4 | # Core functionality - test basic success case with actual response format 5 | - it: "should retrieve job execution summary with proper structure" 6 | request: 7 | jsonrpc: "2.0" 8 | id: "job-summary-basic" 9 | method: "tools/call" 10 | params: 11 | name: "get_job_execution_summary" 12 | arguments: 13 | jobName: "ImportCatalog" 14 | expect: 15 | response: 16 | jsonrpc: "2.0" 17 | id: "job-summary-basic" 18 | result: 19 | content: 20 | match:arrayLength:1 21 | isError: false 22 | stderr: "toBeEmpty" 23 | performance: 24 | maxResponseTime: "2000ms" 25 | 26 | # Test response content format for existing job (based on aegis discovery) 27 | - it: "should return formatted execution summary with timing and status sections" 28 | request: 29 | jsonrpc: "2.0" 30 | id: "job-summary-format" 31 | method: "tools/call" 32 | params: 33 | name: "get_job_execution_summary" 34 | arguments: 35 | jobName: "ImportCatalog" 36 | expect: 37 | response: 38 | jsonrpc: "2.0" 39 | id: "job-summary-format" 40 | result: 41 | content: 42 | match:arrayElements: 43 | match:partial: 44 | type: "text" 45 | text: "match:regex:Job Execution Summary: ImportCatalog[\\s\\S]*⏱️ Timing:[\\s\\S]*📊 Status:" 46 | isError: false 47 | stderr: "toBeEmpty" 48 | performance: 49 | maxResponseTime: "2000ms" 50 | 51 | # Test non-existent job handling (based on aegis discovery) 52 | - it: "should handle non-existent job gracefully" 53 | request: 54 | jsonrpc: "2.0" 55 | id: "job-summary-nonexistent" 56 | method: "tools/call" 57 | params: 58 | name: "get_job_execution_summary" 59 | arguments: 60 | jobName: "NonExistentJob" 61 | expect: 62 | response: 63 | jsonrpc: "2.0" 64 | id: "job-summary-nonexistent" 65 | result: 66 | content: 67 | match:arrayElements: 68 | match:partial: 69 | type: "text" 70 | text: "match:contains:No job logs found for job name: NonExistentJob" 71 | isError: false 72 | stderr: "toBeEmpty" 73 | performance: 74 | maxResponseTime: "1500ms" 75 | 76 | # Essential error validation - missing parameter (based on aegis discovery) 77 | - it: "should return error for missing jobName parameter" 78 | request: 79 | jsonrpc: "2.0" 80 | id: "job-summary-missing-param" 81 | method: "tools/call" 82 | params: 83 | name: "get_job_execution_summary" 84 | arguments: {} 85 | expect: 86 | response: 87 | jsonrpc: "2.0" 88 | id: "job-summary-missing-param" 89 | result: 90 | content: 91 | match:arrayElements: 92 | match:partial: 93 | type: "text" 94 | text: "match:contains:Error: jobName must be a non-empty string" 95 | isError: true 96 | stderr: "toBeEmpty" 97 | performance: 98 | maxResponseTime: "800ms" 99 | 100 | # Essential error validation - empty string (based on aegis discovery) 101 | - it: "should return error for empty jobName parameter" 102 | request: 103 | jsonrpc: "2.0" 104 | id: "job-summary-empty-param" 105 | method: "tools/call" 106 | params: 107 | name: "get_job_execution_summary" 108 | arguments: 109 | jobName: "" 110 | expect: 111 | response: 112 | jsonrpc: "2.0" 113 | id: "job-summary-empty-param" 114 | result: 115 | content: 116 | match:arrayElements: 117 | match:partial: 118 | type: "text" 119 | text: "match:contains:Error: jobName must be a non-empty string" 120 | isError: true 121 | stderr: "toBeEmpty" 122 | performance: 123 | maxResponseTime: "800ms" 124 | 125 | # Test response structure consistency 126 | - it: "should return consistent MCP response structure" 127 | request: 128 | jsonrpc: "2.0" 129 | id: "job-summary-structure" 130 | method: "tools/call" 131 | params: 132 | name: "get_job_execution_summary" 133 | arguments: 134 | jobName: "ImportCatalog" 135 | expect: 136 | response: 137 | jsonrpc: "2.0" 138 | id: "job-summary-structure" 139 | result: 140 | content: 141 | match:arrayElements: 142 | match:partial: 143 | type: "text" 144 | text: "match:type:string" 145 | isError: "match:type:boolean" 146 | stderr: "toBeEmpty" 147 | performance: 148 | maxResponseTime: "2000ms" 149 | ``` -------------------------------------------------------------------------------- /docs/dw_order/InvoiceItem.md: -------------------------------------------------------------------------------- ```markdown 1 | ## Package: dw.order 2 | 3 | # Class InvoiceItem 4 | 5 | ## Inheritance Hierarchy 6 | 7 | - Object 8 | - dw.object.Extensible 9 | - dw.order.AbstractItem 10 | - dw.order.InvoiceItem 11 | 12 | ## Description 13 | 14 | Represents a specific item in an Invoice. Invoice items are added to the invoice on its creation, each item references exactly one order-item. Order post-processing APIs (gillian) are now inactive by default and will throw an exception if accessed. Activation needs preliminary approval by Product Management. Please contact support in this case. Existing customers using these APIs are not affected by this change and can use the APIs until further notice. 15 | 16 | ## Properties 17 | 18 | ### basePrice 19 | 20 | **Type:** Money (Read Only) 21 | 22 | Price of a single unit before discount application. 23 | 24 | ### capturedAmount 25 | 26 | **Type:** Money 27 | 28 | The captured amount for this item. 29 | 30 | ### invoiceNumber 31 | 32 | **Type:** String (Read Only) 33 | 34 | The number of the invoice to which this item belongs. 35 | 36 | ### parentItem 37 | 38 | **Type:** InvoiceItem 39 | 40 | Returns null or the parent item. 41 | 42 | ### quantity 43 | 44 | **Type:** Quantity (Read Only) 45 | 46 | The quantity of this item. 47 | 48 | ### refundedAmount 49 | 50 | **Type:** Money 51 | 52 | The refunded amount for this item. 53 | 54 | ## Constructor Summary 55 | 56 | ## Method Summary 57 | 58 | ### getBasePrice 59 | 60 | **Signature:** `getBasePrice() : Money` 61 | 62 | Price of a single unit before discount application. 63 | 64 | ### getCapturedAmount 65 | 66 | **Signature:** `getCapturedAmount() : Money` 67 | 68 | Returns the captured amount for this item. 69 | 70 | ### getInvoiceNumber 71 | 72 | **Signature:** `getInvoiceNumber() : String` 73 | 74 | Returns the number of the invoice to which this item belongs. 75 | 76 | ### getParentItem 77 | 78 | **Signature:** `getParentItem() : InvoiceItem` 79 | 80 | Returns null or the parent item. 81 | 82 | ### getQuantity 83 | 84 | **Signature:** `getQuantity() : Quantity` 85 | 86 | Returns the quantity of this item. 87 | 88 | ### getRefundedAmount 89 | 90 | **Signature:** `getRefundedAmount() : Money` 91 | 92 | Returns the refunded amount for this item. 93 | 94 | ### setCapturedAmount 95 | 96 | **Signature:** `setCapturedAmount(capturedAmount : Money) : void` 97 | 98 | Updates the captured amount for this item. 99 | 100 | ### setParentItem 101 | 102 | **Signature:** `setParentItem(parentItem : InvoiceItem) : void` 103 | 104 | Set a parent item. 105 | 106 | ### setRefundedAmount 107 | 108 | **Signature:** `setRefundedAmount(refundedAmount : Money) : void` 109 | 110 | Updates the refunded amount for this item. 111 | 112 | ## Method Detail 113 | 114 | ## Method Details 115 | 116 | ### getBasePrice 117 | 118 | **Signature:** `getBasePrice() : Money` 119 | 120 | **Description:** Price of a single unit before discount application. 121 | 122 | **Returns:** 123 | 124 | Price of a single unit before discount application. 125 | 126 | --- 127 | 128 | ### getCapturedAmount 129 | 130 | **Signature:** `getCapturedAmount() : Money` 131 | 132 | **Description:** Returns the captured amount for this item. 133 | 134 | **Returns:** 135 | 136 | the captured amount for this item 137 | 138 | --- 139 | 140 | ### getInvoiceNumber 141 | 142 | **Signature:** `getInvoiceNumber() : String` 143 | 144 | **Description:** Returns the number of the invoice to which this item belongs. 145 | 146 | **Returns:** 147 | 148 | the number of the invoice to which this item belongs 149 | 150 | --- 151 | 152 | ### getParentItem 153 | 154 | **Signature:** `getParentItem() : InvoiceItem` 155 | 156 | **Description:** Returns null or the parent item. 157 | 158 | **Returns:** 159 | 160 | null or the parent item. 161 | 162 | --- 163 | 164 | ### getQuantity 165 | 166 | **Signature:** `getQuantity() : Quantity` 167 | 168 | **Description:** Returns the quantity of this item. 169 | 170 | **Returns:** 171 | 172 | quantity of this item 173 | 174 | --- 175 | 176 | ### getRefundedAmount 177 | 178 | **Signature:** `getRefundedAmount() : Money` 179 | 180 | **Description:** Returns the refunded amount for this item. 181 | 182 | **Returns:** 183 | 184 | the refunded amount for this item 185 | 186 | --- 187 | 188 | ### setCapturedAmount 189 | 190 | **Signature:** `setCapturedAmount(capturedAmount : Money) : void` 191 | 192 | **Description:** Updates the captured amount for this item. 193 | 194 | **Parameters:** 195 | 196 | - `capturedAmount`: the captured amount for this item 197 | 198 | --- 199 | 200 | ### setParentItem 201 | 202 | **Signature:** `setParentItem(parentItem : InvoiceItem) : void` 203 | 204 | **Description:** Set a parent item. The parent item must belong to the same Invoice. An infinite parent-child loop is disallowed as is a parent-child depth greater than 10. Setting a parent item indicates a dependency of the child item on the parent item, and can be used to form a parallel structure to that accessed using ProductLineItem.getParent(). 205 | 206 | **Parameters:** 207 | 208 | - `parentItem`: The parent item, null is allowed 209 | 210 | --- 211 | 212 | ### setRefundedAmount 213 | 214 | **Signature:** `setRefundedAmount(refundedAmount : Money) : void` 215 | 216 | **Description:** Updates the refunded amount for this item. 217 | 218 | **Parameters:** 219 | 220 | - `refundedAmount`: the refunded amount for this item 221 | 222 | --- ``` -------------------------------------------------------------------------------- /docs/dw_order/PaymentMgr.md: -------------------------------------------------------------------------------- ```markdown 1 | ## Package: dw.order 2 | 3 | # Class PaymentMgr 4 | 5 | ## Inheritance Hierarchy 6 | 7 | - Object 8 | - dw.order.PaymentMgr 9 | 10 | ## Description 11 | 12 | PaymentMgr is used to access payment methods and payment cards of the current site. To access payment methods and payment cards explicitly, use methods getPaymentMethod(String) and getPaymentCard(String). To access active payment methods use method getActivePaymentMethods(). To access applicable payment methods for a customer, country and/or payment amount use method getApplicablePaymentMethods(Customer, String, Number). 13 | 14 | ## Properties 15 | 16 | ### activePaymentMethods 17 | 18 | **Type:** List (Read Only) 19 | 20 | The sorted list of all enabled payment methods of the current 21 | site, regardless of any customer group, country, payment amount or currency 22 | restrictions. The payment methods are sorted as defined in the Business 23 | Manager. 24 | 25 | ## Constructor Summary 26 | 27 | ## Method Summary 28 | 29 | ### getActivePaymentMethods 30 | 31 | **Signature:** `static getActivePaymentMethods() : List` 32 | 33 | Returns the sorted list of all enabled payment methods of the current site, regardless of any customer group, country, payment amount or currency restrictions. 34 | 35 | ### getApplicablePaymentMethods 36 | 37 | **Signature:** `static getApplicablePaymentMethods(customer : Customer, countryCode : String, paymentAmount : Number) : List` 38 | 39 | Returns the sorted list of all enabled payment methods of the current site applicable for the session currency, specified customer, country and payment amount. 40 | 41 | ### getPaymentCard 42 | 43 | **Signature:** `static getPaymentCard(cardType : String) : PaymentCard` 44 | 45 | Returns the payment card for the specified cardType or null if no such card exists in the current site. 46 | 47 | ### getPaymentMethod 48 | 49 | **Signature:** `static getPaymentMethod(id : String) : PaymentMethod` 50 | 51 | Returns the payment method for the specified ID or null if no such method exists in the current site. 52 | 53 | ## Method Detail 54 | 55 | ## Method Details 56 | 57 | ### getActivePaymentMethods 58 | 59 | **Signature:** `static getActivePaymentMethods() : List` 60 | 61 | **Description:** Returns the sorted list of all enabled payment methods of the current site, regardless of any customer group, country, payment amount or currency restrictions. The payment methods are sorted as defined in the Business Manager. 62 | 63 | **Returns:** 64 | 65 | List of enabled payment methods of current site 66 | 67 | --- 68 | 69 | ### getApplicablePaymentMethods 70 | 71 | **Signature:** `static getApplicablePaymentMethods(customer : Customer, countryCode : String, paymentAmount : Number) : List` 72 | 73 | **Description:** Returns the sorted list of all enabled payment methods of the current site applicable for the session currency, specified customer, country and payment amount. The payment methods are sorted as defined in the Business Manager. A payment method is applicable if the method is restricted by customer group, and at least one of the groups of the specified customer is assigned to the method the method is restricted by billing country, and the specified country code is assigned to the method the method is restricted by payment amount for the session currency, and the specified payment amount is within the limits of the min/max payment amount defined for the method and the session currency the method is restricted by currency code, and the specified currency code matches session currency. All parameters are optional, and if not specified, the respective restriction won't be validated. For example, if a method is restricted by billing country, but no country code is specified, this method will be returned, unless it is filtered out by customer group or payment amount. 74 | 75 | **Parameters:** 76 | 77 | - `customer`: Customer or null 78 | - `countryCode`: Billing country code or null 79 | - `paymentAmount`: Payment amount or null 80 | 81 | **Returns:** 82 | 83 | List of applicable payment methods of current site 84 | 85 | --- 86 | 87 | ### getPaymentCard 88 | 89 | **Signature:** `static getPaymentCard(cardType : String) : PaymentCard` 90 | 91 | **Description:** Returns the payment card for the specified cardType or null if no such card exists in the current site. 92 | 93 | **Parameters:** 94 | 95 | - `cardType`: PaymentCard type 96 | 97 | **Returns:** 98 | 99 | PaymentCard or null 100 | 101 | --- 102 | 103 | ### getPaymentMethod 104 | 105 | **Signature:** `static getPaymentMethod(id : String) : PaymentMethod` 106 | 107 | **Description:** Returns the payment method for the specified ID or null if no such method exists in the current site. 108 | 109 | **Parameters:** 110 | 111 | - `id`: PaymentMethod ID 112 | 113 | **Returns:** 114 | 115 | PaymentMethod or null 116 | 117 | --- ``` -------------------------------------------------------------------------------- /docs/sfra/account.md: -------------------------------------------------------------------------------- ```markdown 1 | # SFRA Account Model 2 | 3 | ## Overview 4 | 5 | The Account model represents a customer's profile dashboard, containing profile information, addresses, payment instruments, and order history. It provides methods for handling customer account data in SFRA applications. 6 | 7 | ## Constructor 8 | 9 | ```javascript 10 | function account(currentCustomer, addressModel, orderModel) 11 | ``` 12 | 13 | Creates an Account model instance that represents the current customer's profile dashboard. 14 | 15 | ### Parameters 16 | 17 | - `currentCustomer` (Object) - Current customer object 18 | - `addressModel` (Object) - The current customer's preferred address 19 | - `orderModel` (Object) - The current customer's order history 20 | 21 | ## Properties 22 | 23 | ### profile 24 | **Type:** Object | null 25 | 26 | Contains the customer's profile information including: 27 | - `firstName` (string) - Customer's first name 28 | - `lastName` (string) - Customer's last name 29 | - `email` (string) - Customer's email address 30 | - `phone` (string) - Customer's phone number 31 | - `password` (string) - Masked password (always "********") 32 | 33 | ### addresses 34 | **Type:** Array<Object> 35 | 36 | Array of customer's address book addresses. Each address object contains standard address fields. 37 | 38 | ### preferredAddress 39 | **Type:** Object | null 40 | 41 | The customer's preferred/default address from their address book. 42 | 43 | ### orderHistory 44 | **Type:** Object 45 | 46 | The customer's order history information. 47 | 48 | ### payment 49 | **Type:** Object | null 50 | 51 | Primary payment instrument information including: 52 | - `maskedCreditCardNumber` (string) - Masked card number 53 | - `creditCardType` (string) - Type of credit card 54 | - `creditCardExpirationMonth` (number) - Expiration month 55 | - `creditCardExpirationYear` (number) - Expiration year 56 | 57 | ### registeredUser 58 | **Type:** boolean 59 | 60 | Indicates if the customer is both authenticated and registered. 61 | 62 | ### isExternallyAuthenticated 63 | **Type:** boolean 64 | 65 | Indicates if the customer is authenticated through an external provider. 66 | 67 | ### customerPaymentInstruments 68 | **Type:** Array<Object> | null 69 | 70 | Array of customer's saved payment instruments. Each payment instrument contains: 71 | - `creditCardHolder` (string) - Name on the credit card 72 | - `maskedCreditCardNumber` (string) - Masked card number 73 | - `creditCardType` (string) - Type of credit card 74 | - `creditCardExpirationMonth` (number) - Expiration month 75 | - `creditCardExpirationYear` (number) - Expiration year 76 | - `UUID` (string) - Unique identifier 77 | - `cardTypeImage` (Object) - Image source and alt text for card type 78 | - `src` (string) - Image source URL 79 | - `alt` (string) - Alt text for the image 80 | 81 | ## Helper Functions 82 | 83 | ### getProfile(profile) 84 | Creates a plain object containing profile information. 85 | 86 | **Parameters:** 87 | - `profile` (Object) - Customer's profile object 88 | 89 | **Returns:** Object | null - Profile information or null if no profile 90 | 91 | ### getAddresses(addressBook) 92 | Creates an array of address objects from the customer's address book. 93 | 94 | **Parameters:** 95 | - `addressBook` (Object) - Customer's address book 96 | 97 | **Returns:** Array<Object> - Array of address objects 98 | 99 | ### getPreferredAddress(addressBook) 100 | Gets the customer's preferred address. 101 | 102 | **Parameters:** 103 | - `addressBook` (Object) - Customer's address book 104 | 105 | **Returns:** Object | null - Preferred address or null 106 | 107 | ### getPayment(wallet) 108 | Gets the primary payment instrument information. 109 | 110 | **Parameters:** 111 | - `wallet` (Object) - Customer's wallet containing payment instruments 112 | 113 | **Returns:** Object | null - Payment instrument information or null 114 | 115 | ### getCustomerPaymentInstruments(userPaymentInstruments) 116 | Creates an array of payment instrument objects with card type images. 117 | 118 | **Parameters:** 119 | - `userPaymentInstruments` (Array) - Array of customer's payment instruments 120 | 121 | **Returns:** Array<Object> - Array of formatted payment instruments 122 | 123 | ## Usage Example 124 | 125 | ```javascript 126 | var AccountModel = require('*/cartridge/models/account'); 127 | var currentCustomer = customer; 128 | var addressModel = null; // or specific address model 129 | var orderModel = getOrderHistory(); 130 | 131 | var account = new AccountModel(currentCustomer, addressModel, orderModel); 132 | 133 | // Access account properties 134 | console.log(account.profile.email); 135 | console.log(account.addresses.length); 136 | console.log(account.registeredUser); 137 | console.log(account.customerPaymentInstruments); 138 | console.log(account.payment); 139 | ``` 140 | 141 | ## Related Models 142 | 143 | - **Address Model** - Used for address formatting 144 | - **Order Model** - Used for order history 145 | - **Payment Models** - Used for payment instrument handling 146 | ``` -------------------------------------------------------------------------------- /docs/sfra/locale.md: -------------------------------------------------------------------------------- ```markdown 1 | # SFRA Locale Model 2 | 3 | ## Overview 4 | 5 | The Locale model represents current locale information and provides locale switching functionality for internationalized SFRA applications. It manages country codes, currency codes, language settings, and available locale options for site visitors. 6 | 7 | ## Constructor 8 | 9 | ```javascript 10 | function Locale(currentLocale, allowedLocales, siteId) 11 | ``` 12 | 13 | Creates a Locale model instance with current locale information and available locale options. 14 | 15 | ### Parameters 16 | 17 | - `currentLocale` (dw.util.Locale) - Current locale of the request 18 | - `allowedLocales` (string) - List of allowed locales for the site 19 | - `siteId` (string) - ID of the current site 20 | 21 | ## Properties 22 | 23 | ### locale 24 | **Type:** Object 25 | 26 | Object containing comprehensive locale information: 27 | 28 | - `countryCode` (string) - Country code for the current locale 29 | - `name` (string) - Display name of the country 30 | - `currencyCode` (string) - Currency code for the locale 31 | - `displayName` (string) - Full display name of the locale 32 | - `language` (string) - Language code 33 | - `displayLanguage` (string) - Display name of the language 34 | - `localeLinks` (Array<Object>) - Available locale options for switching 35 | - `localLinks` (Array<Object>) - **Deprecated** - Same as localeLinks (kept for backward compatibility) 36 | 37 | ### Locale Link Objects 38 | 39 | Each object in `localeLinks` contains: 40 | - `localID` (string) - Locale identifier 41 | - `country` (string) - Country code 42 | - `displayCountry` (string) - Country display name 43 | - `currencyCode` (string) - Currency code for the locale 44 | - `displayName` (string) - Full locale display name 45 | - `language` (string) - Language code 46 | - `displayLanguage` (string) - Language display name 47 | 48 | ## Helper Functions 49 | 50 | ### getLocaleLinks(allowedLocales, siteId, currentLocaleID) 51 | Returns available locale options for site locale switching. 52 | 53 | **Parameters:** 54 | - `allowedLocales` (string) - List of allowed locales for the site 55 | - `siteId` (string) - Current site ID 56 | - `currentLocaleID` (string) - Current locale ID 57 | 58 | **Returns:** Array<Object> - Array of available locale options (excluding current locale) 59 | 60 | ### isLocaleValid(currentLocale) 61 | Validates that a locale object is properly formed. 62 | 63 | **Parameters:** 64 | - `currentLocale` (dw.util.Locale) - Locale to validate 65 | 66 | **Returns:** boolean - True if locale has required ID property 67 | 68 | ## Usage Example 69 | 70 | ```javascript 71 | var LocaleModel = require('*/cartridge/models/locale'); 72 | var Site = require('dw/system/Site'); 73 | 74 | var currentLocale = request.getLocale(); 75 | var allowedLocales = Site.getCurrent().getAllowedLocales(); 76 | var siteId = Site.getCurrent().getID(); 77 | 78 | var localeModel = new LocaleModel(currentLocale, allowedLocales, siteId); 79 | 80 | // Access current locale information 81 | console.log(localeModel.locale.countryCode); // "US" 82 | console.log(localeModel.locale.currencyCode); // "USD" 83 | console.log(localeModel.locale.displayLanguage); // "English" 84 | 85 | // Access available locale options 86 | localeModel.locale.localeLinks.forEach(function(link) { 87 | console.log(link.displayName + ' (' + link.currencyCode + ')'); 88 | // Output: "English (United Kingdom) (GBP)", "Français (France) (EUR)", etc. 89 | }); 90 | ``` 91 | 92 | ## Backward Compatibility 93 | 94 | The model includes both `localeLinks` and `localLinks` properties: 95 | - **localeLinks** - Correct property name (use this) 96 | - **localLinks** - Deprecated typo maintained for backward compatibility 97 | 98 | **Note**: The SFRA team plans to remove the `localLinks` property in a future version. 99 | 100 | ## Fallback Handling 101 | 102 | If the current locale is invalid or missing: 103 | - Falls back to the first country in the countries configuration 104 | - Ensures the model always has valid locale information 105 | - Prevents errors in locale-dependent functionality 106 | 107 | ## Integration with Countries Configuration 108 | 109 | The model relies on a countries configuration file (`*/cartridge/config/countries`) that defines: 110 | - Available countries and locales 111 | - Currency codes for each locale 112 | - Locale-specific configurations 113 | 114 | ## Notes 115 | 116 | - Excludes the current locale from the locale switching links 117 | - Provides comprehensive locale information for internationalization 118 | - Handles invalid locales gracefully with fallbacks 119 | - Supports multi-currency and multi-language sites 120 | - Integrates with SFCC's built-in locale system 121 | 122 | ## Related Models 123 | 124 | - **Site Configuration** - Defines allowed locales 125 | - **Currency Models** - May use currency information 126 | - **Address Models** - May use country information for formatting 127 | ``` -------------------------------------------------------------------------------- /docs/dw_crypto/CertificateUtils.md: -------------------------------------------------------------------------------- ```markdown 1 | ## Package: dw.crypto 2 | 3 | # Class CertificateUtils 4 | 5 | ## Inheritance Hierarchy 6 | 7 | - Object 8 | - dw.crypto.CertificateUtils 9 | 10 | ## Description 11 | 12 | Utilities for managing certificates and keys. 13 | 14 | ## Constructor Summary 15 | 16 | CertificateUtils() 17 | 18 | ## Method Summary 19 | 20 | ### getCertificate 21 | 22 | **Signature:** `static getCertificate(certificateRef : CertificateRef) : X509Certificate` 23 | 24 | Gets the certificate from the given certificate reference. 25 | 26 | ### getCertificate 27 | 28 | **Signature:** `static getCertificate(keyRef : KeyRef) : X509Certificate` 29 | 30 | Gets the public certificate from the given private key reference. 31 | 32 | ### getEncodedCertificate 33 | 34 | **Signature:** `static getEncodedCertificate(certificateRef : CertificateRef) : String` 35 | 36 | Encode the certificate to the base64-encoded DER format. 37 | 38 | ### getEncodedPublicKey 39 | 40 | **Signature:** `static getEncodedPublicKey(certificateRef : CertificateRef) : String` 41 | 42 | Gets the public key from the given certificate reference. 43 | 44 | ### parseEncodedCertificate 45 | 46 | **Signature:** `static parseEncodedCertificate(certificate : String) : CertificateRef` 47 | 48 | Parse the certificate from the base64-encoded DER format. 49 | 50 | ### parseEncodedPublicKey 51 | 52 | **Signature:** `static parseEncodedPublicKey(algorithm : String, encodedKey : String) : CertificateRef` 53 | 54 | Parse the public key from the given key in X.509 SubjectPublicKeyInfo format. 55 | 56 | ### parsePublicKeyFromJWK 57 | 58 | **Signature:** `static parsePublicKeyFromJWK(jwk : String) : CertificateRef` 59 | 60 | Parse the public key from the given base64-encoded JWK string. 61 | 62 | ## Constructor Detail 63 | 64 | ## Method Detail 65 | 66 | ## Method Details 67 | 68 | ### getCertificate 69 | 70 | **Signature:** `static getCertificate(certificateRef : CertificateRef) : X509Certificate` 71 | 72 | **Description:** Gets the certificate from the given certificate reference. 73 | 74 | **Parameters:** 75 | 76 | - `certificateRef`: the certificate reference 77 | 78 | **Returns:** 79 | 80 | The X509Certificate 81 | 82 | **Throws:** 83 | 84 | Exception - if the reference is invalid or does not refer to an X.509 certificate 85 | 86 | --- 87 | 88 | ### getCertificate 89 | 90 | **Signature:** `static getCertificate(keyRef : KeyRef) : X509Certificate` 91 | 92 | **Description:** Gets the public certificate from the given private key reference. 93 | 94 | **Parameters:** 95 | 96 | - `keyRef`: the key reference 97 | 98 | **Returns:** 99 | 100 | The X509Certificate 101 | 102 | **Throws:** 103 | 104 | Exception - if the reference is invalid or there is no X.509 certificate 105 | 106 | --- 107 | 108 | ### getEncodedCertificate 109 | 110 | **Signature:** `static getEncodedCertificate(certificateRef : CertificateRef) : String` 111 | 112 | **Description:** Encode the certificate to the base64-encoded DER format. 113 | 114 | **Parameters:** 115 | 116 | - `certificateRef`: the certificate to encode 117 | 118 | **Returns:** 119 | 120 | base64-encoded DER certificate 121 | 122 | --- 123 | 124 | ### getEncodedPublicKey 125 | 126 | **Signature:** `static getEncodedPublicKey(certificateRef : CertificateRef) : String` 127 | 128 | **Description:** Gets the public key from the given certificate reference. It is exported in the standard X.509 SubjectPublicKeyInfo format and base64-encoded. 129 | 130 | **Parameters:** 131 | 132 | - `certificateRef`: the certificate reference with the public key to encode 133 | 134 | **Returns:** 135 | 136 | The encoded public key 137 | 138 | --- 139 | 140 | ### parseEncodedCertificate 141 | 142 | **Signature:** `static parseEncodedCertificate(certificate : String) : CertificateRef` 143 | 144 | **Description:** Parse the certificate from the base64-encoded DER format. 145 | 146 | **Parameters:** 147 | 148 | - `certificate`: The encoded certificate 149 | 150 | **Returns:** 151 | 152 | Reference to the parsed certificate 153 | 154 | --- 155 | 156 | ### parseEncodedPublicKey 157 | 158 | **Signature:** `static parseEncodedPublicKey(algorithm : String, encodedKey : String) : CertificateRef` 159 | 160 | **Description:** Parse the public key from the given key in X.509 SubjectPublicKeyInfo format. The resulting reference contains only the public key. It can be used for cryptographic operations, but not anything that requires the full certificate. 161 | 162 | **Parameters:** 163 | 164 | - `algorithm`: The public key algorithm, either EC or RSA 165 | - `encodedKey`: The encoded key 166 | 167 | **Returns:** 168 | 169 | Reference to the public key 170 | 171 | --- 172 | 173 | ### parsePublicKeyFromJWK 174 | 175 | **Signature:** `static parsePublicKeyFromJWK(jwk : String) : CertificateRef` 176 | 177 | **Description:** Parse the public key from the given base64-encoded JWK string. This returns the public key portion of the JWK, not the x5c certificate chain. Only RSA and EC keys are supported. The resulting reference contains only the public key. It can be used for cryptographic operations, but not anything that requires the full certificate. 178 | 179 | **Parameters:** 180 | 181 | - `jwk`: Encoded JWK 182 | 183 | **Returns:** 184 | 185 | Reference to the public key 186 | 187 | --- ``` -------------------------------------------------------------------------------- /docs-site/components/Sidebar.tsx: -------------------------------------------------------------------------------- ```typescript 1 | import React from 'react'; 2 | import { NavLink, useLocation } from 'react-router-dom'; 3 | import { NAVIGATION_LINKS } from '../constants'; 4 | import { NavGroup, NavItem } from '../types'; 5 | import Search from './Search'; 6 | import VersionBadge from './VersionBadge'; 7 | 8 | const Sidebar: React.FC = () => { 9 | const location = useLocation(); 10 | 11 | const isLinkActive = (path: string) => { 12 | if (path === '/') return location.pathname === '/'; 13 | // Normalize paths to have trailing slashes for comparison 14 | const normalizedLocationPath = location.pathname.endsWith('/') ? location.pathname : location.pathname + '/'; 15 | const normalizedPath = path.endsWith('/') ? path : path + '/'; 16 | return normalizedLocationPath === normalizedPath; 17 | } 18 | 19 | return ( 20 | <div className="h-full flex flex-col p-4 sm:p-6"> 21 | {/* Desktop header - hidden on mobile since we have it in Layout */} 22 | <div className="hidden lg:block mb-8"> 23 | <div className="flex items-center gap-2"> 24 | <span className="text-2xl font-bold text-slate-800">SFCC Dev</span> 25 | <span className="text-2xl font-light text-orange-500">MCP</span> 26 | </div> 27 | <div className="flex justify-start"> 28 | <VersionBadge /> 29 | </div> 30 | </div> 31 | 32 | {/* Mobile header spacing */} 33 | <div className="lg:hidden mb-6" /> 34 | 35 | <Search /> 36 | 37 | <nav className="flex-1 overflow-y-auto mt-4 sm:mt-6"> 38 | {NAVIGATION_LINKS.map((group: NavGroup) => ( 39 | <div key={group.title} className="mb-6"> 40 | <h2 className="text-xs font-bold text-slate-500 uppercase tracking-wider mb-3">{group.title}</h2> 41 | <ul> 42 | {group.items.map((item: NavItem) => ( 43 | <li key={item.path}> 44 | <NavLink 45 | to={item.path} 46 | className={`block py-2 px-3 text-sm rounded-md transition-colors ${ 47 | isLinkActive(item.path) 48 | ? 'text-orange-600 font-semibold bg-orange-50' 49 | : 'text-slate-600 hover:text-slate-900 hover:bg-slate-100' 50 | }`} 51 | > 52 | {item.label} 53 | </NavLink> 54 | </li> 55 | ))} 56 | </ul> 57 | </div> 58 | ))} 59 | </nav> 60 | 61 | {/* Links Section */} 62 | <div className="mt-4 pt-4 border-t border-slate-200"> 63 | <div className="flex justify-center gap-4"> 64 | <a 65 | href="https://www.rhino-inquisitor.com/" 66 | target="_blank" 67 | rel="noopener noreferrer" 68 | className="inline-flex items-center gap-2 px-3 py-2 text-sm text-slate-600 hover:text-slate-900 hover:bg-slate-100 rounded-md transition-colors" 69 | title="Rhino Inquisitor - Personal Site" 70 | > 71 | <img 72 | src="https://www.rhino-inquisitor.com/wp-content/uploads/2022/02/rhino-inquisitor.svg" 73 | alt="Rhino Inquisitor" 74 | className="w-5 h-6" 75 | /> 76 | <span>Blog</span> 77 | </a> 78 | <a 79 | href="https://github.com/taurgis/sfcc-dev-mcp" 80 | target="_blank" 81 | rel="noopener noreferrer" 82 | className="inline-flex items-center gap-2 px-3 py-2 text-sm text-slate-600 hover:text-slate-900 hover:bg-slate-100 rounded-md transition-colors" 83 | title="SFCC Dev MCP on GitHub" 84 | > 85 | <svg className="w-5 h-5" fill="currentColor" viewBox="0 0 20 20"> 86 | <path fillRule="evenodd" d="M10 0C4.477 0 0 4.484 0 10.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0110 4.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.203 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.942.359.31.678.921.678 1.856 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0020 10.017C20 4.484 15.522 0 10 0z" clipRule="evenodd" /> 87 | </svg> 88 | <span>GitHub</span> 89 | </a> 90 | </div> 91 | </div> 92 | </div> 93 | ); 94 | }; 95 | 96 | export default Sidebar; ```