This is page 7 of 61. Use http://codebase.md/taurgis/sfcc-dev-mcp?lines=true&page={x} to view the full context. # Directory Structure ``` ├── .DS_Store ├── .github │ ├── dependabot.yml │ ├── instructions │ │ ├── mcp-node-tests.instructions.md │ │ └── mcp-yml-tests.instructions.md │ ├── ISSUE_TEMPLATE │ │ ├── bug_report.yml │ │ ├── config.yml │ │ ├── documentation.yml │ │ ├── feature_request.yml │ │ └── question.yml │ ├── PULL_REQUEST_TEMPLATE │ │ ├── bug_fix.md │ │ ├── documentation.md │ │ └── new_tool.md │ ├── pull_request_template.md │ └── workflows │ ├── ci.yml │ ├── deploy-pages.yml │ ├── publish.yml │ └── update-docs.yml ├── .gitignore ├── .husky │ └── pre-commit ├── aegis.config.docs-only.json ├── aegis.config.json ├── aegis.config.with-dw.json ├── AGENTS.md ├── ai-instructions │ ├── claude-desktop │ │ └── claude_custom_instructions.md │ ├── cursor │ │ └── .cursor │ │ └── rules │ │ ├── debugging-workflows.mdc │ │ ├── hooks-development.mdc │ │ ├── isml-templates.mdc │ │ ├── job-framework.mdc │ │ ├── performance-optimization.mdc │ │ ├── scapi-endpoints.mdc │ │ ├── security-patterns.mdc │ │ ├── sfcc-development.mdc │ │ ├── sfra-controllers.mdc │ │ ├── sfra-models.mdc │ │ ├── system-objects.mdc │ │ └── testing-patterns.mdc │ └── github-copilot │ └── copilot-instructions.md ├── CHANGELOG.md ├── CONTRIBUTING.md ├── docs │ ├── best-practices │ │ ├── cartridge_creation.md │ │ ├── isml_templates.md │ │ ├── job_framework.md │ │ ├── localserviceregistry.md │ │ ├── ocapi_hooks.md │ │ ├── performance.md │ │ ├── scapi_custom_endpoint.md │ │ ├── scapi_hooks.md │ │ ├── security.md │ │ ├── sfra_client_side_js.md │ │ ├── sfra_controllers.md │ │ ├── sfra_models.md │ │ └── sfra_scss.md │ ├── dw_campaign │ │ ├── ABTest.md │ │ ├── ABTestMgr.md │ │ ├── ABTestSegment.md │ │ ├── AmountDiscount.md │ │ ├── ApproachingDiscount.md │ │ ├── BonusChoiceDiscount.md │ │ ├── BonusDiscount.md │ │ ├── Campaign.md │ │ ├── CampaignMgr.md │ │ ├── CampaignStatusCodes.md │ │ ├── Coupon.md │ │ ├── CouponMgr.md │ │ ├── CouponRedemption.md │ │ ├── CouponStatusCodes.md │ │ ├── Discount.md │ │ ├── DiscountPlan.md │ │ ├── FixedPriceDiscount.md │ │ ├── FixedPriceShippingDiscount.md │ │ ├── FreeDiscount.md │ │ ├── FreeShippingDiscount.md │ │ ├── PercentageDiscount.md │ │ ├── PercentageOptionDiscount.md │ │ ├── PriceBookPriceDiscount.md │ │ ├── Promotion.md │ │ ├── PromotionMgr.md │ │ ├── PromotionPlan.md │ │ ├── SlotContent.md │ │ ├── SourceCodeGroup.md │ │ ├── SourceCodeInfo.md │ │ ├── SourceCodeStatusCodes.md │ │ └── TotalFixedPriceDiscount.md │ ├── dw_catalog │ │ ├── Catalog.md │ │ ├── CatalogMgr.md │ │ ├── Category.md │ │ ├── CategoryAssignment.md │ │ ├── CategoryLink.md │ │ ├── PriceBook.md │ │ ├── PriceBookMgr.md │ │ ├── Product.md │ │ ├── ProductActiveData.md │ │ ├── ProductAttributeModel.md │ │ ├── ProductAvailabilityLevels.md │ │ ├── ProductAvailabilityModel.md │ │ ├── ProductInventoryList.md │ │ ├── ProductInventoryMgr.md │ │ ├── ProductInventoryRecord.md │ │ ├── ProductLink.md │ │ ├── ProductMgr.md │ │ ├── ProductOption.md │ │ ├── ProductOptionModel.md │ │ ├── ProductOptionValue.md │ │ ├── ProductPriceInfo.md │ │ ├── ProductPriceModel.md │ │ ├── ProductPriceTable.md │ │ ├── ProductSearchHit.md │ │ ├── ProductSearchModel.md │ │ ├── ProductSearchRefinementDefinition.md │ │ ├── ProductSearchRefinements.md │ │ ├── ProductSearchRefinementValue.md │ │ ├── ProductVariationAttribute.md │ │ ├── ProductVariationAttributeValue.md │ │ ├── ProductVariationModel.md │ │ ├── Recommendation.md │ │ ├── SearchModel.md │ │ ├── SearchRefinementDefinition.md │ │ ├── SearchRefinements.md │ │ ├── SearchRefinementValue.md │ │ ├── SortingOption.md │ │ ├── SortingRule.md │ │ ├── Store.md │ │ ├── StoreGroup.md │ │ ├── StoreInventoryFilter.md │ │ ├── StoreInventoryFilterValue.md │ │ ├── StoreMgr.md │ │ ├── Variant.md │ │ └── VariationGroup.md │ ├── dw_content │ │ ├── Content.md │ │ ├── ContentMgr.md │ │ ├── ContentSearchModel.md │ │ ├── ContentSearchRefinementDefinition.md │ │ ├── ContentSearchRefinements.md │ │ ├── ContentSearchRefinementValue.md │ │ ├── Folder.md │ │ ├── Library.md │ │ ├── MarkupText.md │ │ └── MediaFile.md │ ├── dw_crypto │ │ ├── CertificateRef.md │ │ ├── CertificateUtils.md │ │ ├── Cipher.md │ │ ├── Encoding.md │ │ ├── JWE.md │ │ ├── JWEHeader.md │ │ ├── JWS.md │ │ ├── JWSHeader.md │ │ ├── KeyRef.md │ │ ├── Mac.md │ │ ├── MessageDigest.md │ │ ├── SecureRandom.md │ │ ├── Signature.md │ │ ├── WeakCipher.md │ │ ├── WeakMac.md │ │ ├── WeakMessageDigest.md │ │ ├── WeakSignature.md │ │ └── X509Certificate.md │ ├── dw_customer │ │ ├── AddressBook.md │ │ ├── AgentUserMgr.md │ │ ├── AgentUserStatusCodes.md │ │ ├── AuthenticationStatus.md │ │ ├── Credentials.md │ │ ├── Customer.md │ │ ├── CustomerActiveData.md │ │ ├── CustomerAddress.md │ │ ├── CustomerCDPData.md │ │ ├── CustomerContextMgr.md │ │ ├── CustomerGroup.md │ │ ├── CustomerList.md │ │ ├── CustomerMgr.md │ │ ├── CustomerPasswordConstraints.md │ │ ├── CustomerPaymentInstrument.md │ │ ├── CustomerStatusCodes.md │ │ ├── EncryptedObject.md │ │ ├── ExternalProfile.md │ │ ├── OrderHistory.md │ │ ├── ProductList.md │ │ ├── ProductListItem.md │ │ ├── ProductListItemPurchase.md │ │ ├── ProductListMgr.md │ │ ├── ProductListRegistrant.md │ │ ├── Profile.md │ │ └── Wallet.md │ ├── dw_extensions.applepay │ │ ├── ApplePayHookResult.md │ │ └── ApplePayHooks.md │ ├── dw_extensions.facebook │ │ ├── FacebookFeedHooks.md │ │ └── FacebookProduct.md │ ├── dw_extensions.paymentrequest │ │ ├── PaymentRequestHookResult.md │ │ └── PaymentRequestHooks.md │ ├── dw_extensions.payments │ │ ├── SalesforceBancontactPaymentDetails.md │ │ ├── SalesforceCardPaymentDetails.md │ │ ├── SalesforceEpsPaymentDetails.md │ │ ├── SalesforceIdealPaymentDetails.md │ │ ├── SalesforceKlarnaPaymentDetails.md │ │ ├── SalesforcePaymentDetails.md │ │ ├── SalesforcePaymentIntent.md │ │ ├── SalesforcePaymentMethod.md │ │ ├── SalesforcePaymentRequest.md │ │ ├── SalesforcePaymentsHooks.md │ │ ├── SalesforcePaymentsMgr.md │ │ ├── SalesforcePaymentsSiteConfiguration.md │ │ ├── SalesforcePayPalOrder.md │ │ ├── SalesforcePayPalOrderAddress.md │ │ ├── SalesforcePayPalOrderPayer.md │ │ ├── SalesforcePayPalPaymentDetails.md │ │ ├── SalesforceSepaDebitPaymentDetails.md │ │ └── SalesforceVenmoPaymentDetails.md │ ├── dw_extensions.pinterest │ │ ├── PinterestAvailability.md │ │ ├── PinterestFeedHooks.md │ │ ├── PinterestOrder.md │ │ ├── PinterestOrderHooks.md │ │ └── PinterestProduct.md │ ├── dw_io │ │ ├── CSVStreamReader.md │ │ ├── CSVStreamWriter.md │ │ ├── File.md │ │ ├── FileReader.md │ │ ├── FileWriter.md │ │ ├── InputStream.md │ │ ├── OutputStream.md │ │ ├── PrintWriter.md │ │ ├── RandomAccessFileReader.md │ │ ├── Reader.md │ │ ├── StringWriter.md │ │ ├── Writer.md │ │ ├── XMLIndentingStreamWriter.md │ │ ├── XMLStreamConstants.md │ │ ├── XMLStreamReader.md │ │ └── XMLStreamWriter.md │ ├── dw_job │ │ ├── JobExecution.md │ │ └── JobStepExecution.md │ ├── dw_net │ │ ├── FTPClient.md │ │ ├── FTPFileInfo.md │ │ ├── HTTPClient.md │ │ ├── HTTPRequestPart.md │ │ ├── Mail.md │ │ ├── SFTPClient.md │ │ ├── SFTPFileInfo.md │ │ ├── WebDAVClient.md │ │ └── WebDAVFileInfo.md │ ├── dw_object │ │ ├── ActiveData.md │ │ ├── CustomAttributes.md │ │ ├── CustomObject.md │ │ ├── CustomObjectMgr.md │ │ ├── Extensible.md │ │ ├── ExtensibleObject.md │ │ ├── Note.md │ │ ├── ObjectAttributeDefinition.md │ │ ├── ObjectAttributeGroup.md │ │ ├── ObjectAttributeValueDefinition.md │ │ ├── ObjectTypeDefinition.md │ │ ├── PersistentObject.md │ │ ├── SimpleExtensible.md │ │ └── SystemObjectMgr.md │ ├── dw_order │ │ ├── AbstractItem.md │ │ ├── AbstractItemCtnr.md │ │ ├── Appeasement.md │ │ ├── AppeasementItem.md │ │ ├── Basket.md │ │ ├── BasketMgr.md │ │ ├── BonusDiscountLineItem.md │ │ ├── CouponLineItem.md │ │ ├── CreateAgentBasketLimitExceededException.md │ │ ├── CreateBasketFromOrderException.md │ │ ├── CreateCouponLineItemException.md │ │ ├── CreateOrderException.md │ │ ├── CreateTemporaryBasketLimitExceededException.md │ │ ├── GiftCertificate.md │ │ ├── GiftCertificateLineItem.md │ │ ├── GiftCertificateMgr.md │ │ ├── GiftCertificateStatusCodes.md │ │ ├── Invoice.md │ │ ├── InvoiceItem.md │ │ ├── LineItem.md │ │ ├── LineItemCtnr.md │ │ ├── Order.md │ │ ├── OrderAddress.md │ │ ├── OrderItem.md │ │ ├── OrderMgr.md │ │ ├── OrderPaymentInstrument.md │ │ ├── OrderProcessStatusCodes.md │ │ ├── PaymentCard.md │ │ ├── PaymentInstrument.md │ │ ├── PaymentMethod.md │ │ ├── PaymentMgr.md │ │ ├── PaymentProcessor.md │ │ ├── PaymentStatusCodes.md │ │ ├── PaymentTransaction.md │ │ ├── PriceAdjustment.md │ │ ├── PriceAdjustmentLimitTypes.md │ │ ├── ProductLineItem.md │ │ ├── ProductShippingCost.md │ │ ├── ProductShippingLineItem.md │ │ ├── ProductShippingModel.md │ │ ├── Return.md │ │ ├── ReturnCase.md │ │ ├── ReturnCaseItem.md │ │ ├── ReturnItem.md │ │ ├── Shipment.md │ │ ├── ShipmentShippingCost.md │ │ ├── ShipmentShippingModel.md │ │ ├── ShippingLineItem.md │ │ ├── ShippingLocation.md │ │ ├── ShippingMethod.md │ │ ├── ShippingMgr.md │ │ ├── ShippingOrder.md │ │ ├── ShippingOrderItem.md │ │ ├── SumItem.md │ │ ├── TaxGroup.md │ │ ├── TaxItem.md │ │ ├── TaxMgr.md │ │ ├── TrackingInfo.md │ │ └── TrackingRef.md │ ├── dw_order.hooks │ │ ├── CalculateHooks.md │ │ ├── OrderHooks.md │ │ ├── PaymentHooks.md │ │ ├── ReturnHooks.md │ │ └── ShippingOrderHooks.md │ ├── dw_rpc │ │ ├── SOAPUtil.md │ │ ├── Stub.md │ │ └── WebReference.md │ ├── dw_suggest │ │ ├── BrandSuggestions.md │ │ ├── CategorySuggestions.md │ │ ├── ContentSuggestions.md │ │ ├── CustomSuggestions.md │ │ ├── ProductSuggestions.md │ │ ├── SearchPhraseSuggestions.md │ │ ├── SuggestedCategory.md │ │ ├── SuggestedContent.md │ │ ├── SuggestedPhrase.md │ │ ├── SuggestedProduct.md │ │ ├── SuggestedTerm.md │ │ ├── SuggestedTerms.md │ │ ├── Suggestions.md │ │ └── SuggestModel.md │ ├── dw_svc │ │ ├── FTPService.md │ │ ├── FTPServiceDefinition.md │ │ ├── HTTPFormService.md │ │ ├── HTTPFormServiceDefinition.md │ │ ├── HTTPService.md │ │ ├── HTTPServiceDefinition.md │ │ ├── LocalServiceRegistry.md │ │ ├── Result.md │ │ ├── Service.md │ │ ├── ServiceCallback.md │ │ ├── ServiceConfig.md │ │ ├── ServiceCredential.md │ │ ├── ServiceDefinition.md │ │ ├── ServiceProfile.md │ │ ├── ServiceRegistry.md │ │ ├── SOAPService.md │ │ └── SOAPServiceDefinition.md │ ├── dw_system │ │ ├── AgentUserStatusCodes.md │ │ ├── Cache.md │ │ ├── CacheMgr.md │ │ ├── HookMgr.md │ │ ├── InternalObject.md │ │ ├── JobProcessMonitor.md │ │ ├── Log.md │ │ ├── Logger.md │ │ ├── LogNDC.md │ │ ├── OrganizationPreferences.md │ │ ├── Pipeline.md │ │ ├── PipelineDictionary.md │ │ ├── RemoteInclude.md │ │ ├── Request.md │ │ ├── RequestHooks.md │ │ ├── Response.md │ │ ├── RESTErrorResponse.md │ │ ├── RESTResponseMgr.md │ │ ├── RESTSuccessResponse.md │ │ ├── SearchStatus.md │ │ ├── Session.md │ │ ├── Site.md │ │ ├── SitePreferences.md │ │ ├── Status.md │ │ ├── StatusItem.md │ │ ├── System.md │ │ └── Transaction.md │ ├── dw_util │ │ ├── ArrayList.md │ │ ├── Assert.md │ │ ├── BigInteger.md │ │ ├── Bytes.md │ │ ├── Calendar.md │ │ ├── Collection.md │ │ ├── Currency.md │ │ ├── DateUtils.md │ │ ├── Decimal.md │ │ ├── FilteringCollection.md │ │ ├── Geolocation.md │ │ ├── HashMap.md │ │ ├── HashSet.md │ │ ├── Iterator.md │ │ ├── LinkedHashMap.md │ │ ├── LinkedHashSet.md │ │ ├── List.md │ │ ├── Locale.md │ │ ├── Map.md │ │ ├── MapEntry.md │ │ ├── MappingKey.md │ │ ├── MappingMgr.md │ │ ├── PropertyComparator.md │ │ ├── SecureEncoder.md │ │ ├── SecureFilter.md │ │ ├── SeekableIterator.md │ │ ├── Set.md │ │ ├── SortedMap.md │ │ ├── SortedSet.md │ │ ├── StringUtils.md │ │ ├── Template.md │ │ └── UUIDUtils.md │ ├── dw_value │ │ ├── EnumValue.md │ │ ├── MimeEncodedText.md │ │ ├── Money.md │ │ └── Quantity.md │ ├── dw_web │ │ ├── ClickStream.md │ │ ├── ClickStreamEntry.md │ │ ├── Cookie.md │ │ ├── Cookies.md │ │ ├── CSRFProtection.md │ │ ├── Form.md │ │ ├── FormAction.md │ │ ├── FormElement.md │ │ ├── FormElementValidationResult.md │ │ ├── FormField.md │ │ ├── FormFieldOption.md │ │ ├── FormFieldOptions.md │ │ ├── FormGroup.md │ │ ├── FormList.md │ │ ├── FormListItem.md │ │ ├── Forms.md │ │ ├── HttpParameter.md │ │ ├── HttpParameterMap.md │ │ ├── LoopIterator.md │ │ ├── PageMetaData.md │ │ ├── PageMetaTag.md │ │ ├── PagingModel.md │ │ ├── Resource.md │ │ ├── URL.md │ │ ├── URLAction.md │ │ ├── URLParameter.md │ │ ├── URLRedirect.md │ │ ├── URLRedirectMgr.md │ │ └── URLUtils.md │ ├── sfra │ │ ├── account.md │ │ ├── address.md │ │ ├── billing.md │ │ ├── cart.md │ │ ├── categories.md │ │ ├── content.md │ │ ├── locale.md │ │ ├── order.md │ │ ├── payment.md │ │ ├── price-default.md │ │ ├── price-range.md │ │ ├── price-tiered.md │ │ ├── product-bundle.md │ │ ├── product-full.md │ │ ├── product-line-items.md │ │ ├── product-search.md │ │ ├── product-tile.md │ │ ├── querystring.md │ │ ├── render.md │ │ ├── request.md │ │ ├── response.md │ │ ├── server.md │ │ ├── shipping.md │ │ ├── store.md │ │ ├── stores.md │ │ └── totals.md │ └── TopLevel │ ├── APIException.md │ ├── arguments.md │ ├── Array.md │ ├── ArrayBuffer.md │ ├── BigInt.md │ ├── Boolean.md │ ├── ConversionError.md │ ├── DataView.md │ ├── Date.md │ ├── Error.md │ ├── ES6Iterator.md │ ├── EvalError.md │ ├── Fault.md │ ├── Float32Array.md │ ├── Float64Array.md │ ├── Function.md │ ├── Generator.md │ ├── global.md │ ├── Int16Array.md │ ├── Int32Array.md │ ├── Int8Array.md │ ├── InternalError.md │ ├── IOError.md │ ├── Iterable.md │ ├── Iterator.md │ ├── JSON.md │ ├── Map.md │ ├── Math.md │ ├── Module.md │ ├── Namespace.md │ ├── Number.md │ ├── Object.md │ ├── QName.md │ ├── RangeError.md │ ├── ReferenceError.md │ ├── RegExp.md │ ├── Set.md │ ├── StopIteration.md │ ├── String.md │ ├── Symbol.md │ ├── SyntaxError.md │ ├── SystemError.md │ ├── TypeError.md │ ├── Uint16Array.md │ ├── Uint32Array.md │ ├── Uint8Array.md │ ├── Uint8ClampedArray.md │ ├── URIError.md │ ├── WeakMap.md │ ├── WeakSet.md │ ├── XML.md │ ├── XMLList.md │ └── XMLStreamError.md ├── docs-site │ ├── .gitignore │ ├── App.tsx │ ├── components │ │ ├── Badge.tsx │ │ ├── BreadcrumbSchema.tsx │ │ ├── CodeBlock.tsx │ │ ├── Collapsible.tsx │ │ ├── ConfigBuilder.tsx │ │ ├── ConfigHero.tsx │ │ ├── ConfigModeTabs.tsx │ │ ├── icons.tsx │ │ ├── Layout.tsx │ │ ├── LightCodeContainer.tsx │ │ ├── NewcomerCTA.tsx │ │ ├── NextStepsStrip.tsx │ │ ├── OnThisPage.tsx │ │ ├── Search.tsx │ │ ├── SEO.tsx │ │ ├── Sidebar.tsx │ │ ├── StructuredData.tsx │ │ ├── ToolCard.tsx │ │ ├── ToolFilters.tsx │ │ ├── Typography.tsx │ │ └── VersionBadge.tsx │ ├── constants.tsx │ ├── index.html │ ├── main.tsx │ ├── metadata.json │ ├── package-lock.json │ ├── package.json │ ├── pages │ │ ├── AIInterfacesPage.tsx │ │ ├── ConfigurationPage.tsx │ │ ├── DevelopmentPage.tsx │ │ ├── ExamplesPage.tsx │ │ ├── FeaturesPage.tsx │ │ ├── HomePage.tsx │ │ ├── SecurityPage.tsx │ │ ├── ToolsPage.tsx │ │ └── TroubleshootingPage.tsx │ ├── postcss.config.js │ ├── public │ │ ├── .well-known │ │ │ └── security.txt │ │ ├── 404.html │ │ ├── android-chrome-192x192.png │ │ ├── android-chrome-512x512.png │ │ ├── apple-touch-icon.png │ │ ├── explain-product-pricing-methods-no-mcp.png │ │ ├── explain-product-pricing-methods.png │ │ ├── favicon-16x16.png │ │ ├── favicon-32x32.png │ │ ├── favicon.ico │ │ ├── llms.txt │ │ ├── robots.txt │ │ ├── site.webmanifest │ │ └── sitemap.xml │ ├── README.md │ ├── scripts │ │ ├── generate-search-index.js │ │ ├── generate-sitemap.js │ │ └── search-dev.js │ ├── src │ │ └── styles │ │ ├── input.css │ │ └── prism-theme.css │ ├── tailwind.config.js │ ├── tsconfig.json │ ├── types.ts │ ├── utils │ │ ├── search.ts │ │ └── toolsData.ts │ └── vite.config.ts ├── eslint.config.js ├── jest.config.js ├── LICENSE ├── package-lock.json ├── package.json ├── README.md ├── scripts │ └── convert-docs.js ├── SECURITY.md ├── server.json ├── src │ ├── clients │ │ ├── base │ │ │ ├── http-client.ts │ │ │ ├── oauth-token.ts │ │ │ └── ocapi-auth-client.ts │ │ ├── best-practices-client.ts │ │ ├── cartridge-generation-client.ts │ │ ├── docs │ │ │ ├── class-content-parser.ts │ │ │ ├── class-name-resolver.ts │ │ │ ├── documentation-scanner.ts │ │ │ ├── index.ts │ │ │ └── referenced-types-extractor.ts │ │ ├── docs-client.ts │ │ ├── log-client.ts │ │ ├── logs │ │ │ ├── index.ts │ │ │ ├── log-analyzer.ts │ │ │ ├── log-client.ts │ │ │ ├── log-constants.ts │ │ │ ├── log-file-discovery.ts │ │ │ ├── log-file-reader.ts │ │ │ ├── log-formatter.ts │ │ │ ├── log-processor.ts │ │ │ ├── log-types.ts │ │ │ └── webdav-client-manager.ts │ │ ├── ocapi │ │ │ ├── code-versions-client.ts │ │ │ ├── site-preferences-client.ts │ │ │ └── system-objects-client.ts │ │ ├── ocapi-client.ts │ │ └── sfra-client.ts │ ├── config │ │ ├── configuration-factory.ts │ │ └── dw-json-loader.ts │ ├── core │ │ ├── handlers │ │ │ ├── abstract-log-tool-handler.ts │ │ │ ├── base-handler.ts │ │ │ ├── best-practices-handler.ts │ │ │ ├── cartridge-handler.ts │ │ │ ├── client-factory.ts │ │ │ ├── code-version-handler.ts │ │ │ ├── docs-handler.ts │ │ │ ├── job-log-handler.ts │ │ │ ├── job-log-tool-config.ts │ │ │ ├── log-handler.ts │ │ │ ├── log-tool-config.ts │ │ │ ├── sfra-handler.ts │ │ │ ├── system-object-handler.ts │ │ │ └── validation-helpers.ts │ │ ├── server.ts │ │ └── tool-definitions.ts │ ├── index.ts │ ├── main.ts │ ├── services │ │ ├── file-system-service.ts │ │ ├── index.ts │ │ └── path-service.ts │ ├── tool-configs │ │ ├── best-practices-tool-config.ts │ │ ├── cartridge-tool-config.ts │ │ ├── code-version-tool-config.ts │ │ ├── docs-tool-config.ts │ │ ├── job-log-tool-config.ts │ │ ├── log-tool-config.ts │ │ ├── sfra-tool-config.ts │ │ └── system-object-tool-config.ts │ ├── types │ │ └── types.ts │ └── utils │ ├── cache.ts │ ├── job-log-tool-config.ts │ ├── job-log-utils.ts │ ├── log-cache.ts │ ├── log-tool-config.ts │ ├── log-tool-constants.ts │ ├── log-tool-utils.ts │ ├── logger.ts │ ├── ocapi-url-builder.ts │ ├── path-resolver.ts │ ├── query-builder.ts │ ├── utils.ts │ └── validator.ts ├── tests │ ├── __mocks__ │ │ ├── docs-client.ts │ │ ├── src │ │ │ └── clients │ │ │ └── base │ │ │ └── http-client.js │ │ └── webdav.js │ ├── base-handler.test.ts │ ├── base-http-client.test.ts │ ├── best-practices-handler.test.ts │ ├── cache.test.ts │ ├── cartridge-handler.test.ts │ ├── class-content-parser.test.ts │ ├── class-name-resolver.test.ts │ ├── client-factory.test.ts │ ├── code-version-handler.test.ts │ ├── code-versions-client.test.ts │ ├── config.test.ts │ ├── configuration-factory.test.ts │ ├── docs-handler.test.ts │ ├── documentation-scanner.test.ts │ ├── file-system-service.test.ts │ ├── job-log-handler.test.ts │ ├── job-log-utils.test.ts │ ├── log-client.test.ts │ ├── log-handler.test.ts │ ├── log-processor.test.ts │ ├── logger.test.ts │ ├── mcp │ │ ├── AGENTS.md │ │ ├── node │ │ │ ├── activate-code-version-advanced.full-mode.programmatic.test.js │ │ │ ├── code-versions.full-mode.programmatic.test.js │ │ │ ├── generate-cartridge-structure.docs-only.programmatic.test.js │ │ │ ├── get-available-best-practice-guides.docs-only.programmatic.test.js │ │ │ ├── get-available-sfra-documents.programmatic.test.js │ │ │ ├── get-best-practice-guide.docs-only.programmatic.test.js │ │ │ ├── get-hook-reference.docs-only.programmatic.test.js │ │ │ ├── get-job-execution-summary.full-mode.programmatic.test.js │ │ │ ├── get-job-log-entries.full-mode.programmatic.test.js │ │ │ ├── get-latest-debug.full-mode.programmatic.test.js │ │ │ ├── get-latest-error.full-mode.programmatic.test.js │ │ │ ├── get-latest-info.full-mode.programmatic.test.js │ │ │ ├── get-latest-job-log-files.full-mode.programmatic.test.js │ │ │ ├── get-latest-warn.full-mode.programmatic.test.js │ │ │ ├── get-log-file-contents.full-mode.programmatic.test.js │ │ │ ├── get-sfcc-class-documentation.docs-only.programmatic.test.js │ │ │ ├── get-sfcc-class-info.docs-only.programmatic.test.js │ │ │ ├── get-sfra-categories.docs-only.programmatic.test.js │ │ │ ├── get-sfra-document.programmatic.test.js │ │ │ ├── get-sfra-documents-by-category.docs-only.programmatic.test.js │ │ │ ├── get-system-object-definition.full-mode.programmatic.test.js │ │ │ ├── get-system-object-definitions.docs-only.programmatic.test.js │ │ │ ├── get-system-object-definitions.full-mode.programmatic.test.js │ │ │ ├── list-log-files.full-mode.programmatic.test.js │ │ │ ├── list-sfcc-classes.docs-only.programmatic.test.js │ │ │ ├── search-best-practices.docs-only.programmatic.test.js │ │ │ ├── search-custom-object-attribute-definitions.full-mode.programmatic.test.js │ │ │ ├── search-job-logs-by-name.full-mode.programmatic.test.js │ │ │ ├── search-job-logs.full-mode.programmatic.test.js │ │ │ ├── search-logs.full-mode.programmatic.test.js │ │ │ ├── search-sfcc-classes.docs-only.programmatic.test.js │ │ │ ├── search-sfcc-methods.docs-only.programmatic.test.js │ │ │ ├── search-sfra-documentation.docs-only.programmatic.test.js │ │ │ ├── search-site-preferences.full-mode.programmatic.test.js │ │ │ ├── search-system-object-attribute-definitions.full-mode.programmatic.test.js │ │ │ ├── search-system-object-attribute-groups.full-mode.programmatic.test.js │ │ │ ├── summarize-logs.full-mode.programmatic.test.js │ │ │ ├── tools.docs-only.programmatic.test.js │ │ │ └── tools.full-mode.programmatic.test.js │ │ ├── README.md │ │ ├── test-fixtures │ │ │ └── dw.json │ │ └── yaml │ │ ├── activate-code-version.docs-only.test.mcp.yml │ │ ├── activate-code-version.full-mode.test.mcp.yml │ │ ├── get_latest_error.test.mcp.yml │ │ ├── get-available-best-practice-guides.docs-only.test.mcp.yml │ │ ├── get-available-best-practice-guides.full-mode.test.mcp.yml │ │ ├── get-available-sfra-documents.docs-only.test.mcp.yml │ │ ├── get-available-sfra-documents.full-mode.test.mcp.yml │ │ ├── get-best-practice-guide.docs-only.test.mcp.yml │ │ ├── get-best-practice-guide.full-mode.test.mcp.yml │ │ ├── get-code-versions.docs-only.test.mcp.yml │ │ ├── get-code-versions.full-mode.test.mcp.yml │ │ ├── get-hook-reference.docs-only.test.mcp.yml │ │ ├── get-hook-reference.full-mode.test.mcp.yml │ │ ├── get-job-execution-summary.full-mode.test.mcp.yml │ │ ├── get-job-log-entries.full-mode.test.mcp.yml │ │ ├── get-latest-debug.full-mode.test.mcp.yml │ │ ├── get-latest-error.full-mode.test.mcp.yml │ │ ├── get-latest-info.full-mode.test.mcp.yml │ │ ├── get-latest-job-log-files.full-mode.test.mcp.yml │ │ ├── get-latest-warn.full-mode.test.mcp.yml │ │ ├── get-log-file-contents.full-mode.test.mcp.yml │ │ ├── get-sfcc-class-documentation.docs-only.test.mcp.yml │ │ ├── get-sfcc-class-documentation.full-mode.test.mcp.yml │ │ ├── get-sfcc-class-info.docs-only.test.mcp.yml │ │ ├── get-sfcc-class-info.full-mode.test.mcp.yml │ │ ├── get-sfra-categories.docs-only.test.mcp.yml │ │ ├── get-sfra-categories.full-mode.test.mcp.yml │ │ ├── get-sfra-document.docs-only.test.mcp.yml │ │ ├── get-sfra-document.full-mode.test.mcp.yml │ │ ├── get-sfra-documents-by-category.docs-only.test.mcp.yml │ │ ├── get-sfra-documents-by-category.full-mode.test.mcp.yml │ │ ├── get-system-object-definition.docs-only.test.mcp.yml │ │ ├── get-system-object-definition.full-mode.test.mcp.yml │ │ ├── get-system-object-definitions.docs-only.test.mcp.yml │ │ ├── get-system-object-definitions.full-mode.test.mcp.yml │ │ ├── list-log-files.full-mode.test.mcp.yml │ │ ├── list-sfcc-classes.docs-only.test.mcp.yml │ │ ├── list-sfcc-classes.full-mode.test.mcp.yml │ │ ├── search-best-practices.docs-only.test.mcp.yml │ │ ├── search-best-practices.full-mode.test.mcp.yml │ │ ├── search-custom-object-attribute-definitions.docs-only.test.mcp.yml │ │ ├── search-custom-object-attribute-definitions.test.mcp.yml │ │ ├── search-job-logs-by-name.full-mode.test.mcp.yml │ │ ├── search-job-logs.full-mode.test.mcp.yml │ │ ├── search-logs.full-mode.test.mcp.yml │ │ ├── search-sfcc-classes.docs-only.test.mcp.yml │ │ ├── search-sfcc-classes.full-mode.test.mcp.yml │ │ ├── search-sfcc-methods.docs-only.test.mcp.yml │ │ ├── search-sfcc-methods.full-mode.test.mcp.yml │ │ ├── search-sfra-documentation.docs-only.test.mcp.yml │ │ ├── search-sfra-documentation.full-mode.test.mcp.yml │ │ ├── search-site-preferences.docs-only.test.mcp.yml │ │ ├── search-site-preferences.full-mode.test.mcp.yml │ │ ├── search-system-object-attribute-definitions.docs-only.test.mcp.yml │ │ ├── search-system-object-attribute-definitions.full-mode.test.mcp.yml │ │ ├── search-system-object-attribute-groups.docs-only.test.mcp.yml │ │ ├── search-system-object-attribute-groups.full-mode.test.mcp.yml │ │ ├── summarize-logs.full-mode.test.mcp.yml │ │ ├── tools.docs-only.test.mcp.yml │ │ └── tools.full-mode.test.mcp.yml │ ├── oauth-token.test.ts │ ├── ocapi-auth-client.test.ts │ ├── ocapi-client.test.ts │ ├── path-service.test.ts │ ├── query-builder.test.ts │ ├── referenced-types-extractor.test.ts │ ├── servers │ │ ├── sfcc-mock-server │ │ │ ├── mock-data │ │ │ │ └── ocapi │ │ │ │ ├── code-versions.json │ │ │ │ ├── custom-object-attributes-customapi.json │ │ │ │ ├── custom-object-attributes-globalsettings.json │ │ │ │ ├── custom-object-attributes-versionhistory.json │ │ │ │ ├── site-preferences-ccv.json │ │ │ │ ├── site-preferences-fastforward.json │ │ │ │ ├── site-preferences-sfra.json │ │ │ │ ├── site-preferences-storefront.json │ │ │ │ ├── site-preferences-system.json │ │ │ │ ├── system-object-attribute-groups-campaign.json │ │ │ │ ├── system-object-attribute-groups-category.json │ │ │ │ ├── system-object-attribute-groups-order.json │ │ │ │ ├── system-object-attribute-groups-product.json │ │ │ │ ├── system-object-attribute-groups-sitepreferences.json │ │ │ │ ├── system-object-attributes-customeraddress.json │ │ │ │ ├── system-object-attributes-product-expanded.json │ │ │ │ ├── system-object-attributes-product.json │ │ │ │ ├── system-object-definition-category.json │ │ │ │ ├── system-object-definition-customer.json │ │ │ │ ├── system-object-definition-customeraddress.json │ │ │ │ ├── system-object-definition-order.json │ │ │ │ ├── system-object-definition-product.json │ │ │ │ ├── system-object-definitions-old.json │ │ │ │ └── system-object-definitions.json │ │ │ ├── package-lock.json │ │ │ ├── package.json │ │ │ ├── README.md │ │ │ ├── scripts │ │ │ │ └── setup-logs.js │ │ │ ├── server.js │ │ │ └── src │ │ │ ├── app.js │ │ │ ├── config │ │ │ │ └── server-config.js │ │ │ ├── middleware │ │ │ │ ├── auth.js │ │ │ │ ├── cors.js │ │ │ │ └── logging.js │ │ │ ├── routes │ │ │ │ ├── ocapi │ │ │ │ │ ├── code-versions-handler.js │ │ │ │ │ ├── oauth-handler.js │ │ │ │ │ ├── ocapi-error-utils.js │ │ │ │ │ ├── ocapi-utils.js │ │ │ │ │ ├── site-preferences-handler.js │ │ │ │ │ └── system-objects-handler.js │ │ │ │ ├── ocapi.js │ │ │ │ └── webdav.js │ │ │ └── utils │ │ │ ├── mock-data-loader.js │ │ │ └── webdav-xml.js │ │ └── sfcc-mock-server-manager.ts │ ├── sfcc-mock-server.test.ts │ ├── site-preferences-client.test.ts │ ├── system-objects-client.test.ts │ ├── utils.test.ts │ ├── validation-helpers.test.ts │ └── validator.test.ts ├── tsconfig.json └── tsconfig.test.json ``` # Files -------------------------------------------------------------------------------- /src/utils/job-log-tool-config.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { ToolSpec, LogToolValidators } from './log-tool-utils.js'; 2 | import { ValidationHelpers, CommonValidations } from '../core/handlers/validation-helpers.js'; 3 | import { JobLogToolName, getLimit } from './log-tool-constants.js'; 4 | import { JobLogValidators, JobLogFormatters } from './job-log-utils.js'; 5 | 6 | /** 7 | * Configuration for job log tools 8 | * Maps each tool to its validation, execution, and messaging logic 9 | */ 10 | export const JOB_LOG_TOOL_CONFIG: Record<JobLogToolName, ToolSpec> = { 11 | get_latest_job_log_files: { 12 | defaults: (args) => ({ 13 | limit: getLimit(args.limit as number, 'jobFiles'), 14 | }), 15 | validate: (args, toolName) => LogToolValidators.validateLimit(args.limit as number, toolName), 16 | exec: async (args, client) => client.getLatestJobLogFiles(args.limit as number), 17 | logMessage: (args) => JobLogFormatters.formatJobLogMessage('Fetching latest job log files', { 18 | limit: args.limit as number, 19 | }), 20 | }, 21 | 22 | search_job_logs_by_name: { 23 | defaults: (args) => ({ 24 | limit: getLimit(args.limit as number, 'jobFiles'), 25 | }), 26 | validate: (args, toolName) => { 27 | ValidationHelpers.validateArguments(args, CommonValidations.requiredString('jobName'), toolName); 28 | LogToolValidators.validateLimit(args.limit as number, toolName); 29 | }, 30 | exec: async (args, client) => client.searchJobLogsByName(args.jobName as string, args.limit as number), 31 | logMessage: (args) => JobLogFormatters.formatJobLogMessage('Searching job logs by name', { 32 | jobName: args.jobName as string, 33 | limit: args.limit as number, 34 | }), 35 | }, 36 | 37 | get_job_log_entries: { 38 | defaults: (args) => ({ 39 | level: args.level ?? 'all', 40 | limit: getLimit(args.limit as number, 'jobEntries'), 41 | }), 42 | validate: (args, toolName) => { 43 | JobLogValidators.validateJobLogLevel(args.level as string, toolName); 44 | LogToolValidators.validateLimit(args.limit as number, toolName); 45 | }, 46 | exec: async (args, client) => client.getJobLogEntries( 47 | args.level as any, 48 | args.limit as number, 49 | args.jobName as string, 50 | ), 51 | logMessage: (args) => JobLogFormatters.formatJobLogMessage('Fetching job log entries', { 52 | level: args.level as string, 53 | limit: args.limit as number, 54 | jobName: args.jobName as string, 55 | }), 56 | }, 57 | 58 | search_job_logs: { 59 | defaults: (args) => ({ 60 | level: args.level ?? 'all', 61 | limit: getLimit(args.limit as number, 'jobSearch'), 62 | }), 63 | validate: (args, toolName) => { 64 | ValidationHelpers.validateArguments(args, CommonValidations.requiredString('pattern'), toolName); 65 | JobLogValidators.validateJobLogLevel(args.level as string, toolName); 66 | LogToolValidators.validateLimit(args.limit as number, toolName); 67 | }, 68 | exec: async (args, client) => client.searchJobLogs( 69 | args.pattern as string, 70 | args.level as any, 71 | args.limit as number, 72 | args.jobName as string, 73 | ), 74 | logMessage: (args) => JobLogFormatters.formatJobLogMessage('Searching job logs', { 75 | pattern: args.pattern as string, 76 | level: args.level as string, 77 | limit: args.limit as number, 78 | jobName: args.jobName as string, 79 | }), 80 | }, 81 | 82 | get_job_execution_summary: { 83 | validate: (args, toolName) => { 84 | ValidationHelpers.validateArguments(args, CommonValidations.requiredString('jobName'), toolName); 85 | }, 86 | exec: async (args, client) => client.getJobExecutionSummary(args.jobName as string), 87 | logMessage: (args) => `Getting job execution summary for: ${args.jobName as string}`, 88 | }, 89 | }; 90 | ``` -------------------------------------------------------------------------------- /tests/file-system-service.test.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { FileSystemService, MockFileSystemService } from '../src/services/file-system-service.js'; 2 | 3 | describe('FileSystemService', () => { 4 | describe('Production FileSystemService', () => { 5 | let service: FileSystemService; 6 | 7 | beforeEach(() => { 8 | service = new FileSystemService(); 9 | }); 10 | 11 | it('should be instantiable', () => { 12 | expect(service).toBeInstanceOf(FileSystemService); 13 | }); 14 | 15 | // Note: Testing actual file operations would require integration tests 16 | // For unit tests, we mainly test the interface compliance 17 | }); 18 | 19 | describe('MockFileSystemService', () => { 20 | let mockService: MockFileSystemService; 21 | 22 | beforeEach(() => { 23 | mockService = new MockFileSystemService(); 24 | }); 25 | 26 | afterEach(() => { 27 | mockService.clearMocks(); 28 | }); 29 | 30 | it('should be instantiable', () => { 31 | expect(mockService).toBeInstanceOf(MockFileSystemService); 32 | }); 33 | 34 | it('should handle mock files correctly', async () => { 35 | const filePath = '/test/file.txt'; 36 | const content = 'test content'; 37 | 38 | // Initially file should not exist 39 | expect(await mockService.exists(filePath)).toBe(false); 40 | 41 | // Set mock file 42 | mockService.setMockFile(filePath, content); 43 | expect(await mockService.exists(filePath)).toBe(true); 44 | 45 | // Read mock file 46 | const readContent = await mockService.readFile(filePath); 47 | expect(readContent).toBe(content); 48 | }); 49 | 50 | it('should handle mock directories correctly', async () => { 51 | const dirPath = '/test/dir'; 52 | 53 | // Initially directory should not exist 54 | expect(await mockService.exists(dirPath)).toBe(false); 55 | 56 | // Set mock directory 57 | mockService.setMockDirectory(dirPath); 58 | expect(await mockService.exists(dirPath)).toBe(true); 59 | }); 60 | 61 | it('should create directories through mkdir', async () => { 62 | const dirPath = '/test/new-dir'; 63 | 64 | await mockService.mkdir(dirPath, { recursive: true }); 65 | expect(await mockService.exists(dirPath)).toBe(true); 66 | }); 67 | 68 | it('should create files through writeFile', async () => { 69 | const filePath = '/test/new-file.txt'; 70 | const content = 'new content'; 71 | 72 | await mockService.writeFile(filePath, content); 73 | expect(await mockService.exists(filePath)).toBe(true); 74 | 75 | const readContent = await mockService.readFile(filePath); 76 | expect(readContent).toBe(content); 77 | }); 78 | 79 | it('should throw error when reading non-existent file', async () => { 80 | const filePath = '/test/non-existent.txt'; 81 | 82 | await expect(mockService.readFile(filePath)).rejects.toThrow('File not found'); 83 | }); 84 | 85 | it('should handle access correctly', async () => { 86 | const existingPath = '/test/existing'; 87 | const nonExistentPath = '/test/non-existent'; 88 | 89 | mockService.setMockFile(existingPath, 'content'); 90 | 91 | await expect(mockService.access(existingPath)).resolves.not.toThrow(); 92 | await expect(mockService.access(nonExistentPath)).rejects.toThrow('Path not accessible'); 93 | }); 94 | 95 | it('should clear mocks correctly', async () => { 96 | const filePath = '/test/file.txt'; 97 | const dirPath = '/test/dir'; 98 | 99 | mockService.setMockFile(filePath, 'content'); 100 | mockService.setMockDirectory(dirPath); 101 | 102 | expect(await mockService.exists(filePath)).toBe(true); 103 | expect(await mockService.exists(dirPath)).toBe(true); 104 | 105 | mockService.clearMocks(); 106 | 107 | expect(await mockService.exists(filePath)).toBe(false); 108 | expect(await mockService.exists(dirPath)).toBe(false); 109 | }); 110 | }); 111 | }); 112 | ``` -------------------------------------------------------------------------------- /docs/dw_svc/ServiceRegistry.md: -------------------------------------------------------------------------------- ```markdown 1 | ## Package: dw.svc 2 | 3 | # Class ServiceRegistry 4 | 5 | ## Inheritance Hierarchy 6 | 7 | - Object 8 | - dw.svc.ServiceRegistry 9 | 10 | ## Description 11 | 12 | The ServiceRegistry is responsible for managing Service definitions and their instances. Typical usage involves several steps: The service is defined in the Business Manager and configured with necessary credentials. The service callback is configured once during cartridge initialization: ServiceRegistry.configure("MyFTPService", { mockExec : function(svc:FTPService, params) { return [ { "name": "file1", "timestamp": new Date(2011, 02, 21)}, { "name": "file2", "timestamp": new Date(2012, 02, 21)}, { "name": "file3", "timestamp": new Date(2013, 02, 21)} ]; }, createRequest: function(svc:FTPService, params) { svc.setOperation("list", "/"); }, parseResponse : function(svc:FTPService, listOutput) { var x : Array = []; var resp : Array = listOutput; for(var i = 0; i < resp.length; i++) { var f = resp[i]; x.push( { "name": f['name'], "timestamp": f['timestamp'] } ); } return x; } }); A new service instance is created and called in order to perform the operation: var result : Result = ServiceRegistry.get("MyFTPService").call(); if(result.status == 'OK') { // The result.object is the object returned by the 'after' callback. } else { // Handle the error. See result.error for more information. } See ServiceCallback for all the callback options, and individual ServiceDefinition classes for customization specific to a service type. 13 | 14 | ## Constructor Summary 15 | 16 | ## Method Summary 17 | 18 | ### configure 19 | 20 | **Signature:** `static configure(serviceID : String, configObj : Object) : ServiceDefinition` 21 | 22 | Configure the given serviceId with a callback. 23 | 24 | ### get 25 | 26 | **Signature:** `static get(serviceID : String) : Service` 27 | 28 | Constructs a new instance of the given service. 29 | 30 | ### getDefinition 31 | 32 | **Signature:** `static getDefinition(serviceID : String) : ServiceDefinition` 33 | 34 | Gets a Service Definition. 35 | 36 | ### isConfigured 37 | 38 | **Signature:** `static isConfigured(serviceID : String) : boolean` 39 | 40 | Returns the status of whether the given service has been configured with a callback. 41 | 42 | ## Method Detail 43 | 44 | ## Method Details 45 | 46 | ### configure 47 | 48 | **Signature:** `static configure(serviceID : String, configObj : Object) : ServiceDefinition` 49 | 50 | **Description:** Configure the given serviceId with a callback. If the service is already configured, the given callback will replace any existing one. 51 | 52 | **Parameters:** 53 | 54 | - `serviceID`: Unique Service ID. 55 | - `configObj`: Configuration callback. See ServiceCallback for a description of available callback methods. 56 | 57 | **Returns:** 58 | 59 | Associated ServiceDefinition, which can be used for further protocol-specific configuration. 60 | 61 | --- 62 | 63 | ### get 64 | 65 | **Signature:** `static get(serviceID : String) : Service` 66 | 67 | **Description:** Constructs a new instance of the given service. 68 | 69 | **Parameters:** 70 | 71 | - `serviceID`: Unique Service ID. 72 | 73 | **Returns:** 74 | 75 | Service instance. 76 | 77 | --- 78 | 79 | ### getDefinition 80 | 81 | **Signature:** `static getDefinition(serviceID : String) : ServiceDefinition` 82 | 83 | **Description:** Gets a Service Definition. This Service Definition is shared across all Service instances returned by get(String). 84 | 85 | **Parameters:** 86 | 87 | - `serviceID`: Unique Service ID. 88 | 89 | **Returns:** 90 | 91 | ServiceDefinition 92 | 93 | --- 94 | 95 | ### isConfigured 96 | 97 | **Signature:** `static isConfigured(serviceID : String) : boolean` 98 | 99 | **Description:** Returns the status of whether the given service has been configured with a callback. 100 | 101 | **Parameters:** 102 | 103 | - `serviceID`: Unique Service ID. 104 | 105 | **Returns:** 106 | 107 | true if configure has already been called, false otherwise. 108 | 109 | --- ``` -------------------------------------------------------------------------------- /src/core/handlers/job-log-tool-config.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { ToolSpec, LogToolValidators } from '../../utils/log-tool-utils.js'; 2 | import { ValidationHelpers, CommonValidations } from './validation-helpers.js'; 3 | import { JobLogToolName, getLimit } from '../../utils/log-tool-constants.js'; 4 | import { JobLogValidators, JobLogFormatters } from '../../utils/job-log-utils.js'; 5 | 6 | /** 7 | * Configuration for job log tools 8 | * Maps each tool to its validation, execution, and messaging logic 9 | */ 10 | export const JOB_LOG_TOOL_CONFIG: Record<JobLogToolName, ToolSpec> = { 11 | get_latest_job_log_files: { 12 | defaults: (args) => ({ 13 | limit: getLimit(args.limit as number, 'jobFiles'), 14 | }), 15 | validate: (args, toolName) => LogToolValidators.validateLimit(args.limit as number, toolName), 16 | exec: async (args, client) => client.getLatestJobLogFiles(args.limit as number), 17 | logMessage: (args) => JobLogFormatters.formatJobLogMessage('Fetching latest job log files', { 18 | limit: args.limit as number, 19 | }), 20 | }, 21 | 22 | search_job_logs_by_name: { 23 | defaults: (args) => ({ 24 | limit: getLimit(args.limit as number, 'jobFiles'), 25 | }), 26 | validate: (args, toolName) => { 27 | ValidationHelpers.validateArguments(args, CommonValidations.requiredString('jobName'), toolName); 28 | LogToolValidators.validateLimit(args.limit as number, toolName); 29 | }, 30 | exec: async (args, client) => client.searchJobLogsByName(args.jobName as string, args.limit as number), 31 | logMessage: (args) => JobLogFormatters.formatJobLogMessage('Searching job logs by name', { 32 | jobName: args.jobName as string, 33 | limit: args.limit as number, 34 | }), 35 | }, 36 | 37 | get_job_log_entries: { 38 | defaults: (args) => ({ 39 | level: args.level ?? 'all', 40 | limit: getLimit(args.limit as number, 'jobEntries'), 41 | }), 42 | validate: (args, toolName) => { 43 | JobLogValidators.validateJobLogLevel(args.level as string, toolName); 44 | LogToolValidators.validateLimit(args.limit as number, toolName); 45 | }, 46 | exec: async (args, client) => client.getJobLogEntries( 47 | args.level as any, 48 | args.limit as number, 49 | args.jobName as string, 50 | ), 51 | logMessage: (args) => JobLogFormatters.formatJobLogMessage('Fetching job log entries', { 52 | level: args.level as string, 53 | limit: args.limit as number, 54 | jobName: args.jobName as string, 55 | }), 56 | }, 57 | 58 | search_job_logs: { 59 | defaults: (args) => ({ 60 | level: args.level ?? 'all', 61 | limit: getLimit(args.limit as number, 'jobSearch'), 62 | }), 63 | validate: (args, toolName) => { 64 | ValidationHelpers.validateArguments(args, CommonValidations.requiredString('pattern'), toolName); 65 | JobLogValidators.validateJobLogLevel(args.level as string, toolName); 66 | LogToolValidators.validateLimit(args.limit as number, toolName); 67 | }, 68 | exec: async (args, client) => client.searchJobLogs( 69 | args.pattern as string, 70 | args.level as any, 71 | args.limit as number, 72 | args.jobName as string, 73 | ), 74 | logMessage: (args) => JobLogFormatters.formatJobLogMessage('Searching job logs', { 75 | pattern: args.pattern as string, 76 | level: args.level as string, 77 | limit: args.limit as number, 78 | jobName: args.jobName as string, 79 | }), 80 | }, 81 | 82 | get_job_execution_summary: { 83 | validate: (args, toolName) => { 84 | ValidationHelpers.validateArguments(args, CommonValidations.requiredString('jobName'), toolName); 85 | }, 86 | exec: async (args, client) => client.getJobExecutionSummary(args.jobName as string), 87 | logMessage: (args) => `Getting job execution summary for: ${args.jobName as string}`, 88 | }, 89 | }; 90 | ``` -------------------------------------------------------------------------------- /docs-site/scripts/search-dev.js: -------------------------------------------------------------------------------- ```javascript 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * Development utility script for the search index 5 | * Provides commands for generation, validation, and testing 6 | */ 7 | 8 | import { generateSearchIndex, writeSearchIndex } from './generate-search-index.js'; 9 | import fs from 'fs'; 10 | import path from 'path'; 11 | import { fileURLToPath } from 'url'; 12 | 13 | const __filename = fileURLToPath(import.meta.url); 14 | const __dirname = path.dirname(__filename); 15 | 16 | const command = process.argv[2]; 17 | 18 | switch (command) { 19 | case 'generate': 20 | console.log('🔄 Generating search index...'); 21 | try { 22 | const index = generateSearchIndex(); 23 | writeSearchIndex(index); 24 | } catch (error) { 25 | console.error('❌ Failed to generate search index:', error.message); 26 | process.exit(1); 27 | } 28 | break; 29 | 30 | case 'validate': 31 | console.log('✅ Validating search index...'); 32 | try { 33 | const indexPath = path.join(__dirname, '../src/generated-search-index.ts'); 34 | if (!fs.existsSync(indexPath)) { 35 | console.error('❌ Search index file not found. Run "generate" first.'); 36 | process.exit(1); 37 | } 38 | 39 | const stats = fs.statSync(indexPath); 40 | const content = fs.readFileSync(indexPath, 'utf-8'); 41 | const lines = content.split('\n').length; 42 | const size = (stats.size / 1024).toFixed(1); 43 | 44 | // Extract the number of entries 45 | const match = content.match(/GENERATED_SEARCH_INDEX: SearchableItem\[\] = \[([\s\S]*)\];/); 46 | if (match) { 47 | const entriesCount = (match[1].match(/\{/g) || []).length; 48 | console.log('📊 Search index statistics:'); 49 | console.log(` • File size: ${size} KB`); 50 | console.log(` • Lines: ${lines}`); 51 | console.log(` • Search entries: ${entriesCount}`); 52 | console.log(` • Last modified: ${stats.mtime.toLocaleString()}`); 53 | console.log('✅ Search index is valid'); 54 | } else { 55 | throw new Error('Invalid search index format'); 56 | } 57 | } catch (error) { 58 | console.error('❌ Search index validation failed:', error.message); 59 | process.exit(1); 60 | } 61 | break; 62 | 63 | case 'search': { 64 | const query = process.argv[3]; 65 | if (!query) { 66 | console.error('❌ Please provide a search query: npm run search-dev search "your query"'); 67 | process.exit(1); 68 | } 69 | 70 | console.log(`🔍 Testing search for: "${query}"`); 71 | try { 72 | // Dynamically import and test the search function 73 | const { searchDocs } = await import('../utils/search.ts'); 74 | const results = searchDocs(query); 75 | 76 | if (results.length === 0) { 77 | console.log('📭 No results found'); 78 | } else { 79 | console.log(`📋 Found ${results.length} results:`); 80 | results.forEach((result, index) => { 81 | console.log(`\n${index + 1}. ${result.heading} (${result.pageTitle})`); 82 | console.log(` Path: ${result.path}`); 83 | console.log(` Score: ${result.score}`); 84 | console.log(` Snippet: ${result.snippet.substring(0, 100)}...`); 85 | }); 86 | } 87 | } catch (error) { 88 | console.error('❌ Search test failed:', error.message); 89 | process.exit(1); 90 | } 91 | break; 92 | } 93 | 94 | default: 95 | console.log(` 96 | 🔧 Search Index Development Utility 97 | 98 | Usage: 99 | node scripts/search-dev.js <command> 100 | 101 | Commands: 102 | generate Generate the search index from React components 103 | validate Check if the search index is valid and show statistics 104 | search Test search functionality with a query 105 | 106 | Examples: 107 | node scripts/search-dev.js generate 108 | node scripts/search-dev.js validate 109 | node scripts/search-dev.js search "pattern matching" 110 | `); 111 | break; 112 | } 113 | ``` -------------------------------------------------------------------------------- /docs/dw_customer/ExternalProfile.md: -------------------------------------------------------------------------------- ```markdown 1 | ## Package: dw.customer 2 | 3 | # Class ExternalProfile 4 | 5 | ## Inheritance Hierarchy 6 | 7 | - Object 8 | - dw.customer.ExternalProfile 9 | 10 | ## Description 11 | 12 | Represents the credentials of a customer. Since 13.6 it is possible to have customers who are not authenticated through a login and password but through an external authentication provider via the OAuth2 protocol. In such cases, the AuthenticationProviderID will point to an OAuth provider configured in the system and the ExternalID will be the unique identifier of the customer on the Authentication Provider's system. For example, if an authentication provider with ID "Google123" is configured pointing to Google and the customer has a logged in into Google in the past and has created a profile there, Google assigns a unique number identifier to that customer. If the storefront is configured to allow authentication through Google and a new customer logs into the storefront using Google, the AuthenticationProviderID property of his Credentials will contain "Google123" and the ExternalID property will contain whatever unique identifier Google has assigned to him. 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 | ### authenticationProviderID 17 | 18 | **Type:** String (Read Only) 19 | 20 | The authentication provider ID. 21 | 22 | ### customer 23 | 24 | **Type:** Customer (Read Only) 25 | 26 | The customer object related to this profile. 27 | 28 | ### email 29 | 30 | **Type:** String 31 | 32 | The customer's email address. 33 | 34 | ### externalID 35 | 36 | **Type:** String (Read Only) 37 | 38 | The external ID. 39 | 40 | ### lastLoginTime 41 | 42 | **Type:** Date (Read Only) 43 | 44 | The last login time of the customer through the external provider 45 | 46 | ## Constructor Summary 47 | 48 | ## Method Summary 49 | 50 | ### getAuthenticationProviderID 51 | 52 | **Signature:** `getAuthenticationProviderID() : String` 53 | 54 | Returns the authentication provider ID. 55 | 56 | ### getCustomer 57 | 58 | **Signature:** `getCustomer() : Customer` 59 | 60 | Returns the customer object related to this profile. 61 | 62 | ### getEmail 63 | 64 | **Signature:** `getEmail() : String` 65 | 66 | Returns the customer's email address. 67 | 68 | ### getExternalID 69 | 70 | **Signature:** `getExternalID() : String` 71 | 72 | Returns the external ID. 73 | 74 | ### getLastLoginTime 75 | 76 | **Signature:** `getLastLoginTime() : Date` 77 | 78 | Returns the last login time of the customer through the external provider 79 | 80 | ### setEmail 81 | 82 | **Signature:** `setEmail(email : String) : void` 83 | 84 | Sets the customer's email address. 85 | 86 | ## Method Detail 87 | 88 | ## Method Details 89 | 90 | ### getAuthenticationProviderID 91 | 92 | **Signature:** `getAuthenticationProviderID() : String` 93 | 94 | **Description:** Returns the authentication provider ID. 95 | 96 | **Returns:** 97 | 98 | the authentication provider ID. 99 | 100 | --- 101 | 102 | ### getCustomer 103 | 104 | **Signature:** `getCustomer() : Customer` 105 | 106 | **Description:** Returns the customer object related to this profile. 107 | 108 | **Returns:** 109 | 110 | customer object related to profile. 111 | 112 | --- 113 | 114 | ### getEmail 115 | 116 | **Signature:** `getEmail() : String` 117 | 118 | **Description:** Returns the customer's email address. 119 | 120 | **Returns:** 121 | 122 | the customer's email address. 123 | 124 | --- 125 | 126 | ### getExternalID 127 | 128 | **Signature:** `getExternalID() : String` 129 | 130 | **Description:** Returns the external ID. 131 | 132 | **Returns:** 133 | 134 | the external ID. 135 | 136 | --- 137 | 138 | ### getLastLoginTime 139 | 140 | **Signature:** `getLastLoginTime() : Date` 141 | 142 | **Description:** Returns the last login time of the customer through the external provider 143 | 144 | **Returns:** 145 | 146 | the time, when the customer was last logged in through this external provider 147 | 148 | --- 149 | 150 | ### setEmail 151 | 152 | **Signature:** `setEmail(email : String) : void` 153 | 154 | **Description:** Sets the customer's email address. 155 | 156 | **Parameters:** 157 | 158 | - `email`: the customer's email address. 159 | 160 | --- ``` -------------------------------------------------------------------------------- /tests/servers/sfcc-mock-server/src/middleware/logging.js: -------------------------------------------------------------------------------- ```javascript 1 | /** 2 | * Logging Middleware 3 | * 4 | * Provides request/response logging functionality for debugging and monitoring. 5 | * Configurable logging levels and output formatting. 6 | */ 7 | 8 | /** 9 | * Create request logging middleware 10 | */ 11 | function createRequestLogger(isDevMode = false) { 12 | if (!isDevMode) { 13 | // Return no-op middleware in production mode 14 | return (req, res, next) => next(); 15 | } 16 | 17 | return (req, res, next) => { 18 | const timestamp = new Date().toISOString(); 19 | const method = req.method; 20 | const url = req.url; 21 | const userAgent = req.headers['user-agent'] || 'Unknown'; 22 | 23 | console.log(`📥 [${timestamp}] ${method} ${url}`, { 24 | headers: { 25 | authorization: req.headers.authorization ? '[REDACTED]' : undefined, 26 | 'content-type': req.headers['content-type'], 27 | 'depth': req.headers.depth, 28 | 'range': req.headers.range, 29 | 'user-agent': userAgent 30 | }, 31 | query: Object.keys(req.query).length > 0 ? req.query : undefined, 32 | body: req.body && Object.keys(req.body).length > 0 ? req.body : undefined 33 | }); 34 | 35 | next(); 36 | }; 37 | } 38 | 39 | /** 40 | * Create response logging middleware 41 | */ 42 | function createResponseLogger(isDevMode = false) { 43 | if (!isDevMode) { 44 | // Return no-op middleware in production mode 45 | return (req, res, next) => next(); 46 | } 47 | 48 | return (req, res, next) => { 49 | const originalSend = res.send; 50 | const originalJson = res.json; 51 | 52 | // Override res.send 53 | res.send = function(body) { 54 | logResponse(req, res, body, 'send'); 55 | return originalSend.call(this, body); 56 | }; 57 | 58 | // Override res.json 59 | res.json = function(obj) { 60 | logResponse(req, res, obj, 'json'); 61 | return originalJson.call(this, obj); 62 | }; 63 | 64 | next(); 65 | }; 66 | } 67 | 68 | /** 69 | * Log response details 70 | */ 71 | function logResponse(req, res, body, type) { 72 | const timestamp = new Date().toISOString(); 73 | const method = req.method; 74 | const url = req.url; 75 | const statusCode = res.statusCode; 76 | 77 | let bodyPreview = body; 78 | 79 | // Truncate large responses for readability 80 | if (typeof body === 'string' && body.length > 500) { 81 | bodyPreview = body.substring(0, 500) + '... [truncated]'; 82 | } else if (typeof body === 'object' && body !== null) { 83 | const bodyStr = JSON.stringify(body); 84 | if (bodyStr.length > 500) { 85 | bodyPreview = JSON.stringify(body, null, 2).substring(0, 500) + '... [truncated]'; 86 | } 87 | } 88 | 89 | console.log(`📤 [${timestamp}] ${method} ${url} -> ${statusCode}`, { 90 | headers: { 91 | 'content-type': res.getHeader('content-type'), 92 | 'content-length': res.getHeader('content-length'), 93 | 'content-range': res.getHeader('content-range') 94 | }, 95 | type, 96 | body: bodyPreview 97 | }); 98 | } 99 | 100 | /** 101 | * Create error logging middleware 102 | */ 103 | function createErrorLogger() { 104 | return (err, req, res, next) => { 105 | const timestamp = new Date().toISOString(); 106 | const method = req.method; 107 | const url = req.url; 108 | 109 | console.error(`❌ [${timestamp}] ERROR ${method} ${url}:`, { 110 | message: err.message, 111 | stack: err.stack, 112 | code: err.code 113 | }); 114 | 115 | // Don't handle the error, just log it 116 | next(err); 117 | }; 118 | } 119 | 120 | module.exports = { 121 | createRequestLogger, 122 | createResponseLogger, 123 | createErrorLogger 124 | }; ``` -------------------------------------------------------------------------------- /docs/dw_campaign/CouponMgr.md: -------------------------------------------------------------------------------- ```markdown 1 | ## Package: dw.campaign 2 | 3 | # Class CouponMgr 4 | 5 | ## Inheritance Hierarchy 6 | 7 | - Object 8 | - dw.campaign.CouponMgr 9 | 10 | ## Description 11 | 12 | Manager to access coupons. 13 | 14 | ## Constants 15 | 16 | ### MR_ERROR_INVALID_SITE_ID 17 | 18 | **Type:** String = "MASKREDEMPTIONS_SITE_NOT_FOUND" 19 | 20 | Indicates that an error occurred because a valid data domain cannot be found for given siteID. 21 | 22 | ## Properties 23 | 24 | ### coupons 25 | 26 | **Type:** Collection (Read Only) 27 | 28 | All coupons in the current site in no specific order. 29 | 30 | ## Constructor Summary 31 | 32 | ## Method Summary 33 | 34 | ### getCoupon 35 | 36 | **Signature:** `static getCoupon(couponID : String) : Coupon` 37 | 38 | Returns the coupon with the specified ID. 39 | 40 | ### getCouponByCode 41 | 42 | **Signature:** `static getCouponByCode(couponCode : String) : Coupon` 43 | 44 | Tries to find a coupon for the given coupon code. 45 | 46 | ### getCoupons 47 | 48 | **Signature:** `static getCoupons() : Collection` 49 | 50 | Returns all coupons in the current site in no specific order. 51 | 52 | ### getRedemptions 53 | 54 | **Signature:** `static getRedemptions(couponID : String, couponCode : String) : Collection` 55 | 56 | Returns list of CouponRedemptions for the specified coupon and coupon code, sorted by redemption date descending (i.e. 57 | 58 | ### maskRedemptions 59 | 60 | **Signature:** `static maskRedemptions(siteID : String, email : String) : Status` 61 | 62 | Mask customer email address in coupon redemptions for the given siteID and email address 63 | 64 | ## Method Detail 65 | 66 | ## Method Details 67 | 68 | ### getCoupon 69 | 70 | **Signature:** `static getCoupon(couponID : String) : Coupon` 71 | 72 | **Description:** Returns the coupon with the specified ID. 73 | 74 | **Parameters:** 75 | 76 | - `couponID`: the coupon identifier. 77 | 78 | **Returns:** 79 | 80 | Coupon with specified ID or null 81 | 82 | --- 83 | 84 | ### getCouponByCode 85 | 86 | **Signature:** `static getCouponByCode(couponCode : String) : Coupon` 87 | 88 | **Description:** Tries to find a coupon for the given coupon code. The method first searches for a coupon with a fixed code matching the passed value. If no such fixed coupon is found, it searches for a coupon with a system-generated code matching the passed value. If found, the coupon is returned. Otherwise, the method returns null. 89 | 90 | **Parameters:** 91 | 92 | - `couponCode`: The coupon code to get the coupon for. 93 | 94 | **Returns:** 95 | 96 | The coupon with the matching coupon code or null if no coupon was found. 97 | 98 | --- 99 | 100 | ### getCoupons 101 | 102 | **Signature:** `static getCoupons() : Collection` 103 | 104 | **Description:** Returns all coupons in the current site in no specific order. 105 | 106 | **Returns:** 107 | 108 | Coupons in current site 109 | 110 | --- 111 | 112 | ### getRedemptions 113 | 114 | **Signature:** `static getRedemptions(couponID : String, couponCode : String) : Collection` 115 | 116 | **Description:** Returns list of CouponRedemptions for the specified coupon and coupon code, sorted by redemption date descending (i.e. last redemption first). Usually, there should only either be 0 or 1 redemption. But if a coupon and code is removed and recreated and re-issued later, there might be multiple such redemption records. Returns an empty list if no redemption record exists in system for the specified coupon and code. 117 | 118 | **Parameters:** 119 | 120 | - `couponID`: The coupon id to find redemption for. 121 | - `couponCode`: The coupon code to find redemption for. 122 | 123 | **Returns:** 124 | 125 | A sorted list of CouponRedemptions for the specified coupon and coupon code or an empty list if no redemption record exists. 126 | 127 | --- 128 | 129 | ### maskRedemptions 130 | 131 | **Signature:** `static maskRedemptions(siteID : String, email : String) : Status` 132 | 133 | **Description:** Mask customer email address in coupon redemptions for the given siteID and email address 134 | 135 | **Parameters:** 136 | 137 | - `siteID`: the site ID 138 | - `email`: the customer email address 139 | 140 | **Returns:** 141 | 142 | The status of the masking result 143 | 144 | --- ``` -------------------------------------------------------------------------------- /docs/dw_content/ContentMgr.md: -------------------------------------------------------------------------------- ```markdown 1 | ## Package: dw.content 2 | 3 | # Class ContentMgr 4 | 5 | ## Inheritance Hierarchy 6 | 7 | - Object 8 | - dw.content.ContentMgr 9 | 10 | ## Description 11 | 12 | Provides helper methods for getting content assets, library folders and the content library of the current site. 13 | 14 | ## Constants 15 | 16 | ### PRIVATE_LIBRARY 17 | 18 | **Type:** String = "PrivateLibrary" 19 | 20 | The input string to identify that the library is a private site library when invoking getLibrary(String). 21 | 22 | ## Properties 23 | 24 | ### siteLibrary 25 | 26 | **Type:** Library (Read Only) 27 | 28 | The content library of the current site. 29 | 30 | ## Constructor Summary 31 | 32 | ## Method Summary 33 | 34 | ### getContent 35 | 36 | **Signature:** `static getContent(id : String) : Content` 37 | 38 | Returns the content with the corresponding identifier within the current site's site library. 39 | 40 | ### getContent 41 | 42 | **Signature:** `static getContent(library : Library, id : String) : Content` 43 | 44 | Returns the content with the corresponding identifier within the specified library. 45 | 46 | ### getFolder 47 | 48 | **Signature:** `static getFolder(id : String) : Folder` 49 | 50 | Returns the folder identified by the specified id within the current site's site library. 51 | 52 | ### getFolder 53 | 54 | **Signature:** `static getFolder(library : Library, id : String) : Folder` 55 | 56 | Returns the folder identified by the specified id within the specified library. 57 | 58 | ### getLibrary 59 | 60 | **Signature:** `static getLibrary(libraryId : String) : Library` 61 | 62 | Returns the content library specified by the given id. 63 | 64 | ### getSiteLibrary 65 | 66 | **Signature:** `static getSiteLibrary() : Library` 67 | 68 | Returns the content library of the current site. 69 | 70 | ## Method Detail 71 | 72 | ## Method Details 73 | 74 | ### getContent 75 | 76 | **Signature:** `static getContent(id : String) : Content` 77 | 78 | **Description:** Returns the content with the corresponding identifier within the current site's site library. 79 | 80 | **Parameters:** 81 | 82 | - `id`: the ID of the content asset to find. 83 | 84 | **Returns:** 85 | 86 | the content if found, or null if not found. 87 | 88 | --- 89 | 90 | ### getContent 91 | 92 | **Signature:** `static getContent(library : Library, id : String) : Content` 93 | 94 | **Description:** Returns the content with the corresponding identifier within the specified library. 95 | 96 | **Parameters:** 97 | 98 | - `library`: the content library to look for the content in 99 | - `id`: the ID of the content asset to find. 100 | 101 | **Returns:** 102 | 103 | the content if found, or null if not found. 104 | 105 | --- 106 | 107 | ### getFolder 108 | 109 | **Signature:** `static getFolder(id : String) : Folder` 110 | 111 | **Description:** Returns the folder identified by the specified id within the current site's site library. 112 | 113 | **Parameters:** 114 | 115 | - `id`: the ID of the folder to find. 116 | 117 | **Returns:** 118 | 119 | the folder, or null if not found. 120 | 121 | --- 122 | 123 | ### getFolder 124 | 125 | **Signature:** `static getFolder(library : Library, id : String) : Folder` 126 | 127 | **Description:** Returns the folder identified by the specified id within the specified library. 128 | 129 | **Parameters:** 130 | 131 | - `library`: the content library to look for the folder in 132 | - `id`: the ID of the folder to find. 133 | 134 | **Returns:** 135 | 136 | the folder, or null if not found. 137 | 138 | --- 139 | 140 | ### getLibrary 141 | 142 | **Signature:** `static getLibrary(libraryId : String) : Library` 143 | 144 | **Description:** Returns the content library specified by the given id. If PRIVATE_LIBRARY is used, then the current site's private library will be returned. 145 | 146 | **Parameters:** 147 | 148 | - `libraryId`: the id of the library to return. 149 | 150 | **Returns:** 151 | 152 | the library for the passed id. Returns null if there is no content library with that id. 153 | 154 | --- 155 | 156 | ### getSiteLibrary 157 | 158 | **Signature:** `static getSiteLibrary() : Library` 159 | 160 | **Description:** Returns the content library of the current site. 161 | 162 | **Returns:** 163 | 164 | the content library of the current site, or null if there is not content library assigned to the current site. 165 | 166 | --- ``` -------------------------------------------------------------------------------- /docs/dw_customer/CustomerGroup.md: -------------------------------------------------------------------------------- ```markdown 1 | ## Package: dw.customer 2 | 3 | # Class CustomerGroup 4 | 5 | ## Inheritance Hierarchy 6 | 7 | - Object 8 | - dw.object.PersistentObject 9 | - dw.object.ExtensibleObject 10 | - dw.customer.CustomerGroup 11 | 12 | ## Description 13 | 14 | CustomerGroups provide a means to segment customers by various criteria. A merchant can then provide different site experiences (e.g. promotions, prices, sorting rules) to each customer segment. Customer groups can consist of either an explicit list of customers or a business rule that dynamically determines whether a customer is a member. The former type is called "explicit" and the latter type is called "dynamic". Explicit customer group: Consists of an explicit list of customers. Only registered customers can be member of such a group. isRuleBased==false. Dynamic customer group: Memberships are evaluated by a business rule that is attached to the customer group. Registered as well as anonymous customers can be member of such a group. isRuleBased==true. Note: this class might allow access to sensitive personal and private information, depending on how you segment your customers and the names given to your custoemer groups. Pay attention to appropriate legal and regulatory requirements when developing with this data. 15 | 16 | ## Properties 17 | 18 | ### description 19 | 20 | **Type:** String (Read Only) 21 | 22 | Gets the value of the description of the customer group. 23 | 24 | ### ID 25 | 26 | **Type:** String (Read Only) 27 | 28 | The unique ID of the customer group. 29 | 30 | ### ruleBased 31 | 32 | **Type:** boolean (Read Only) 33 | 34 | Returns true if the group determines the membership of customers 35 | based on rules. Returns false if the group provides explicit assignement 36 | of customers. 37 | 38 | ## Constructor Summary 39 | 40 | ## Method Summary 41 | 42 | ### assignCustomer 43 | 44 | **Signature:** `assignCustomer(customer : Customer) : void` 45 | 46 | Assigns the specified customer to this group. 47 | 48 | ### getDescription 49 | 50 | **Signature:** `getDescription() : String` 51 | 52 | Gets the value of the description of the customer group. 53 | 54 | ### getID 55 | 56 | **Signature:** `getID() : String` 57 | 58 | Returns the unique ID of the customer group. 59 | 60 | ### isRuleBased 61 | 62 | **Signature:** `isRuleBased() : boolean` 63 | 64 | Returns true if the group determines the membership of customers based on rules. 65 | 66 | ### unassignCustomer 67 | 68 | **Signature:** `unassignCustomer(customer : Customer) : void` 69 | 70 | Unassigns the specified customer from this group. 71 | 72 | ## Method Detail 73 | 74 | ## Method Details 75 | 76 | ### assignCustomer 77 | 78 | **Signature:** `assignCustomer(customer : Customer) : void` 79 | 80 | **Description:** Assigns the specified customer to this group. The customer must be registered and the group must not be rule-based. 81 | 82 | **Parameters:** 83 | 84 | - `customer`: Registered customer, must not be null. 85 | 86 | --- 87 | 88 | ### getDescription 89 | 90 | **Signature:** `getDescription() : String` 91 | 92 | **Description:** Gets the value of the description of the customer group. 93 | 94 | **Returns:** 95 | 96 | the description of the customer group 97 | 98 | --- 99 | 100 | ### getID 101 | 102 | **Signature:** `getID() : String` 103 | 104 | **Description:** Returns the unique ID of the customer group. 105 | 106 | **Returns:** 107 | 108 | The unique semantic ID of the customer group. 109 | 110 | --- 111 | 112 | ### isRuleBased 113 | 114 | **Signature:** `isRuleBased() : boolean` 115 | 116 | **Description:** Returns true if the group determines the membership of customers based on rules. Returns false if the group provides explicit assignement of customers. 117 | 118 | **Returns:** 119 | 120 | True, if the customer group is rule based. 121 | 122 | --- 123 | 124 | ### unassignCustomer 125 | 126 | **Signature:** `unassignCustomer(customer : Customer) : void` 127 | 128 | **Description:** Unassigns the specified customer from this group. The customer must be registered and the group must not be rule-based. 129 | 130 | **Parameters:** 131 | 132 | - `customer`: Registered customer, must not be null. 133 | 134 | --- ``` -------------------------------------------------------------------------------- /src/core/handlers/client-factory.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { HandlerContext } from './base-handler.js'; 2 | import { SFCCLogClient } from '../../clients/log-client.js'; 3 | import { OCAPIClient } from '../../clients/ocapi-client.js'; 4 | import { OCAPICodeVersionsClient } from '../../clients/ocapi/code-versions-client.js'; 5 | import { CartridgeGenerationClient } from '../../clients/cartridge-generation-client.js'; 6 | import { Logger } from '../../utils/logger.js'; 7 | import { IFileSystemService, IPathService, FileSystemService, PathService } from '../../services/index.js'; 8 | 9 | /** 10 | * Centralized client factory that handles complex initialization logic 11 | * and encapsulates the requirements for different client types. 12 | */ 13 | export class ClientFactory { 14 | private context: HandlerContext; 15 | private logger: Logger; 16 | 17 | constructor(context: HandlerContext, logger: Logger) { 18 | this.context = context; 19 | this.logger = logger; 20 | } 21 | 22 | /** 23 | * Create an SFCC Log Client if log access is available 24 | */ 25 | createLogClient(): SFCCLogClient | null { 26 | if (!this.context.capabilities?.canAccessLogs || !this.context.config) { 27 | this.logger.debug('Log client not created: missing log access capability or config'); 28 | return null; 29 | } 30 | 31 | this.logger.debug('Creating SFCC Log Client'); 32 | return new SFCCLogClient(this.context.config); 33 | } 34 | 35 | /** 36 | * Create an OCAPI Client if OCAPI access is available 37 | */ 38 | createOCAPIClient(): OCAPIClient | null { 39 | if (!this.hasOCAPICredentials()) { 40 | this.logger.debug('OCAPI client not created: missing OCAPI credentials or capability'); 41 | return null; 42 | } 43 | 44 | this.logger.debug('Creating OCAPI Client'); 45 | return new OCAPIClient({ 46 | hostname: this.context.config!.hostname!, 47 | clientId: this.context.config!.clientId!, 48 | clientSecret: this.context.config!.clientSecret!, 49 | version: 'v23_2', 50 | }); 51 | } 52 | 53 | /** 54 | * Create an OCAPI Code Versions Client if OCAPI access is available 55 | */ 56 | createCodeVersionsClient(): OCAPICodeVersionsClient | null { 57 | if (!this.hasOCAPICredentials()) { 58 | this.logger.debug('Code versions client not created: missing OCAPI credentials or capability'); 59 | return null; 60 | } 61 | 62 | this.logger.debug('Creating OCAPI Code Versions Client'); 63 | return new OCAPICodeVersionsClient({ 64 | hostname: this.context.config!.hostname!, 65 | clientId: this.context.config!.clientId!, 66 | clientSecret: this.context.config!.clientSecret!, 67 | version: 'v23_2', 68 | }); 69 | } 70 | 71 | /** 72 | * Check if OCAPI credentials and capability are available 73 | */ 74 | private hasOCAPICredentials(): boolean { 75 | return !!( 76 | this.context.capabilities?.canAccessOCAPI && 77 | this.context.config?.hostname && 78 | this.context.config?.clientId && 79 | this.context.config?.clientSecret 80 | ); 81 | } 82 | 83 | /** 84 | * Create a Cartridge Generation Client with injected dependencies 85 | */ 86 | createCartridgeClient( 87 | fileSystemService?: IFileSystemService, 88 | pathService?: IPathService, 89 | ): CartridgeGenerationClient { 90 | this.logger.debug('Creating Cartridge Generation Client'); 91 | return new CartridgeGenerationClient( 92 | fileSystemService ?? new FileSystemService(), 93 | pathService ?? new PathService(), 94 | ); 95 | } 96 | 97 | /** 98 | * Get the required error message for a client type 99 | */ 100 | static getClientRequiredError(clientType: 'OCAPI' | 'Log'): string { 101 | switch (clientType) { 102 | case 'OCAPI': 103 | return 'OCAPI client not configured - ensure credentials are provided in full mode.'; 104 | case 'Log': 105 | return 'Log client not configured - ensure log access is enabled.'; 106 | default: 107 | return 'Required client not configured.'; 108 | } 109 | } 110 | } 111 | ``` -------------------------------------------------------------------------------- /docs/dw_catalog/ProductOption.md: -------------------------------------------------------------------------------- ```markdown 1 | ## Package: dw.catalog 2 | 3 | # Class ProductOption 4 | 5 | ## Inheritance Hierarchy 6 | 7 | - Object 8 | - dw.object.PersistentObject 9 | - dw.object.ExtensibleObject 10 | - dw.catalog.ProductOption 11 | 12 | ## Description 13 | 14 | Represents a product option. 15 | 16 | ## Properties 17 | 18 | ### defaultValue 19 | 20 | **Type:** ProductOptionValue (Read Only) 21 | 22 | The default value for the product option. 23 | 24 | ### description 25 | 26 | **Type:** String (Read Only) 27 | 28 | The product option's short description in the current locale. 29 | 30 | ### displayName 31 | 32 | **Type:** String (Read Only) 33 | 34 | The product option's display name in the current locale. 35 | 36 | ### htmlName 37 | 38 | **Type:** String (Read Only) 39 | 40 | An HTML representation of the option id. 41 | 42 | ### ID 43 | 44 | **Type:** String (Read Only) 45 | 46 | The product option ID. 47 | 48 | ### image 49 | 50 | **Type:** MediaFile (Read Only) 51 | 52 | The product option's image. 53 | 54 | ### optionValues 55 | 56 | **Type:** Collection (Read Only) 57 | 58 | A collection containing the product option values. 59 | 60 | ## Constructor Summary 61 | 62 | ## Method Summary 63 | 64 | ### getDefaultValue 65 | 66 | **Signature:** `getDefaultValue() : ProductOptionValue` 67 | 68 | Returns the default value for the product option. 69 | 70 | ### getDescription 71 | 72 | **Signature:** `getDescription() : String` 73 | 74 | Returns the product option's short description in the current locale. 75 | 76 | ### getDisplayName 77 | 78 | **Signature:** `getDisplayName() : String` 79 | 80 | Returns the product option's display name in the current locale. 81 | 82 | ### getHtmlName 83 | 84 | **Signature:** `getHtmlName() : String` 85 | 86 | Returns an HTML representation of the option id. 87 | 88 | ### getHtmlName 89 | 90 | **Signature:** `getHtmlName(prefix : String) : String` 91 | 92 | Returns an HTML representation of the option id with the custom prefix. 93 | 94 | ### getID 95 | 96 | **Signature:** `getID() : String` 97 | 98 | Returns the product option ID. 99 | 100 | ### getImage 101 | 102 | **Signature:** `getImage() : MediaFile` 103 | 104 | Returns the product option's image. 105 | 106 | ### getOptionValues 107 | 108 | **Signature:** `getOptionValues() : Collection` 109 | 110 | Returns a collection containing the product option values. 111 | 112 | ## Method Detail 113 | 114 | ## Method Details 115 | 116 | ### getDefaultValue 117 | 118 | **Signature:** `getDefaultValue() : ProductOptionValue` 119 | 120 | **Description:** Returns the default value for the product option. 121 | 122 | **Returns:** 123 | 124 | the object for the relation 'defaultValue' 125 | 126 | --- 127 | 128 | ### getDescription 129 | 130 | **Signature:** `getDescription() : String` 131 | 132 | **Description:** Returns the product option's short description in the current locale. 133 | 134 | **Returns:** 135 | 136 | The value of the short description in the current locale, or null if it wasn't found. 137 | 138 | --- 139 | 140 | ### getDisplayName 141 | 142 | **Signature:** `getDisplayName() : String` 143 | 144 | **Description:** Returns the product option's display name in the current locale. 145 | 146 | **Returns:** 147 | 148 | The value of the display name in the current locale, or null if it wasn't found. 149 | 150 | --- 151 | 152 | ### getHtmlName 153 | 154 | **Signature:** `getHtmlName() : String` 155 | 156 | **Description:** Returns an HTML representation of the option id. 157 | 158 | **Returns:** 159 | 160 | an HTML representation of the option id. 161 | 162 | --- 163 | 164 | ### getHtmlName 165 | 166 | **Signature:** `getHtmlName(prefix : String) : String` 167 | 168 | **Description:** Returns an HTML representation of the option id with the custom prefix. 169 | 170 | **Parameters:** 171 | 172 | - `prefix`: a custom prefix for the html name. 173 | 174 | **Returns:** 175 | 176 | an HTML representation of the option id. 177 | 178 | --- 179 | 180 | ### getID 181 | 182 | **Signature:** `getID() : String` 183 | 184 | **Description:** Returns the product option ID. 185 | 186 | **Returns:** 187 | 188 | the product option identifier. 189 | 190 | --- 191 | 192 | ### getImage 193 | 194 | **Signature:** `getImage() : MediaFile` 195 | 196 | **Description:** Returns the product option's image. 197 | 198 | **Returns:** 199 | 200 | the product option's image. 201 | 202 | --- 203 | 204 | ### getOptionValues 205 | 206 | **Signature:** `getOptionValues() : Collection` 207 | 208 | **Description:** Returns a collection containing the product option values. 209 | 210 | **Returns:** 211 | 212 | a collection containing the product option values. 213 | 214 | --- ``` -------------------------------------------------------------------------------- /docs/dw_suggest/SuggestedTerm.md: -------------------------------------------------------------------------------- ```markdown 1 | ## Package: dw.suggest 2 | 3 | # Class SuggestedTerm 4 | 5 | ## Inheritance Hierarchy 6 | 7 | - Object 8 | - dw.suggest.SuggestedTerm 9 | 10 | ## Description 11 | 12 | A single suggested term. Each user input term of the search phrase is being processed separately by the suggestion engine. For each original term, a list of terms will be suggested, either completed terms, corrected terms or even the exact term if it is known to the engine. Each suggested term is represented by a instance of this class. The list of suggested terms belonging to a single original term is represented by a instance of SuggestedTerms class. The suggested term value can either be the completed version of the original term, the corrected version of the original term or exactly the original term. 13 | 14 | ## Properties 15 | 16 | ### additional 17 | 18 | **Type:** boolean (Read Only) 19 | 20 | Returns whether this suggested term is a additional term that has no corresponding term in the original search phrase. 21 | 22 | ### completed 23 | 24 | **Type:** boolean (Read Only) 25 | 26 | Returns whether this suggested term is a auto completed version of the original term. 27 | In other words, this method returns true if the original term is a prefix of this suggested term. 28 | 29 | ### corrected 30 | 31 | **Type:** boolean (Read Only) 32 | 33 | Returns whether this suggested term is a corrected version of the original term. 34 | 35 | ### exactMatch 36 | 37 | **Type:** boolean (Read Only) 38 | 39 | Returns whether this suggested term is exactly matching the original term. 40 | 41 | ### value 42 | 43 | **Type:** String (Read Only) 44 | 45 | Returns this suggested term as String value. 46 | 47 | ## Constructor Summary 48 | 49 | ## Method Summary 50 | 51 | ### getValue 52 | 53 | **Signature:** `getValue() : String` 54 | 55 | Returns this suggested term as String value. 56 | 57 | ### isAdditional 58 | 59 | **Signature:** `isAdditional() : boolean` 60 | 61 | Returns whether this suggested term is a additional term that has no corresponding term in the original search phrase. 62 | 63 | ### isCompleted 64 | 65 | **Signature:** `isCompleted() : boolean` 66 | 67 | Returns whether this suggested term is a auto completed version of the original term. 68 | 69 | ### isCorrected 70 | 71 | **Signature:** `isCorrected() : boolean` 72 | 73 | Returns whether this suggested term is a corrected version of the original term. 74 | 75 | ### isExactMatch 76 | 77 | **Signature:** `isExactMatch() : boolean` 78 | 79 | Returns whether this suggested term is exactly matching the original term. 80 | 81 | ## Method Detail 82 | 83 | ## Method Details 84 | 85 | ### getValue 86 | 87 | **Signature:** `getValue() : String` 88 | 89 | **Description:** Returns this suggested term as String value. 90 | 91 | **Returns:** 92 | 93 | the string representation of this suggested term 94 | 95 | --- 96 | 97 | ### isAdditional 98 | 99 | **Signature:** `isAdditional() : boolean` 100 | 101 | **Description:** Returns whether this suggested term is a additional term that has no corresponding term in the original search phrase. 102 | 103 | **Returns:** 104 | 105 | true if this suggested term is a additional term, false otherwise 106 | 107 | --- 108 | 109 | ### isCompleted 110 | 111 | **Signature:** `isCompleted() : boolean` 112 | 113 | **Description:** Returns whether this suggested term is a auto completed version of the original term. In other words, this method returns true if the original term is a prefix of this suggested term. 114 | 115 | **Returns:** 116 | 117 | true if this suggested term is evaluated by auto completion, false otherwise 118 | 119 | --- 120 | 121 | ### isCorrected 122 | 123 | **Signature:** `isCorrected() : boolean` 124 | 125 | **Description:** Returns whether this suggested term is a corrected version of the original term. 126 | 127 | **Returns:** 128 | 129 | true if this suggested term is a corrected version of the original term, false otherwise 130 | 131 | --- 132 | 133 | ### isExactMatch 134 | 135 | **Signature:** `isExactMatch() : boolean` 136 | 137 | **Description:** Returns whether this suggested term is exactly matching the original term. 138 | 139 | **Returns:** 140 | 141 | true if this suggested term exactly matches the original term, false otherwise 142 | 143 | --- ``` -------------------------------------------------------------------------------- /tests/servers/sfcc-mock-server/src/utils/webdav-xml.js: -------------------------------------------------------------------------------- ```javascript 1 | /** 2 | * WebDAV XML Response Utilities 3 | * 4 | * Handles generation of WebDAV XML responses for PROPFIND and other operations. 5 | * Provides clean, reusable functions for XML generation. 6 | */ 7 | 8 | const path = require('path'); 9 | 10 | /** 11 | * Generate WebDAV XML response for a single file 12 | */ 13 | function generateFileXmlResponse(urlPath, stats) { 14 | const filename = path.basename(urlPath); 15 | 16 | return `<?xml version="1.0" encoding="utf-8"?> 17 | <D:multistatus xmlns:D="DAV:"> 18 | <D:response> 19 | <D:href>${urlPath}</D:href> 20 | <D:propstat> 21 | <D:prop> 22 | <D:displayname>${filename}</D:displayname> 23 | <D:getcontentlength>${stats.size}</D:getcontentlength> 24 | <D:getlastmodified>${stats.mtime.toUTCString()}</D:getlastmodified> 25 | <D:resourcetype></D:resourcetype> 26 | <D:getcontenttype>text/plain</D:getcontenttype> 27 | </D:prop> 28 | <D:status>HTTP/1.1 200 OK</D:status> 29 | </D:propstat> 30 | </D:response> 31 | </D:multistatus>`; 32 | } 33 | 34 | /** 35 | * Generate WebDAV XML response for directory listing 36 | */ 37 | function generateDirectoryXmlResponse(urlPath, items, stats) { 38 | const directoryName = path.basename(urlPath) || 'Logs'; 39 | 40 | // Generate individual item entries 41 | const xmlItems = items.map(item => { 42 | const isDirectory = item.stats.isDirectory(); 43 | const itemUrl = urlPath.endsWith('/') ? `${urlPath}${item.name}` : `${urlPath}/${item.name}`; 44 | 45 | return ` 46 | <D:response> 47 | <D:href>${itemUrl}${isDirectory ? '/' : ''}</D:href> 48 | <D:propstat> 49 | <D:prop> 50 | <D:displayname>${item.name}</D:displayname> 51 | <D:getcontentlength>${isDirectory ? '' : item.stats.size}</D:getcontentlength> 52 | <D:getlastmodified>${item.stats.mtime.toUTCString()}</D:getlastmodified> 53 | <D:resourcetype>${isDirectory ? '<D:collection/>' : ''}</D:resourcetype> 54 | ${!isDirectory ? '<D:getcontenttype>text/plain</D:getcontenttype>' : ''} 55 | </D:prop> 56 | <D:status>HTTP/1.1 200 OK</D:status> 57 | </D:propstat> 58 | </D:response>`; 59 | }).join(''); 60 | 61 | return `<?xml version="1.0" encoding="utf-8"?> 62 | <D:multistatus xmlns:D="DAV:"> 63 | <D:response> 64 | <D:href>${urlPath}</D:href> 65 | <D:propstat> 66 | <D:prop> 67 | <D:displayname>${directoryName}</D:displayname> 68 | <D:resourcetype><D:collection/></D:resourcetype> 69 | </D:prop> 70 | <D:status>HTTP/1.1 200 OK</D:status> 71 | </D:propstat> 72 | </D:response>${xmlItems} 73 | </D:multistatus>`; 74 | } 75 | 76 | /** 77 | * Generate WebDAV error response 78 | */ 79 | function generateErrorXmlResponse(urlPath, statusCode, message) { 80 | return `<?xml version="1.0" encoding="utf-8"?> 81 | <D:multistatus xmlns:D="DAV:"> 82 | <D:response> 83 | <D:href>${urlPath}</D:href> 84 | <D:propstat> 85 | <D:status>HTTP/1.1 ${statusCode} ${message}</D:status> 86 | </D:propstat> 87 | </D:response> 88 | </D:multistatus>`; 89 | } 90 | 91 | /** 92 | * Parse WebDAV depth header 93 | */ 94 | function parseDepthHeader(depthHeader) { 95 | if (!depthHeader) return 'infinity'; 96 | 97 | const depth = depthHeader.toLowerCase(); 98 | if (depth === '0') return 0; 99 | if (depth === '1') return 1; 100 | return 'infinity'; 101 | } 102 | 103 | /** 104 | * Escape XML special characters 105 | */ 106 | function escapeXml(text) { 107 | return text 108 | .replace(/&/g, '&') 109 | .replace(/</g, '<') 110 | .replace(/>/g, '>') 111 | .replace(/"/g, '"') 112 | .replace(/'/g, '''); 113 | } 114 | 115 | module.exports = { 116 | generateFileXmlResponse, 117 | generateDirectoryXmlResponse, 118 | generateErrorXmlResponse, 119 | parseDepthHeader, 120 | escapeXml 121 | }; ``` -------------------------------------------------------------------------------- /docs/sfra/store.md: -------------------------------------------------------------------------------- ```markdown 1 | # SFRA Store Model 2 | 3 | ## Overview 4 | 5 | The Store model represents a physical store location in SFRA applications. It provides store information including location details, contact information, and store hours for store locator functionality and in-store pickup features. 6 | 7 | ## Constructor 8 | 9 | ```javascript 10 | function store(storeObject) 11 | ``` 12 | 13 | Creates a Store model instance from a store object. 14 | 15 | ### Parameters 16 | 17 | - `storeObject` (dw.catalog.Store) - A Store object from the SFCC API 18 | 19 | ## Properties 20 | 21 | ### ID 22 | **Type:** string 23 | 24 | Unique identifier for the store. 25 | 26 | ### name 27 | **Type:** string 28 | 29 | Display name of the store. 30 | 31 | ### address1 32 | **Type:** string 33 | 34 | Primary address line of the store location. 35 | 36 | ### address2 37 | **Type:** string 38 | 39 | Secondary address line (suite, building, etc.). 40 | 41 | ### city 42 | **Type:** string 43 | 44 | City where the store is located. 45 | 46 | ### postalCode 47 | **Type:** string 48 | 49 | Postal/ZIP code for the store location. 50 | 51 | ### latitude 52 | **Type:** number 53 | 54 | Latitude coordinate for the store location (used for mapping and distance calculations). 55 | 56 | ### longitude 57 | **Type:** number 58 | 59 | Longitude coordinate for the store location (used for mapping and distance calculations). 60 | 61 | ### phone 62 | **Type:** string (optional) 63 | 64 | Store phone number for customer contact. 65 | 66 | ### stateCode 67 | **Type:** string (optional) 68 | 69 | State or province code for the store location. 70 | 71 | ### countryCode 72 | **Type:** string (optional) 73 | 74 | Country code for the store location (extracted from countryCode.value). 75 | 76 | ### storeHours 77 | **Type:** string (optional) 78 | 79 | Store hours information as markup/HTML content for display. 80 | 81 | ## Usage Example 82 | 83 | ```javascript 84 | var store = require('*/cartridge/models/store'); 85 | var StoreMgr = require('dw/catalog/StoreMgr'); 86 | 87 | // Get a specific store 88 | var storeObject = StoreMgr.getStore('store-001'); 89 | var storeModel = new store(storeObject); 90 | 91 | // Access store properties 92 | console.log(storeModel.name); // "Downtown Location" 93 | console.log(storeModel.address1); // "123 Main St" 94 | console.log(storeModel.city); // "New York" 95 | console.log(storeModel.phone); // "555-123-4567" 96 | 97 | // Use coordinates for mapping 98 | if (storeModel.latitude && storeModel.longitude) { 99 | console.log('Location: ' + storeModel.latitude + ', ' + storeModel.longitude); 100 | } 101 | 102 | // Display store hours 103 | if (storeModel.storeHours) { 104 | console.log(storeModel.storeHours); // HTML markup for hours display 105 | } 106 | ``` 107 | 108 | ## Coordinate System 109 | 110 | The model provides geographic coordinates for: 111 | - **Mapping Integration** - Display stores on maps 112 | - **Distance Calculations** - Find nearest stores 113 | - **Location Services** - GPS-based store finding 114 | 115 | ## Conditional Properties 116 | 117 | Several properties are only included if they exist in the source store object: 118 | - **phone** - Only included if store has a phone number 119 | - **stateCode** - Only included for locations with state/province 120 | - **countryCode** - Only included if country is specified 121 | - **storeHours** - Only included if store hours are configured 122 | 123 | ## Store Hours Format 124 | 125 | Store hours are provided as markup/HTML content, allowing for: 126 | - Rich formatting of hours display 127 | - Multiple day ranges and special hours 128 | - Holiday hours and exceptions 129 | - Custom styling and presentation 130 | 131 | ## Notes 132 | 133 | - Handles missing store data gracefully 134 | - Provides essential location information for store locators 135 | - Includes geographic coordinates for mapping functionality 136 | - Supports international stores with flexible address formats 137 | - Store hours support rich HTML formatting 138 | - Null-safe property access for optional fields 139 | 140 | ## Related Models 141 | 142 | - **Stores Model** - Collection of store models 143 | - **Product Models** - May include store availability 144 | - **Cart Models** - May include store pickup options 145 | - **Address Models** - Similar address structure 146 | ``` -------------------------------------------------------------------------------- /docs/dw_campaign/SourceCodeInfo.md: -------------------------------------------------------------------------------- ```markdown 1 | ## Package: dw.campaign 2 | 3 | # Class SourceCodeInfo 4 | 5 | ## Inheritance Hierarchy 6 | 7 | - Object 8 | - dw.campaign.SourceCodeInfo 9 | 10 | ## Description 11 | 12 | Class representing a code (i.e. a "source code") that has been applied to a customer's session. Source codes can qualify customers for different campaigns, promotions, and other site experiences from those that the typical customer sees. Codes are organized into source code groups. Typically, a code is applied to a customer's session automatically by Commerce Cloud Digital when a customer accesses a Digital URL with a well known request parameter in the querystring. A code may also be explicitly applied to a customer session using the SetSourceCode pipelet. 13 | 14 | ## Constants 15 | 16 | ### STATUS_ACTIVE 17 | 18 | **Type:** Number = 2 19 | 20 | The literal source-code is found and currently active. 21 | 22 | ### STATUS_INACTIVE 23 | 24 | **Type:** Number = 1 25 | 26 | The literal source-code is found but not active. 27 | 28 | ### STATUS_INVALID 29 | 30 | **Type:** Number = 0 31 | 32 | The literal source-code is not found in the system. 33 | 34 | ## Properties 35 | 36 | ### code 37 | 38 | **Type:** String (Read Only) 39 | 40 | The literal source-code. 41 | 42 | ### group 43 | 44 | **Type:** SourceCodeGroup (Read Only) 45 | 46 | The associated source-code group. 47 | 48 | ### redirect 49 | 50 | **Type:** URLRedirect (Read Only) 51 | 52 | Retrieves the redirect information from the last processed SourceCodeGroup (active or inactive). If none exists, 53 | then the redirect information is retrieved from the source-code preferences, based on the active/inactive status 54 | of the SourceCodeGroup. The redirect information is then resolved to the output URL. If the redirect information 55 | cannot be resolved to a URL, or there is an error retrieving the preferences, then null is returned. 56 | 57 | ### status 58 | 59 | **Type:** Number (Read Only) 60 | 61 | The status of the source-code. One of the following: 62 | STATUS_INVALID - The source code is not found in the system. 63 | STATUS_INACTIVE - The source code is found but not active. 64 | STATUS_INACTIVE - The source code is found and active. 65 | 66 | ## Constructor Summary 67 | 68 | ## Method Summary 69 | 70 | ### getCode 71 | 72 | **Signature:** `getCode() : String` 73 | 74 | The literal source-code. 75 | 76 | ### getGroup 77 | 78 | **Signature:** `getGroup() : SourceCodeGroup` 79 | 80 | The associated source-code group. 81 | 82 | ### getRedirect 83 | 84 | **Signature:** `getRedirect() : URLRedirect` 85 | 86 | Retrieves the redirect information from the last processed SourceCodeGroup (active or inactive). 87 | 88 | ### getStatus 89 | 90 | **Signature:** `getStatus() : Number` 91 | 92 | The status of the source-code. 93 | 94 | ## Method Detail 95 | 96 | ## Method Details 97 | 98 | ### getCode 99 | 100 | **Signature:** `getCode() : String` 101 | 102 | **Description:** The literal source-code. 103 | 104 | **Returns:** 105 | 106 | the source-code. 107 | 108 | --- 109 | 110 | ### getGroup 111 | 112 | **Signature:** `getGroup() : SourceCodeGroup` 113 | 114 | **Description:** The associated source-code group. 115 | 116 | **Returns:** 117 | 118 | the source-code group. 119 | 120 | --- 121 | 122 | ### getRedirect 123 | 124 | **Signature:** `getRedirect() : URLRedirect` 125 | 126 | **Description:** Retrieves the redirect information from the last processed SourceCodeGroup (active or inactive). If none exists, then the redirect information is retrieved from the source-code preferences, based on the active/inactive status of the SourceCodeGroup. The redirect information is then resolved to the output URL. If the redirect information cannot be resolved to a URL, or there is an error retrieving the preferences, then null is returned. 127 | 128 | **Returns:** 129 | 130 | URLRedirect containing the location and status code, null in case of no redirect was found 131 | 132 | --- 133 | 134 | ### getStatus 135 | 136 | **Signature:** `getStatus() : Number` 137 | 138 | **Description:** The status of the source-code. One of the following: STATUS_INVALID - The source code is not found in the system. STATUS_INACTIVE - The source code is found but not active. STATUS_INACTIVE - The source code is found and active. 139 | 140 | **Returns:** 141 | 142 | the status. 143 | 144 | --- ``` -------------------------------------------------------------------------------- /docs/dw_util/FilteringCollection.md: -------------------------------------------------------------------------------- ```markdown 1 | ## Package: dw.util 2 | 3 | # Class FilteringCollection 4 | 5 | ## Inheritance Hierarchy 6 | 7 | - Object 8 | - dw.util.Collection 9 | - dw.util.FilteringCollection 10 | 11 | ## Description 12 | 13 | FilteringCollection is an extension of Collection which provides possibilities to filter the elements to return a new FilteringCollection with a filtered set of elements sort the elements to return a new FilteringCollection with a defined sort order transform the elements to return a new FilteringCollection containing related elements provide a map of the elements against a predefined key Usage - In the current version each FilteringCollection provides a set of predefined qualifier constants which can be passed into the select(Object) method used to filter the elements. Generally qualifiers have the prefix QUALIFIER_. A second method sort(Object) is used to create a new instance with a different element ordering, which takes an orderB< constant. Generally orderBys have the prefix ORDERBY_: examples are ShippingOrder.ORDERBY_ITEMID, ShippingOrder.ORDERBY_ITEMPOSITION, and ORDERBY_REVERSE can be used to provide a FilteringCollection with the reverse ordering. An example with method ShippingOrder.getItems(): var allItems : FilteringCollection = shippingOrder.items; var productItems : FilteringCollection = allItems.select(ShippingOrder.QUALIFIER_PRODUCTITEMS); var serviceItems : FilteringCollection = allItems.select(ShippingOrder.QUALIFIER_SERVICEITEMS); var byPosition : FilteringCollection = productItems.sort(ShippingOrder.ORDERBY_ITEMPOSITION); var revByPosition: FilteringCollection = byPosition.sort(FilteringCollection.ORDERBY_REVERSE); var mapByItemID : Map = allItems.asMap(); 14 | 15 | ## Constants 16 | 17 | ### ORDERBY_REVERSE 18 | 19 | **Type:** Object 20 | 21 | Pass this orderBy with the sort(Object) method to obtain a new FilteringCollection with the reversed sort order. Only use on a FilteringCollection which has been previously sorted. 22 | 23 | ## Properties 24 | 25 | ## Constructor Summary 26 | 27 | ## Method Summary 28 | 29 | ### asMap 30 | 31 | **Signature:** `asMap() : Map` 32 | 33 | Returns a Map containing the elements of this FilteringCollection against a predefined key. 34 | 35 | ### select 36 | 37 | **Signature:** `select(qualifier : Object) : FilteringCollection` 38 | 39 | Select a new FilteringCollection instance by passing a predefined qualifier as an argument to this method. 40 | 41 | ### sort 42 | 43 | **Signature:** `sort(orderBy : Object) : FilteringCollection` 44 | 45 | Select a new FilteringCollection instance by passing a predefined orderBy as an argument to this method. 46 | 47 | ## Method Detail 48 | 49 | ## Method Details 50 | 51 | ### asMap 52 | 53 | **Signature:** `asMap() : Map` 54 | 55 | **Description:** Returns a Map containing the elements of this FilteringCollection against a predefined key. The key used is documented in the method returning the FilteringCollection and is typically the ItemID assigned to an element in the collection. 56 | 57 | **Returns:** 58 | 59 | a Map containing the elements of this FilteringCollection against a predefined key. 60 | 61 | --- 62 | 63 | ### select 64 | 65 | **Signature:** `select(qualifier : Object) : FilteringCollection` 66 | 67 | **Description:** Select a new FilteringCollection instance by passing a predefined qualifier as an argument to this method. See FilteringCollection. 68 | 69 | **Parameters:** 70 | 71 | - `qualifier`: possible qualifiers are documented in the method returning the FilteringCollection 72 | 73 | **Returns:** 74 | 75 | a new FilteringCollection instance 76 | 77 | --- 78 | 79 | ### sort 80 | 81 | **Signature:** `sort(orderBy : Object) : FilteringCollection` 82 | 83 | **Description:** Select a new FilteringCollection instance by passing a predefined orderBy as an argument to this method. See FilteringCollection. 84 | 85 | **Parameters:** 86 | 87 | - `orderBy`: possible orderBys are documented in the method returning the FilteringCollection 88 | 89 | **Returns:** 90 | 91 | a new FilteringCollection instance 92 | 93 | --- ``` -------------------------------------------------------------------------------- /docs/dw_catalog/CategoryAssignment.md: -------------------------------------------------------------------------------- ```markdown 1 | ## Package: dw.catalog 2 | 3 | # Class CategoryAssignment 4 | 5 | ## Inheritance Hierarchy 6 | 7 | - Object 8 | - dw.object.PersistentObject 9 | - dw.object.ExtensibleObject 10 | - dw.catalog.CategoryAssignment 11 | 12 | ## Description 13 | 14 | Represents a category assignment in Commerce Cloud Digital. 15 | 16 | ## Properties 17 | 18 | ### calloutMsg 19 | 20 | **Type:** MarkupText (Read Only) 21 | 22 | The category assignment's callout message in the current locale. 23 | 24 | ### category 25 | 26 | **Type:** Category (Read Only) 27 | 28 | The category to which this category assignment is bound. 29 | 30 | ### image 31 | 32 | **Type:** MediaFile (Read Only) 33 | 34 | The category assignment's image. 35 | 36 | ### longDescription 37 | 38 | **Type:** MarkupText (Read Only) 39 | 40 | The category assignment's long description in the current locale. 41 | 42 | ### name 43 | 44 | **Type:** String (Read Only) 45 | 46 | The name of the category assignment in the current locale. 47 | 48 | ### product 49 | 50 | **Type:** Product (Read Only) 51 | 52 | The product to which this category assignment is bound. 53 | 54 | ### shortDescription 55 | 56 | **Type:** MarkupText (Read Only) 57 | 58 | The category assignment's short description in the current locale. 59 | 60 | ## Constructor Summary 61 | 62 | ## Method Summary 63 | 64 | ### getCalloutMsg 65 | 66 | **Signature:** `getCalloutMsg() : MarkupText` 67 | 68 | Returns the category assignment's callout message in the current locale. 69 | 70 | ### getCategory 71 | 72 | **Signature:** `getCategory() : Category` 73 | 74 | Returns the category to which this category assignment is bound. 75 | 76 | ### getImage 77 | 78 | **Signature:** `getImage() : MediaFile` 79 | 80 | Returns the category assignment's image. 81 | 82 | ### getLongDescription 83 | 84 | **Signature:** `getLongDescription() : MarkupText` 85 | 86 | Returns the category assignment's long description in the current locale. 87 | 88 | ### getName 89 | 90 | **Signature:** `getName() : String` 91 | 92 | Returns the name of the category assignment in the current locale. 93 | 94 | ### getProduct 95 | 96 | **Signature:** `getProduct() : Product` 97 | 98 | Returns the product to which this category assignment is bound. 99 | 100 | ### getShortDescription 101 | 102 | **Signature:** `getShortDescription() : MarkupText` 103 | 104 | Returns the category assignment's short description in the current locale. 105 | 106 | ## Method Detail 107 | 108 | ## Method Details 109 | 110 | ### getCalloutMsg 111 | 112 | **Signature:** `getCalloutMsg() : MarkupText` 113 | 114 | **Description:** Returns the category assignment's callout message in the current locale. 115 | 116 | **Returns:** 117 | 118 | the category assignment's callout message in the current locale, or null if it wasn't found. 119 | 120 | --- 121 | 122 | ### getCategory 123 | 124 | **Signature:** `getCategory() : Category` 125 | 126 | **Description:** Returns the category to which this category assignment is bound. 127 | 128 | **Returns:** 129 | 130 | The category to which this category assignment is bound. 131 | 132 | --- 133 | 134 | ### getImage 135 | 136 | **Signature:** `getImage() : MediaFile` 137 | 138 | **Description:** Returns the category assignment's image. 139 | 140 | **Returns:** 141 | 142 | the category assignment's image. 143 | 144 | --- 145 | 146 | ### getLongDescription 147 | 148 | **Signature:** `getLongDescription() : MarkupText` 149 | 150 | **Description:** Returns the category assignment's long description in the current locale. 151 | 152 | **Returns:** 153 | 154 | The category assignment's long description in the current locale, or null if it wasn't found. 155 | 156 | --- 157 | 158 | ### getName 159 | 160 | **Signature:** `getName() : String` 161 | 162 | **Description:** Returns the name of the category assignment in the current locale. 163 | 164 | **Returns:** 165 | 166 | The name of the category assignment for the current locale, or null if it wasn't found. 167 | 168 | --- 169 | 170 | ### getProduct 171 | 172 | **Signature:** `getProduct() : Product` 173 | 174 | **Description:** Returns the product to which this category assignment is bound. 175 | 176 | **Returns:** 177 | 178 | The product to which this category assignment is bound. 179 | 180 | --- 181 | 182 | ### getShortDescription 183 | 184 | **Signature:** `getShortDescription() : MarkupText` 185 | 186 | **Description:** Returns the category assignment's short description in the current locale. 187 | 188 | **Returns:** 189 | 190 | the category assignment's short description in the current locale, or null if it wasn't found. 191 | 192 | --- ``` -------------------------------------------------------------------------------- /tests/servers/sfcc-mock-server/src/config/server-config.js: -------------------------------------------------------------------------------- ```javascript 1 | /** 2 | * Server Configuration Management 3 | * 4 | * Handles server configuration with sensible defaults and environment overrides. 5 | * Follows single responsibility principle for configuration management. 6 | */ 7 | 8 | class ServerConfig { 9 | constructor(options = {}) { 10 | // Server basics 11 | this.port = options.port || process.env.PORT || 3000; 12 | this.host = options.host || process.env.HOST || 'localhost'; 13 | this.isDevMode = options.dev || process.env.NODE_ENV === 'development' || false; 14 | 15 | // API versions 16 | this.ocapiVersion = options.ocapiVersion || 'v23_2'; 17 | 18 | // Paths 19 | this.mockDataPath = options.mockDataPath || require('path').join(__dirname, '../../mock-data'); 20 | this.webdavBasePath = '/on/demandware.servlet/webdav/Sites'; 21 | 22 | // Authentication - Mock credentials for testing 23 | this.validCredentials = { 24 | clientId: 'test-client-id', 25 | clientSecret: 'test-client-secret', 26 | username: 'test-user', 27 | password: 'test-password' 28 | }; 29 | 30 | // Features toggle 31 | this.features = { 32 | webdav: options.enableWebdav !== false, // enabled by default 33 | ocapi: options.enableOcapi !== false, // enabled by default 34 | cors: options.enableCors !== false, // enabled by default 35 | logging: options.enableLogging !== false, // enabled by default 36 | randomErrors: options.enableRandomErrors === true // disabled by default for reliable tests 37 | }; 38 | } 39 | 40 | /** 41 | * Get WebDAV configuration 42 | */ 43 | getWebdavConfig() { 44 | return { 45 | basePath: this.webdavBasePath, 46 | logsPath: require('path').join(this.mockDataPath, 'logs'), 47 | enabled: this.features.webdav 48 | }; 49 | } 50 | 51 | /** 52 | * Get OCAPI configuration 53 | */ 54 | getOcapiConfig() { 55 | return { 56 | version: this.ocapiVersion, 57 | basePath: `/s/-/dw/data/${this.ocapiVersion}`, 58 | mockDataPath: require('path').join(this.mockDataPath, 'ocapi'), 59 | enabled: this.features.ocapi 60 | }; 61 | } 62 | 63 | /** 64 | * Get full server URL 65 | */ 66 | getServerUrl() { 67 | return `http://${this.host}:${this.port}`; 68 | } 69 | 70 | /** 71 | * Get WebDAV logs URL 72 | */ 73 | getWebdavLogsUrl() { 74 | return `${this.getServerUrl()}${this.webdavBasePath}/Logs/`; 75 | } 76 | 77 | /** 78 | * Get OCAPI base URL 79 | */ 80 | getOcapiBaseUrl() { 81 | return `${this.getServerUrl()}/s/-/dw/data/${this.ocapiVersion}`; 82 | } 83 | 84 | /** 85 | * Validate configuration 86 | */ 87 | validate() { 88 | const errors = []; 89 | 90 | if (!this.port || this.port < 1 || this.port > 65535) { 91 | errors.push('Invalid port number'); 92 | } 93 | 94 | if (!this.host || typeof this.host !== 'string') { 95 | errors.push('Invalid host'); 96 | } 97 | 98 | if (!this.features.webdav && !this.features.ocapi) { 99 | errors.push('At least one feature (WebDAV or OCAPI) must be enabled'); 100 | } 101 | 102 | return errors; 103 | } 104 | 105 | /** 106 | * Get configuration summary for logging 107 | */ 108 | getSummary() { 109 | return { 110 | server: `${this.host}:${this.port}`, 111 | mode: this.isDevMode ? 'development' : 'production', 112 | features: Object.entries(this.features) 113 | .filter(([_, enabled]) => enabled) 114 | .map(([feature, _]) => feature), 115 | endpoints: { 116 | ...(this.features.webdav && { webdav: this.getWebdavLogsUrl() }), 117 | ...(this.features.ocapi && { ocapi: this.getOcapiBaseUrl() }), 118 | health: `${this.getServerUrl()}/health` 119 | } 120 | }; 121 | } 122 | } 123 | 124 | module.exports = ServerConfig; ``` -------------------------------------------------------------------------------- /docs/dw_system/RemoteInclude.md: -------------------------------------------------------------------------------- ```markdown 1 | ## Package: dw.system 2 | 3 | # Class RemoteInclude 4 | 5 | ## Inheritance Hierarchy 6 | 7 | - Object 8 | - dw.system.RemoteInclude 9 | 10 | ## Description 11 | 12 | The class represents a remote include value that can be assigned to JSON Object properties. Important notes: Authentication and authorization checks are performed only for the top level request, but NOT for remote include requests. The RestResponseMgr method createScapiRemoteInclude() allows only SCAPI URLs. The RestResponseMgr method createStorefrontControllerRemoteInclude() allows only Controller URLs. Correct rendering of RemoteInclude-containing objects is only performed when processed by dw.system.RESTSuccessResponse.render() method. Please check the provided examples. Example 1. Specify remote include properties. function specifyRemoteIncludeProperties() { var includeValue0 = dw.system.RESTResponseMgr.createScapiRemoteInclude("custom", "sample", "v1", "resource/path/0", dw.web.URLParameter("siteId", "TestWapi")); var includeValue1 = dw.system.RESTResponseMgr.createScapiRemoteInclude("custom", "sample", "v1", "resource/path/1", dw.web.URLParameter("siteId", "TestWapi")); var greeting = { "hello": "world", "includeProperty0": includeValue0, "includeProperty1": includeValue1 }; dw.system.RESTResponseMgr.createSuccess(greeting).render(); } Example 2. Specify array of remote include properties. function specifyArrayOfRemoteIncludes() { var includeValue0 = dw.system.RESTResponseMgr.createScapiRemoteInclude("custom", "sample", "v1", "resource/path/0", dw.web.URLParameter("siteId", "TestWapi")); var includeValue1 = dw.system.RESTResponseMgr.createScapiRemoteInclude("custom", "sample", "v1", "resource/path/1", dw.web.URLParameter("siteId", "TestWapi")); var greeting = { "hello": "world", "includeArray": [includeValue0, includeValue1] }; dw.system.RESTResponseMgr.createSuccess(greeting).render(); } Example 3. Storefront controller remote include. function storefrontRemoteInclude() { let remoteInclude = dw.system.RESTResponseMgr.createStorefrontControllerRemoteInclude(new URLAction("Category-Show", "Sites-MyShop-Site", dw.web.URLParameter("cid", "root"))); let json = { status: "JSONOK", include: remoteInclude }; dw.system.RESTResponseMgr.createSuccess(json).render(); } Error handling: SCAPI: In case of 404 response received on included resource, an empty JSON object '{}' will be supplied in final JSON. In case of 201..299, 3xx, 4xx (excluding 404), 5xx response from included resource, final response status will be 500 'Internal Server Error' Controllers: In case of any non 200 response from the included resource an empty string will be included. Note: In case your response format is JSON be aware that this can result in invalid JSON. 13 | 14 | ## Properties 15 | 16 | ### url 17 | 18 | **Type:** String (Read Only) 19 | 20 | The URL string value specified for the current instance. 21 | 22 | ### value 23 | 24 | **Type:** String (Read Only) 25 | 26 | ## Constructor Summary 27 | 28 | ## Method Summary 29 | 30 | ### getUrl 31 | 32 | **Signature:** `getUrl() : String` 33 | 34 | Returns the URL string value specified for the current instance. 35 | 36 | ### toString 37 | 38 | **Signature:** `toString() : String` 39 | 40 | Returns the URL string value specified for the current instance, same as getUrl(). 41 | 42 | ### valueOf 43 | 44 | **Signature:** `valueOf() : Object` 45 | 46 | Returns the URL string value specified for the current instance, same as getUrl(). 47 | 48 | ## Method Detail 49 | 50 | ## Method Details 51 | 52 | ### getUrl 53 | 54 | **Signature:** `getUrl() : String` 55 | 56 | **Description:** Returns the URL string value specified for the current instance. 57 | 58 | --- 59 | 60 | ### toString 61 | 62 | **Signature:** `toString() : String` 63 | 64 | **Description:** Returns the URL string value specified for the current instance, same as getUrl(). 65 | 66 | --- 67 | 68 | ### valueOf 69 | 70 | **Signature:** `valueOf() : Object` 71 | 72 | **Description:** Returns the URL string value specified for the current instance, same as getUrl(). 73 | 74 | --- ``` -------------------------------------------------------------------------------- /docs/sfra/price-tiered.md: -------------------------------------------------------------------------------- ```markdown 1 | # SFRA Tiered Price Model 2 | 3 | ## Overview 4 | 5 | The Tiered Price model represents quantity-based pricing in SFRA applications, where products have different prices based on the quantity purchased. This enables bulk discounts and volume pricing strategies. 6 | 7 | ## Constructor 8 | 9 | ```javascript 10 | function TieredPrice(priceTable, useSimplePrice) 11 | ``` 12 | 13 | Creates a Tiered Price model instance with quantity-based pricing tiers. 14 | 15 | ### Parameters 16 | 17 | - `priceTable` (dw.catalog.ProductPriceTable) - Product price table from the API 18 | - `useSimplePrice` (boolean) - Flag indicating if this is for a product tile (optional) 19 | 20 | ## Properties 21 | 22 | ### type 23 | **Type:** string 24 | 25 | Always set to 'tiered' to identify this as a tiered price model. 26 | 27 | ### useSimplePrice 28 | **Type:** boolean 29 | 30 | Flag indicating whether this price is intended for simplified display (e.g., product tiles). Defaults to false. 31 | 32 | ### tiers 33 | **Type:** Array<Object> 34 | 35 | Array of pricing tier objects, each containing: 36 | - `quantity` (number) - Minimum quantity for this price tier 37 | - `price` (DefaultPrice) - Price object for this quantity tier 38 | 39 | ### startingFromPrice 40 | **Type:** DefaultPrice 41 | 42 | The lowest price available across all tiers, representing the "starting from" price for marketing display. Access the formatted price via `.sales.formatted`. 43 | 44 | ## Tier Structure 45 | 46 | Each tier object in the tiers array contains: 47 | 48 | ### quantity 49 | Minimum quantity required to qualify for this price tier. 50 | 51 | ### price 52 | ### price 53 | Complete DefaultPrice object created with only the sales price for this tier (accessed via `.sales` property). 54 | 55 | ## Usage Example 56 | 57 | ```javascript 58 | var TieredPrice = require('*/cartridge/models/price/tiered'); 59 | 60 | // Get tiered pricing from product 61 | var product = ProductMgr.getProduct('bulk-product-id'); 62 | var priceTable = product.getPriceModel().getPriceTable(); 63 | 64 | var tieredPrice = new TieredPrice(priceTable, false); 65 | 66 | console.log(tieredPrice.type); // "tiered" 67 | console.log('Starting from: ' + tieredPrice.startingFromPrice.sales.formatted); 68 | 69 | // Display all price tiers 70 | tieredPrice.tiers.forEach(function(tier) { 71 | console.log('Buy ' + tier.quantity + '+ for ' + tier.price.sales.formatted + ' each'); 72 | }); 73 | 74 | // Example output: 75 | // Buy 1+ for $10.00 each 76 | // Buy 5+ for $9.00 each 77 | // Buy 10+ for $8.00 each 78 | ``` 79 | 80 | ## Price Calculation Logic 81 | 82 | The model automatically: 83 | 1. **Processes all quantity breaks** from the price table using `collections.map` 84 | 2. **Creates DefaultPrice instances** with only sales price for each tier 85 | 3. **Identifies the lowest price** by comparing `price.sales.value` across all tiers 86 | 4. **Sets startingFromPrice** to the best available price 87 | 5. **Maintains tier order** based on quantity requirements 88 | 6. **Converts quantities** to numeric values using `quantity.getValue()` 89 | 90 | ## Display Modes 91 | 92 | ### Full Pricing (useSimplePrice = false) 93 | - Shows all pricing tiers 94 | - Includes complete quantity break information 95 | - Used on product detail pages 96 | 97 | ### Simple Pricing (useSimplePrice = true) 98 | - Optimized for product tiles and listings 99 | - Focuses on starting price and key tiers 100 | - Simplified display for grid views 101 | 102 | ## Notes 103 | 104 | - Automatically calculates the best "starting from" price by comparing sales values 105 | - Each tier DefaultPrice is created with only sales price (access via `.sales` property) 106 | - Uses `collections.map` utility to process price table quantities 107 | - Supports unlimited number of quantity tiers 108 | - Each tier uses DefaultPrice for consistent formatting 109 | - Useful for B2B and bulk purchasing scenarios 110 | - Type property enables template conditional logic 111 | - `useSimplePrice` defaults to `false` if not provided 112 | 113 | ## Related Models 114 | 115 | - **DefaultPrice Model** - Used for individual tier pricing 116 | - **RangePrice Model** - Alternative pricing model for price ranges 117 | - **Product Models** - Use tiered prices for bulk products 118 | ``` -------------------------------------------------------------------------------- /docs/sfra/cart.md: -------------------------------------------------------------------------------- ```markdown 1 | # SFRA Cart Model 2 | 3 | ## Overview 4 | 5 | The Cart model represents the current customer's shopping basket in SFRA applications. It provides comprehensive cart functionality including product line items, shipping methods, totals, discounts, and cart actions. 6 | 7 | ## Constructor 8 | 9 | ```javascript 10 | function CartModel(basket) 11 | ``` 12 | 13 | Creates a Cart model instance from a basket object. 14 | 15 | ### Parameters 16 | 17 | - `basket` (dw.order.Basket) - Current user's basket 18 | 19 | ## Properties 20 | 21 | ### items 22 | **Type:** Array<Object> 23 | 24 | Array of product line items in the cart. Each item contains product information, quantity, pricing, and other details. 25 | 26 | ### numItems 27 | **Type:** number 28 | 29 | Total number of items (quantity) in the cart. 30 | 31 | ### totals 32 | **Type:** TotalsModel 33 | 34 | Totals model containing cart pricing information including subtotals, taxes, shipping costs, and grand total. 35 | 36 | ### shipments 37 | **Type:** Array<Object> 38 | 39 | Array of shipment objects, each containing: 40 | - `shippingMethods` - Available shipping methods for the shipment 41 | - `selectedShippingMethod` - ID of the currently selected shipping method 42 | 43 | ### numOfShipments 44 | **Type:** number 45 | 46 | Number of shipments in the cart. 47 | 48 | ### hasBonusProduct 49 | **Type:** boolean 50 | 51 | Indicates whether the cart contains any bonus products from promotions. 52 | 53 | ### actionUrls 54 | **Type:** Object 55 | 56 | Object containing URLs for cart actions: 57 | - `removeProductLineItemUrl` - URL to remove product line items 58 | - `updateQuantityUrl` - URL to update item quantities 59 | - `selectShippingUrl` - URL to select shipping methods 60 | - `submitCouponCodeUrl` - URL to add coupon codes 61 | - `removeCouponLineItem` - URL to remove coupon line items 62 | 63 | ### approachingDiscounts 64 | **Type:** Array<Object> 65 | 66 | Array of approaching discount objects, each containing: 67 | - `discountMsg` - Message describing the approaching discount 68 | 69 | ### valid 70 | **Type:** boolean 71 | 72 | Indicates whether the basket is valid based on validation hooks. 73 | 74 | ### resources 75 | **Type:** Object 76 | 77 | Object containing localized resource strings: 78 | - `numberOfItems` - Formatted message showing number of items in cart 79 | - `minicartCountOfItems` - Formatted message for minicart count 80 | - `emptyCartMsg` - Message displayed when cart is empty 81 | 82 | ## Helper Functions 83 | 84 | ### getApproachingDiscounts(basket, discountPlan) 85 | Generates an object of approaching discounts based on current basket and discount plan. 86 | 87 | **Parameters:** 88 | - `basket` (dw.order.Basket) - Current user's basket 89 | - `discountPlan` (dw.campaign.DiscountPlan) - Set of applicable discounts 90 | 91 | **Returns:** Object - Object containing approaching discount information 92 | 93 | ### getCartActionUrls() 94 | Generates an object of URLs used for cart actions. 95 | 96 | **Returns:** Object - Object containing cart action URLs in string format 97 | 98 | ## Usage Example 99 | 100 | ```javascript 101 | var CartModel = require('*/cartridge/models/cart'); 102 | var BasketMgr = require('dw/order/BasketMgr'); 103 | 104 | var currentBasket = BasketMgr.getCurrentBasket(); 105 | var cart = new CartModel(currentBasket); 106 | 107 | // Access cart properties 108 | console.log(cart.numItems); 109 | console.log(cart.totals.grandTotal); 110 | console.log(cart.actionUrls.updateQuantityUrl); 111 | 112 | // Check if cart has items 113 | if (cart.items && cart.items.length > 0) { 114 | // Process cart items 115 | cart.items.forEach(function(item) { 116 | console.log(item.productName); 117 | }); 118 | } 119 | ``` 120 | 121 | ## Notes 122 | 123 | - If basket is null, the cart will have empty items array and numItems of 0 124 | - The model automatically calculates shipping methods for each shipment 125 | - Bonus products from promotions are tracked separately 126 | - Cart validation is performed using hooks 127 | - All action URLs are generated dynamically using URLUtils 128 | 129 | ## Related Models 130 | 131 | - **TotalsModel** - Used for cart pricing calculations 132 | - **ProductLineItemsModel** - Used for product line item formatting 133 | - **Shipping Models** - Used for shipping method information 134 | - **Address Model** - Used for shipping addresses 135 | ``` -------------------------------------------------------------------------------- /eslint.config.js: -------------------------------------------------------------------------------- ```javascript 1 | import js from '@eslint/js'; 2 | import tseslint from 'typescript-eslint'; 3 | 4 | export default tseslint.config( 5 | // Base recommended configs 6 | js.configs.recommended, 7 | ...tseslint.configs.recommended, 8 | 9 | // Global settings 10 | { 11 | languageOptions: { 12 | ecmaVersion: 2022, 13 | sourceType: 'module', 14 | globals: { 15 | console: 'readonly', 16 | process: 'readonly', 17 | Buffer: 'readonly', 18 | __dirname: 'readonly', 19 | __filename: 'readonly', 20 | }, 21 | }, 22 | }, 23 | 24 | // TypeScript files 25 | { 26 | files: ['**/*.ts', '**/*.tsx'], 27 | languageOptions: { 28 | parser: tseslint.parser, 29 | parserOptions: { 30 | project: ['./tsconfig.json', './tsconfig.test.json'], 31 | tsconfigRootDir: import.meta.dirname, 32 | }, 33 | }, 34 | rules: { 35 | // TypeScript specific rules 36 | '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }], 37 | '@typescript-eslint/no-explicit-any': 'off', 38 | '@typescript-eslint/explicit-function-return-type': 'off', 39 | '@typescript-eslint/explicit-module-boundary-types': 'off', 40 | '@typescript-eslint/no-non-null-assertion': 'off', 41 | '@typescript-eslint/prefer-nullish-coalescing': 'error', 42 | '@typescript-eslint/prefer-optional-chain': 'error', 43 | '@typescript-eslint/no-empty-object-type': 'off', 44 | 45 | // General code quality rules 46 | 'no-console': 'off', 47 | 'prefer-const': 'error', 48 | 'no-var': 'error', 49 | 'object-shorthand': 'error', 50 | 'prefer-arrow-callback': 'error', 51 | 'prefer-template': 'error', 52 | 'no-trailing-spaces': 'error', 53 | 'eol-last': 'error', 54 | 'comma-dangle': ['error', 'always-multiline'], 55 | 'quotes': ['error', 'single', { avoidEscape: true }], 56 | 'semi': ['error', 'always'], 57 | 58 | // Basic formatting rules 59 | 'indent': ['error', 2, { SwitchCase: 1 }], 60 | 'linebreak-style': ['error', 'unix'], 61 | 'max-len': ['error', { code: 120, ignoreUrls: true, ignoreStrings: true, ignoreTemplateLiterals: true }], 62 | 'no-multiple-empty-lines': ['error', { max: 2, maxEOF: 1 }], 63 | 'object-curly-spacing': ['error', 'always'], 64 | 'array-bracket-spacing': ['error', 'never'], 65 | 'key-spacing': ['error', { beforeColon: false, afterColon: true }], 66 | 'comma-spacing': ['error', { before: false, after: true }], 67 | 'space-before-blocks': ['error', 'always'], 68 | 'space-infix-ops': 'error', 69 | 'brace-style': ['error', '1tbs', { allowSingleLine: true }], 70 | 'curly': ['error', 'all'], 71 | }, 72 | }, 73 | 74 | // Test files 75 | { 76 | files: ['**/*.test.ts', '**/*.spec.ts', 'tests/**/*.ts'], 77 | languageOptions: { 78 | globals: { 79 | jest: 'readonly', 80 | describe: 'readonly', 81 | it: 'readonly', 82 | expect: 'readonly', 83 | beforeEach: 'readonly', 84 | afterEach: 'readonly', 85 | beforeAll: 'readonly', 86 | afterAll: 'readonly', 87 | }, 88 | }, 89 | rules: { 90 | '@typescript-eslint/no-explicit-any': 'off', 91 | '@typescript-eslint/no-non-null-assertion': 'off', 92 | }, 93 | }, 94 | 95 | // Script files 96 | { 97 | files: ['scripts/**/*.js'], 98 | languageOptions: { 99 | sourceType: 'module', 100 | globals: { 101 | console: 'readonly', 102 | process: 'readonly', 103 | Buffer: 'readonly', 104 | __dirname: 'readonly', 105 | __filename: 'readonly', 106 | }, 107 | }, 108 | }, 109 | 110 | // Mock files (CommonJS format) 111 | { 112 | files: ['**/__mocks__/**/*.js'], 113 | languageOptions: { 114 | sourceType: 'script', 115 | globals: { 116 | module: 'writable', 117 | exports: 'writable', 118 | jest: 'readonly', 119 | }, 120 | }, 121 | }, 122 | 123 | // Ignore patterns 124 | { 125 | ignores: [ 126 | 'tmp/**', 127 | 'dist/**', 128 | 'node_modules/**', 129 | 'coverage/**', 130 | 'docs-site/**', 131 | 'docs-site-old/**', 132 | '*.config.js', 133 | 'jest.config.js', 134 | 'tests/servers/**', 135 | ], 136 | }, 137 | ); 138 | ``` -------------------------------------------------------------------------------- /docs/dw_crypto/X509Certificate.md: -------------------------------------------------------------------------------- ```markdown 1 | ## Package: dw.crypto 2 | 3 | # Class X509Certificate 4 | 5 | ## Inheritance Hierarchy 6 | 7 | - Object 8 | - dw.crypto.CertificateRef 9 | - dw.crypto.X509Certificate 10 | 11 | ## Description 12 | 13 | Represents an X.509 public key certificate as defined in RFC 5280. It provides access to the standard fields of an X.509 certificate including version, serial number, validity period, distinguished names, and signature algorithm. 14 | 15 | ## Properties 16 | 17 | ### issuerDN 18 | 19 | **Type:** String (Read Only) 20 | 21 | The X.500 distinguished name of the entity that signed this certificate. 22 | 23 | ### notAfter 24 | 25 | **Type:** Date (Read Only) 26 | 27 | The end date of the certificate validity period. 28 | 29 | ### notBefore 30 | 31 | **Type:** Date (Read Only) 32 | 33 | The start date of the certificate validity period. 34 | 35 | ### serialNumber 36 | 37 | **Type:** String (Read Only) 38 | 39 | The certificate serial number in string format. The serial number is a unique positive integer assigned 40 | by the CA to each certificate. 41 | 42 | ### sigAlgName 43 | 44 | **Type:** String (Read Only) 45 | 46 | The algorithm used to sign this certificate. The name follows the format defined in RFC 5280 (e.g., 47 | "SHA256withRSA", "SHA384withECDSA"). 48 | 49 | ### subjectDN 50 | 51 | **Type:** String (Read Only) 52 | 53 | The X.500 distinguished name of the entity this certificate belongs to. 54 | 55 | ### version 56 | 57 | **Type:** Number (Read Only) 58 | 59 | The X.509 certificate version number. 60 | 61 | ## Constructor Summary 62 | 63 | ## Method Summary 64 | 65 | ### getIssuerDN 66 | 67 | **Signature:** `getIssuerDN() : String` 68 | 69 | Returns the X.500 distinguished name of the entity that signed this certificate. 70 | 71 | ### getNotAfter 72 | 73 | **Signature:** `getNotAfter() : Date` 74 | 75 | Returns the end date of the certificate validity period. 76 | 77 | ### getNotBefore 78 | 79 | **Signature:** `getNotBefore() : Date` 80 | 81 | Returns the start date of the certificate validity period. 82 | 83 | ### getSerialNumber 84 | 85 | **Signature:** `getSerialNumber() : String` 86 | 87 | Returns the certificate serial number in string format. 88 | 89 | ### getSigAlgName 90 | 91 | **Signature:** `getSigAlgName() : String` 92 | 93 | Returns the algorithm used to sign this certificate. 94 | 95 | ### getSubjectDN 96 | 97 | **Signature:** `getSubjectDN() : String` 98 | 99 | Returns the X.500 distinguished name of the entity this certificate belongs to. 100 | 101 | ### getVersion 102 | 103 | **Signature:** `getVersion() : Number` 104 | 105 | Returns the X.509 certificate version number. 106 | 107 | ## Method Detail 108 | 109 | ## Method Details 110 | 111 | ### getIssuerDN 112 | 113 | **Signature:** `getIssuerDN() : String` 114 | 115 | **Description:** Returns the X.500 distinguished name of the entity that signed this certificate. 116 | 117 | **Returns:** 118 | 119 | the issuer's X.500 distinguished name 120 | 121 | --- 122 | 123 | ### getNotAfter 124 | 125 | **Signature:** `getNotAfter() : Date` 126 | 127 | **Description:** Returns the end date of the certificate validity period. 128 | 129 | **Returns:** 130 | 131 | the date after which this certificate is not valid 132 | 133 | --- 134 | 135 | ### getNotBefore 136 | 137 | **Signature:** `getNotBefore() : Date` 138 | 139 | **Description:** Returns the start date of the certificate validity period. 140 | 141 | **Returns:** 142 | 143 | the date before which this certificate is not valid 144 | 145 | --- 146 | 147 | ### getSerialNumber 148 | 149 | **Signature:** `getSerialNumber() : String` 150 | 151 | **Description:** Returns the certificate serial number in string format. The serial number is a unique positive integer assigned by the CA to each certificate. 152 | 153 | **Returns:** 154 | 155 | the certificate serial number as a string 156 | 157 | --- 158 | 159 | ### getSigAlgName 160 | 161 | **Signature:** `getSigAlgName() : String` 162 | 163 | **Description:** Returns the algorithm used to sign this certificate. The name follows the format defined in RFC 5280 (e.g., "SHA256withRSA", "SHA384withECDSA"). 164 | 165 | **Returns:** 166 | 167 | the signature algorithm name 168 | 169 | --- 170 | 171 | ### getSubjectDN 172 | 173 | **Signature:** `getSubjectDN() : String` 174 | 175 | **Description:** Returns the X.500 distinguished name of the entity this certificate belongs to. 176 | 177 | **Returns:** 178 | 179 | the subject's X.500 distinguished name 180 | 181 | --- 182 | 183 | ### getVersion 184 | 185 | **Signature:** `getVersion() : Number` 186 | 187 | **Description:** Returns the X.509 certificate version number. 188 | 189 | **Returns:** 190 | 191 | certificate version (typically 1, 2, or 3) 192 | 193 | --- ``` -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.yml: -------------------------------------------------------------------------------- ```yaml 1 | name: 🐛 Bug Report 2 | description: Report a bug or unexpected behavior in the SFCC Development MCP Server 3 | title: "[Bug]: " 4 | labels: ["bug", "needs-triage"] 5 | assignees: [] 6 | body: 7 | - type: markdown 8 | attributes: 9 | value: | 10 | Thanks for taking the time to report a bug! Please fill out the information below to help us investigate and fix the issue. 11 | 12 | - type: checkboxes 13 | id: terms 14 | attributes: 15 | label: Pre-flight Checklist 16 | description: Please confirm you have completed these steps before submitting the bug report. 17 | options: 18 | - label: I have searched existing issues to ensure this bug hasn't been reported already 19 | required: true 20 | - label: I have read the documentation and troubleshooting guide 21 | required: true 22 | - label: I am using a supported Node.js version (18+) 23 | required: true 24 | 25 | - type: dropdown 26 | id: operating-mode 27 | attributes: 28 | label: Operating Mode 29 | description: Which mode were you using when the bug occurred? 30 | options: 31 | - Documentation-only mode 32 | - Full mode (with SFCC credentials) 33 | - Not sure 34 | validations: 35 | required: true 36 | 37 | - type: textarea 38 | id: bug-description 39 | attributes: 40 | label: Bug Description 41 | description: A clear and concise description of what the bug is. 42 | placeholder: Describe what happened and what you expected to happen instead. 43 | validations: 44 | required: true 45 | 46 | - type: textarea 47 | id: reproduction-steps 48 | attributes: 49 | label: Steps to Reproduce 50 | description: Detailed steps to reproduce the behavior. 51 | placeholder: | 52 | 1. Start the MCP server with... 53 | 2. Call the tool... 54 | 3. Observe the error... 55 | validations: 56 | required: true 57 | 58 | - type: textarea 59 | id: expected-behavior 60 | attributes: 61 | label: Expected Behavior 62 | description: What you expected to happen. 63 | validations: 64 | required: true 65 | 66 | - type: textarea 67 | id: actual-behavior 68 | attributes: 69 | label: Actual Behavior 70 | description: What actually happened, including any error messages. 71 | validations: 72 | required: true 73 | 74 | - type: textarea 75 | id: environment 76 | attributes: 77 | label: Environment Information 78 | description: Information about your environment 79 | value: | 80 | - OS: [e.g., macOS 14.1, Windows 11, Ubuntu 22.04] 81 | - Node.js version: [run `node --version`] 82 | - NPM/Yarn version: [run `npm --version` or `yarn --version`] 83 | - SFCC Dev MCP version: [check package.json version] 84 | - MCP Client: [e.g., Claude Desktop, Custom implementation] 85 | validations: 86 | required: true 87 | 88 | - type: textarea 89 | id: logs 90 | attributes: 91 | label: Relevant Logs 92 | description: Any relevant log output or error messages 93 | render: shell 94 | placeholder: Paste any relevant logs here (please remove any sensitive information like credentials) 95 | 96 | - type: textarea 97 | id: configuration 98 | attributes: 99 | label: Configuration (Sanitized) 100 | description: Your configuration (with sensitive information removed) 101 | render: json 102 | placeholder: | 103 | { 104 | "hostname": "your-instance.demandware.net", 105 | "clientId": "[REDACTED]", 106 | "version": "v21_3" 107 | } 108 | 109 | - type: dropdown 110 | id: affected-tools 111 | attributes: 112 | label: Affected Tools 113 | description: Which MCP tools are affected by this bug? 114 | multiple: true 115 | options: 116 | - SFCC Class Documentation Tools 117 | - Best Practices Guide Tools 118 | - Log Analysis Tools 119 | - System Object Tools 120 | - Authentication/OAuth 121 | - Configuration Loading 122 | - All Tools 123 | - Not sure 124 | 125 | - type: textarea 126 | id: additional-context 127 | attributes: 128 | label: Additional Context 129 | description: Any other context, screenshots, or information that might be helpful. 130 | ``` -------------------------------------------------------------------------------- /docs-site/scripts/generate-sitemap.js: -------------------------------------------------------------------------------- ```javascript 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * Sitemap Generator for SFCC Development MCP Server Documentation 5 | * 6 | * This script generates an XML sitemap for the SFCC Development MCP Server documentation site. 7 | * Run this whenever you add new pages or want to update the sitemap. 8 | * 9 | * Usage: node scripts/generate-sitemap.js 10 | */ 11 | 12 | import fs from 'fs'; 13 | import path from 'path'; 14 | import { fileURLToPath } from 'url'; 15 | 16 | const __filename = fileURLToPath(import.meta.url); 17 | const __dirname = path.dirname(__filename); 18 | 19 | const baseUrl = 'https://sfcc-mcp-dev.rhino-inquisitor.com'; 20 | const currentDate = new Date().toISOString().split('T')[0]; 21 | 22 | // Define all pages with their priorities and change frequencies 23 | const pages = [ 24 | { 25 | path: '/', 26 | priority: '1.0', 27 | changefreq: 'weekly', 28 | description: 'SFCC Development MCP Server Homepage', 29 | }, 30 | { 31 | path: '/configuration/', 32 | priority: '0.9', 33 | changefreq: 'monthly', 34 | description: 'Configuration Guide', 35 | }, 36 | { 37 | path: '/ai-interfaces/', 38 | priority: '0.8', 39 | changefreq: 'monthly', 40 | description: 'AI Interface Setup Guide', 41 | }, 42 | { 43 | path: '/features/', 44 | priority: '0.8', 45 | changefreq: 'monthly', 46 | description: 'Features Overview', 47 | }, 48 | { 49 | path: '/tools/', 50 | priority: '0.8', 51 | changefreq: 'monthly', 52 | description: 'Available Tools', 53 | }, 54 | { 55 | path: '/examples/', 56 | priority: '0.8', 57 | changefreq: 'monthly', 58 | description: 'Examples and Use Cases', 59 | }, 60 | { 61 | path: '/security/', 62 | priority: '0.7', 63 | changefreq: 'monthly', 64 | description: 'Security Guidelines', 65 | }, 66 | { 67 | path: '/development/', 68 | priority: '0.6', 69 | changefreq: 'monthly', 70 | description: 'Development Guide', 71 | }, 72 | { 73 | path: '/troubleshooting/', 74 | priority: '0.7', 75 | changefreq: 'monthly', 76 | description: 'Troubleshooting Guide', 77 | }, 78 | ]; 79 | 80 | function generateSitemap() { 81 | const header = `<?xml version="1.0" encoding="UTF-8"?> 82 | <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" 83 | xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 84 | xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 85 | http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">`; 86 | 87 | const footer = ` 88 | </urlset>`; 89 | 90 | const urls = pages.map(page => { 91 | // For SSG routing, URLs should point to clean paths without hash fragments 92 | const url = page.path === '/' ? baseUrl : `${baseUrl}${page.path}`; 93 | return ` 94 | <!-- ${page.description} --> 95 | <url> 96 | <loc>${url}</loc> 97 | <lastmod>${currentDate}</lastmod> 98 | <changefreq>${page.changefreq}</changefreq> 99 | <priority>${page.priority}</priority> 100 | </url>`; 101 | }).join(''); 102 | 103 | return header + urls + footer; 104 | } 105 | 106 | function generateRobotsTxt() { 107 | return `User-agent: * 108 | Allow: / 109 | 110 | # Sitemap 111 | Sitemap: ${baseUrl}/sitemap.xml 112 | 113 | # Crawl-delay for respectful crawling 114 | Crawl-delay: 1 115 | 116 | # Allow all common search engines 117 | User-agent: Googlebot 118 | Allow: / 119 | 120 | User-agent: Bingbot 121 | Allow: / 122 | 123 | User-agent: Slurp 124 | Allow: / 125 | 126 | User-agent: DuckDuckBot 127 | Allow: / 128 | 129 | # Block certain paths if needed 130 | # Disallow: /temp/ 131 | # Disallow: /private/`; 132 | } 133 | 134 | // Generate files 135 | const sitemap = generateSitemap(); 136 | const robots = generateRobotsTxt(); 137 | 138 | // Write files 139 | const publicDir = path.join(__dirname, '..', 'public'); 140 | if (!fs.existsSync(publicDir)) { 141 | fs.mkdirSync(publicDir, { recursive: true }); 142 | } 143 | 144 | fs.writeFileSync(path.join(publicDir, 'sitemap.xml'), sitemap); 145 | fs.writeFileSync(path.join(publicDir, 'robots.txt'), robots); 146 | 147 | console.log('✅ Sitemap and robots.txt generated successfully!'); 148 | console.log(`📄 Generated ${pages.length} URLs in sitemap.xml`); 149 | console.log('🤖 Updated robots.txt with sitemap reference'); 150 | console.log(`📅 Last modified: ${currentDate}`); 151 | 152 | // Also log the pages for verification 153 | console.log('\n📋 Pages included in sitemap:'); 154 | pages.forEach(page => { 155 | console.log(` ${page.path} (Priority: ${page.priority}, ${page.changefreq})`); 156 | }); 157 | ``` -------------------------------------------------------------------------------- /docs/dw_catalog/Catalog.md: -------------------------------------------------------------------------------- ```markdown 1 | ## Package: dw.catalog 2 | 3 | # Class Catalog 4 | 5 | ## Inheritance Hierarchy 6 | 7 | - Object 8 | - dw.object.PersistentObject 9 | - dw.object.ExtensibleObject 10 | - dw.catalog.Catalog 11 | 12 | ## Description 13 | 14 | Represents a Commerce Cloud Digital Catalog. Catalogs are containers of products and other product-related information and can be shared between sites. Every product in the system is contained in (or "owned by") exactly one catalog. Every site has a single "site catalog" which defines the products that are available to purchase on that site. The static method CatalogMgr.getSiteCatalog() returns the site catalog for the current site. Catalogs are organized into a tree of categories with a single top-level root category. Products are assigned to categories within catalogs. They can be assigned to categories in their owning catalog, or other catalogs. They can be assigned to multiple categories within the same catalog. Products that are not assigned to any categories are considered "uncategorized." A product has a single "classification category" in some catalog, and one "primary category" per catalog. The classification category defines the attribute set of the product. The primary category is used as standard presentation context within that catalog in the storefront. While Commerce Cloud Digital does not currently distinguish different catalog types, it is common practice to have two general types of catalog: "Product catalogs" typically contain detailed product information and are frequently generated from some backend PIM system. "Site Catalogs" define the category structure of the storefront and contain primarily the assignments of these categories to the products defined in the product catalogs. The site catalog is assigned to the site. In addition to products and categories, catalogs contain recommendations, shared variation attributes which can be used by multiple master products, and shared product options which can be used by multiple option products. 15 | 16 | ## Properties 17 | 18 | ### description 19 | 20 | **Type:** String (Read Only) 21 | 22 | The value of the localized extensible object attribute 23 | "shortDescription" for the current locale. 24 | 25 | ### displayName 26 | 27 | **Type:** String (Read Only) 28 | 29 | The value of the localized extensible object attribute 30 | "displayName" for the current locale. 31 | 32 | ### ID 33 | 34 | **Type:** String (Read Only) 35 | 36 | The value of attribute 'id'. 37 | 38 | ### root 39 | 40 | **Type:** Category (Read Only) 41 | 42 | The object for the relation 'root'. 43 | 44 | ## Constructor Summary 45 | 46 | ## Method Summary 47 | 48 | ### getDescription 49 | 50 | **Signature:** `getDescription() : String` 51 | 52 | Returns the value of the localized extensible object attribute "shortDescription" for the current locale. 53 | 54 | ### getDisplayName 55 | 56 | **Signature:** `getDisplayName() : String` 57 | 58 | Returns the value of the localized extensible object attribute "displayName" for the current locale. 59 | 60 | ### getID 61 | 62 | **Signature:** `getID() : String` 63 | 64 | Returns the value of attribute 'id'. 65 | 66 | ### getRoot 67 | 68 | **Signature:** `getRoot() : Category` 69 | 70 | Returns the object for the relation 'root'. 71 | 72 | ## Method Detail 73 | 74 | ## Method Details 75 | 76 | ### getDescription 77 | 78 | **Signature:** `getDescription() : String` 79 | 80 | **Description:** Returns the value of the localized extensible object attribute "shortDescription" for the current locale. 81 | 82 | **Returns:** 83 | 84 | The value of the attribute for the current locale, or null if it wasn't found. 85 | 86 | --- 87 | 88 | ### getDisplayName 89 | 90 | **Signature:** `getDisplayName() : String` 91 | 92 | **Description:** Returns the value of the localized extensible object attribute "displayName" for the current locale. 93 | 94 | **Returns:** 95 | 96 | The value of the attribute for the current locale, or null if it wasn't found. 97 | 98 | --- 99 | 100 | ### getID 101 | 102 | **Signature:** `getID() : String` 103 | 104 | **Description:** Returns the value of attribute 'id'. 105 | 106 | **Returns:** 107 | 108 | the value of the attribute 'id' 109 | 110 | --- 111 | 112 | ### getRoot 113 | 114 | **Signature:** `getRoot() : Category` 115 | 116 | **Description:** Returns the object for the relation 'root'. 117 | 118 | **Returns:** 119 | 120 | the object for the relation 'root'. 121 | 122 | --- ``` -------------------------------------------------------------------------------- /docs/dw_catalog/ProductMgr.md: -------------------------------------------------------------------------------- ```markdown 1 | ## Package: dw.catalog 2 | 3 | # Class ProductMgr 4 | 5 | ## Inheritance Hierarchy 6 | 7 | - Object 8 | - dw.catalog.ProductMgr 9 | 10 | ## Description 11 | 12 | Provides helper methods for getting products based on Product ID or Catalog. 13 | 14 | ## Constructor Summary 15 | 16 | ## Method Summary 17 | 18 | ### getProduct 19 | 20 | **Signature:** `static getProduct(productID : String) : Product` 21 | 22 | Returns the product with the specified id. 23 | 24 | ### queryAllSiteProducts 25 | 26 | **Signature:** `static queryAllSiteProducts() : SeekableIterator` 27 | 28 | Returns all products assigned to the current site. 29 | 30 | ### queryAllSiteProductsSorted 31 | 32 | **Signature:** `static queryAllSiteProductsSorted() : SeekableIterator` 33 | 34 | Returns all products assigned to the current site. 35 | 36 | ### queryProductsInCatalog 37 | 38 | **Signature:** `static queryProductsInCatalog(catalog : Catalog) : SeekableIterator` 39 | 40 | Returns all products assigned to the the specified catalog, where assignment has the same meaning as it does for queryAllSiteProducts(). 41 | 42 | ### queryProductsInCatalogSorted 43 | 44 | **Signature:** `static queryProductsInCatalogSorted(catalog : Catalog) : SeekableIterator` 45 | 46 | Returns all products assigned to the the specified catalog. 47 | 48 | ## Method Detail 49 | 50 | ## Method Details 51 | 52 | ### getProduct 53 | 54 | **Signature:** `static getProduct(productID : String) : Product` 55 | 56 | **Description:** Returns the product with the specified id. 57 | 58 | **Parameters:** 59 | 60 | - `productID`: the product identifier. 61 | 62 | **Returns:** 63 | 64 | Product for specified id or null 65 | 66 | --- 67 | 68 | ### queryAllSiteProducts 69 | 70 | **Signature:** `static queryAllSiteProducts() : SeekableIterator` 71 | 72 | **Description:** Returns all products assigned to the current site. A product is assigned to a site if it is assigned to at least one category of the site catalog or it is a variant and it's master product is assigned to the current site It is strongly recommended to call close() on the returned SeekableIterator if not all of its elements are being retrieved. This will ensure the proper cleanup of system resources. 73 | 74 | **Returns:** 75 | 76 | Iterator of all site products 77 | 78 | **See Also:** 79 | 80 | SeekableIterator.close() 81 | 82 | --- 83 | 84 | ### queryAllSiteProductsSorted 85 | 86 | **Signature:** `static queryAllSiteProductsSorted() : SeekableIterator` 87 | 88 | **Description:** Returns all products assigned to the current site. Works like queryAllSiteProducts(), but additionally sorts the result set by product ID. It is strongly recommended to call close() on the returned SeekableIterator if not all of its elements are being retrieved. This will ensure the proper cleanup of system resources. 89 | 90 | **Returns:** 91 | 92 | Iterator of all site products sorted by product ID. 93 | 94 | **See Also:** 95 | 96 | SeekableIterator.close() 97 | 98 | --- 99 | 100 | ### queryProductsInCatalog 101 | 102 | **Signature:** `static queryProductsInCatalog(catalog : Catalog) : SeekableIterator` 103 | 104 | **Description:** Returns all products assigned to the the specified catalog, where assignment has the same meaning as it does for queryAllSiteProducts(). It is strongly recommended to call close() on the returned SeekableIterator if not all of its elements are being retrieved. This will ensure the proper cleanup of system resources. 105 | 106 | **Parameters:** 107 | 108 | - `catalog`: The catalog whose assigned products should be returned. 109 | 110 | **Returns:** 111 | 112 | Iterator of all products assigned to specified catalog. 113 | 114 | **See Also:** 115 | 116 | SeekableIterator.close() 117 | 118 | --- 119 | 120 | ### queryProductsInCatalogSorted 121 | 122 | **Signature:** `static queryProductsInCatalogSorted(catalog : Catalog) : SeekableIterator` 123 | 124 | **Description:** Returns all products assigned to the the specified catalog. Works like queryProductsInCatalog(), but additionally sorts the result set by product ID. It is strongly recommended to call close() on the returned SeekableIterator if not all of its elements are being retrieved. This will ensure the proper cleanup of system resources. 125 | 126 | **Parameters:** 127 | 128 | - `catalog`: The catalog whose assigned products should be returned. 129 | 130 | **Returns:** 131 | 132 | Iterator of all products assigned to specified catalog sorted by product ID. 133 | 134 | **See Also:** 135 | 136 | SeekableIterator.close() 137 | 138 | --- ``` -------------------------------------------------------------------------------- /docs/dw_catalog/CatalogMgr.md: -------------------------------------------------------------------------------- ```markdown 1 | ## Package: dw.catalog 2 | 3 | # Class CatalogMgr 4 | 5 | ## Inheritance Hierarchy 6 | 7 | - Object 8 | - dw.catalog.CatalogMgr 9 | 10 | ## Description 11 | 12 | Provides helper methods for getting categories. 13 | 14 | ## Properties 15 | 16 | ### siteCatalog 17 | 18 | **Type:** Catalog (Read Only) 19 | 20 | The catalog of the current site or null if no catalog is assigned to the site. 21 | 22 | ### sortingOptions 23 | 24 | **Type:** List (Read Only) 25 | 26 | A list containing the sorting options configured for this site. 27 | 28 | ### sortingRules 29 | 30 | **Type:** Collection (Read Only) 31 | 32 | A collection containing all of the sorting rules for this site, including global sorting rules. 33 | 34 | ## Constructor Summary 35 | 36 | ## Method Summary 37 | 38 | ### getCatalog 39 | 40 | **Signature:** `static getCatalog(id : String) : Catalog` 41 | 42 | Returns the catalog identified by the specified catalog id. 43 | 44 | ### getCategory 45 | 46 | **Signature:** `static getCategory(id : String) : Category` 47 | 48 | Returns the category of the site catalog identified by the specified category id. 49 | 50 | ### getSiteCatalog 51 | 52 | **Signature:** `static getSiteCatalog() : Catalog` 53 | 54 | Returns the catalog of the current site or null if no catalog is assigned to the site. 55 | 56 | ### getSortingOption 57 | 58 | **Signature:** `static getSortingOption(id : String) : SortingOption` 59 | 60 | Returns the sorting option with the given ID for this site, or null if there is no such option. 61 | 62 | ### getSortingOptions 63 | 64 | **Signature:** `static getSortingOptions() : List` 65 | 66 | Returns a list containing the sorting options configured for this site. 67 | 68 | ### getSortingRule 69 | 70 | **Signature:** `static getSortingRule(id : String) : SortingRule` 71 | 72 | Returns the sorting rule with the given ID for this site, or null if there is no such rule. 73 | 74 | ### getSortingRules 75 | 76 | **Signature:** `static getSortingRules() : Collection` 77 | 78 | Returns a collection containing all of the sorting rules for this site, including global sorting rules. 79 | 80 | ## Method Detail 81 | 82 | ## Method Details 83 | 84 | ### getCatalog 85 | 86 | **Signature:** `static getCatalog(id : String) : Catalog` 87 | 88 | **Description:** Returns the catalog identified by the specified catalog id. Returns null if no catalog with the specified id exists in the current organization context. 89 | 90 | **Parameters:** 91 | 92 | - `id`: Catalog id 93 | 94 | **Returns:** 95 | 96 | the catalog or null. 97 | 98 | --- 99 | 100 | ### getCategory 101 | 102 | **Signature:** `static getCategory(id : String) : Category` 103 | 104 | **Description:** Returns the category of the site catalog identified by the specified category id. Returns null if no site catalog is defined, or no category with the specified id is found in the site catalog. 105 | 106 | **Parameters:** 107 | 108 | - `id`: the category identifier. 109 | 110 | **Returns:** 111 | 112 | the category of the site catalog identified by the specified category id or null if no site catalog is found. 113 | 114 | --- 115 | 116 | ### getSiteCatalog 117 | 118 | **Signature:** `static getSiteCatalog() : Catalog` 119 | 120 | **Description:** Returns the catalog of the current site or null if no catalog is assigned to the site. 121 | 122 | **Returns:** 123 | 124 | the catalog of the current site or null. 125 | 126 | --- 127 | 128 | ### getSortingOption 129 | 130 | **Signature:** `static getSortingOption(id : String) : SortingOption` 131 | 132 | **Description:** Returns the sorting option with the given ID for this site, or null if there is no such option. 133 | 134 | **Parameters:** 135 | 136 | - `id`: the ID of the sorting option 137 | 138 | **Returns:** 139 | 140 | a SortingOption or null. 141 | 142 | --- 143 | 144 | ### getSortingOptions 145 | 146 | **Signature:** `static getSortingOptions() : List` 147 | 148 | **Description:** Returns a list containing the sorting options configured for this site. 149 | 150 | **Returns:** 151 | 152 | a list of SortingOption objects 153 | 154 | --- 155 | 156 | ### getSortingRule 157 | 158 | **Signature:** `static getSortingRule(id : String) : SortingRule` 159 | 160 | **Description:** Returns the sorting rule with the given ID for this site, or null if there is no such rule. 161 | 162 | **Parameters:** 163 | 164 | - `id`: the ID of the sorting rule 165 | 166 | **Returns:** 167 | 168 | a SortingRule or null. 169 | 170 | --- 171 | 172 | ### getSortingRules 173 | 174 | **Signature:** `static getSortingRules() : Collection` 175 | 176 | **Description:** Returns a collection containing all of the sorting rules for this site, including global sorting rules. 177 | 178 | **Returns:** 179 | 180 | a collection of SortingRule objects 181 | 182 | --- ``` -------------------------------------------------------------------------------- /docs/dw_util/SortedSet.md: -------------------------------------------------------------------------------- ```markdown 1 | ## Package: dw.util 2 | 3 | # Class SortedSet 4 | 5 | ## Inheritance Hierarchy 6 | 7 | - Object 8 | - dw.util.Collection 9 | - dw.util.Set 10 | - dw.util.SortedSet 11 | 12 | ## Description 13 | 14 | A set that further guarantees that its iterator will traverse the set in ascending element order, sorted according to the natural ordering of its elements (only supported for Number, String, Date, Money and Quantity), or by a comparator provided at sorted set creation time. 15 | 16 | ## Constructor Summary 17 | 18 | SortedSet() Constructor to create a new SortedSet. 19 | 20 | SortedSet(comparator : Object) Constructor to create a new SortedSet. 21 | 22 | SortedSet(collection : Collection) Constructor for a new SortedSet. 23 | 24 | ## Method Summary 25 | 26 | ### clone 27 | 28 | **Signature:** `clone() : SortedSet` 29 | 30 | Returns a shallow copy of this set. 31 | 32 | ### first 33 | 34 | **Signature:** `first() : Object` 35 | 36 | Returns the first (lowest) element currently in this sorted set. 37 | 38 | ### headSet 39 | 40 | **Signature:** `headSet(key : Object) : SortedSet` 41 | 42 | Returns a view of the portion of this sorted set whose elements are strictly less than toElement. 43 | 44 | ### last 45 | 46 | **Signature:** `last() : Object` 47 | 48 | Returns the last (highest) element currently in this sorted set. 49 | 50 | ### subSet 51 | 52 | **Signature:** `subSet(from : Object, to : Object) : SortedSet` 53 | 54 | Returns a view of the portion of this sorted set whose elements range from fromElement, inclusive, to toElement, exclusive. 55 | 56 | ### tailSet 57 | 58 | **Signature:** `tailSet(key : Object) : SortedSet` 59 | 60 | Returns a view of the portion of this sorted set whose elements are greater than or equal to fromElement. 61 | 62 | ## Constructor Detail 63 | 64 | ## Method Detail 65 | 66 | ## Method Details 67 | 68 | ### clone 69 | 70 | **Signature:** `clone() : SortedSet` 71 | 72 | **Description:** Returns a shallow copy of this set. 73 | 74 | **Returns:** 75 | 76 | a shallow copy of this set. 77 | 78 | --- 79 | 80 | ### first 81 | 82 | **Signature:** `first() : Object` 83 | 84 | **Description:** Returns the first (lowest) element currently in this sorted set. 85 | 86 | **Returns:** 87 | 88 | the first (lowest) element currently in this sorted set. 89 | 90 | --- 91 | 92 | ### headSet 93 | 94 | **Signature:** `headSet(key : Object) : SortedSet` 95 | 96 | **Description:** Returns a view of the portion of this sorted set whose elements are strictly less than toElement. The returned sorted set is backed by this sorted set, so changes in the returned sorted set are reflected in this sorted set, and vice-versa. The returned sorted set supports all optional set operations. 97 | 98 | **Parameters:** 99 | 100 | - `key`: high endpoint (exclusive) of the headSet. 101 | 102 | **Returns:** 103 | 104 | a view of the specified initial range of this sorted set. 105 | 106 | --- 107 | 108 | ### last 109 | 110 | **Signature:** `last() : Object` 111 | 112 | **Description:** Returns the last (highest) element currently in this sorted set. 113 | 114 | **Returns:** 115 | 116 | the last (highest) element currently in this sorted set. 117 | 118 | --- 119 | 120 | ### subSet 121 | 122 | **Signature:** `subSet(from : Object, to : Object) : SortedSet` 123 | 124 | **Description:** Returns a view of the portion of this sorted set whose elements range from fromElement, inclusive, to toElement, exclusive. (If fromElement and toElement are equal, the returned sorted set is empty.) The returned sorted set is backed by this sorted set, so changes in the returned sorted set are reflected in this sorted set, and vice-versa. The returned sorted set supports all optional set operations that this sorted set supports. 125 | 126 | **Parameters:** 127 | 128 | - `from`: low endpoint (inclusive) of the subSet. 129 | - `to`: high endpoint (exclusive) of the subSet. 130 | 131 | **Returns:** 132 | 133 | a view of the specified range within this sorted set. 134 | 135 | --- 136 | 137 | ### tailSet 138 | 139 | **Signature:** `tailSet(key : Object) : SortedSet` 140 | 141 | **Description:** Returns a view of the portion of this sorted set whose elements are greater than or equal to fromElement. The returned sorted set is backed by this sorted set, so changes in the returned sorted set are reflected in this sorted set, and vice-versa. The returned sorted set supports all optional set operations. 142 | 143 | **Parameters:** 144 | 145 | - `key`: low endpoint (inclusive) of the tailSet. 146 | 147 | **Returns:** 148 | 149 | a view of the specified final range of this sorted set. 150 | 151 | --- ``` -------------------------------------------------------------------------------- /docs/dw_catalog/PriceBook.md: -------------------------------------------------------------------------------- ```markdown 1 | ## Package: dw.catalog 2 | 3 | # Class PriceBook 4 | 5 | ## Inheritance Hierarchy 6 | 7 | - Object 8 | - dw.object.PersistentObject 9 | - dw.object.ExtensibleObject 10 | - dw.catalog.PriceBook 11 | 12 | ## Description 13 | 14 | Represents a price book. 15 | 16 | ## Properties 17 | 18 | ### currencyCode 19 | 20 | **Type:** String (Read Only) 21 | 22 | The currency code of the price book. 23 | 24 | ### description 25 | 26 | **Type:** String (Read Only) 27 | 28 | The description of the price book. 29 | 30 | ### displayName 31 | 32 | **Type:** String (Read Only) 33 | 34 | The display name of the price book. 35 | 36 | ### ID 37 | 38 | **Type:** String (Read Only) 39 | 40 | The ID of the price book. 41 | 42 | ### online 43 | 44 | **Type:** boolean (Read Only) 45 | 46 | The online status of the price book. The online status 47 | is calculated from the online status flag and the onlineFrom 48 | onlineTo dates defined for the price book. 49 | 50 | ### onlineFlag 51 | 52 | **Type:** boolean (Read Only) 53 | 54 | The online status flag of the price book. 55 | 56 | ### onlineFrom 57 | 58 | **Type:** Date (Read Only) 59 | 60 | The date from which the price book is online or valid. 61 | 62 | ### onlineTo 63 | 64 | **Type:** Date (Read Only) 65 | 66 | The date until which the price book is online or valid. 67 | 68 | ### parentPriceBook 69 | 70 | **Type:** PriceBook (Read Only) 71 | 72 | The parent price book. 73 | 74 | ## Constructor Summary 75 | 76 | ## Method Summary 77 | 78 | ### getCurrencyCode 79 | 80 | **Signature:** `getCurrencyCode() : String` 81 | 82 | Returns the currency code of the price book. 83 | 84 | ### getDescription 85 | 86 | **Signature:** `getDescription() : String` 87 | 88 | Returns the description of the price book. 89 | 90 | ### getDisplayName 91 | 92 | **Signature:** `getDisplayName() : String` 93 | 94 | Returns the display name of the price book. 95 | 96 | ### getID 97 | 98 | **Signature:** `getID() : String` 99 | 100 | Returns the ID of the price book. 101 | 102 | ### getOnlineFlag 103 | 104 | **Signature:** `getOnlineFlag() : boolean` 105 | 106 | Returns the online status flag of the price book. 107 | 108 | ### getOnlineFrom 109 | 110 | **Signature:** `getOnlineFrom() : Date` 111 | 112 | Returns the date from which the price book is online or valid. 113 | 114 | ### getOnlineTo 115 | 116 | **Signature:** `getOnlineTo() : Date` 117 | 118 | Returns the date until which the price book is online or valid. 119 | 120 | ### getParentPriceBook 121 | 122 | **Signature:** `getParentPriceBook() : PriceBook` 123 | 124 | Returns the parent price book. 125 | 126 | ### isOnline 127 | 128 | **Signature:** `isOnline() : boolean` 129 | 130 | Returns the online status of the price book. 131 | 132 | ## Method Detail 133 | 134 | ## Method Details 135 | 136 | ### getCurrencyCode 137 | 138 | **Signature:** `getCurrencyCode() : String` 139 | 140 | **Description:** Returns the currency code of the price book. 141 | 142 | **Returns:** 143 | 144 | Currency code of the price book 145 | 146 | --- 147 | 148 | ### getDescription 149 | 150 | **Signature:** `getDescription() : String` 151 | 152 | **Description:** Returns the description of the price book. 153 | 154 | **Returns:** 155 | 156 | Currency code of the price book 157 | 158 | --- 159 | 160 | ### getDisplayName 161 | 162 | **Signature:** `getDisplayName() : String` 163 | 164 | **Description:** Returns the display name of the price book. 165 | 166 | **Returns:** 167 | 168 | Display name of the price book 169 | 170 | --- 171 | 172 | ### getID 173 | 174 | **Signature:** `getID() : String` 175 | 176 | **Description:** Returns the ID of the price book. 177 | 178 | **Returns:** 179 | 180 | ID of the price book 181 | 182 | --- 183 | 184 | ### getOnlineFlag 185 | 186 | **Signature:** `getOnlineFlag() : boolean` 187 | 188 | **Description:** Returns the online status flag of the price book. 189 | 190 | **Returns:** 191 | 192 | the online status flag of the price book. 193 | 194 | --- 195 | 196 | ### getOnlineFrom 197 | 198 | **Signature:** `getOnlineFrom() : Date` 199 | 200 | **Description:** Returns the date from which the price book is online or valid. 201 | 202 | **Returns:** 203 | 204 | the date from which the price book is online or valid. 205 | 206 | --- 207 | 208 | ### getOnlineTo 209 | 210 | **Signature:** `getOnlineTo() : Date` 211 | 212 | **Description:** Returns the date until which the price book is online or valid. 213 | 214 | **Returns:** 215 | 216 | the date until which the price book is online or valid. 217 | 218 | --- 219 | 220 | ### getParentPriceBook 221 | 222 | **Signature:** `getParentPriceBook() : PriceBook` 223 | 224 | **Description:** Returns the parent price book. 225 | 226 | **Returns:** 227 | 228 | Parent price book 229 | 230 | --- 231 | 232 | ### isOnline 233 | 234 | **Signature:** `isOnline() : boolean` 235 | 236 | **Description:** Returns the online status of the price book. The online status is calculated from the online status flag and the onlineFrom onlineTo dates defined for the price book. 237 | 238 | **Returns:** 239 | 240 | The online status of the price book. 241 | 242 | --- ``` -------------------------------------------------------------------------------- /docs/dw_system/Cache.md: -------------------------------------------------------------------------------- ```markdown 1 | ## Package: dw.system 2 | 3 | # Class Cache 4 | 5 | ## Inheritance Hierarchy 6 | 7 | - Object 8 | - dw.system.Cache 9 | 10 | ## Description 11 | 12 | The Cache class represents a custom cache. A cache stores data over multiple requests. Each cartridge can define its own caches for different business requirements. To limit the visibility of cache entries by scope, for example, by site, catalog, or external system, include the scope reference when constructing the key. For example: var cache = CacheMgr.getCache( 'SiteConfigurations' ); cache.get( Site.current.ID + "config", function loadSiteConfiguration() {return loadCfg( Site.current );} ); Do not build the cache key using personal user data, since the key might be visible in log messages. There is never a guarantee that a stored object can be retrieved from the cache. The storage allocated for entries is limited and clearing or invalidation might occur at any time. To maintain the cache size limits, the cache evicts entries that are less likely to be used again. For example, the cache might evict an entry because it hasn't been used recently or very often. Cache entries aren't synchronized between different application servers. The cache returns immutable copies of the original objects put into the cache. Lists are converted to arrays during this process. Only JavaScript primitive values and tree-like object structures can be stored as entries. Object structures can consist of arrays, lists, and basic JavaScript objects. Script API classes are not supported, except List and its subclasses. null can be stored as a value. undefined can't be stored. See CacheMgr for details about how to configure a custom cache. 13 | 14 | ## Constructor Summary 15 | 16 | ## Method Summary 17 | 18 | ### get 19 | 20 | **Signature:** `get(key : String, loader : Function) : Object` 21 | 22 | Returns the value associated with key in this cache, or invokes the loader function to generate the entry if there is no entry found. 23 | 24 | ### get 25 | 26 | **Signature:** `get(key : String) : Object` 27 | 28 | Returns the value associated with key in this cache. 29 | 30 | ### invalidate 31 | 32 | **Signature:** `invalidate(key : String) : void` 33 | 34 | Removes the cache entry for key (if one exists) manually before the cache's eviction strategy goes into effect. 35 | 36 | ### put 37 | 38 | **Signature:** `put(key : String, value : Object) : void` 39 | 40 | Stores the specified entry directly into the cache, replacing any previously cached entry for key if one exists. 41 | 42 | ## Method Detail 43 | 44 | ## Method Details 45 | 46 | ### get 47 | 48 | **Signature:** `get(key : String, loader : Function) : Object` 49 | 50 | **Description:** Returns the value associated with key in this cache, or invokes the loader function to generate the entry if there is no entry found. The generated entry is stored for future retrieval. If the loader function returns undefined, this value is not stored in the cache. 51 | 52 | **Parameters:** 53 | 54 | - `key`: The cache key. 55 | - `loader`: The loader function that is called if no value is stored in the cache. 56 | 57 | **Returns:** 58 | 59 | The value found in the cache or the value returned from the loader function call. 60 | 61 | --- 62 | 63 | ### get 64 | 65 | **Signature:** `get(key : String) : Object` 66 | 67 | **Description:** Returns the value associated with key in this cache. If there is no entry in the cache then undefined is returned. 68 | 69 | **Parameters:** 70 | 71 | - `key`: The cache key. 72 | 73 | **Returns:** 74 | 75 | The stored value or undefined if no value is found in the cache. 76 | 77 | --- 78 | 79 | ### invalidate 80 | 81 | **Signature:** `invalidate(key : String) : void` 82 | 83 | **Description:** Removes the cache entry for key (if one exists) manually before the cache's eviction strategy goes into effect. 84 | 85 | **Parameters:** 86 | 87 | - `key`: The cache key. 88 | 89 | --- 90 | 91 | ### put 92 | 93 | **Signature:** `put(key : String, value : Object) : void` 94 | 95 | **Description:** Stores the specified entry directly into the cache, replacing any previously cached entry for key if one exists. Storing undefined as value has the same effect as calling invalidate(String) for that key. 96 | 97 | **Parameters:** 98 | 99 | - `key`: The cache key. 100 | - `value`: The value to be store in the cache. 101 | 102 | --- ```