{"id":43830420,"url":"https://github.com/commercetools-demo/demotools","last_synced_at":"2026-02-06T03:12:33.744Z","repository":{"id":65517204,"uuid":"327451022","full_name":"commercetools-demo/demotools","owner":"commercetools-demo","description":"Tools \u0026 utilities for building commercetools demos","archived":false,"fork":false,"pushed_at":"2025-10-20T20:42:18.000Z","size":120,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-10-20T22:29:32.037Z","etag":null,"topics":["commercetools"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/commercetools-demo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2021-01-06T23:16:16.000Z","updated_at":"2025-10-20T20:42:22.000Z","dependencies_parsed_at":"2025-10-20T22:19:47.954Z","dependency_job_id":"167f8c8e-ae33-4412-b5b5-6433fc092f09","html_url":"https://github.com/commercetools-demo/demotools","commit_stats":{"total_commits":31,"total_committers":1,"mean_commits":31.0,"dds":0.0,"last_synced_commit":"9c7bba70242f274eb092fc2b9d6f4f3423ac2d20"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/commercetools-demo/demotools","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/commercetools-demo%2Fdemotools","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/commercetools-demo%2Fdemotools/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/commercetools-demo%2Fdemotools/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/commercetools-demo%2Fdemotools/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/commercetools-demo","download_url":"https://codeload.github.com/commercetools-demo/demotools/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/commercetools-demo%2Fdemotools/sbom","scorecard":{"id":300880,"data":{"date":"2025-08-11","repo":{"name":"github.com/commercetools-demo/demotools","commit":"c12bbe1a836f36247221af48d593352b41d8ea31"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.3,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Maintained","score":5,"reason":"7 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 5","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":0,"reason":"license file not detected","details":["Warn: project does not have a license file"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'main'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}}]},"last_synced_at":"2025-08-17T20:35:35.020Z","repository_id":65517204,"created_at":"2025-08-17T20:35:35.020Z","updated_at":"2025-08-17T20:35:35.020Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29147519,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-06T02:39:25.012Z","status":"ssl_error","status_checked_at":"2026-02-06T02:37:22.784Z","response_time":59,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["commercetools"],"created_at":"2026-02-06T03:12:32.934Z","updated_at":"2026-02-06T03:12:33.736Z","avatar_url":"https://github.com/commercetools-demo.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# demotools\n\nTools to aid in the process of building demos, scripts, etc. for commercetools.  \nThe primary focus is on transforming product catalog data and importing into the commercetools platform for standing up demos quickly.\n\n## Components\n\n### commercetools.js\n\nEncapsulation of the commercetools platform API client:\n\n- **apiRoot** - Main API client for commercetools Platform API\n- **allow404(p)** - Wrapper for an execute function which returns null instead of throwing an error if a 404 is encountered\n  - `p`: Promise to execute, typically an API call that might return 404 Not Found\n  - Returns: Result of the promise or null if a 404 error occurred\n\n### importApi.js\n\nClient for the commercetools Import API:\n\n- **importApiRoot** - API client for commercetools Import API\n\n### connectApi.js\n\nClient for the commercetools Connect API:\n\n- **connectRoot** - API client for commercetools Connect API\n\n### getAll.js\n\nFunctions to retrieve large datasets from commercetools:\n\n- **getAll(args)** - Issues a query that will potentially return large amounts of data, handling pagination automatically\n  - Parameters:\n    - `args.endpoint`: (Required) The commercetools API endpoint to query (e.g., apiRoot.products(), apiRoot.categories())\n    - `args.queryArgs`: (Optional) Object containing query parameters such as:\n      - `where`: String or array of where conditions\n      - `expand`: String or array of expansion paths\n      - `priceCurrency`, `priceCountry`, `priceCustomerGroup`, `priceChannel`: Price selection parameters\n    - `args.callback`: (Optional) Function to process results in batches of up to 500 items\n    - `args.max`: (Optional) Maximum number of results to return, defaults to all\n    - `args.debug`: (Optional) Boolean to enable debug logging\n  - Returns: Array of all results (or none if using callback)\n  \n  Example:\n  ```js\n  // Get all products\n  const products = await getAll({\n    endpoint: apiRoot.products()\n  });\n  \n  // Get products with filtering and process in batches\n  await getAll({\n    endpoint: apiRoot.productProjections(),\n    queryArgs: { where: 'categories(id=\"123\")', expand: 'categories[*]' },\n    callback: (batch) =\u003e processBatch(batch),\n    max: 1000\n  });\n  ```\n\n### getCount.js\n\nFunctions for counting large datasets:\n\n- **getCount(args)** - Retrieves an accurate count of items, even when the count exceeds the platform's standard limit of 10,000\n  - Parameters:\n    - `args.endpoint`: (Required) The commercetools API endpoint to query (e.g., apiRoot.products())\n    - `args.queryArgs`: (Optional) Object containing query parameters such as `where` conditions\n  - Returns: Total count of matching items\n  \n  Example:\n  ```js\n  // Count all products\n  const totalProducts = await getCount({\n    endpoint: apiRoot.products()\n  });\n  \n  // Count products matching a condition\n  const totalProductsInCategory = await getCount({\n    endpoint: apiRoot.products(),\n    queryArgs: { where: 'masterData(current(categories(id=\"123\")))' }\n  });\n  ```\n\n### product.js\n\nProduct-specific utilities:\n\n- **actionAllProducts(actionCallback, args)** - Perform update actions for all products\n  - Parameters:\n    - `actionCallback`: (Required) Function that takes a product and returns an array of update actions\n    - `args`: (Optional) Object with options:\n      - `debug`: Boolean to enable debug logging\n      - Can include any parameters accepted by getAll() such as queryArgs\n  - Returns: Object with count of updated products and errors: `{count, errors}`\n  \n  Example:\n  ```js\n  // Add a custom attribute to all products\n  const result = await actionAllProducts(\n    (product) =\u003e [{\n      action: 'setAttribute',\n      variantId: product.masterData.current.masterVariant.id,\n      name: 'customFlag',\n      value: true\n    }],\n    { debug: true }\n  );\n  console.log(`Updated ${result.count} products with ${result.errors} errors`);\n  ```\n\n- **actionAllVariants(actionCallback, debug)** - Perform update actions for all product variants (master and regular variants)\n  - Parameters:\n    - `actionCallback`: (Required) Function that takes a product and variant and returns an array of update actions\n    - `debug`: (Optional) Boolean to enable debug logging (default: false)\n  - Returns: Object with count of updated products and errors: `{count, errors}`\n  \n  Example:\n  ```js\n  // Add an attribute to all variants of all products\n  const result = await actionAllVariants(\n    (product, variant) =\u003e [{\n      action: 'setAttribute',\n      variantId: variant.id,\n      name: 'processed',\n      value: true\n    }],\n    true\n  );\n  console.log(`Updated ${result.count} products with ${result.errors} errors`);\n  ```\n\n### productType.js\n\nProduct type management utilities:\n\n- **getProductType(key)** - Retrieve a product type by key, returns null if not found\n  - `key`: (Required) The product type key to look up\n  - Returns: The product type object or null if not found\n\n- **createProductType(body)** - Create a new product type\n  - `body`: (Required) Product type definition object\n  - Returns: Result of the create operation\n\n- **deleteProductType(key, version)** - Delete a product type by key and version\n  - Parameters:\n    - `key`: (Required) The product type key to delete\n    - `version`: (Required) The version number of the product type to delete\n  - Returns: Result of the delete operation\n\n- **updateProductType(key, body)** - Update an existing product type\n  - Parameters:\n    - `key`: (Required) The product type key to update\n    - `body`: (Required) Product type definition object with version\n  - Returns: Updated version number if successful, null otherwise\n\n### type.js\n\nType management utilities:\n\n- **getType(key)** - Retrieve a type by key, returns null if not found\n  - `key`: (Required) The type key to look up\n  - Returns: The type object or null if not found\n\n- **createOrUpdateType(type)** - Create a new type or update an existing one\n  - `type`: (Required) Type definition object\n  - Returns: Result of the create or update operation\n\n- **deleteType(key, version)** - Delete a type by key and version\n  - Parameters:\n    - `key`: (Required) The type key to delete\n    - `version`: (Required) The version number of the type to delete\n  - Returns: Result of the delete operation\n\n### transform.js\n\nData mapping and transformation utilities:\n\n- **mapFields(mapperList, input, output, initDebug)** - Maps fields from a source object to a destination object using mapper configurations\n  - Parameters:\n    - `mapperList`: (Required) Array of mapper objects defining the transformation rules\n    - `input`: (Required) Source object containing the data to transform\n    - `output`: (Required) Destination object to populate with transformed data\n    - `initDebug`: (Optional) Boolean to enable debug logging\n  - Returns: No return value; modifies the output object directly\n  \n- **toSlug(s)** - Creates a commercetools-compatible URL slug from a string\n  - `s`: (Required) String to convert to a slug\n  - Returns: Slugified string\n\n- **addVariantToProduct(product, variant)** - Adds a variant to a product\n  - Parameters:\n    - `product`: (Required) Product object to add the variant to\n    - `variant`: (Required) Variant object to add to the product\n  - Returns: No return value; modifies the product object directly\n\nA Mapper has (up to) five fields:\n\n* **src**: The name of the field in the source object\n* **dest**: The name of the field in the destination object\n* **convert**: (optional) - a conversion operation to perform. One of:\n    slug, category, price, number, boolean, image, list, newline-list, array-list, text, flatten, flatten-list\n* **type**: (optional) - the data type of the destination field. One of:\n  attr, array\n* **locale**: (optional) - for localized fields, specifies the locale (e.g., 'en-US')\n\nExamples:\n```js\n{\n  src: 'ProductID',\n  dest: 'key',\n}\n```\nThe field *ProductID* in the source object will be mapped to the field *key* in the destination object -- no transformations performed (straight copy)\n\n#### Price\nConvert a Price:\n```js\n{\n  src: 'SalePrice',\n  dest: 'prices',\n  convert: 'price'\n}\n```\n\n#### Localized Fields:\n\n```js\n{\n  src: 'ProductName',\n  dest: 'name',\n  locale: 'en-US'\n}\n```\nIn this case, ProductName in the source will map to a localized field *name* in the destination, in a structure used by commercetools localized fields.\n\n#### Attributes\n```js\n{\n  src: 'Department',\n  dest: 'department',\n  type: 'attr'\n}\n```\nThe source field Department will be copied to an attribute called *department* in an *attributes* array of the destination object\n\n#### Category (reference by key)\nUse both a 'convert' (to convert to a reference to a category), and a 'type' (array)\n```js\n{\n  src: 'CategoryID',\n  dest: 'categories',\n  convert: 'category',\n  type: 'array'\n}\n```\n\n#### Images\nConvert to an (external) image format\n```js\n{\n  src: 'MainImageURL',\n  dest: 'images',\n  convert: 'image',\n  type: 'array'\n}\n```\n\n### files.js\n\nFile I/O utilities:\n\n- **readCsv(filename, delimiter, quote, verbose)** - Read CSV file and return as an array of objects\n  - Parameters:\n    - `filename`: (Required) Path to the CSV file\n    - `delimiter`: (Optional) Column delimiter character (default: ',')\n    - `quote`: (Optional) Quote character (default: '\"')\n    - `verbose`: (Optional) Boolean flag to enable verbose logging (default: false)\n  - Returns: Array of objects with properties named by headers from the first row\n\n- **writeCsv(filename, data, options)** - Write array of objects to a CSV file\n  - Parameters:\n    - `filename`: (Required) Path to write the CSV file\n    - `data`: (Required) Array of objects to write\n    - `options`: (Optional) Object with options:\n      - `headers`: Array of column headers (if not to be auto-generated from first object)\n      - `delimiter`: Column delimiter character (default: ',')\n  - Returns: No return value\n\n- **readJSON(filename)** - Read JSON file and return parsed object\n  - `filename`: (Required) Path to the JSON file\n  - Returns: Parsed JavaScript object\n\n- **writeJSON(filename, data)** - Write object to a JSON file\n  - Parameters:\n    - `filename`: (Required) Path to write the JSON file\n    - `data`: (Required) Object to serialize and write\n  - Returns: No return value\n\n- **inspect(obj)** - Utility for inspecting object structures\n  - `obj`: (Required) Object to inspect\n  - Returns: String representation of the object structure\n\n### cache.js\n\nCaching utilities:\n\n- **readFromCache(key)** - Read data from cache\n  - `key`: (Required) Cache entry identifier\n  - Returns: Cached data or null if not found\n\n- **writeToCache(key, data)** - Write data to cache\n  - Parameters:\n    - `key`: (Required) Cache entry identifier\n    - `data`: (Required) Data to store in the cache\n  - Returns: No return value\n\n## Environment Configuration\n\nPlace the commercetools connection parameters in a file named **.env** in a folder adjacent to your calling script or in the current directory.\n\nRequired environment variables:\n```\nCTP_PROJECT_KEY=your-project-key\nCTP_CLIENT_SECRET=your-client-secret\nCTP_CLIENT_ID=your-client-id\nCTP_AUTH_URL=https://auth.region.commercetools.com\nCTP_API_URL=https://api.region.commercetools.com\nCTP_SCOPES=your-scopes\n```\n\nOptional:\n```\nLOG_API_CALLS=true\n```\n\n## Linking locally\n\nIf developing locally, do 'yarn link' in this directory, then 'yarn link @cboyke/demotools' in the dependent folder.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcommercetools-demo%2Fdemotools","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcommercetools-demo%2Fdemotools","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcommercetools-demo%2Fdemotools/lists"}