├── .env.test ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── pull_request_template.md ├── release-drafter.yml └── workflows │ ├── ci-cd.yml │ ├── deploy.yml │ └── release-drafter.yml ├── .gitignore ├── .npmignore ├── .travis.yml ├── .xo-config.json ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── ReadMe.md ├── SECURITY.md ├── docs ├── .vitepress │ └── config.mts ├── guide │ ├── Guide │ │ ├── Advanced │ │ │ ├── custom-headers.md │ │ │ ├── custom-logging.md │ │ │ ├── custom-transport.md │ │ │ ├── debugging.md │ │ │ ├── endpoint-override.md │ │ │ ├── index.md │ │ │ ├── manage-apis.md │ │ │ ├── pagination.md │ │ │ ├── sideload.md │ │ │ └── throttling.md │ │ ├── authentication.md │ │ ├── final.md │ │ └── installation.md │ └── index.md ├── index.md ├── old │ ├── api-coverage.md │ ├── future-features.md │ ├── meetings │ │ └── 2015-05-09.md │ └── side-loading.md └── public │ └── Node_Zendesk_logo.svg ├── examples ├── activities-list.js ├── automations-list.js ├── busey.gif ├── check-auth-promise.js ├── check-auth-token.js ├── check-auth.js ├── check-oauth-token.js ├── create-oauth-token.js ├── delete-many-organizations.js ├── endpoint.js ├── example-config.js ├── groupmemberships-list-group.js ├── groupmemberships-list-user.js ├── groupmemberships-list.js ├── groups-list-assignable.js ├── groups-list.js ├── macros-active-list.js ├── optional-axios-transport.js ├── optional-deprecated-request-transport.js ├── organization-fields-list.js ├── organization-memberships-list.js ├── organization-upsert.js ├── organizations-delete-bulk.js ├── organizations-delete.js ├── organizations-list.js ├── search-query.js ├── suspended-tickets-list.js ├── tags-list.js ├── ticket-create-promise.js ├── ticket-create.js ├── ticket-delete.js ├── ticket-list-observer.js ├── ticket-list.js ├── ticketaudits-list.js ├── ticketmetric-list.js ├── triggers-list.js ├── upload-attachment.js ├── user-create-many.js ├── user-create-promise.js ├── user-create.js ├── user-fields-list.js ├── users-list.js ├── users-listbygroup.js ├── usertags-list.js └── views-list.js ├── package-lock.json ├── package.json ├── src ├── clients │ ├── authorization-handler.js │ ├── client.js │ ├── core │ │ ├── accountsettings.js │ │ ├── activitystream.js │ │ ├── attachments.js │ │ ├── automations.js │ │ ├── brand.js │ │ ├── customagentroles.js │ │ ├── dynamiccontent.js │ │ ├── dynamiccontentvariants.js │ │ ├── groupmemberships.js │ │ ├── groups.js │ │ ├── imports.js │ │ ├── installations.js │ │ ├── jobstatuses.js │ │ ├── locales.js │ │ ├── macros.js │ │ ├── oauthclients.js │ │ ├── oauthtokens.js │ │ ├── organizationfields.js │ │ ├── organizationmemberships.js │ │ ├── organizations.js │ │ ├── permissiongroups.js │ │ ├── policies.js │ │ ├── requests.js │ │ ├── satisfactionratings.js │ │ ├── search.js │ │ ├── sessions.js │ │ ├── sharingagreement.js │ │ ├── sideconversations.js │ │ ├── suspendedtickets.js │ │ ├── tags.js │ │ ├── targetfailures.js │ │ ├── targets.js │ │ ├── ticketaudits.js │ │ ├── ticketevents.js │ │ ├── ticketexport.js │ │ ├── ticketfields.js │ │ ├── ticketforms.js │ │ ├── ticketimport.js │ │ ├── ticketmetrics.js │ │ ├── tickets.js │ │ ├── triggers.js │ │ ├── userfields.js │ │ ├── useridentities.js │ │ ├── users.js │ │ ├── views.js │ │ └── webhooks.js │ ├── custom-event-target.js │ ├── endpoint-checker.js │ ├── helpcenter │ │ ├── accesspolicies.js │ │ ├── articleattachments.js │ │ ├── articlecomments.js │ │ ├── articlelabels.js │ │ ├── articles.js │ │ ├── categories.js │ │ ├── index.js │ │ ├── search.js │ │ ├── sections.js │ │ ├── subscriptions.js │ │ ├── translations.js │ │ ├── usersegments.js │ │ └── votes.js │ ├── helpers.js │ ├── job-monitor.js │ ├── services │ │ ├── index.js │ │ └── links.js │ ├── throttle.js │ ├── transporter.js │ └── voice │ │ ├── agentactivity.js │ │ ├── availabilities.js │ │ ├── currentqueueactivity.js │ │ ├── greetingcategories.js │ │ ├── greetings.js │ │ ├── historicalqueueactivity.js │ │ ├── index.js │ │ └── phonenumbers.js ├── constants.js ├── index.js └── logger.js └── test ├── authentication.test.js ├── endpoint-checker.test.js ├── exceptionshandling.test.js ├── fixtures ├── authentication_test_correct_oauthtoken.json ├── authentication_test_correct_u_token.json ├── authentication_test_endpoint_uri.json ├── authentication_test_incorrect_sans_token.json ├── authentication_test_incorrect_subdomain.json ├── authentication_test_incorrect_token.json ├── authentication_test_incorrect_u_p.json ├── authentication_test_no_creds.json ├── authentication_test_user_pass.json ├── organizations_many_test_bulk_delete.json ├── organizations_many_test_create_multiple.json ├── organizations_many_test_update_multiple.json ├── organizations_test_autocomplete_organization.json ├── organizations_test_create.json ├── organizations_test_delete_not_found_organization.json ├── organizations_test_delete_organization.json ├── organizations_test_list_all.json ├── organizations_test_search_organization.json ├── organizations_test_show_single.json ├── organizations_test_update_organization.json ├── pagination_test_cleanup.json ├── pagination_test_execute.json ├── pagination_test_setup.json └── webhooks_endpoint.json ├── job-runner.js ├── node-zendesk-tests.js ├── organizations.many.test.js ├── organizations.test.js ├── pagination.test.js ├── setup.js └── webhooks.test.js /.env.test: -------------------------------------------------------------------------------- 1 | # .env 2 | 3 | # Zendesk authentication details 4 | ZENDESK_FULL_NAME="TEST USER" 5 | ZENDESK_USERNAME=myUsername 6 | ZENDESK_TOKEN=myToken 7 | ZENDESK_PASSWORD=myPassword 8 | ZENDESK_SUBDOMAIN=nodejsapi 9 | ZENDESK_OAUTH_ACCESS_TOKEN=myOAuthAccessToken 10 | ZENDESK_ENDPOINT_URI=https://nodejsapi.zendesk.com/api/v2 11 | 12 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: blakmatrix 4 | open_collective: node-zendesk 5 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the Bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **Example Code** 14 | ```javascript 15 | // Your example code that produces the issue goes here 16 | ``` 17 | 18 | **Expected Behavior** 19 | A clear and concise description of what you expected to happen. 20 | 21 | **Actual Behavior** 22 | What actually happened. If applicable, add screenshots or error messages to help explain the problem. 23 | 24 | **Environment Information** 25 | - `node-zendesk` version: 26 | - Node.js version: 27 | - Operating System: 28 | - Any other relevant software versions? 29 | 30 | **Additional Context** 31 | Add any other context about the problem here. 32 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea or enhancement for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Feature Description** 11 | Briefly describe the feature you'd like to see implemented. 12 | 13 | **Example Use Case** 14 | Provide an example or context where this feature would be beneficial. 15 | 16 | **Additional Information** 17 | Any other details or ideas related to the feature. 18 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Pull Request Description 2 | 3 | Please provide a brief description of your changes. 4 | 5 | --- 6 | 7 | ## Related Issue(s) 8 | 9 | - [ ] This PR fixes/closes issue #... 10 | - [ ] This is a new feature and does not have an associated issue. 11 | 12 | --- 13 | 14 | ## Additional Information 15 | 16 | - [ ] This change is a breaking change (may require a major version update) 17 | - [ ] This change is a new feature (non-breaking change which adds functionality) 18 | - [ ] This change improves the code (e.g., refactoring, etc.) 19 | - [ ] This change includes dependency updates 20 | 21 | --- 22 | 23 | ## Test Cases 24 | 25 | Include any test cases or steps you took to test your changes. If you have added new functionality, please include relevant unit tests. 26 | 27 | --- 28 | 29 | ## Documentation 30 | 31 | - [ ] I have updated the documentation accordingly. 32 | - [ ] No updates are required. 33 | 34 | --- 35 | 36 | ## Checklist 37 | 38 | - [ ] I have read the [CONTRIBUTING](./CONTRIBUTING.md) documentation. 39 | - [ ] My code follows the coding standards of this project. 40 | - [ ] All new and existing tests passed. 41 | 42 | -------------------------------------------------------------------------------- /.github/release-drafter.yml: -------------------------------------------------------------------------------- 1 | name-template: 'v$NEXT_PATCH_VERSION 🌈' 2 | tag-template: 'v$NEXT_PATCH_VERSION' 3 | categories: 4 | - title: '🚀 Features' 5 | labels: 6 | - 'feature' 7 | - 'enhancement' 8 | - title: '🐛 Bug Fixes' 9 | labels: 10 | - 'fix' 11 | - 'bugfix' 12 | - 'bug' 13 | - title: '🧰 Maintenance' 14 | label: 'chore' 15 | change-template: '- $TITLE @$AUTHOR (#$NUMBER)' 16 | exclude-labels: 17 | - 'skip-changelog' 18 | template: | 19 | ## Changes 20 | 21 | $CHANGES 22 | -------------------------------------------------------------------------------- /.github/workflows/ci-cd.yml: -------------------------------------------------------------------------------- 1 | name: Continuous Integration and Deployment 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | # Combined CI and CD Jobs to reduce redundancy 11 | build-and-deploy: 12 | runs-on: ubuntu-latest 13 | 14 | # Sets permissions for the GITHUB_TOKEN 15 | permissions: 16 | contents: read 17 | pages: write 18 | id-token: write 19 | 20 | steps: 21 | # Checkout code just once 22 | - uses: actions/checkout@v3 23 | 24 | # Setup Node.js only once 25 | - name: Setup Node.js 26 | uses: actions/setup-node@v3 27 | with: 28 | node-version: 22 29 | cache: 'npm' 30 | 31 | # Install dependencies only once 32 | - name: Install Dependencies 33 | run: npm ci 34 | 35 | # Lint, Test, Build, and Generate Documentation 36 | - name: Lint 37 | run: npm run lint 38 | 39 | - name: Test 40 | run: npm run test 41 | 42 | - name: Build 43 | run: npm run build 44 | 45 | - name: Generate Documentation 46 | run: npm run docs:code 47 | env: 48 | NODE_OPTIONS: --max-old-space-size=4096 49 | NO_COLOR: true 50 | 51 | # Conditional Deployment steps 52 | - name: Setup Pages 53 | if: github.event_name == 'push' && github.ref == 'refs/heads/master' 54 | uses: actions/configure-pages@v3 55 | 56 | - name: Build with VitePress 57 | if: github.event_name == 'push' && github.ref == 'refs/heads/master' 58 | run: npm run docs:deploy-github-pages 59 | 60 | - name: Upload artifact 61 | if: github.event_name == 'push' && github.ref == 'refs/heads/master' 62 | uses: actions/upload-pages-artifact@v2 63 | with: 64 | path: docs/.vitepress/dist 65 | 66 | - name: Deploy to GitHub Pages 67 | if: github.event_name == 'push' && github.ref == 'refs/heads/master' 68 | uses: actions/deploy-pages@v2 69 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | # Sample workflow for building and deploying a VitePress site to GitHub Pages 2 | # 3 | name: Deploy VitePress site to Pages 4 | 5 | on: 6 | # Runs on pushes targeting the `main` branch. Change this to `master` if you're 7 | # using the `master` branch as the default branch. 8 | # push: 9 | # branches: [master] 10 | 11 | # Allows you to run this workflow manually from the Actions tab 12 | workflow_dispatch: 13 | 14 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages 15 | permissions: 16 | contents: read 17 | pages: write 18 | id-token: write 19 | 20 | # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. 21 | # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. 22 | concurrency: 23 | group: pages 24 | cancel-in-progress: false 25 | 26 | jobs: 27 | # Build job 28 | build: 29 | runs-on: ubuntu-latest 30 | steps: 31 | - name: Checkout 32 | uses: actions/checkout@v3 33 | with: 34 | fetch-depth: 0 # Not needed if lastUpdated is not enabled 35 | # - uses: pnpm/action-setup@v2 # Uncomment this if you're using pnpm 36 | # - uses: oven-sh/setup-bun@v1 # Uncomment this if you're using Bun 37 | - name: Setup Node 38 | uses: actions/setup-node@v3 39 | with: 40 | node-version: 22 41 | cache: npm # or pnpm / yarn 42 | - name: Setup Pages 43 | uses: actions/configure-pages@v3 44 | - name: Install dependencies 45 | run: npm ci # or pnpm install / yarn install / bun install 46 | - name: Build with VitePress 47 | run: | 48 | npm run docs:deploy-github-pages 49 | - name: Upload artifact 50 | uses: actions/upload-pages-artifact@v2 51 | with: 52 | path: docs/.vitepress/dist 53 | 54 | # Deployment job 55 | deploy: 56 | environment: 57 | name: github-pages 58 | url: ${{ steps.deployment.outputs.page_url }} 59 | needs: build 60 | runs-on: ubuntu-latest 61 | name: Deploy 62 | steps: 63 | - name: Deploy to GitHub Pages 64 | id: deployment 65 | uses: actions/deploy-pages@v2 66 | -------------------------------------------------------------------------------- /.github/workflows/release-drafter.yml: -------------------------------------------------------------------------------- 1 | name: Release Drafter 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | jobs: 8 | release-drafter: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: release-drafter/release-drafter@v5 12 | env: 13 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | .pnpm-debug.log* 9 | 10 | # Diagnostic reports (https://nodejs.org/api/report.html) 11 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 12 | 13 | # Runtime data 14 | pids 15 | *.pid 16 | *.seed 17 | *.pid.lock 18 | 19 | # Dependency directories 20 | node_modules/ 21 | jspm_packages/ 22 | 23 | # Optional npm cache directory 24 | .npm 25 | 26 | # Optional REPL history 27 | .node_repl_history 28 | 29 | # Output of 'npm pack' 30 | *.tgz 31 | 32 | # Others 33 | .DS_Store 34 | *.iml 35 | *.ipr 36 | *.iws 37 | /.idea 38 | .vscode 39 | 40 | # dotenv environment variable files 41 | .env 42 | .env.development.local 43 | .env.test.local 44 | .env.production.local 45 | .env.local 46 | 47 | # vitepress build/dev output 48 | docs/.vitepress/dist 49 | docs/.vitepress/cache 50 | docs/.vitepress/.temp 51 | docs/api/ 52 | docs/code/ 53 | 54 | # vitest 55 | coverage/ 56 | 57 | dist/ 58 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | npm-debug.log 3 | node_modules 4 | examples/ 5 | .github/ 6 | .vscode/ 7 | .travis.yml 8 | coverage/ 9 | test/ 10 | docs/ 11 | doc/ 12 | CODE_OF_CONDUCT.md 13 | CONTRIBUTING.md 14 | deploy.docs.* 15 | SECURITY.md 16 | .env 17 | .env.example 18 | .xo-config.json -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | branches: 3 | only: 4 | - master 5 | node_js: 6 | - 0.10 7 | 8 | notifications: 9 | email: 10 | - blakmatrix@gmail.com 11 | -------------------------------------------------------------------------------- /.xo-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugin": ["jsdoc"], 3 | "prettier": true, 4 | "space": 2, 5 | "rules": { 6 | "jsdoc/check-access": 1, 7 | "jsdoc/check-alignment": 1, 8 | "jsdoc/check-param-names": 1, 9 | "jsdoc/check-property-names": 1, 10 | "jsdoc/check-tag-names": 1, 11 | "jsdoc/check-types": 1, 12 | "jsdoc/check-values": 1, 13 | "jsdoc/empty-tags": 1, 14 | "jsdoc/implements-on-classes": 1, 15 | "jsdoc/multiline-blocks": 1, 16 | "jsdoc/no-multi-asterisks": 1, 17 | "jsdoc/no-undefined-types": 1, 18 | "jsdoc/require-jsdoc": 1, 19 | "jsdoc/require-param": 1, 20 | "jsdoc/require-param-description": 1, 21 | "jsdoc/require-param-name": 1, 22 | "jsdoc/require-param-type": 1, 23 | "jsdoc/require-property": 1, 24 | "jsdoc/require-property-description": 1, 25 | "jsdoc/require-property-name": 1, 26 | "jsdoc/require-property-type": 1, 27 | "jsdoc/require-returns": 1, 28 | "jsdoc/require-returns-check": 1, 29 | "jsdoc/require-returns-description": 1, 30 | "jsdoc/require-returns-type": 1, 31 | "jsdoc/require-yields": 1, 32 | "jsdoc/require-yields-check": 1, 33 | "jsdoc/sort-tags": 1, 34 | "jsdoc/tag-lines": 1, 35 | "jsdoc/valid-types": 1, 36 | 37 | "unicorn/prefer-module": "off", 38 | "unicorn/prefer-top-level-await": "off", 39 | "import/extensions": "off", 40 | "no-multi-assign": "off", 41 | "camelcase": [ 42 | "warn", 43 | { 44 | "allow": [ 45 | "automation_ids", 46 | "label_names", 47 | "phone_number", 48 | "previous_password", 49 | "start_time", 50 | "ticket_ids", 51 | "trigger_ids", 52 | "host_mapping", 53 | "malware_access_override", 54 | "group_memberships", 55 | "available_locales", 56 | "organization_field_ids", 57 | "external_id", 58 | "sla_policy_ids", 59 | "job_status", 60 | "sharing_agreement", 61 | "prepend_clone_title", 62 | "ticket_form_ids", 63 | "user_field_ids", 64 | "view_order", 65 | "custom_role", 66 | "http_method", 67 | "request_format", 68 | "client_id", 69 | "organization_membership", 70 | "organization_memberships" 71 | ] 72 | } 73 | ] 74 | } 75 | } -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Being Considerate as Contributors 2 | 3 | We ask all contributors to this project to be mindful of others and make meaningful additions. Though there is no formal code, we trust that everyone will interact thoughtfully, with patience, good faith, and kindness. If you have any concerns, please contact the maintainers. 4 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to `node-zendesk` 2 | 3 | First and foremost, thank you! We appreciate that you want to contribute to `node-zendesk`. Your time is valuable, and your contributions mean a lot to us. 4 | 5 | ## Getting Started 6 | 7 | - **Fork the repository** and clone it locally. Connect your local repository to the original `node-zendesk` repository by adding it as an upstream remote: 8 | 9 | ``` 10 | git clone https://github.com/[your-username]/node-zendesk.git 11 | git remote add upstream https://github.com/blakmatrix/node-zendesk.git 12 | ``` 13 | 14 | - **Install the dependencies**: 15 | 16 | ``` 17 | npm install 18 | ``` 19 | 20 | ## How to Contribute 21 | 22 | 1. **Find an issue to work on**. Check out the open [issues](https://github.com/blakmatrix/node-zendesk/issues) or create a new one describing a feature, bug, or other project-related task. ( Check out the [API Coverage Document](https://github.com/blakmatrix/node-zendesk/blob/master/doc/api-coverage.md) for ideas) 23 | 24 | 2. **Work on your feature or bugfix**. Ensure your code is clean and well-documented. Adhere to the project's coding style. 25 | 26 | 3. **Write tests**. If you're adding a new feature, make sure you add relevant tests. If you're fixing a bug, try to write a test that would have caught the bug. 27 | 28 | 4. **Create a pull request**. Push to your fork and [submit a pull request](https://github.com/blakmatrix/node-zendesk/pulls) to the main `node-zendesk` repository. Describe your changes comprehensively. 29 | 30 | 5. **Wait for the review**. The maintainers will review your PR, suggest changes if necessary, and merge it once it's approved. 31 | 32 | ## Coding Style 33 | 34 | - We use the `xo` package as our JavaScript/TypeScript linter. Please ensure your code conforms to the linter's rules. You can check your code with `xo` by running: 35 | 36 | ``` 37 | npm run lint 38 | ``` 39 | 40 | - For those who prefer integrating the linter into their editors, [`xo` offers editor plugins](https://github.com/xojs/xo/tree/main#editor-plugins) for smoother development. 41 | 42 | - Use clear and meaningful variable and function names. 43 | - Include comments and keep your code as readable as possible. 44 | 45 | ## Documentation Reference 46 | 47 | - Zendesk's documentation can be found [here](https://developer.zendesk.com/rest_api/docs/core/introduction). 48 | 49 | ## Communication 50 | 51 | - If you have a question or need assistance, feel free to open an issue or email blakmatrix@gmail.com. 52 | 53 | ## Thanks Again! 54 | 55 | Thank you for your contribution! By participating in this project, you agree to abide by its terms and the expectations set in the Code of Conduct. 56 | 57 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2012-2023 Farrin Reid 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Only the latest version of `node-zendesk` is currently being supported with security updates. 6 | 7 | | Version | Supported | 8 | | --------- | ------------------ | 9 | | latest | :white_check_mark: | 10 | | < latest | :x: | 11 | 12 | ## Reporting a Vulnerability 13 | 14 | If you believe you've found a security vulnerability in `node-zendesk`, please send an email to [blakmatrix@gmail.com](mailto:blakmatrix@gmail.com) detailing the suspected issue. Do **not** open a public GitHub issue if the bug is a security vulnerability. 15 | 16 | ### What to include in your report 17 | 18 | To help us understand the scope and impact of the security issue, please include as much detail as possible. This might include: 19 | 20 | - Steps to reproduce the issue, ideally a minimized test case. 21 | - Your expected result. 22 | - Your observed result. 23 | 24 | ### What to expect 25 | 26 | After you've submitted a vulnerability report: 27 | 28 | - We will acknowledge receipt of your vulnerability report. 29 | - We'll do our best to validate the reported vulnerability. 30 | - If valid, please understand that `node-zendesk` is a labor of love and maintained without any sponsorship(yet). While we always aim to address vulnerabilities as quickly as possible, it might take some time depending on the availability of maintainers. 31 | - Once resolved, we will provide an update on the report and possible mention in release notes (if you agree). 32 | 33 | Thank you for helping to improve `node-zendesk` and for your patience. 34 | -------------------------------------------------------------------------------- /docs/.vitepress/config.mts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vitepress' 2 | import { generateSidebar } from "vitepress-sidebar"; 3 | 4 | 5 | 6 | const getSideBar = (): any => { 7 | const generatedSidebar = generateSidebar([ 8 | { 9 | documentRootPath: "docs", 10 | scanStartPath: "guide", 11 | resolvePath: "/guide/", 12 | useTitleFromFileHeading: true, 13 | hyphenToSpace: true, 14 | keepMarkdownSyntaxFromTitle: true, 15 | manualSortFileNameByPriority: [ "installation.md", "authentication.md", "final.md" , 'Advanced'] 16 | }, 17 | { 18 | documentRootPath: "docs", 19 | scanStartPath: "code", 20 | resolvePath: "/code/", 21 | useTitleFromFileHeading: true, 22 | hyphenToSpace: true, 23 | keepMarkdownSyntaxFromTitle: true, 24 | }, 25 | ]); 26 | return generatedSidebar ?? []; 27 | }; 28 | 29 | // https://vitepress.dev/reference/site-config 30 | export default defineConfig({ 31 | title: "node-zendesk", 32 | description: "A Zendesk API client wrapper", 33 | base: "/node-zendesk/", 34 | themeConfig: { 35 | // https://vitepress.dev/reference/default-theme-config 36 | logo: '/Node_Zendesk_logo.svg', 37 | nav: [ 38 | { text: "Home", link: "/" }, 39 | { text: "Guide", link: "/guide/" }, 40 | { text: "API Example", link: "/code/README" }, 41 | ], 42 | 43 | sidebar: getSideBar(), 44 | outline: { level: [2, 6] }, 45 | 46 | search: { 47 | provider: 'local' 48 | }, 49 | 50 | socialLinks: [ 51 | { icon: 'github', link: 'https://github.com/blakmatrix/node-zendesk' } 52 | ], 53 | footer: { 54 | message: 'Released under the MIT License.', 55 | copyright: 'Copyright © 2012-present | Made by Farrin A. Reid with ❤️' 56 | }, 57 | }, 58 | }) 59 | -------------------------------------------------------------------------------- /docs/guide/Guide/Advanced/custom-headers.md: -------------------------------------------------------------------------------- 1 | # Custom Headers 2 | 3 | You can provide additional custom headers for your requests: 4 | 5 | ```js 6 | const clientOptions = { 7 | customHeaders: { 8 | 'X-Custom-Header': 'CustomValue' 9 | } 10 | }; 11 | ``` -------------------------------------------------------------------------------- /docs/guide/Guide/Advanced/custom-logging.md: -------------------------------------------------------------------------------- 1 | # Custom Logging 2 | 3 | `node-zendesk` provides an option to log to your own logger object. By default, it uses its own `ConsoleLogger`. To use a custom logger: 4 | 5 | ```js 6 | const clientOptions = { 7 | username: 'your_username', 8 | token: 'your_token', 9 | subdomain: 'your_subdomain', 10 | logger: yourCustomLogger, 11 | debug: true 12 | }; 13 | const client = zendesk.createClient(clientOptions); 14 | ``` -------------------------------------------------------------------------------- /docs/guide/Guide/Advanced/custom-transport.md: -------------------------------------------------------------------------------- 1 | # Custom Transport Configuration 2 | 3 | If you prefer not to use the default `cross-fetch`, you can configure a custom transport. Here's an example using `axios`: 4 | 5 | ```js 6 | const transportConfigUsingAxios = { 7 | async transportFn(uri, options) { 8 | // Convert the options to be compatible with axios 9 | const requestOptions = { 10 | ...options, 11 | url: uri, 12 | method: options.method || 'GET', 13 | data: options.body, 14 | }; 15 | 16 | try { 17 | const response = await axios(requestOptions); 18 | return response; 19 | } catch (error) { 20 | if (error.response) { 21 | return error.response; 22 | } 23 | throw error; 24 | } 25 | }, 26 | 27 | responseAdapter(response) { 28 | return { 29 | json: () => Promise.resolve(response.data), 30 | status: response.status, 31 | headers: { 32 | get: (headerName) => response.headers[headerName.toLowerCase()], 33 | }, 34 | statusText: response.statusText, 35 | }; 36 | }, 37 | }; 38 | 39 | const setupClient = (config) => { 40 | return zd.createClient({ 41 | username: ZENDESK_USERNAME, 42 | subdomain: ZENDESK_SUBDOMAIN, 43 | token: ZENDESK_TOKEN, 44 | transportConfig: transportConfigUsingAxios, 45 | ...config, 46 | }); 47 | }; 48 | 49 | async function foo() { 50 | try { 51 | const client = setupClient({debug: false}); 52 | const result = await client.users.list(); 53 | console.dir(result); 54 | } catch (error) { 55 | console.error(`Failed: ${error.message}`); 56 | } 57 | } 58 | 59 | foo(); 60 | ``` 61 | 62 | This example demonstrates how to set up a client using `axios` as the transport mechanism instead of the default `cross-fetch`. -------------------------------------------------------------------------------- /docs/guide/Guide/Advanced/debugging.md: -------------------------------------------------------------------------------- 1 | # Debug Logging 2 | 3 | Enable or disable debug logging using the `debug` property: 4 | 5 | ```js 6 | const clientOptions = { 7 | debug: true 8 | }; 9 | ``` 10 | -------------------------------------------------------------------------------- /docs/guide/Guide/Advanced/endpoint-override.md: -------------------------------------------------------------------------------- 1 | # Endpoint URI Override 2 | 3 | If you have a middleware service or a proxy in front of the Zendesk API, you can override the default `endpointUri`. This can be useful for custom routing or handling of requests. Note that using this override will disable the `subdomain` option. 4 | 5 | ## Throttling 6 | 7 | Enable request throttling by setting the `throttle` flag: 8 | 9 | ```js 10 | const clientOptions = { 11 | throttle: true 12 | }; 13 | ``` -------------------------------------------------------------------------------- /docs/guide/Guide/Advanced/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | order:5 3 | --- -------------------------------------------------------------------------------- /docs/guide/Guide/Advanced/manage-apis.md: -------------------------------------------------------------------------------- 1 | # API Types 2 | 3 | `node-zendesk` supports different types of Zendesk APIs. By default, it uses the 'core' API. If you want to access the helpdesk API, you need to call it explicitly: 4 | 5 | ```js 6 | client.helpdesk.categories.list(); 7 | ``` 8 | 9 | Currently, there are only `helpdesk`, `services`, and `voice` and you can use them all by including the upon client instantiation as follows: 10 | 11 | ```js 12 | const clientOptions = { 13 | username: 'your_username', 14 | token: 'your_token', 15 | subdomain: 'your_subdomain', 16 | apiType: ['core', 'helpdesk', 'services', 'voice'], 17 | }; 18 | const client = zendesk.createClient(clientOptions); 19 | ``` 20 | -------------------------------------------------------------------------------- /docs/guide/Guide/Advanced/pagination.md: -------------------------------------------------------------------------------- 1 | # Pagination 2 | 3 | `node-zendesk` optimizes pagination by default, ensuring efficient retrieval of large datasets. However, if you wish to override the default pagination mechanism, you can do so during client instantiation: 4 | 5 | ```js 6 | const clientOptions = { 7 | username: 'your_username', 8 | token: 'your_token', 9 | subdomain: 'your_subdomain', 10 | query: { page: { size: 1 } } 11 | }; 12 | const client = zendesk.createClient(clientOptions); 13 | ``` 14 | 15 | ::: danger **Warning** 16 | Overriding the default pagination mechanism is not recommended. Additionally, cursor-based pagination in the Zendesk API does not support more than 100 items for most cursor-based endpoints. 17 | ::: -------------------------------------------------------------------------------- /docs/guide/Guide/Advanced/sideload.md: -------------------------------------------------------------------------------- 1 | # Side-Loading 2 | 3 | Side-loading allows you to retrieve related records along with the primary records you're querying. To set side-loading, use the `setSideLoad` method: 4 | 5 | ```js 6 | client.users.setSideLoad(['group', 'role']); 7 | ``` -------------------------------------------------------------------------------- /docs/guide/Guide/Advanced/throttling.md: -------------------------------------------------------------------------------- 1 | # Throttling 2 | 3 | Enable request throttling by setting the `throttle` flag: 4 | 5 | ```js 6 | const clientOptions = { 7 | throttle: true 8 | }; -------------------------------------------------------------------------------- /docs/guide/Guide/authentication.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 2 3 | --- 4 | 5 | # Authentication 6 | 7 | To interact with the Zendesk API using `node-zendesk`, you'll need to authenticate your requests. This section will guide you through the different authentication methods supported by the library. 8 | 9 | ## Basic Authentication 10 | 11 | Using a combination of your username, token, and subdomain, you can quickly set up basic authentication: 12 | 13 | ::: code-group 14 | 15 | ```js 16 | var zendesk = require('node-zendesk'); 17 | 18 | var client = zendesk.createClient({ 19 | username: 'your_username', 20 | token: 'your_token', 21 | subdomain: 'your_subdomain' 22 | }); 23 | ``` 24 | 25 | ```ts 26 | import {createClient} from 'node-zendesk' 27 | 28 | var client = createClient({ 29 | username: 'your_username', 30 | token: 'your_token', 31 | subdomain: 'your_subdomain' 32 | }); 33 | ``` 34 | ::: 35 | 36 | ## OAuth Authentication 37 | 38 | If you prefer to use an OAuth token for authentication, set the oauth key to true when creating the client. You can learn more about obtaining OAuth tokens from Zendesk's developer site. 39 | 40 | ::: code-group 41 | ```js 42 | var zendesk = require('node-zendesk'); 43 | 44 | var client = zendesk.createClient({ 45 | token: 'your_oauth_token', 46 | oauth: true 47 | }); 48 | ``` 49 | 50 | ```ts 51 | import {createClient} from 'node-zendesk' 52 | 53 | var client = zendesk.createClient({ 54 | token: 'your_oauth_token', 55 | oauth: true 56 | }); 57 | ``` 58 | ::: 59 | 60 | ## Impersonation 61 | 62 | To make API requests on behalf of end users, you can use the impersonation feature. Ensure you've granted the impersonate scope and then pass the end-user's email when creating the client: 63 | 64 | ::: code-group 65 | ```js 66 | var zendesk = require('node-zendesk'); 67 | 68 | var client = createClient({ 69 | username: 'your_username', 70 | token: 'your_oauth_token', 71 | subdomain: 'your_subdomain', 72 | oauth: true, 73 | asUser: 'end-user@example.com' 74 | }); 75 | ``` 76 | 77 | ```ts 78 | import {createClient} from 'node-zendesk' 79 | 80 | var client = createClient({ 81 | username: 'your_username', 82 | token: 'your_oauth_token', 83 | subdomain: 'your_subdomain', 84 | oauth: true, 85 | asUser: 'end-user@example.com' 86 | }); 87 | ``` 88 | ::: 89 | 90 | With authentication set up, you're ready to start making requests to the Zendesk API. In the following sections, we'll delve into more advanced features and usage patterns of node-zendesk. -------------------------------------------------------------------------------- /docs/guide/Guide/final.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 4 3 | --- 4 | 5 | 8 | 9 | # Facing Issues or Want to Contribute? 10 | 11 | 🌟 **Love `node-zendesk`?** Please consider [starring the project on GitHub](https://github.com/blakmatrix/node-zendesk)! 12 | 13 | Star 14 | 15 | It's a quick way to show your appreciation and helps us reach more users. 16 | 17 | `node-zendesk` is a community-driven project, and we highly value your feedback and contributions. If you encounter any challenges, have suggestions for improvements, or want to be a part of its growth, here's how you can participate: 18 | 19 | ## Reporting Issues 20 | 21 | If you stumble upon a bug, experience unexpected behavior, or have questions about `node-zendesk`, please [open an issue](https://github.com/blakmatrix/node-zendesk/issues) on our GitHub repository. When reporting an issue: 22 | 23 | - **Be Specific**: Clearly describe the problem you're encountering. Detail the steps to reproduce it, if possible. 24 | - **Include Version Info**: Specify the version of `node-zendesk` you're using, and any other pertinent details about your environment. 25 | - **Screenshots & Logs**: Attach screenshots or logs when relevant to provide a clearer picture of the issue. 26 | 27 | ## Contributing via Pull Requests 28 | 29 | Have you enhanced `node-zendesk` or fixed an existing bug? We'd be thrilled to review your contributions! Here's how you can submit a pull request: 30 | 31 | - Fork the [`node-zendesk` repository](https://github.com/blakmatrix/node-zendesk). 32 | - Create a new branch dedicated to your modifications. 33 | - Commit your changes with a comprehensive description of your updates. 34 | - Initiate a pull request against the main branch of the `node-zendesk` repository. 35 | 36 | Before finalizing your submission, ensure your code aligns with our coding standards and has undergone testing. 37 | 38 | ## Support the Project 39 | 40 | Your feedback and contributions significantly influence the development and success of `node-zendesk`. If you find this project beneficial and wish to offer further support, consider [sponsoring](https://github.com/blakmatrix/node-zendesk/sponsors) or starring our repository. 41 | 42 | We're grateful for your involvement in our community and your efforts to enhance `node-zendesk` for all users! 43 | -------------------------------------------------------------------------------- /docs/guide/Guide/installation.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 1 3 | --- 4 | 5 | # Installation 6 | 7 | Setting up `node-zendesk` is straightforward. Follow the steps below to get it up and running in your project. 8 | 9 | ## Installing via npm 10 | 11 | To install `node-zendesk`, use the npm command: 12 | 13 | ```shell 14 | npm install --save node-zendesk 15 | ``` 16 | This command installs `node-zendesk` as a dependency in your project, making it available for you to import and use. 17 | 18 | ## TypeScript Support 19 | 20 | Starting from version `v5.0.0`, `node-zendesk` automatically generates TypeScript types. This means you no longer need to seek out third-party type definitions from DefinitelyTyped or elsewhere. Just install the library, and you'll have access to accurate and up-to-date TypeScript definitions out of the box. 21 | 22 | In the next sections, we'll guide you through basic usage and authentication to get you started with interacting with the Zendesk API. -------------------------------------------------------------------------------- /docs/guide/index.md: -------------------------------------------------------------------------------- 1 | # Getting Started with `node-zendesk` 2 | 3 | Welcome to the `node-zendesk` guide! This guide is designed to help you seamlessly integrate `node-zendesk` into your projects, ensuring efficient interactions with the Zendesk API using Node.js. 4 | 5 | ## Prerequisites 6 | 7 | - A JavaScript/TypeScript project setup. 8 | - Familiarity with asynchronous programming in JavaScript. 9 | 10 | In the subsequent sections, we'll guide you through the installation process, basic usage, advanced features, and more. Dive in to get started! 11 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | # https://vitepress.dev/reference/default-theme-home-page 3 | layout: home 4 | 5 | hero: 6 | name: "node-zendesk" 7 | text: "A Zendesk API client wrapper" 8 | tagline: Power Up Zendesk: A robust wrapper for seamless API interactions. 9 | actions: 10 | - theme: brand 11 | text: Guide 12 | link: /guide/ 13 | - theme: alt 14 | text: API Examples 15 | link: /code/README 16 | image: 17 | src: /Node_Zendesk_logo.svg 18 | alt: node-zendesk logo 19 | 20 | features: 21 | - icon: 🌍 22 | title: Seamless Integration with Zendesk 23 | details: Elevate your apps with node-zendesk. Seamlessly and efficiently connect your applications with Zendesk's vast suite of customer service and engagement products. Our library is purpose-built to tap into Zendesk's APIs without a hiccup. 24 | link: "https://developer.zendesk.com/rest_api/docs/core/introduction" 25 | linkText: "Zendesk's documentation" 26 | - icon: ⚡️ 27 | title: Modern and Lightweight 28 | details: Built with the modern developer in mind, node-zendesk is lightweight and optimized for performance. Experience rapid setup and minimal overhead, with top-notch support for both JavaScript and TypeScript. 29 | - icon: 30 | title: "Extensive Linting with xo" 31 | details: "No more bikeshedding about code styles. node-zendesk adopts the xo package, ensuring code is always in its best shape. Benefit from built-in linting that covers almost all coding scenarios and integrates seamlessly with many editors." 32 | link: https://github.com/xojs/xo/tree/main#editor-plugins 33 | linkText: "Learn about xo's editor plugins" 34 | - icon: 🤝 35 | title: "Active Community and Transparent Development" 36 | details: "With node-zendesk, you're never coding alone. Join an active community of developers, get swift answers to queries, and enjoy the benefits of open and transparent development. We value every contributor, and our maintenance is a labor of love." 37 | link: https://github.com/blakmatrix/node-zendesk/blob/master/CONTRIBUTING.md 38 | linkText: "Contribute to node-zendesk" 39 | 40 | 41 | --- 42 | -------------------------------------------------------------------------------- /docs/old/api-coverage.md: -------------------------------------------------------------------------------- 1 | API Coverage Doc 2 | ===================== 3 | 4 | This document specifies the endpoints that are not yet included in the node-zendesk library. Its contents will change as Zendesk updates its documentation and as PRs are merged. 5 | 6 | ## Core API 7 | 8 | ``` 9 | PUT /api/v2/dynamic_content/items/{id}/variants/update_many.json 10 | ``` 11 | 12 | ## Help Center API 13 | 14 | 15 | 16 | ## Zopim API 17 | 18 | Client authentication and all APIs need some love. 19 | 20 | ## Reseller API 21 | 22 | All APIs need some love. However, the Reseller API is only accessible to Zendesk partners and resellers. Contact channel@zendesk.com if you're interested in gaining access. 23 | -------------------------------------------------------------------------------- /docs/old/future-features.md: -------------------------------------------------------------------------------- 1 | ### Future Features 2 | 3 | * provide option to disable auto-paging https://github.com/blakmatrix/node-zendesk/issues/46 4 | * better memory managment for users that request all tickets ever https://github.com/blakmatrix/node-zendesk/issues/93 5 | * query sorting https://github.com/blakmatrix/node-zendesk/issues/111 6 | * rate-limiting zendesk API confusion https://github.com/blakmatrix/node-zendesk/issues/126 7 | * expose `.client.request` https://github.com/blakmatrix/node-zendesk/issues/129 8 | * Missing locale support for help-center category list https://github.com/blakmatrix/node-zendesk/issues/149 9 | * Implement `tickets.createMany()` https://github.com/blakmatrix/node-zendesk/issues/153 10 | * Promise support? https://github.com/blakmatrix/node-zendesk/issues/156 11 | * Create user with default password https://github.com/blakmatrix/node-zendesk/issues/157 12 | * Support URL source for file upload -------------------------------------------------------------------------------- /docs/old/meetings/2015-05-09.md: -------------------------------------------------------------------------------- 1 | # node-zendesk WG 2015-05-09 2 | 3 | ### Present 4 | - Farin 5 | - Xiaochen 6 | - Eriks 7 | 8 | ### Discussion Notes 9 | - Intro of working group 10 | - Divvy up responsibilities 11 | - Eriks: WG Doc and API Coverage Roadmap 12 | - Xiaochen: Assess use of nconf (as it relates to [issue #80](https://github.com/blakmatrix/node-zendesk/issues/80)) 13 | - Farin: Assess Core API coverage 14 | 15 | ### Next Meeting 16 | ~ May 23 17 | -------------------------------------------------------------------------------- /examples/activities-list.js: -------------------------------------------------------------------------------- 1 | const process = require('node:process'); 2 | const zd = require('../lib/client'); 3 | const exampleConfig = require('./exampleConfig'); 4 | 5 | const client = zd.createClient({ 6 | username: process.env.ZENDESK_TEST_USERNAME || exampleConfig.auth.username, 7 | token: process.env.ZENDESK_TEST_TOKEN || exampleConfig.auth.token, 8 | remoteUri: process.env.ZENDESK_TEST_REMOTEURI || exampleConfig.auth.remoteUri, 9 | }); 10 | 11 | client.activitystream.list(function (error, request, result) { 12 | if (error) { 13 | console.log(error); 14 | return; 15 | } 16 | 17 | console.log(JSON.stringify(result)); 18 | console.log('Total activities: ' + result.length); 19 | }); 20 | -------------------------------------------------------------------------------- /examples/automations-list.js: -------------------------------------------------------------------------------- 1 | const process = require('node:process'); 2 | const zd = require('../lib/client'); 3 | const exampleConfig = require('./exampleConfig'); 4 | 5 | const client = zd.createClient({ 6 | username: process.env.ZENDESK_TEST_USERNAME || exampleConfig.auth.username, 7 | token: process.env.ZENDESK_TEST_TOKEN || exampleConfig.auth.token, 8 | remoteUri: process.env.ZENDESK_TEST_REMOTEURI || exampleConfig.auth.remoteUri, 9 | }); 10 | 11 | client.automations.list(function (error, request, result) { 12 | if (error) { 13 | console.log(error); 14 | return; 15 | } 16 | 17 | console.log(JSON.stringify(result)); 18 | console.log('Total automations: ' + result.length); 19 | }); 20 | -------------------------------------------------------------------------------- /examples/busey.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blakmatrix/node-zendesk/514199080d654bfbb5a6638fdee48e7a9a595809/examples/busey.gif -------------------------------------------------------------------------------- /examples/check-auth-promise.js: -------------------------------------------------------------------------------- 1 | const process = require('node:process'); 2 | const zd = require('../lib/client'); 3 | const exampleConfig = require('./exampleConfig'); 4 | 5 | const client = zd.createClient({ 6 | username: process.env.ZENDESK_TEST_USERNAME || exampleConfig.auth.username, 7 | token: process.env.ZENDESK_TEST_TOKEN || exampleConfig.auth.token, 8 | remoteUri: process.env.ZENDESK_TEST_REMOTEURI || exampleConfig.auth.remoteUri, 9 | }); 10 | 11 | client.users 12 | .auth() 13 | .then(function (response) { 14 | const result = response; 15 | console.dir(result.verified); 16 | }) 17 | .catch(function (error) { 18 | console.log(error); 19 | }); 20 | -------------------------------------------------------------------------------- /examples/check-auth-token.js: -------------------------------------------------------------------------------- 1 | const process = require('node:process'); 2 | const zd = require('../lib/client'); 3 | const exampleConfig = require('./exampleConfig'); 4 | 5 | const client = zd.createClient({ 6 | username: process.env.ZENDESK_TEST_USERNAME || exampleConfig.auth.username, 7 | token: process.env.ZENDESK_TEST_TOKEN || exampleConfig.auth.token, 8 | remoteUri: process.env.ZENDESK_TEST_REMOTEURI || exampleConfig.auth.remoteUri, 9 | }); 10 | 11 | client.users.auth(function (error, request, result) { 12 | if (error) { 13 | console.log(error); 14 | return; 15 | } 16 | 17 | console.log(JSON.stringify(result.verified, null, 2, true)); 18 | }); 19 | -------------------------------------------------------------------------------- /examples/check-auth.js: -------------------------------------------------------------------------------- 1 | const process = require('node:process'); 2 | const zd = require('../lib/client'); 3 | const exampleConfig = require('./exampleConfig'); 4 | 5 | const client = zd.createClient({ 6 | username: process.env.ZENDESK_TEST_USERNAME || exampleConfig.auth.username, 7 | token: process.env.ZENDESK_TEST_TOKEN || exampleConfig.auth.token, 8 | remoteUri: process.env.ZENDESK_TEST_REMOTEURI || exampleConfig.auth.remoteUri, 9 | }); 10 | 11 | client.users.auth(function (error, request, result) { 12 | if (error) { 13 | // Console.log(err); 14 | return; 15 | } 16 | 17 | console.log(JSON.stringify(result.verified, null, 2, true)); 18 | }); 19 | -------------------------------------------------------------------------------- /examples/check-oauth-token.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | const process = require('node:process'); 3 | const dotenv = require('dotenv'); 4 | const zd = require('../src/index.js'); 5 | 6 | dotenv.config(); 7 | 8 | const setupClient = () => { 9 | return zd.createClient({ 10 | token: process.env.ZENDESK_OAUTH_ACCESS_TOKEN, 11 | subdomain: process.env.ZENDESK_SUBDOMAIN, 12 | useOAuth: true, 13 | }); 14 | }; 15 | 16 | const client = setupClient(); 17 | 18 | /** 19 | * Checks the OAuth authentication for the Zendesk client and logs the verification status. 20 | * @returns {Promise} A promise that resolves when the check is complete. 21 | */ 22 | async function checkOAuth() { 23 | try { 24 | const {result: user} = await client.users.auth(); 25 | console.log(user.verified); 26 | } catch (error) { 27 | console.error(`Failed to check OAuth: ${error.message}`); 28 | } 29 | } 30 | 31 | checkOAuth(); 32 | -------------------------------------------------------------------------------- /examples/create-oauth-token.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | const process = require('node:process'); 3 | const dotenv = require('dotenv'); 4 | const zd = require('../src/index.js'); 5 | 6 | // Load environment variables from .env file 7 | dotenv.config(); 8 | 9 | /** 10 | * Set up and return a Zendesk client with the given configuration. 11 | * @param {object} config - Additional configuration for the Zendesk client. 12 | * @returns {object} Zendesk client instance. 13 | */ 14 | const setupClient = (config) => { 15 | return zd.createClient({ 16 | username: process.env.ZENDESK_USERNAME, 17 | subdomain: process.env.ZENDESK_SUBDOMAIN, 18 | token: process.env.ZENDESK_TOKEN, 19 | ...config, 20 | }); 21 | }; 22 | 23 | /** 24 | * Retrieves the numeric ID of an OAuth client based on its unique identifier. 25 | * @param {string} identifier - The unique identifier of the OAuth client. 26 | * @returns {Promise} The numeric ID of the OAuth client or null if not found. 27 | * @throws {Error} If there's an error in retrieving the OAuth client list. 28 | */ 29 | async function getClientId(identifier) { 30 | try { 31 | const client = setupClient({debug: false}); 32 | const result = await client.oauthclients.list(); 33 | const oauthClient = result.find((c) => c.identifier === identifier); 34 | return oauthClient ? oauthClient.id : null; 35 | } catch (error) { 36 | console.error('Error retrieving OAuth client ID:', error.message); 37 | return null; 38 | } 39 | } 40 | 41 | /** 42 | * Creates a read-only OAuth token for accessing users and tickets. 43 | * This function first retrieves the OAuth client ID using its unique identifier, 44 | * and then uses this ID to create a token with the specified scopes. 45 | * @throws {Error} If the OAuth client ID is not found or if there's an error in creating the OAuth token. 46 | */ 47 | async function createReadOnlyOAuthToken() { 48 | try { 49 | const oauthClientId = await getClientId( 50 | process.env.ZENDESK_OAUTH_CLIENT_UNIQUE_IDENTIFIER, 51 | ); 52 | if (!oauthClientId) { 53 | throw new Error('OAuth client ID not found for the given identifier.'); 54 | } 55 | 56 | const client = setupClient({debug: false}); 57 | 58 | // Create an OAuth token with read-only access to users and tickets 59 | const {result} = await client.oauthtokens.create({ 60 | token: { 61 | client_id: oauthClientId, // Numeric OAuth client ID 62 | scopes: ['users:read', 'tickets:read'], // Scopes for read-only access 63 | }, 64 | }); 65 | 66 | console.log('OAuth Token Created:', result); 67 | } catch (error) { 68 | console.error('Error creating OAuth token:', error.message); 69 | } 70 | } 71 | 72 | createReadOnlyOAuthToken(); 73 | -------------------------------------------------------------------------------- /examples/delete-many-organizations.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | /* eslint-disable no-await-in-loop */ 3 | const process = require('node:process'); 4 | const dotenv = require('dotenv'); 5 | const zd = require('../src/index.js'); 6 | 7 | dotenv.config(); 8 | 9 | const setupClient = (config) => { 10 | return zd.createClient({ 11 | username: process.env.ZENDESK_USERNAME, 12 | subdomain: process.env.ZENDESK_SUBDOMAIN, 13 | token: process.env.ZENDESK_TOKEN, 14 | ...config, 15 | }); 16 | }; 17 | 18 | // Placeholder organization ID for development/testing. 19 | // IMPORTANT: Replace with a valid organization ID before running in production. 20 | 21 | /** 22 | * 23 | */ 24 | async function organizationsDelete() { 25 | let collector = []; 26 | try { 27 | const client = setupClient({debug: false}); 28 | const allOrgs = await client.organizations.list(); 29 | for (const element of allOrgs) { 30 | if (element.name.startsWith('testOrganization')) { 31 | collector.push(element); 32 | } 33 | 34 | if (collector.length >= 30) { 35 | const ids = collector.map(function (i) { 36 | return i.id; 37 | }); 38 | await client.organizations.bulkDelete(ids); 39 | collector = []; 40 | } 41 | } 42 | } catch (error) { 43 | console.error(`Failed to delete organization: ${error.message}`); 44 | } 45 | } 46 | 47 | organizationsDelete(); 48 | -------------------------------------------------------------------------------- /examples/endpoint.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | const process = require('node:process'); 3 | const dotenv = require('dotenv'); 4 | const zd = require('../src/index.js'); 5 | 6 | dotenv.config(); 7 | 8 | const setupClient = (config) => { 9 | return zd.createClient({ 10 | username: process.env.ZENDESK_USERNAME, 11 | endpointUri: process.env.ZENDESK_ENDPOINT_URI, 12 | token: process.env.ZENDESK_TOKEN, 13 | ...config, 14 | }); 15 | }; 16 | 17 | /** 18 | * 19 | */ 20 | async function usersList() { 21 | try { 22 | const client = setupClient({debug: false}); 23 | const result = await client.users.list(); 24 | console.log( 25 | JSON.stringify( 26 | result.map(function (user) { 27 | return user.name; 28 | }), 29 | null, 30 | 2, 31 | true, 32 | ), 33 | ); // Gets the first page 34 | console.log('Total Users: ' + result.length); 35 | } catch (error) { 36 | console.error(`Failed to get list of users: ${error.message}`); 37 | } 38 | } 39 | 40 | usersList(); 41 | -------------------------------------------------------------------------------- /examples/example-config.js: -------------------------------------------------------------------------------- 1 | exports.auth = { 2 | username: 'example@zendesk.com', 3 | token: '', 4 | remoteUri: 'https://example.zendesk.com/api/v2', 5 | }; 6 | -------------------------------------------------------------------------------- /examples/groupmemberships-list-group.js: -------------------------------------------------------------------------------- 1 | const process = require('node:process'); 2 | const zd = require('../lib/client'); 3 | const exampleConfig = require('./exampleConfig'); 4 | 5 | const client = zd.createClient({ 6 | username: process.env.ZENDESK_TEST_USERNAME || exampleConfig.auth.username, 7 | token: process.env.ZENDESK_TEST_TOKEN || exampleConfig.auth.token, 8 | remoteUri: process.env.ZENDESK_TEST_REMOTEURI || exampleConfig.auth.remoteUri, 9 | }); 10 | 11 | /** 12 | * 13 | */ 14 | async function listGroupMemberships() { 15 | try { 16 | const groups = await client.groups.list(); 17 | const group = groups[0]; 18 | 19 | if (!group) { 20 | console.log('No groups found.'); 21 | return; 22 | } 23 | 24 | const memberships = await client.groupmemberships.listByGroup(group.id); 25 | console.log(JSON.stringify(memberships)); 26 | } catch (error) { 27 | console.error('Error fetching group memberships:', error); 28 | } 29 | } 30 | 31 | listGroupMemberships(); 32 | -------------------------------------------------------------------------------- /examples/groupmemberships-list-user.js: -------------------------------------------------------------------------------- 1 | const process = require('node:process'); 2 | const zd = require('../lib/client'); 3 | const exampleConfig = require('./exampleConfig'); 4 | 5 | const client = zd.createClient({ 6 | username: process.env.ZENDESK_TEST_USERNAME || exampleConfig.auth.username, 7 | token: process.env.ZENDESK_TEST_TOKEN || exampleConfig.auth.token, 8 | remoteUri: process.env.ZENDESK_TEST_REMOTEURI || exampleConfig.auth.remoteUri, 9 | }); 10 | 11 | /** 12 | * 13 | */ 14 | async function listUserMemberships() { 15 | try { 16 | const users = await client.users.list(); 17 | const user = users[0]; 18 | 19 | if (!user) { 20 | console.log('No users found.'); 21 | return; 22 | } 23 | 24 | const memberships = await client.groupmemberships.listByUser(user.id); 25 | console.log(JSON.stringify(memberships)); 26 | } catch (error) { 27 | console.error('Error fetching user memberships:', error); 28 | } 29 | } 30 | 31 | listUserMemberships(); 32 | -------------------------------------------------------------------------------- /examples/groupmemberships-list.js: -------------------------------------------------------------------------------- 1 | const process = require('node:process'); 2 | const zd = require('../lib/client'); 3 | const exampleConfig = require('./exampleConfig'); 4 | 5 | const client = zd.createClient({ 6 | username: process.env.ZENDESK_TEST_USERNAME || exampleConfig.auth.username, 7 | token: process.env.ZENDESK_TEST_TOKEN || exampleConfig.auth.token, 8 | remoteUri: process.env.ZENDESK_TEST_REMOTEURI || exampleConfig.auth.remoteUri, 9 | }); 10 | 11 | client.groupmemberships.list(function (error, request, result) { 12 | if (error) { 13 | console.log(error); 14 | return; 15 | } 16 | 17 | console.log(JSON.stringify(result)); 18 | console.log('Total Memberships: ' + result.length); 19 | }); 20 | -------------------------------------------------------------------------------- /examples/groups-list-assignable.js: -------------------------------------------------------------------------------- 1 | const process = require('node:process'); 2 | const zd = require('../lib/client'); 3 | const exampleConfig = require('./exampleConfig'); 4 | 5 | const client = zd.createClient({ 6 | username: process.env.ZENDESK_TEST_USERNAME || exampleConfig.auth.username, 7 | token: process.env.ZENDESK_TEST_TOKEN || exampleConfig.auth.token, 8 | remoteUri: process.env.ZENDESK_TEST_REMOTEURI || exampleConfig.auth.remoteUri, 9 | }); 10 | 11 | client.groups.assignable(function (error, request, result) { 12 | if (error) { 13 | console.log(error); 14 | return; 15 | } 16 | 17 | console.log( 18 | JSON.stringify( 19 | result.map(function (grp) { 20 | return grp.name; 21 | }), 22 | null, 23 | 2, 24 | true, 25 | ), 26 | ); // Gets the first page 27 | console.log('Total Groups: ' + result.length); 28 | }); 29 | -------------------------------------------------------------------------------- /examples/groups-list.js: -------------------------------------------------------------------------------- 1 | const process = require('node:process'); 2 | const zd = require('../lib/client'); 3 | const exampleConfig = require('./exampleConfig'); 4 | 5 | const client = zd.createClient({ 6 | username: process.env.ZENDESK_TEST_USERNAME || exampleConfig.auth.username, 7 | token: process.env.ZENDESK_TEST_TOKEN || exampleConfig.auth.token, 8 | remoteUri: process.env.ZENDESK_TEST_REMOTEURI || exampleConfig.auth.remoteUri, 9 | }); 10 | 11 | client.groups.list(function (error, request, result) { 12 | if (error) { 13 | console.log(error); 14 | return; 15 | } 16 | 17 | console.log( 18 | JSON.stringify( 19 | result.map(function (grp) { 20 | return grp.name; 21 | }), 22 | null, 23 | 2, 24 | true, 25 | ), 26 | ); // Gets the first page 27 | console.log('Total Groups: ' + result.length); 28 | }); 29 | -------------------------------------------------------------------------------- /examples/macros-active-list.js: -------------------------------------------------------------------------------- 1 | const process = require('node:process'); 2 | const zd = require('../lib/client'); 3 | const exampleConfig = require('./exampleConfig'); 4 | 5 | const client = zd.createClient({ 6 | username: process.env.ZENDESK_TEST_USERNAME || exampleConfig.auth.username, 7 | token: process.env.ZENDESK_TEST_TOKEN || exampleConfig.auth.token, 8 | remoteUri: process.env.ZENDESK_TEST_REMOTEURI || exampleConfig.auth.remoteUri, 9 | }); 10 | 11 | client.macros.listByParams(['?active=true'], function (error, request, result) { 12 | if (error) { 13 | console.log(error); 14 | return; 15 | } 16 | 17 | console.log(JSON.stringify(result)); 18 | console.log('Total Groups: ' + result.length); 19 | }); 20 | -------------------------------------------------------------------------------- /examples/optional-axios-transport.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | const process = require('node:process'); 3 | const dotenv = require('dotenv'); 4 | const axios = require('axios'); 5 | const zd = require('../src/index.js'); 6 | 7 | dotenv.config(); 8 | 9 | const transportConfigUsingAxios = { 10 | async transportFn(uri, options) { 11 | // Convert the options to be compatible with axios 12 | const requestOptions = { 13 | ...options, 14 | url: uri, 15 | method: options.method || 'GET', // Axios uses 'method', not just 'GET' or 'POST' as direct options 16 | data: options.body, // Axios uses 'data' instead of 'body' 17 | }; 18 | 19 | try { 20 | const response = await axios(requestOptions); 21 | return response; 22 | } catch (error) { 23 | // If axios throws an error, it usually encapsulates the actual server response within error.response. 24 | // This is to ensure that even for error HTTP statuses, the response can be adapted consistently. 25 | if (error.response) { 26 | return error.response; 27 | } 28 | 29 | throw error; // If there's no error.response, then throw the error as is. 30 | } 31 | }, 32 | 33 | responseAdapter(response) { 34 | return { 35 | json: () => Promise.resolve(response.data), 36 | status: response.status, 37 | headers: { 38 | get: (headerName) => response.headers[headerName.toLowerCase()], 39 | }, 40 | statusText: response.statusText, 41 | }; 42 | }, 43 | }; 44 | 45 | const setupClient = (config) => { 46 | return zd.createClient({ 47 | username: process.env.ZENDESK_USERNAME, 48 | subdomain: process.env.ZENDESK_SUBDOMAIN, 49 | token: process.env.ZENDESK_TOKEN, 50 | transportConfig: transportConfigUsingAxios, 51 | ...config, 52 | }); 53 | }; 54 | 55 | /** 56 | * 57 | */ 58 | async function foo() { 59 | try { 60 | const client = setupClient({debug: false}); 61 | const result = await client.users.list(); 62 | 63 | console.dir(result); 64 | } catch (error) { 65 | console.error(`Failed: ${error.message}`); 66 | } 67 | } 68 | 69 | foo(); 70 | -------------------------------------------------------------------------------- /examples/optional-deprecated-request-transport.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | const process = require('node:process'); 3 | const dotenv = require('dotenv'); 4 | const request = require('request'); 5 | const zd = require('../src/index.js'); 6 | 7 | dotenv.config(); 8 | 9 | const transportConfigUsingRequest = { 10 | transportFn(uri, options) { 11 | // Convert the options to be compatible with the request library 12 | const requestOptions = { 13 | ...options, 14 | uri, 15 | headers: options.headers, 16 | }; 17 | 18 | return new Promise((resolve, reject) => { 19 | request(requestOptions, (error, response, body) => { 20 | if (error) { 21 | reject(error); 22 | } else { 23 | // Include the body in the response object for the adapter to handle 24 | response.body = body; 25 | resolve(response); 26 | } 27 | }); 28 | }); 29 | }, 30 | 31 | responseAdapter(response) { 32 | return { 33 | json() { 34 | try { 35 | return Promise.resolve(JSON.parse(response.body)); 36 | } catch (error) { 37 | return Promise.reject( 38 | new Error(`Failed to parse JSON: ${error.message}`), 39 | ); 40 | } 41 | }, 42 | status: response.statusCode, 43 | headers: { 44 | get: (headerName) => response.headers[headerName.toLowerCase()], 45 | }, 46 | statusText: response.statusMessage, 47 | }; 48 | }, 49 | }; 50 | 51 | const setupClient = (config) => { 52 | return zd.createClient({ 53 | username: process.env.ZENDESK_USERNAME, 54 | subdomain: process.env.ZENDESK_SUBDOMAIN, 55 | token: process.env.ZENDESK_TOKEN, 56 | transportConfig: transportConfigUsingRequest, 57 | ...config, 58 | }); 59 | }; 60 | 61 | /** 62 | * 63 | */ 64 | async function foo() { 65 | try { 66 | const client = setupClient({debug: false}); 67 | const result = await client.users.list(); 68 | 69 | console.dir(result); 70 | } catch (error) { 71 | console.error(`Failed: ${error.message}`); 72 | } 73 | } 74 | 75 | foo(); 76 | -------------------------------------------------------------------------------- /examples/organization-fields-list.js: -------------------------------------------------------------------------------- 1 | const process = require('node:process'); 2 | const zd = require('../lib/client'); 3 | const exampleConfig = require('./exampleConfig'); 4 | 5 | const client = zd.createClient({ 6 | username: process.env.ZENDESK_TEST_USERNAME || exampleConfig.auth.username, 7 | token: process.env.ZENDESK_TEST_TOKEN || exampleConfig.auth.token, 8 | remoteUri: process.env.ZENDESK_TEST_REMOTEURI || exampleConfig.auth.remoteUri, 9 | }); 10 | 11 | client.organizationfields.list(function (error, statusList, body) { 12 | if (error) { 13 | console.log(error); 14 | return; 15 | } 16 | 17 | console.log(JSON.stringify(body, null, 2, true)); 18 | }); 19 | -------------------------------------------------------------------------------- /examples/organization-memberships-list.js: -------------------------------------------------------------------------------- 1 | const process = require('node:process'); 2 | const zd = require('../lib/client'); 3 | const exampleConfig = require('./exampleConfig'); 4 | 5 | const client = zd.createClient({ 6 | username: process.env.ZENDESK_TEST_USERNAME || exampleConfig.auth.username, 7 | token: process.env.ZENDESK_TEST_TOKEN || exampleConfig.auth.token, 8 | remoteUri: process.env.ZENDESK_TEST_REMOTEURI || exampleConfig.auth.remoteUri, 9 | }); 10 | 11 | client.organizationmemberships.list(function (error, request, result) { 12 | if (error) { 13 | console.log(error); 14 | return; 15 | } 16 | 17 | console.log(JSON.stringify(result)); // Gets the first page 18 | console.log('Total memberships: ' + result.length); 19 | }); 20 | -------------------------------------------------------------------------------- /examples/organization-upsert.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | const process = require('node:process'); 3 | const zd = require('../lib/client'); 4 | const exampleConfig = require('./exampleConfig'); 5 | 6 | const client = zd.createClient({ 7 | username: process.env.ZENDESK_TEST_USERNAME || exampleConfig.auth.username, 8 | token: process.env.ZENDESK_TEST_TOKEN || exampleConfig.auth.token, 9 | remoteUri: process.env.ZENDESK_TEST_REMOTEURI || exampleConfig.auth.remoteUri, 10 | }); 11 | 12 | const organization = { 13 | organization: { 14 | id: 35_436, 15 | name: 'My Organization', 16 | }, 17 | }; 18 | 19 | client.organizations.upsert(organization, function (error, request, result) { 20 | if (error) return handleError(error); 21 | console.log(JSON.stringify(result, null, 2, true)); 22 | }); 23 | 24 | /** 25 | * Handles errors by logging them and exiting the process. 26 | * @param {Error} error - The error object to be handled. 27 | */ 28 | function handleError(error) { 29 | console.log(error); 30 | process.exit(-1); 31 | } 32 | -------------------------------------------------------------------------------- /examples/organizations-delete-bulk.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | /* eslint-disable no-await-in-loop */ 3 | 4 | const process = require('node:process'); 5 | const dotenv = require('dotenv'); 6 | const zd = require('../src/index.js'); 7 | 8 | dotenv.config(); 9 | 10 | /** 11 | * Initializes and returns a Zendesk client. 12 | * @returns {object} Zendesk client instance. 13 | */ 14 | function initializeZendeskClient() { 15 | return zd.createClient({ 16 | username: process.env.ZENDESK_USERNAME, 17 | subdomain: process.env.ZENDESK_SUBDOMAIN, 18 | token: process.env.ZENDESK_TOKEN, 19 | debug: false, 20 | }); 21 | } 22 | 23 | /** 24 | * Filters and returns organization IDs that start with "test" or "Test". 25 | * @param {Array} organizations - List of organizations. 26 | * @returns {Array} List of organization IDs. 27 | */ 28 | function getTestOrganizationIds(organizations) { 29 | return organizations 30 | .filter((org) => org.name.startsWith('test') || org.name.startsWith('Test')) 31 | .map((org) => org.id); 32 | } 33 | 34 | /** 35 | * Splits an array into chunks of a specified size. 36 | * @param {Array} array - The array to split. 37 | * @param {number} chunkSize - The size of each chunk. 38 | * @returns {Array} An array of chunks. 39 | */ 40 | function chunkArray(array, chunkSize) { 41 | const chunks = []; 42 | for (let i = 0; i < array.length; i += chunkSize) { 43 | chunks.push(array.slice(i, i + chunkSize)); 44 | } 45 | 46 | return chunks; 47 | } 48 | 49 | /** 50 | * Monitors the completion of a job. 51 | * @param {object} client - The Zendesk client instance. 52 | * @param {string} jobID - The ID of the job to monitor. 53 | * @returns {Promise} Resolves when the job is complete. 54 | */ 55 | async function monitorJobCompletion(client, jobID) { 56 | try { 57 | await client.jobstatuses.watch(jobID, 1000, 30); 58 | } catch (error) { 59 | console.error('Error watching job status:', error); 60 | throw error; 61 | } 62 | } 63 | 64 | /** 65 | * Performs a bulk deletion of test organizations. 66 | * @returns {Promise} Resolves when all organizations are deleted. 67 | */ 68 | async function bulkDeleteTestOrganizations() { 69 | const client = initializeZendeskClient(); 70 | 71 | try { 72 | const organizations = await client.organizations.list(); 73 | const orgIdsToDelete = getTestOrganizationIds(organizations); 74 | const chunks = chunkArray(orgIdsToDelete, 30); 75 | 76 | for (const chunk of chunks) { 77 | const {result} = await client.organizations.bulkDelete(chunk); 78 | const {job_status} = result; 79 | 80 | if (job_status && job_status.id) { 81 | await monitorJobCompletion(client, job_status.id); 82 | } 83 | 84 | if (job_status && job_status.status) { 85 | console.log( 86 | `Successfully deleted chunk of ${chunk.length} organizations.`, 87 | ); 88 | } else { 89 | console.dir(job_status); 90 | } 91 | } 92 | 93 | console.log('All organizations deleted successfully.'); 94 | } catch (error) { 95 | if (error.message.includes('TooManyJobs')) { 96 | console.error( 97 | 'Too many jobs are currently queued or running. Try again later.', 98 | ); 99 | } else { 100 | console.error( 101 | `Failed to bulk delete test organizations: ${error.message}`, 102 | ); 103 | } 104 | } 105 | } 106 | 107 | bulkDeleteTestOrganizations(); 108 | -------------------------------------------------------------------------------- /examples/organizations-delete.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | const process = require('node:process'); 3 | const dotenv = require('dotenv'); 4 | const zd = require('../src/index.js'); 5 | 6 | dotenv.config(); 7 | 8 | const setupClient = (config) => { 9 | return zd.createClient({ 10 | username: process.env.ZENDESK_USERNAME, 11 | subdomain: process.env.ZENDESK_SUBDOMAIN, 12 | token: process.env.ZENDESK_TOKEN, 13 | ...config, 14 | }); 15 | }; 16 | 17 | // Placeholder organization ID for development/testing. 18 | // IMPORTANT: Replace with a valid organization ID before running in production. 19 | const organizationID = 1_234_567_890; 20 | 21 | /** 22 | * 23 | */ 24 | async function organizationsDelete() { 25 | try { 26 | const client = setupClient({debug: false}); 27 | const {result} = await client.organizations.delete(organizationID); 28 | if (result.message === 'No Content') { 29 | console.log('Organization deleted'); 30 | } else { 31 | console.dir(result); 32 | } 33 | } catch (error) { 34 | console.error(`Failed to delete organization: ${error.message}`); 35 | } 36 | } 37 | 38 | organizationsDelete(); 39 | -------------------------------------------------------------------------------- /examples/organizations-list.js: -------------------------------------------------------------------------------- 1 | const process = require('node:process'); 2 | const zd = require('../lib/client'); 3 | const exampleConfig = require('./exampleConfig'); 4 | 5 | const client = zd.createClient({ 6 | username: process.env.ZENDESK_TEST_USERNAME || exampleConfig.auth.username, 7 | token: process.env.ZENDESK_TEST_TOKEN || exampleConfig.auth.token, 8 | remoteUri: process.env.ZENDESK_TEST_REMOTEURI || exampleConfig.auth.remoteUri, 9 | }); 10 | 11 | client.organizations.list(function (error, request, result) { 12 | if (error) { 13 | console.log(error); 14 | return; 15 | } 16 | 17 | console.log( 18 | JSON.stringify( 19 | result.map(function (org) { 20 | return org.name; 21 | }), 22 | null, 23 | 2, 24 | true, 25 | ), 26 | ); // Gets the first page 27 | console.log('Total Orgs: ' + result.length); 28 | }); 29 | -------------------------------------------------------------------------------- /examples/search-query.js: -------------------------------------------------------------------------------- 1 | const process = require('node:process'); 2 | const zd = require('../lib/client'); 3 | const exampleConfig = require('./exampleConfig'); 4 | 5 | const client = zd.createClient({ 6 | username: process.env.ZENDESK_TEST_USERNAME || exampleConfig.auth.username, 7 | token: process.env.ZENDESK_TEST_TOKEN || exampleConfig.auth.token, 8 | remoteUri: process.env.ZENDESK_TEST_REMOTEURI || exampleConfig.auth.remoteUri, 9 | }); 10 | 11 | const query = 'status { 22 | try { 23 | const result = await client.tickets.create(ticket); 24 | console.log(JSON.stringify(result, null, 2, true)); 25 | } catch (error) { 26 | handleError(error); 27 | } 28 | })(); 29 | 30 | /** 31 | * Handles errors by logging them and exiting the process. 32 | * @param {Error} error - The error object to be handled. 33 | */ 34 | function handleError(error) { 35 | console.log(error); 36 | process.exit(-1); 37 | } 38 | -------------------------------------------------------------------------------- /examples/ticket-create.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | const process = require('node:process'); 3 | const zd = require('../lib/client'); 4 | const exampleConfig = require('./exampleConfig'); 5 | 6 | const client = zd.createClient({ 7 | username: process.env.ZENDESK_TEST_USERNAME || exampleConfig.auth.username, 8 | token: process.env.ZENDESK_TEST_TOKEN || exampleConfig.auth.token, 9 | remoteUri: process.env.ZENDESK_TEST_REMOTEURI || exampleConfig.auth.remoteUri, 10 | }); 11 | 12 | const ticket = { 13 | ticket: { 14 | subject: 'My printer is on fire!', 15 | comment: { 16 | body: 'The smoke is very colorful.', 17 | }, 18 | }, 19 | }; 20 | 21 | client.tickets.create(ticket, function (error, request, result) { 22 | if (error) return handleError(error); 23 | console.log(JSON.stringify(result, null, 2, true)); 24 | }); 25 | 26 | /** 27 | * Handles errors by logging them and exiting the process. 28 | * @param {Error} error - The error object to be handled. 29 | */ 30 | function handleError(error) { 31 | console.log(error); 32 | process.exit(-1); 33 | } 34 | -------------------------------------------------------------------------------- /examples/ticket-delete.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | const process = require('node:process'); 3 | const zd = require('../lib/client'); 4 | const exampleConfig = require('./exampleConfig'); 5 | 6 | const client = zd.createClient({ 7 | username: process.env.ZENDESK_TEST_USERNAME || exampleConfig.auth.username, 8 | token: process.env.ZENDESK_TEST_TOKEN || exampleConfig.auth.token, 9 | remoteUri: process.env.ZENDESK_TEST_REMOTEURI || exampleConfig.auth.remoteUri, 10 | }); 11 | 12 | const ticketId = 12_345; 13 | client.tickets.delete(ticketId, function (error) { 14 | if (error) return handleError(error); 15 | }); 16 | 17 | /** 18 | * Handles errors by logging them and exiting the process. 19 | * @param {Error} error - The error object to be handled. 20 | */ 21 | function handleError(error) { 22 | console.log(error); 23 | process.exit(-1); 24 | } 25 | -------------------------------------------------------------------------------- /examples/ticket-list-observer.js: -------------------------------------------------------------------------------- 1 | const process = require('node:process'); 2 | const zd = require('../lib/client'); 3 | const exampleConfig = require('./exampleConfig'); 4 | 5 | const client = zd.createClient({ 6 | username: process.env.ZENDESK_TEST_USERNAME || exampleConfig.auth.username, 7 | token: process.env.ZENDESK_TEST_TOKEN || exampleConfig.auth.token, 8 | remoteUri: process.env.ZENDESK_TEST_REMOTEURI || exampleConfig.auth.remoteUri, 9 | }); 10 | 11 | const observer = { 12 | error: console.error, 13 | // eslint-disable-next-line max-params 14 | next(status, body, response, result, nextPage) { 15 | console.log(JSON.stringify(body, null, 2, true)); 16 | console.log('Next page:', nextPage); 17 | }, 18 | complete(statusList, body /* , responseList, resultList */) { 19 | console.log('Pagination complete.'); 20 | console.log(body); // Will display all tickets 21 | }, 22 | }; 23 | 24 | client.tickets.list(observer); 25 | -------------------------------------------------------------------------------- /examples/ticket-list.js: -------------------------------------------------------------------------------- 1 | const process = require('node:process'); 2 | const zd = require('../lib/client'); 3 | const exampleConfig = require('./exampleConfig'); 4 | 5 | const client = zd.createClient({ 6 | username: process.env.ZENDESK_TEST_USERNAME || exampleConfig.auth.username, 7 | token: process.env.ZENDESK_TEST_TOKEN || exampleConfig.auth.token, 8 | remoteUri: process.env.ZENDESK_TEST_REMOTEURI || exampleConfig.auth.remoteUri, 9 | }); 10 | 11 | client.tickets.list( 12 | function (error, statusList, body /* , responseList, resultList */) { 13 | if (error) { 14 | console.log(error); 15 | return; 16 | } 17 | 18 | console.log(JSON.stringify(body, null, 2, true)); // Will display all tickets 19 | }, 20 | ); 21 | -------------------------------------------------------------------------------- /examples/ticketaudits-list.js: -------------------------------------------------------------------------------- 1 | const process = require('node:process'); 2 | const zd = require('../lib/client'); 3 | const exampleConfig = require('./exampleConfig'); 4 | 5 | const client = zd.createClient({ 6 | username: process.env.ZENDESK_TEST_USERNAME || exampleConfig.auth.username, 7 | token: process.env.ZENDESK_TEST_TOKEN || exampleConfig.auth.token, 8 | remoteUri: process.env.ZENDESK_TEST_REMOTEURI || exampleConfig.auth.remoteUri, 9 | }); 10 | 11 | /** 12 | * 13 | */ 14 | async function listTicketAudits() { 15 | try { 16 | const tickets = await client.tickets.list(); 17 | const ticket = tickets[0]; 18 | 19 | if (!ticket) { 20 | console.log('No tickets found.'); 21 | return; 22 | } 23 | 24 | const audits = await client.ticketaudits.list(ticket.id); 25 | console.log(JSON.stringify(audits)); 26 | } catch (error) { 27 | console.error('Error fetching ticket audits:', error); 28 | } 29 | } 30 | 31 | listTicketAudits(); 32 | -------------------------------------------------------------------------------- /examples/ticketmetric-list.js: -------------------------------------------------------------------------------- 1 | const process = require('node:process'); 2 | const zd = require('../lib/client'); 3 | const exampleConfig = require('./exampleConfig'); 4 | 5 | const client = zd.createClient({ 6 | username: process.env.ZENDESK_TEST_USERNAME || exampleConfig.auth.username, 7 | token: process.env.ZENDESK_TEST_TOKEN || exampleConfig.auth.token, 8 | remoteUri: process.env.ZENDESK_TEST_REMOTEURI || exampleConfig.auth.remoteUri, 9 | }); 10 | 11 | client.ticketmetrics.listAll( 12 | function (error, statusList, body /* , responseList, resultList */) { 13 | if (error) { 14 | console.log(error); 15 | return; 16 | } 17 | 18 | console.log(JSON.stringify(body)); 19 | }, 20 | ); 21 | -------------------------------------------------------------------------------- /examples/triggers-list.js: -------------------------------------------------------------------------------- 1 | const process = require('node:process'); 2 | const zd = require('../lib/client'); 3 | const exampleConfig = require('./exampleConfig'); 4 | 5 | const client = zd.createClient({ 6 | username: process.env.ZENDESK_TEST_USERNAME || exampleConfig.auth.username, 7 | token: process.env.ZENDESK_TEST_TOKEN || exampleConfig.auth.token, 8 | remoteUri: process.env.ZENDESK_TEST_REMOTEURI || exampleConfig.auth.remoteUri, 9 | }); 10 | 11 | client.triggers.list( 12 | function (error, statusList, body /* , responseList, resultList */) { 13 | if (error) { 14 | console.log(error); 15 | return; 16 | } 17 | 18 | console.log(JSON.stringify(body)); // Will display all triggers 19 | }, 20 | ); 21 | -------------------------------------------------------------------------------- /examples/upload-attachment.js: -------------------------------------------------------------------------------- 1 | const process = require('node:process'); 2 | const path = require('node:path'); 3 | const zd = require('../lib/client'); 4 | const exampleConfig = require('./exampleConfig'); 5 | 6 | const ATTACHMENT_PATH = path.resolve('./examples/busey.gif'); 7 | const FILENAME = 'busey.gif'; 8 | 9 | /** 10 | * Initializes and returns a Zendesk client. 11 | * @returns {object} Zendesk client instance. 12 | */ 13 | function getZendeskConfig() { 14 | return { 15 | username: process.env.ZENDESK_TEST_USERNAME || exampleConfig.auth.username, 16 | token: process.env.ZENDESK_TEST_TOKEN || exampleConfig.auth.token, 17 | remoteUri: 18 | process.env.ZENDESK_TEST_REMOTEURI || exampleConfig.auth.remoteUri, 19 | }; 20 | } 21 | 22 | const client = zd.createClient(getZendeskConfig()); 23 | 24 | /** 25 | * Uploads an attachment to Zendesk. 26 | * @param {string} filePath - The path to the file to be uploaded. 27 | * @param {string} fileName - The name of the file to be uploaded. 28 | */ 29 | async function uploadAttachment(filePath, fileName) { 30 | try { 31 | const result = await client.attachments.upload(filePath, { 32 | filename: fileName, 33 | }); 34 | console.log(JSON.stringify(result, null, 2)); 35 | } catch (error) { 36 | console.error(`Failed to upload attachment: ${error.message}`); 37 | } 38 | } 39 | 40 | uploadAttachment(ATTACHMENT_PATH, FILENAME); 41 | -------------------------------------------------------------------------------- /examples/user-create-many.js: -------------------------------------------------------------------------------- 1 | const process = require('node:process'); 2 | const zd = require('../lib/client'); 3 | const exampleConfig = require('./exampleConfig'); 4 | 5 | const client = zd.createClient({ 6 | username: process.env.ZENDESK_TEST_USERNAME || exampleConfig.auth.username, 7 | token: process.env.ZENDESK_TEST_TOKEN || exampleConfig.auth.token, 8 | remoteUri: process.env.ZENDESK_TEST_REMOTEURI || exampleConfig.auth.remoteUri, 9 | }); 10 | 11 | const users = { 12 | users: [ 13 | { 14 | name: 'Roger Wilco', 15 | email: 'roge@example.org', 16 | role: 'agent', 17 | }, 18 | { 19 | name: 'Woger Rilco', 20 | email: 'woge@example.org', 21 | role: 'admin', 22 | }, 23 | ], 24 | }; 25 | 26 | client.users.createMany(users, function (error, request, result) { 27 | if (error) { 28 | console.log(error); 29 | return; 30 | } 31 | 32 | client.jobstatuses.watch( 33 | result.job_status.id, 34 | 500, 35 | 5, 36 | function (error_, request, result) { 37 | console.log(JSON.stringify(result, null, 2, true)); 38 | }, 39 | ); 40 | }); 41 | -------------------------------------------------------------------------------- /examples/user-create-promise.js: -------------------------------------------------------------------------------- 1 | const process = require('node:process'); 2 | const zd = require('../lib/client'); 3 | const exampleConfig = require('./exampleConfig'); 4 | 5 | const client = zd.createClient({ 6 | username: process.env.ZENDESK_TEST_USERNAME || exampleConfig.auth.username, 7 | token: process.env.ZENDESK_TEST_TOKEN || exampleConfig.auth.token, 8 | remoteUri: process.env.ZENDESK_TEST_REMOTEURI || exampleConfig.auth.remoteUri, 9 | }); 10 | 11 | const user = { 12 | user: { 13 | name: 'Foo Bar', 14 | email: 'FooBar@example.org', 15 | }, 16 | }; 17 | 18 | (async () => { 19 | try { 20 | const result = await client.users.create(user); 21 | console.log(JSON.stringify(result, null, 2, true)); 22 | } catch (error) { 23 | console.log(error); 24 | } 25 | })(); 26 | -------------------------------------------------------------------------------- /examples/user-create.js: -------------------------------------------------------------------------------- 1 | const process = require('node:process'); 2 | const zd = require('../lib/client'); 3 | const exampleConfig = require('./exampleConfig'); 4 | 5 | const client = zd.createClient({ 6 | username: process.env.ZENDESK_TEST_USERNAME || exampleConfig.auth.username, 7 | token: process.env.ZENDESK_TEST_TOKEN || exampleConfig.auth.token, 8 | remoteUri: process.env.ZENDESK_TEST_REMOTEURI || exampleConfig.auth.remoteUri, 9 | }); 10 | 11 | const user = { 12 | user: { 13 | name: 'Foo Bar', 14 | email: 'FooBar@example.org', 15 | }, 16 | }; 17 | 18 | client.users.create(user, function (error, request, result) { 19 | if (error) { 20 | console.log(error); 21 | return; 22 | } 23 | 24 | console.log(JSON.stringify(result, null, 2, true)); 25 | }); 26 | -------------------------------------------------------------------------------- /examples/user-fields-list.js: -------------------------------------------------------------------------------- 1 | const process = require('node:process'); 2 | const zd = require('../lib/client'); 3 | const exampleConfig = require('./exampleConfig'); 4 | 5 | const client = zd.createClient({ 6 | username: process.env.ZENDESK_TEST_USERNAME || exampleConfig.auth.username, 7 | token: process.env.ZENDESK_TEST_TOKEN || exampleConfig.auth.token, 8 | remoteUri: process.env.ZENDESK_TEST_REMOTEURI || exampleConfig.auth.remoteUri, 9 | }); 10 | 11 | client.userfields.list(function (error, request, result) { 12 | if (error) { 13 | console.log(error); 14 | return; 15 | } 16 | 17 | console.log( 18 | JSON.stringify( 19 | result.map(function (userField) { 20 | return userField.key; 21 | }), 22 | null, 23 | 2, 24 | true, 25 | ), 26 | ); // Gets the first page 27 | console.log('Total User Fields: ' + result.length); 28 | }); 29 | -------------------------------------------------------------------------------- /examples/users-list.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | const process = require('node:process'); 3 | const dotenv = require('dotenv'); 4 | const zd = require('../src/index.js'); 5 | 6 | dotenv.config(); 7 | 8 | const setupClient = (config) => { 9 | return zd.createClient({ 10 | username: process.env.ZENDESK_USERNAME, 11 | subdomain: process.env.ZENDESK_SUBDOMAIN, 12 | token: process.env.ZENDESK_TOKEN, 13 | ...config, 14 | }); 15 | }; 16 | 17 | /** 18 | * 19 | */ 20 | async function usersList() { 21 | try { 22 | const client = setupClient({debug: false}); 23 | const result = await client.users.list(); 24 | console.log( 25 | JSON.stringify( 26 | result.map(function (user) { 27 | return user.name; 28 | }), 29 | null, 30 | 2, 31 | true, 32 | ), 33 | ); // Gets the first page 34 | console.log('Total Users: ' + result.length); 35 | } catch (error) { 36 | console.error(`Failed to get list of users: ${error.message}`); 37 | } 38 | } 39 | 40 | usersList(); 41 | -------------------------------------------------------------------------------- /examples/users-listbygroup.js: -------------------------------------------------------------------------------- 1 | const process = require('node:process'); 2 | const zd = require('../lib/client'); 3 | const exampleConfig = require('./exampleConfig'); 4 | 5 | const client = zd.createClient({ 6 | username: process.env.ZENDESK_TEST_USERNAME || exampleConfig.auth.username, 7 | token: process.env.ZENDESK_TEST_TOKEN || exampleConfig.auth.token, 8 | remoteUri: process.env.ZENDESK_TEST_REMOTEURI || exampleConfig.auth.remoteUri, 9 | }); 10 | 11 | /** 12 | * 13 | */ 14 | async function listUsersByFirstGroup() { 15 | try { 16 | const groups = await client.groups.list(); 17 | const firstGroup = groups[0]; 18 | 19 | if (!firstGroup) { 20 | console.log('No groups found.'); 21 | return; 22 | } 23 | 24 | const users = await client.users.listByGroup(firstGroup.id); 25 | console.log(users); 26 | } catch (error) { 27 | console.error(error); 28 | } 29 | } 30 | 31 | listUsersByFirstGroup(); 32 | -------------------------------------------------------------------------------- /examples/usertags-list.js: -------------------------------------------------------------------------------- 1 | const process = require('node:process'); 2 | const zd = require('../lib/client'); 3 | const exampleConfig = require('./exampleConfig'); 4 | 5 | const client = zd.createClient({ 6 | username: process.env.ZENDESK_TEST_USERNAME || exampleConfig.auth.username, 7 | token: process.env.ZENDESK_TEST_TOKEN || exampleConfig.auth.token, 8 | remoteUri: process.env.ZENDESK_TEST_REMOTEURI || exampleConfig.auth.remoteUri, 9 | }); 10 | 11 | /** 12 | * 13 | */ 14 | async function listTagsForFirstUser() { 15 | try { 16 | const users = await client.users.list(); 17 | const firstUser = users[0]; 18 | 19 | if (!firstUser) { 20 | console.log('No users found.'); 21 | return; 22 | } 23 | 24 | const tags = await client.users.listTags(firstUser.id); 25 | console.log(tags); 26 | } catch (error) { 27 | console.error(error); 28 | } 29 | } 30 | 31 | listTagsForFirstUser(); 32 | -------------------------------------------------------------------------------- /examples/views-list.js: -------------------------------------------------------------------------------- 1 | const process = require('node:process'); 2 | const zd = require('../lib/client'); 3 | const exampleConfig = require('./exampleConfig'); 4 | 5 | const client = zd.createClient({ 6 | username: process.env.ZENDESK_TEST_USERNAME || exampleConfig.auth.username, 7 | token: process.env.ZENDESK_TEST_TOKEN || exampleConfig.auth.token, 8 | remoteUri: process.env.ZENDESK_TEST_REMOTEURI || exampleConfig.auth.remoteUri, 9 | }); 10 | 11 | client.views.list(function (error, request, result) { 12 | if (error) { 13 | console.log(error); 14 | return; 15 | } 16 | 17 | console.log(JSON.stringify(result)); 18 | console.log('Total Users: ' + result.length); 19 | }); 20 | -------------------------------------------------------------------------------- /src/clients/authorization-handler.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Handles the creation of authorization headers based on the provided configuration. 3 | * Supports both OAuth and Basic Authentication methods. 4 | */ 5 | class AuthorizationHandler { 6 | /** 7 | * Creates a new instance of the AuthorizationHandler. 8 | * @param {Map} options - A Map object containing the necessary configuration options. 9 | */ 10 | constructor(options) { 11 | this.options = options; 12 | } 13 | 14 | /** 15 | * Determines the authentication method and creates the appropriate authorization header. 16 | * @returns {string} The resulting authorization header string. 17 | */ 18 | createAuthorizationHeader() { 19 | if (this.isOAuth()) { 20 | return this.createOAuthHeader(); 21 | } 22 | 23 | return this.createBasicAuthHeader(); 24 | } 25 | 26 | /** 27 | * Checks if OAuth should be used for authentication. 28 | * @returns {boolean} True if OAuth is the chosen method; false otherwise. 29 | */ 30 | isOAuth() { 31 | return ( 32 | this.options.get('useOAuth') === true || 33 | this.options.get('oauth') === true 34 | ); 35 | } 36 | 37 | /** 38 | * Creates the OAuth authorization header. 39 | * @returns {string} The OAuth authorization header. 40 | * @throws {Error} When the token is missing in the options. 41 | */ 42 | createOAuthHeader() { 43 | const token = this.options.get('token'); 44 | 45 | if (!token) { 46 | throw new Error('OAuth is enabled, but token is missing.'); 47 | } 48 | 49 | return `Bearer ${token}`; 50 | } 51 | 52 | /** 53 | * Creates the Basic Authentication authorization header. 54 | * @returns {string} The Basic Authentication header. 55 | * @throws {Error} When username or password/token is missing in the options. 56 | */ 57 | createBasicAuthHeader() { 58 | const username = this.options.get('username'); 59 | const passwordOrToken = this.getPasswordOrToken(); 60 | 61 | if (!username || !passwordOrToken) { 62 | throw new Error('Missing credentials for Basic Authentication.'); 63 | } 64 | 65 | const encoded = this.encodeCredentials(`${username}${passwordOrToken}`); 66 | return `Basic ${encoded}`; 67 | } 68 | 69 | /** 70 | * Retrieves the password or token for Basic Authentication. 71 | * The method first checks for a password and if none is found, it fetches the token. 72 | * @returns {string} The password or token prefixed with the appropriate separator. 73 | */ 74 | getPasswordOrToken() { 75 | const password = this.options.get('password'); 76 | if (password) { 77 | return `:${password}`; 78 | } 79 | 80 | return `/token:${this.options.get('token')}`; 81 | } 82 | 83 | /** 84 | * Encodes the provided credentials using base64 encoding. 85 | * @param {string} credentials - The credentials to be encoded. 86 | * @returns {string} The base64 encoded string of the provided credentials. 87 | */ 88 | encodeCredentials(credentials) { 89 | return require('node:buffer').Buffer.from(credentials).toString('base64'); 90 | } 91 | } 92 | 93 | exports.AuthorizationHandler = AuthorizationHandler; 94 | -------------------------------------------------------------------------------- /src/clients/core/accountsettings.js: -------------------------------------------------------------------------------- 1 | // AccountSettings.js: Client for the zendesk API. 2 | 3 | const {Client} = require('../client'); 4 | 5 | /** 6 | * The AccountSettings class provides methods for interacting with account settings in the Zendesk JSON API. 7 | * {@link https://developer.zendesk.com/api-reference/ticketing/account-configuration/account_settings/ | See the Zendesk API documentation for more details}. 8 | */ 9 | class AccountSettings extends Client { 10 | constructor(options) { 11 | super(options); 12 | this.jsonAPINames = ['settings']; 13 | } 14 | 15 | /** 16 | * Retrieves the account settings. 17 | * @returns {Promise<{response: object, result: object}>} A promise that resolves to the account settings. 18 | * {@link https://developer.zendesk.com/api-reference/ticketing/account-configuration/account_settings/#show-settings | See the Zendesk API documentation for more details}. 19 | * @example 20 | * const settings = await client.accountsettings.show(); 21 | */ 22 | async show() { 23 | return this.get(['account', 'settings']); 24 | } 25 | 26 | /** 27 | * Updates the account settings. 28 | * @param {object} settings - The settings to update. 29 | * @returns {Promise<{response: object, result: object}>} A promise that resolves to the updated account settings. 30 | * {@link https://developer.zendesk.com/api-reference/ticketing/account-configuration/account_settings/#update-account-settings | See the Zendesk API documentation for more details}. 31 | * @example 32 | * const settings = await client.accountsettings.update({ "settings": { "active_features": { "customer_satisfaction": false }}}); 33 | */ 34 | async update(settings) { 35 | return this.put(['account', 'settings'], settings); 36 | } 37 | } 38 | 39 | exports.AccountSettings = AccountSettings; 40 | -------------------------------------------------------------------------------- /src/clients/core/activitystream.js: -------------------------------------------------------------------------------- 1 | // File: activitystream.js 2 | 3 | const {Client} = require('../client'); 4 | 5 | /** 6 | * `ActivityStream` provides methods to interact with Zendesk ticket activities. 7 | * This class extends the base Client class and is tailored to fetch activity data. 8 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/tickets/activity_stream/ | Zendesk Activity Stream API} 9 | * @example 10 | * const client = new Client({ /* ...options... * / }); 11 | * const activities = await client.activitystream.list(); 12 | */ 13 | class ActivityStream extends Client { 14 | /** 15 | * Creates an instance of the ActivityStream client. 16 | * @param {object} options - Configuration options for the client. 17 | */ 18 | constructor(options) { 19 | super(options); 20 | this.jsonAPINames = ['activities', 'activity']; 21 | } 22 | 23 | /** 24 | * Lists all ticket activities from the Zendesk API. 25 | * @returns {Array} An array of activity objects. 26 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/tickets/activity_stream/#list-activities | Zendesk API - List Activities} 27 | * @example 28 | * const activities = await client.activitystream.list(); 29 | */ 30 | async list() { 31 | return this.getAll('GET', ['activities']); 32 | } 33 | 34 | /** 35 | * Retrieves a specific ticket activity by its ID. 36 | * @param {number} activityID - The unique ID of the activity to fetch. 37 | * @returns {Promise<{response: object, result: object}>} A promise that resolves to the activity object corresponding to the provided activityID. 38 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/tickets/activity_stream/#show-activity | Zendesk API - Show Activity} 39 | * @example 40 | * const activity = await client.activitystream.show(12345); // Where 12345 is an activity ID. 41 | */ 42 | async show(activityID) { 43 | return this.get(['activities', activityID]); 44 | } 45 | 46 | /** 47 | * Returns an approximate count of ticket activities in the last 30 days affecting the agent making the request. 48 | * If the count exceeds 100,000, the count will return a cached result which updates every 24 hours. 49 | * 50 | * The count[refreshed_at] property is a timestamp that indicates when the count was last updated. 51 | * Note: When the count exceeds 100,000, count[refreshed_at] may occasionally be null. This indicates 52 | * that the count is being updated in the background, and count[value] is limited to 100,000 until the update is complete. 53 | * @returns {Promise<{response: object, result: object}>} A promise that resolves to an object containing the activity count and the refreshed_at timestamp. 54 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/tickets/activity_stream/#count-activities | Zendesk API - Count Activities} 55 | * @example 56 | * const activityCount = await client.activitystream.count(); 57 | * console.log(activityCount); // { count: { refreshed_at: "2020-04-06T02:18:17Z", value: 102 } } 58 | */ 59 | async count() { 60 | return this.get(['activities', 'count']); 61 | } 62 | } 63 | 64 | exports.ActivityStream = ActivityStream; 65 | -------------------------------------------------------------------------------- /src/clients/core/brand.js: -------------------------------------------------------------------------------- 1 | // File: brands.js 2 | const {Client} = require('../client'); 3 | /** 4 | * Class representing the Brand API endpoints. 5 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/account-configuration/brands/} 6 | */ 7 | class Brand extends Client { 8 | constructor(options) { 9 | super(options); 10 | this.jsonAPINames = ['brands']; 11 | } 12 | 13 | /** 14 | * List all brands. 15 | * @returns {Promise<{response: object, result: Array}>} The list of brands. 16 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/account-configuration/brands/#list-brands} 17 | * @example const brands = await client.brands.list(); 18 | */ 19 | async list() { 20 | return this.get(['brands']); 21 | } 22 | 23 | /** 24 | * Show a specific brand by ID. 25 | * @param {number} brandId - The ID of the brand. 26 | * @returns {Promise<{response: object, result: object}>} The brand details. 27 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/account-configuration/brands/#show-a-brand} 28 | * @example const brand = await client.brands.show(47); 29 | */ 30 | async show(brandId) { 31 | return this.get(['brands', brandId]); 32 | } 33 | 34 | /** 35 | * Create a new brand. 36 | * @param {object} brand - The brand data. 37 | * @returns {Promise<{response: object, result: object}>} The created brand details. 38 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/account-configuration/brands/#create-brand} 39 | * @example const newBrand = await client.brands.create({name: "Brand 1", subdomain: "Brand1"}); 40 | */ 41 | async create(brand) { 42 | return this.post(['brands'], brand); 43 | } 44 | 45 | /** 46 | * Update an existing brand. 47 | * @param {object} brand - The updated brand data. 48 | * @param {number} brandId - The ID of the brand to update. 49 | * @returns {Promise<{response: object, result: object}>} The updated brand details. 50 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/account-configuration/brands/#update-a-brand} 51 | * @example const updatedBrand = await client.brands.update({name: "Updated Brand"}, 47); 52 | */ 53 | async update(brand, brandId) { 54 | return this.put(['brands', brandId], brand); 55 | } 56 | 57 | /** 58 | * Delete a brand. 59 | * @param {number} brandId - The ID of the brand to delete. 60 | * @returns {Promise} The deletion status. 61 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/account-configuration/brands/#delete-a-brand} 62 | * @example await client.brands.delete(47); 63 | */ 64 | async delete(brandId) { 65 | return super.delete(['brands', brandId]); 66 | } 67 | 68 | /** 69 | * Check host mapping validity for a given subdomain and host mapping. 70 | * @param {string} hostMapping - The host mapping to check. 71 | * @param {string} subdomain - The subdomain to check. 72 | * @returns {Promise<{response: object, result: object}>} The check result. 73 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/account-configuration/brands/#check-host-mapping-validity} 74 | * @example await client.brands.checkHostMapping("brand1.com", "brand1"); 75 | */ 76 | async checkHostMapping(hostMapping, subdomain) { 77 | return this.get([ 78 | 'brands', 79 | 'check_host_mapping', 80 | {host_mapping: hostMapping, subdomain}, 81 | ]); 82 | } 83 | 84 | /** 85 | * Check host mapping validity for an existing brand. 86 | * @param {number} brandId - The ID of the brand to check. 87 | * @returns {Promise<{response: object, result: object}>} The check result. 88 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/account-configuration/brands/#check-host-mapping-validity-for-an-existing-brand} 89 | * @example await client.brands.checkHostMappingForExistingBrand(47); 90 | */ 91 | async checkHostMappingForExistingBrand(brandId) { 92 | return this.get(['brands', brandId, 'check_host_mapping']); 93 | } 94 | } 95 | 96 | exports.Brand = Brand; 97 | -------------------------------------------------------------------------------- /src/clients/core/customagentroles.js: -------------------------------------------------------------------------------- 1 | // File: customAgentRoles.js 2 | const {Client} = require('../client'); 3 | 4 | /** 5 | * Client for Zendesk's Custom Agent Roles API. 6 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/account-configuration/custom_roles/} 7 | */ 8 | class CustomAgentRoles extends Client { 9 | constructor(options) { 10 | super(options); 11 | this.jsonAPINames = ['custom_roles']; 12 | } 13 | 14 | /** 15 | * List all Custom Agent Roles. 16 | * @returns {Promise} Returns a promise that resolves with the list of custom agent roles. 17 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/account-configuration/custom_roles/#list-custom-roles} 18 | * @example 19 | * const client = createClient({...}); 20 | * const roles = await client.customagentroles.list(); 21 | */ 22 | list() { 23 | return this.getAll(['custom_roles']); 24 | } 25 | 26 | /** 27 | * Retrieve a specific Custom Agent Role by its ID. 28 | * @param {number} roleId The ID of the custom agent role to retrieve. 29 | * @returns {Promise<{response: object, result: object}>} Returns a promise that resolves with the specified custom agent role. 30 | * @throws Will throw an error if unable to retrieve the role. 31 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/account-configuration/custom_roles/#show-custom-role} 32 | * @example 33 | * const client = createClient({...}); 34 | * const role = await client.customagentroles.show(12345); 35 | */ 36 | show(roleId) { 37 | return this.get(['custom_roles', roleId]); 38 | } 39 | 40 | /** 41 | * Creates a new custom agent role. 42 | * @param {object} roleData - The data for the new custom agent role. 43 | * @returns {Promise<{response: object, result: object}>} The created custom agent role. 44 | * @throws Will throw an error if creation fails. 45 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/account-configuration/custom_roles/#create-custom-role} 46 | * @example 47 | * const newRole = { 48 | * name: "Sample Role", 49 | * description: "Description here", 50 | * configuration: { chat_access: true } 51 | * }; 52 | * const role = await client.customagentroles.create(newRole); 53 | */ 54 | create(roleData) { 55 | return this.post(['custom_roles'], {custom_role: roleData}); 56 | } 57 | 58 | /** 59 | * Updates an existing custom agent role. 60 | * @param {number} customRoleId - The ID of the custom agent role to update. 61 | * @param {object} updatedData - The updated data for the custom agent role. 62 | * @returns {Promise<{response: object, result: object}>} The updated custom agent role. 63 | * @throws Will throw an error if the update fails or custom agent role ID is not found. 64 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/account-configuration/custom_roles/#update-custom-role} 65 | * @example 66 | * const updatedData = { name: "Updated Role", description: "Updated Description" }; 67 | * const updatedRole = await client.customagentroles.update(12345, updatedData); 68 | */ 69 | update(customRoleId, updatedData) { 70 | return this.put(['custom_roles', customRoleId], {custom_role: updatedData}); 71 | } 72 | 73 | /** 74 | * Delete a specific Custom Agent Role by its ID. 75 | * @param {number} roleId The ID of the custom agent role to delete. 76 | * @returns {Promise} Returns a promise that resolves when the role is deleted. 77 | * @throws Will throw an error if unable to delete the role. 78 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/account-configuration/custom_roles/#delete-custom-role} 79 | * @example 80 | * const client = createClient({...}); 81 | * await client.customagentroles.delete(12345); 82 | */ 83 | delete(roleId) { 84 | return super.delete(['custom_roles', roleId]); 85 | } 86 | } 87 | 88 | exports.CustomAgentRoles = CustomAgentRoles; 89 | -------------------------------------------------------------------------------- /src/clients/core/imports.js: -------------------------------------------------------------------------------- 1 | // File: imports.js 2 | const {Client} = require('../client'); 3 | 4 | /** 5 | * Client for the Zendesk Ticket Import API. 6 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/tickets/ticket_import/} 7 | */ 8 | class Imports extends Client { 9 | constructor(options) { 10 | super(options); 11 | this.jsonAPINames = ['tickets', 'ticket']; 12 | } 13 | 14 | /** 15 | * Imports a single ticket to Zendesk. 16 | * @param {object} ticket - The ticket data to be imported. 17 | * @returns {Promise<{response: object, result: object}>} The response from the Zendesk API. 18 | * @throws {Error} Throws an error if the request fails. 19 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/tickets/ticket_import/#ticket-import} 20 | * @example 21 | * const ticketData = { 22 | * ticket: { 23 | * assignee_id: 19, 24 | * comments: [{ 25 | * author_id: 827, 26 | * created_at: "2009-06-25T10:15:18Z", 27 | * value: "This is a comment" 28 | * }], 29 | * description: "A description", 30 | * requester_id: 827, 31 | * subject: "Help" 32 | * } 33 | * }; 34 | * const response = await client.imports.ticket(ticketData); 35 | */ 36 | async ticket(ticket) { 37 | return this.post(['imports', 'tickets'], ticket); 38 | } 39 | 40 | /** 41 | * Imports multiple tickets to Zendesk in bulk. 42 | * @param {object[]} tickets - An array of ticket data to be imported. 43 | * @returns {Promise} The response from the Zendesk API. 44 | * @throws {Error} Throws an error if the request fails. 45 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/tickets/ticket_import/#ticket-bulk-import} 46 | * @example 47 | * const ticketsData = [{ 48 | * assignee_id: 19, 49 | * comments: [{ 50 | * author_id: 827, 51 | * created_at: "2009-06-25T10:15:18Z", 52 | * value: "This is a comment" 53 | * }], 54 | * description: "A description", 55 | * requester_id: 827, 56 | * subject: "Help" 57 | * }]; 58 | * const response = await client.imports.ticketMany(ticketsData); 59 | */ 60 | async ticketMany(tickets) { 61 | return this.requestAll( 62 | 'POST', 63 | ['imports', 'tickets', 'create_many'], 64 | tickets, 65 | ); 66 | } 67 | } 68 | 69 | exports.Imports = Imports; 70 | -------------------------------------------------------------------------------- /src/clients/core/oauthclients.js: -------------------------------------------------------------------------------- 1 | // File: oauthclients.js 2 | const {Client} = require('../client'); 3 | 4 | /** 5 | * Represents a client for Zendesk OAuth Clients API. 6 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/oauth/oauth_clients/} 7 | */ 8 | class OAuthClients extends Client { 9 | constructor(options) { 10 | super(options); 11 | this.jsonAPINames = ['oauthclients', 'oauthclient', 'clients']; 12 | } 13 | 14 | /** 15 | * Lists all OAuth clients. 16 | * @returns {Promise} A list of OAuth clients. 17 | * @throws {Error} Throws an error if the request fails. 18 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/oauth/oauth_clients/#list-clients} 19 | * @example const clientsList = await client.oauthclients.list(); 20 | */ 21 | async list() { 22 | return this.getAll(['oauth', 'clients']); 23 | } 24 | 25 | /** 26 | * Retrieves a specific OAuth client by ID. 27 | * @param {number} id - The ID of the OAuth client. 28 | * @returns {Promise<{response: object, result: object}>} The OAuth client details. 29 | * @throws {Error} Throws an error if the request fails. 30 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/oauth/oauth_clients/#show-client} 31 | * @example const clientDetails = await client.oauthclients.show(1234); 32 | */ 33 | async show(id) { 34 | return this.get(['oauth', 'clients', id]); 35 | } 36 | 37 | /** 38 | * Creates a new OAuth client with the provided details. 39 | * @param {object} client - The details of the client to be created. 40 | * @returns {Promise<{response: object, result: object}>} The details of the created OAuth client. 41 | * @throws {Error} Throws an error if the request fails. 42 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/oauth/oauth_clients/#create-client} 43 | * @example 44 | * const newClient = { 45 | * name: "Test Client", 46 | * identifier: "unique_id" 47 | * }; 48 | * const createdClient = await client.oauthclients.create(newClient); 49 | */ 50 | async create(client) { 51 | return this.post(['oauth', 'clients'], {client}); 52 | } 53 | 54 | /** 55 | * Updates a specific OAuth client by ID. 56 | * @param {number} id - The ID of the OAuth client. 57 | * @param {object} client - The new details of the client. 58 | * @returns {Promise<{response: object, result: object}>} The updated OAuth client details. 59 | * @throws {Error} Throws an error if the request fails. 60 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/oauth/oauth_clients/#update-client} 61 | * @example 62 | * const updatedClient = { 63 | * name: "My New OAuth2 Client" 64 | * }; 65 | * const updatedDetails = await client.oauthclients.update(1234, updatedClient); 66 | */ 67 | async update(id, client) { 68 | return this.put(['oauth', 'clients', id], {client}); 69 | } 70 | 71 | /** 72 | * Deletes a specific OAuth client by ID. 73 | * @param {number} id - The ID of the OAuth client. 74 | * @returns {Promise} 75 | * @throws {Error} Throws an error if the request fails. 76 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/oauth/oauth_clients/#delete-client} 77 | * @example await client.oauthclients.delete(1234); 78 | */ 79 | async delete(id) { 80 | return super.delete(['oauth', 'clients', id]); 81 | } 82 | 83 | /** 84 | * Generates a new client secret for a specific OAuth client by ID. 85 | * @param {number} id - The ID of the OAuth client. 86 | * @returns {Promise<{response: object, result: object}>} The new client secret. 87 | * @throws {Error} Throws an error if the request fails. 88 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/oauth/oauth_clients/#generate-secret} 89 | * @example const newSecret = await client.oauthclients.generateSecret(1234); 90 | */ 91 | async generateSecret(id) { 92 | return this.put(['oauth', 'clients', id, 'generate_secret']); 93 | } 94 | } 95 | 96 | exports.OAuthClients = OAuthClients; 97 | -------------------------------------------------------------------------------- /src/clients/core/oauthtokens.js: -------------------------------------------------------------------------------- 1 | // File: oauthtokens.js 2 | const {Client} = require('../client'); 3 | 4 | /** 5 | * Represents a client for Zendesk OAuth Tokens API. 6 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/oauth/oauth_tokens/} 7 | */ 8 | class OAuthTokens extends Client { 9 | constructor(options) { 10 | super(options); 11 | this.jsonAPINames = ['oauthtokens', 'oauthtoken', 'token']; 12 | } 13 | 14 | /** 15 | * Retrieves a specific OAuth token by ID. 16 | * @param {number|string} id - The ID of the OAuth token or "current" for the currently authenticated token. 17 | * @returns {Promise<{response: object, result: object}>} The OAuth token details. 18 | * @throws {Error} Throws an error if the request fails. 19 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/oauth/oauth_tokens/#show-token} 20 | * @example const tokenDetails = await client.oauthtokens.show(1234); 21 | */ 22 | async show(id) { 23 | return this.get(['oauth', 'tokens', id]); 24 | } 25 | 26 | /** 27 | * Retrieves the details of the currently authenticated OAuth token. 28 | * @returns {Promise<{response: object, result: object}>} The details of the currently authenticated OAuth token. 29 | * @throws {Error} Throws an error if the request fails. 30 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/oauth/oauth_tokens/#show-token} 31 | * @example const currentTokenDetails = await client.oauthtokens.current(); 32 | */ 33 | async current() { 34 | return this.show('current'); 35 | } 36 | 37 | /** 38 | * Lists all available OAuth tokens. 39 | * @returns {Promise} A list of OAuth tokens. 40 | * @throws {Error} Throws an error if the request fails. 41 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/oauth/oauth_tokens/#list-tokens} 42 | * @example const tokensList = await client.oauthtokens.list(); 43 | */ 44 | async list() { 45 | return this.getAll(['oauth', 'tokens']); 46 | } 47 | 48 | /** 49 | * Revokes a specific OAuth token by ID. 50 | * @param {number} id - The ID of the OAuth token. 51 | * @returns {Promise} 52 | * @throws {Error} Throws an error if the request fails. 53 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/oauth/oauth_tokens/#revoke-token} 54 | * @example await client.oauthtokens.revoke(1234); 55 | */ 56 | async revoke(id) { 57 | return super.delete(['oauth', 'tokens', id]); 58 | } 59 | 60 | /** 61 | * Creates a new OAuth token with the provided details. 62 | * @param {object} token - The details of the token to be created. Must include client_id and scopes. 63 | * @returns {Promise<{response: object, result: object}>} The details of the created OAuth token. 64 | * @throws {Error} Throws an error if the request fails. 65 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/oauth/oauth_tokens/#create-token} 66 | * @example const createdToken = await client.oauthtokens.create({client_id: 1234, scopes: ["read", "write"]}); 67 | */ 68 | async create(token) { 69 | return this.post(['oauth', 'tokens'], token); 70 | } 71 | } 72 | 73 | exports.OAuthTokens = OAuthTokens; 74 | -------------------------------------------------------------------------------- /src/clients/core/satisfactionratings.js: -------------------------------------------------------------------------------- 1 | const {Client} = require('../client'); 2 | 3 | /** 4 | * Client for the Satisfaction Ratings section of the Zendesk API. 5 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/ticket-management/satisfaction_ratings/} 6 | */ 7 | class SatisfactionRatings extends Client { 8 | /** 9 | * Creates a new SatisfactionRatings instance. 10 | * @param {object} options - Options for initializing the client. 11 | */ 12 | constructor(options) { 13 | super(options); 14 | this.jsonAPINames = ['satisfaction_ratings']; 15 | } 16 | 17 | /** 18 | * Lists all satisfaction ratings. 19 | * @returns {Array} A list of satisfaction ratings. 20 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/ticket-management/satisfaction_ratings/#list-satisfaction-ratings} 21 | * @example const ratings = await client.satisfactionratings.list(); 22 | */ 23 | async list() { 24 | return this.getAll(['satisfaction_ratings']); 25 | } 26 | 27 | /** 28 | * Lists all received satisfaction ratings. 29 | * @returns {Array} A list of received satisfaction ratings. 30 | * @example const ratingsReceived = await client.satisfactionratings.received(); 31 | */ 32 | async received() { 33 | return this.getAll(['satisfaction_ratings', 'received']); 34 | } 35 | 36 | /** 37 | * Retrieves details of a specific satisfaction rating. 38 | * @param {number} satisfactionRatingID - The ID of the satisfaction rating to retrieve. 39 | * @returns {Promise<{response: object, result: object}>} Details of the satisfaction rating. 40 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/ticket-management/satisfaction_ratings/#show-satisfaction-rating} 41 | * @example const ratingDetails = await client.satisfactionratings.show(12345); 42 | */ 43 | async show(satisfactionRatingID) { 44 | return this.get(['satisfaction_ratings', satisfactionRatingID]); 45 | } 46 | 47 | /** 48 | * Creates a satisfaction rating for a ticket. 49 | * @param {number} ticketID - The ID of the ticket. 50 | * @param {object} satisfactionRating - The details of the satisfaction rating to create. 51 | * @returns {Promise<{response: object, result: object}>} The created satisfaction rating. 52 | * @throws Will throw an error if the requester is not an end user of the ticket or if the ticket is not solved. 53 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/ticket-management/satisfaction_ratings/#create-a-satisfaction-rating} 54 | * @example 55 | * const rating = { 56 | * satisfaction_rating: { score: "good", comment: "Awesome support." } 57 | * }; 58 | * const newRating = await client.satisfactionratings.create(12345, rating); 59 | */ 60 | async create(ticketID, satisfactionRating) { 61 | return this.post( 62 | ['tickets', ticketID, 'satisfaction_rating'], 63 | satisfactionRating, 64 | ); 65 | } 66 | 67 | /** 68 | * Incrementally exports satisfaction ratings based on a start time. 69 | * @param {number} startTime - The start time for the incremental export (Unix epoch time). 70 | * @returns {Promise<{response: object, result: object[]}>} A list of satisfaction ratings from the specified start time. 71 | * @see {@link https://developer.zendesk.com/api-reference/live-chat/chat-api/incremental_export/#start-time} 72 | * @example const ratingsExported = await client.satisfactionratings.incremental(1498151194); 73 | */ 74 | async incremental(startTime) { 75 | this.get(['satisfaction_ratings', {start_time: startTime}]); 76 | } 77 | } 78 | 79 | exports.SatisfactionRatings = SatisfactionRatings; 80 | -------------------------------------------------------------------------------- /src/clients/core/search.js: -------------------------------------------------------------------------------- 1 | // Search.js: Client for the zendesk API. 2 | const {Client} = require('../client'); 3 | 4 | /** 5 | * Client for the Zendesk Search API. 6 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/ticket-management/search/} 7 | */ 8 | class Search extends Client { 9 | constructor(options) { 10 | super(options); 11 | this.jsonAPINames = ['results']; 12 | } 13 | 14 | /** 15 | * Search for the given term and retrieve results. 16 | * @param {string} searchTerm - The term to search for. 17 | * @returns {Promise<{response: object, result: object}>} A JSON object with the search results. 18 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/ticket-management/search/#list-search-results} 19 | * @example 20 | * const results = await client.search.query('open tickets'); 21 | */ 22 | async query(searchTerm) { 23 | return this.get(['search', {query: searchTerm}]); 24 | } 25 | 26 | /** 27 | * Search for the given term and retrieve all results. 28 | * @param {string} searchTerm - The term to search for. 29 | * @returns {Promise} An array of search results. 30 | * @example 31 | * const allResults = await client.search.queryAll('open tickets'); 32 | */ 33 | async queryAll(searchTerm) { 34 | return this.getAll(['search', {query: searchTerm}]); 35 | } 36 | 37 | /** 38 | * Anonymous search for the given term and retrieve results. 39 | * @param {string} searchTerm - The term to search for. 40 | * @returns {Promise<{response: object, result: object}>} A JSON object with the search results. 41 | * @example 42 | * const anonResults = await client.search.queryAnonymous('open tickets'); 43 | */ 44 | async queryAnonymous(searchTerm) { 45 | return this.get(['portal', 'search', {query: searchTerm}]); 46 | } 47 | 48 | /** 49 | * Anonymous search for the given term and retrieve all results. 50 | * @param {string} searchTerm - The term to search for. 51 | * @returns {Promise} An array of search results. 52 | * @example 53 | * const allAnonResults = await client.search.queryAnonymousAll('open tickets'); 54 | */ 55 | async queryAnonymousAll(searchTerm) { 56 | return this.getAll(['portal', 'search', {query: searchTerm}]); 57 | } 58 | 59 | /** 60 | * Retrieve the count of search results for the given term. 61 | * @param {string} searchTerm - The term to search for. 62 | * @returns {Promise<{response: object, result: object}>} An Object with the number of items matching the query. 63 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/ticket-management/search/#show-results-count} 64 | * @example 65 | * const { count } = await client.search.showResultsCount('open tickets'); 66 | */ 67 | async showResultsCount(searchTerm) { 68 | return this.get(['search', 'count', {query: searchTerm}]); 69 | } 70 | 71 | /** 72 | * Export the search results for the given term. 73 | * @param {string} searchTerm - The term to search for. 74 | * @param {string} objectType - The type of object to return (ticket, organization, user, or group). 75 | * @param {number} [pageSize=100] - The number of results per page. 76 | * @returns {Promise} An array of search results. 77 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/ticket-management/search/#export-search-results} 78 | * @example 79 | * const { results } = await client.search.exportResults('open tickets', 'ticket'); 80 | */ 81 | async exportResults(searchTerm, objectType, pageSize = 100) { 82 | return this.getAll([ 83 | 'search', 84 | 'export', 85 | {query: searchTerm, 'filter[type]': objectType, 'page[size]': pageSize}, 86 | ]); 87 | } 88 | } 89 | 90 | exports.Search = Search; 91 | -------------------------------------------------------------------------------- /src/clients/core/sharingagreement.js: -------------------------------------------------------------------------------- 1 | // SharingAgreement.js: Client for the zendesk API. 2 | 3 | const {Client} = require('../client'); 4 | 5 | /** 6 | * Class representing the SharingAgreement API methods. 7 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/tickets/sharing_agreements/} 8 | */ 9 | class SharingAgreement extends Client { 10 | constructor(options) { 11 | super(options); 12 | this.jsonAPINames = ['sharing-agreement']; 13 | } 14 | 15 | /** 16 | * List all Sharing Agreements. 17 | * @returns {Promise<{response: object, result: object[]}>} An array of Sharing Agreement objects. 18 | * @throws {Error} Throws an error if the request fails. 19 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/tickets/sharing_agreements/#list-sharing-agreements} 20 | * @example 21 | * const sharingAgreements = await client.sharingagreement.show(); 22 | */ 23 | async show() { 24 | return this.get(['sharing_agreements']); 25 | } 26 | 27 | /** 28 | * Show a specific Sharing Agreement by its ID. 29 | * @param {number} id The ID of the Sharing Agreement. 30 | * @returns {Promise<{response: object, result: object}>} The Sharing Agreement object. 31 | * @throws {Error} Throws an error if the request fails. 32 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/tickets/sharing_agreements/#show-a-sharing-agreement} 33 | * @example 34 | * const sharingAgreement = await client.sharingagreement.showById(12345); 35 | */ 36 | async showById(id) { 37 | return this.get(['sharing_agreements', id]); 38 | } 39 | 40 | /** 41 | * Create a new Sharing Agreement. 42 | * @param {object} data The data for the new Sharing Agreement. 43 | * @returns {Promise<{response: object, result: object}>} The created Sharing Agreement object. 44 | * @throws {Error} Throws an error if the request fails. 45 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/tickets/sharing_agreements/#create-sharing-agreement} 46 | * @example 47 | * const newSharingAgreement = { 48 | * remote_subdomain: "Foo" 49 | * }; 50 | * const createdAgreement = await client.sharingagreement.create(newSharingAgreement); 51 | */ 52 | async create(data) { 53 | return this.post(['sharing_agreements'], {sharing_agreement: data}); 54 | } 55 | 56 | /** 57 | * Update an existing Sharing Agreement. 58 | * @param {number} id The ID of the Sharing Agreement to update. 59 | * @param {object} data The data to update the Sharing Agreement with. Only 'status' is allowed. 60 | * @returns {Promise<{response: object, result: object}>} The updated Sharing Agreement object. 61 | * @throws {Error} Throws an error if the request fails. 62 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/tickets/sharing_agreements/#update-a-sharing-agreement} 63 | * @example 64 | * const updatedData = { 65 | * status: "accepted" 66 | * }; 67 | * const updatedAgreement = await client.sharingagreement.update(12345, updatedData); 68 | */ 69 | async update(id, data) { 70 | return this.put(['sharing_agreements', id], {sharing_agreement: data}); 71 | } 72 | 73 | /** 74 | * Delete a specific Sharing Agreement by its ID. 75 | * @param {number} id The ID of the Sharing Agreement. 76 | * @returns {Promise} 77 | * @throws {Error} Throws an error if the request fails. 78 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/tickets/sharing_agreements/#delete-a-sharing-agreement} 79 | * @example 80 | * await client.sharingagreement.delete(12345); 81 | */ 82 | async delete(id) { 83 | return super.delete(['sharing_agreements', id]); 84 | } 85 | } 86 | 87 | exports.SharingAgreement = SharingAgreement; 88 | -------------------------------------------------------------------------------- /src/clients/core/tags.js: -------------------------------------------------------------------------------- 1 | const {Client} = require('../client'); 2 | 3 | /** 4 | * Client for the Zendesk Tags API. 5 | * @see {@link https://developer.zendesk.com/api-reference/sales-crm/resources/tags/} 6 | */ 7 | class Tags extends Client { 8 | constructor(options) { 9 | super(options); 10 | this.jsonAPINames = ['tags']; 11 | } 12 | 13 | /** 14 | * Retrieves all tags available to the user. 15 | * @returns {Promise} A promise that resolves with the list of tags. 16 | * @see {@link https://developer.zendesk.com/api-reference/sales-crm/resources/tags/#retrieve-all-tags} 17 | * @example 18 | * const client = createClient({...}); 19 | * const tags = await client.tags.list(); 20 | */ 21 | async list() { 22 | return this.getAll(['tags']); 23 | } 24 | 25 | /** 26 | * Creates a new tag. 27 | * @param {object} tagData - Data for the new tag. 28 | * @param {string} tagData.name - Name of the tag. 29 | * @param {string} tagData.resource_type - Type of resource the tag is attached to (lead, contact, deal). 30 | * @returns {Promise<{response: object, result: object}>} A promise that resolves with the created tag. 31 | * @throws Will throw an error if the API call fails. 32 | * @see {@link https://developer.zendesk.com/api-reference/sales-crm/resources/tags/#create-a-tag} 33 | * @example 34 | * const client = createClient({...}); 35 | * const newTag = await client.tags.create({ name: 'important', resource_type: 'contact' }); 36 | */ 37 | async create(tagData) { 38 | return this.post(['tags'], tagData); 39 | } 40 | 41 | /** 42 | * Retrieves a single tag by its ID. 43 | * @param {number} id - Unique identifier of the tag. 44 | * @returns {Promise<{response: object, result: object}>} A promise that resolves with the retrieved tag. 45 | * @throws Will throw an error if the API call fails. 46 | * @see {@link https://developer.zendesk.com/api-reference/sales-crm/resources/tags/#retrieve-a-single-tag} 47 | * @example 48 | * const client = createClient({...}); 49 | * const tag = await client.tags.show(5); 50 | */ 51 | async show(id) { 52 | return this.get(['tags', id]); 53 | } 54 | 55 | /** 56 | * Updates a tag's information. 57 | * @param {number} id - Unique identifier of the tag. 58 | * @param {object} updatedData - Data to update. 59 | * @returns {Promise<{response: object, result: object}>} A promise that resolves with the updated tag. 60 | * @throws Will throw an error if the API call fails. 61 | * @see {@link https://developer.zendesk.com/api-reference/sales-crm/resources/tags/#update-a-tag} 62 | * @example 63 | * const client = createClient({...}); 64 | * const updatedTag = await client.tags.update(5, { name: 'super important' }); 65 | */ 66 | async update(id, updatedData) { 67 | return this.put(['tags', id], updatedData); 68 | } 69 | 70 | /** 71 | * Deletes a tag by its ID. 72 | * @param {number} id - Unique identifier of the tag. 73 | * @returns {Promise} A promise that resolves when the tag has been deleted. 74 | * @throws Will throw an error if the API call fails. 75 | * @see {@link https://developer.zendesk.com/api-reference/sales-crm/resources/tags/#delete-a-tag} 76 | * @example 77 | * const client = createClient({...}); 78 | * await client.tags.delete(1); 79 | */ 80 | async delete(id) { 81 | return super.delete(['tags', id]); 82 | } 83 | } 84 | 85 | exports.Tags = Tags; 86 | -------------------------------------------------------------------------------- /src/clients/core/targetfailures.js: -------------------------------------------------------------------------------- 1 | // Targetfailures.js: Client for the zendesk API. 2 | const {Client} = require('../client'); 3 | 4 | /** 5 | * A class for interacting with the Zendesk Target Failures API. 6 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/targets/target_failures/} 7 | */ 8 | class TargetFailures extends Client { 9 | constructor(options) { 10 | super(options); 11 | this.jsonAPINames = ['targetfailures', 'targetsfailures']; 12 | } 13 | 14 | /** 15 | * Lists the 25 most recent target failures, per target. 16 | * @returns {Array} An array of target failures. 17 | * @throws {Error} Throws an error if the request fails. 18 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/targets/target_failures/#list-target-failures} 19 | * @example 20 | * const client = createClient({...}); 21 | * const failures = await client.targetfailures.list(); 22 | */ 23 | async list() { 24 | return this.getAll(['target_failures']); 25 | } 26 | 27 | /** 28 | * Retrieves the details of a specific target failure by its ID. 29 | * @param {number} targetFailureID - The ID of the target failure. 30 | * @returns {Promise<{response: object, result: object}>} The target failure details. 31 | * @throws {Error} Throws an error if the request fails or if the target failure ID is not found. 32 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/targets/target_failures/#show-target-failure} 33 | * @example 34 | * const client = createClient({...}); 35 | * const failureDetails = await client.targetfailures.show(6001326); 36 | */ 37 | async show(targetFailureID) { 38 | return this.get(['target_failures', targetFailureID]); 39 | } 40 | } 41 | 42 | exports.TargetFailures = TargetFailures; 43 | -------------------------------------------------------------------------------- /src/clients/core/targets.js: -------------------------------------------------------------------------------- 1 | const {Client} = require('../client'); 2 | 3 | /** 4 | * Represents a client for the Zendesk Targets API. 5 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/targets/targets/} 6 | */ 7 | class Targets extends Client { 8 | constructor(options) { 9 | super(options); 10 | this.jsonAPINames = ['targets', 'target']; 11 | } 12 | 13 | /** 14 | * Lists all targets. 15 | * @returns {Promise} A promise that resolves to the list of targets. 16 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/targets/targets/#list-targets} 17 | * @example 18 | * const targets = await client.targets.list(); 19 | */ 20 | async list() { 21 | return this.getAll(['targets']); 22 | } 23 | 24 | /** 25 | * Retrieves details of a specific target. 26 | * @param {number} targetId - The ID of the target to retrieve. 27 | * @returns {Promise<{response: object, result: object}>} A promise that resolves to the target details. 28 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/targets/targets/#show-target} 29 | * @example 30 | * const target = await client.targets.show(12345); 31 | */ 32 | async show(targetId) { 33 | return this.get(['targets', targetId]); 34 | } 35 | 36 | /** 37 | * Creates a new target. 38 | * @param {object} target - The target data. 39 | * @returns {Promise<{response: object, result: object}>} A promise that resolves to the created target's details. 40 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/targets/targets/#create-target} 41 | * @example 42 | * const target = { 43 | * type: 'email_target', 44 | * title: 'Test Email Target', 45 | * email: 'hello@example.com', 46 | * subject: 'Test Target' 47 | * }; 48 | * const response = await client.targets.create(target); 49 | */ 50 | async create(target) { 51 | return this.post(['targets'], target); 52 | } 53 | 54 | /** 55 | * Updates a specific target. 56 | * @param {number} targetId - The ID of the target to update. 57 | * @param {object} target - The updated target data. 58 | * @returns {Promise<{response: object, result: object}>} A promise that resolves to the updated target's details. 59 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/targets/targets/#update-target} 60 | * @example 61 | * const updatedData = { email: 'updated@example.com' }; 62 | * const response = await client.targets.update(12345, updatedData); 63 | */ 64 | async update(targetId, target) { 65 | return this.put(['targets', targetId], target); 66 | } 67 | 68 | /** 69 | * Deletes a specific target. 70 | * @param {number} targetId - The ID of the target to delete. 71 | * @returns {Promise} A promise that resolves once the target has been deleted. 72 | * @throws {Error} Throws an error if deletion fails. 73 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/targets/targets/#delete-target} 74 | * @example 75 | * await client.targets.delete(12345); 76 | */ 77 | async delete(targetId) { 78 | return super.delete(['targets', targetId]); 79 | } 80 | } 81 | 82 | exports.Targets = Targets; 83 | -------------------------------------------------------------------------------- /src/clients/core/ticketaudits.js: -------------------------------------------------------------------------------- 1 | const {Client} = require('../client'); 2 | 3 | /** 4 | * Client for the Zendesk Ticket Audits API. 5 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/tickets/ticket_audits/} 6 | */ 7 | class TicketAudits extends Client { 8 | constructor(options) { 9 | super(options); 10 | this.jsonAPINames = ['audits', 'audit']; 11 | this.sideLoadMap = [ 12 | {field: 'author_id', name: 'author', dataset: 'users'}, 13 | {field: 'ticket_id', name: 'ticket', dataset: 'tickets'}, 14 | ]; 15 | } 16 | 17 | /** 18 | * List all ticket audits. Note: Archived tickets are not included. 19 | * @returns {Promise>} Returns an array of ticket audit objects. 20 | * @throws {Error} Throws an error if request fails. 21 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/tickets/ticket_audits/#list-all-ticket-audits} 22 | * @example 23 | * const client = createClient({...}); 24 | * const allAudits = await client.ticketaudits.listAll(); 25 | */ 26 | async listAll() { 27 | return this.get('ticket_audits'); 28 | } 29 | 30 | /** 31 | * List all audits for a specified ticket. 32 | * @param {number} ticketID - The ID of the ticket. 33 | * @returns {Promise>} Returns an array of ticket audit objects. 34 | * @throws {Error} Throws an error if request fails. 35 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/tickets/ticket_audits/#list-audits-for-a-ticket} 36 | * @example 37 | * const client = createClient({...}); 38 | * const audits = await client.ticketaudits.list(12345); 39 | */ 40 | async list(ticketID) { 41 | return this.getAll(['tickets', ticketID, 'audits']); 42 | } 43 | 44 | /** 45 | * Get an approximate count of audits for a specified ticket. 46 | * @param {number} ticketID - The ID of the ticket. 47 | * @returns {Promise<{response: object, result: number}>} Returns an approximate count of audits. 48 | * @throws {Error} Throws an error if request fails. 49 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/tickets/ticket_audits/#count-audits-for-a-ticket} 50 | * @example 51 | * const client = createClient({...}); 52 | * const auditCount = await client.ticketaudits.count(12345); 53 | */ 54 | async count(ticketID) { 55 | return this.get(['tickets', ticketID, 'audits', 'count']); 56 | } 57 | 58 | /** 59 | * Show details of a specific ticket audit. 60 | * @param {number} ticketID - The ID of the ticket. 61 | * @param {number} auditID - The ID of the ticket audit. 62 | * @returns {Promise<{response: object, result: object}>} Returns details of the ticket audit. 63 | * @throws {Error} Throws an error if request fails. 64 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/tickets/ticket_audits/#show-audit} 65 | * @example 66 | * const client = createClient({...}); 67 | * const auditDetails = await client.ticketaudits.show(12345, 67890); 68 | */ 69 | async show(ticketID, auditID) { 70 | return this.get(['tickets', ticketID, 'audits', auditID]); 71 | } 72 | 73 | /** 74 | * Change a comment from public to private for a specific ticket audit. 75 | * @param {number} ticketID - The ID of the ticket. 76 | * @param {number} auditID - The ID of the ticket audit. 77 | * @returns {Promise<{response: object, result: object}>} Returns the updated ticket audit details. 78 | * @throws {Error} Throws an error if request fails. 79 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/tickets/ticket_audits/#change-a-comment-from-public-to-private} 80 | * @example 81 | * const client = createClient({...}); 82 | * await client.ticketaudits.makePrivate(12345, 67890); 83 | */ 84 | async makePrivate(ticketID, auditID) { 85 | return this.put(['tickets', ticketID, 'audits', auditID, 'make_private']); 86 | } 87 | } 88 | 89 | exports.TicketAudits = TicketAudits; 90 | -------------------------------------------------------------------------------- /src/clients/core/ticketevents.js: -------------------------------------------------------------------------------- 1 | // TicketEvents.js: Client for the zendesk API. 2 | const {Client} = require('../client'); 3 | 4 | /** 5 | * TicketEvents class to handle operations related to the Zendesk Ticket Events API. 6 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/ticket-management/incremental_exports/} 7 | */ 8 | class TicketEvents extends Client { 9 | constructor(options) { 10 | super(options); 11 | this.jsonAPINames = ['ticket_events', 'ticket_event']; 12 | } 13 | 14 | /** 15 | * Fetches incremental ticket events with optional inclusion. 16 | * @param {number} startTime - The time to start the incremental export from. 17 | * @param {string} include - Additional entities to include in the response. 18 | * @returns {Promise} Returns the result of the API call. 19 | * @throws {Error} Throws an error if the API call fails. 20 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/ticket-management/incremental_exports/#incremental-ticket-event-export} 21 | * @example const result = await client.ticketevents.incrementalInclude(1632505559, 'comment_events'); 22 | */ 23 | async incrementalInclude(startTime, include) { 24 | return this.getAll([ 25 | 'incremental', 26 | 'ticket_events', 27 | {start_time: startTime, include}, 28 | ]); 29 | } 30 | 31 | /** 32 | * Fetches incremental ticket events. 33 | * @param {number} startTime - The time to start the incremental export from. 34 | * @returns {Promise} Returns the result of the API call. 35 | * @throws {Error} Throws an error if the API call fails. 36 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/ticket-management/incremental_exports/#incremental-ticket-event-export} 37 | * @example const result = await client.ticketevents.incremental(1632505559); 38 | */ 39 | async incremental(startTime) { 40 | return this.getAll([ 41 | 'incremental', 42 | 'ticket_events', 43 | {start_time: startTime}, 44 | ]); 45 | } 46 | 47 | /** 48 | * Fetches a sample of ticket events for testing purposes. 49 | * @param {number} startTime - The time to start the incremental export from. 50 | * @returns {Promise<{response: object, result: object}>} Returns the result of the API call. 51 | * @throws {Error} Throws an error if the API call fails. 52 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/ticket-management/incremental_exports/#incremental-sample-export} 53 | * @example const result = await client.ticketevents.incrementalSample(1632505559); 54 | */ 55 | async incrementalSample(startTime) { 56 | return this.get([ 57 | 'incremental', 58 | 'ticket_events', 59 | 'sample', 60 | {start_time: startTime}, 61 | ]); 62 | } 63 | } 64 | 65 | exports.TicketEvents = TicketEvents; 66 | -------------------------------------------------------------------------------- /src/clients/core/ticketmetrics.js: -------------------------------------------------------------------------------- 1 | const {Client} = require('../client'); 2 | 3 | /** 4 | * TicketMetrics client for the Zendesk API. 5 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/tickets/ticket_metrics/} 6 | */ 7 | class TicketMetrics extends Client { 8 | constructor(options) { 9 | super(options); 10 | this.jsonAPINames = ['ticket_metrics', 'ticket_metric']; 11 | } 12 | 13 | /** 14 | * Lists the Ticket Metrics for a specific ticket. 15 | * @param {number} ticketID - The ID of the ticket. 16 | * @returns {Promise<{response: object, result: object}>} The ticket metrics data. 17 | * @throws {Error} Throws an error if the request fails. 18 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/tickets/ticket_metrics/#show-ticket-metrics} 19 | * @example 20 | * const client = createClient({...}); 21 | * const metrics = await client.ticketmetrics.list(12345); 22 | */ 23 | async list(ticketID) { 24 | return this.get(['tickets', ticketID, 'metrics']); 25 | } 26 | 27 | /** 28 | * Lists all Ticket Metrics. 29 | * @returns {Promise} An array of all ticket metrics data. 30 | * @throws {Error} Throws an error if the request fails. 31 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/tickets/ticket_metrics/#list-ticket-metrics} 32 | * @example 33 | * const client = createClient({...}); 34 | * const allMetrics = await client.ticketmetrics.listAll(); 35 | */ 36 | async listAll() { 37 | return this.getAll(['ticket_metrics']); 38 | } 39 | 40 | /** 41 | * Shows a specific Ticket Metric by its ID. 42 | * @param {number} ticketMetricId - The ID of the ticket metric to retrieve. 43 | * @returns {Promise<{response: object, result: object}>} The ticket metric data. 44 | * @throws {Error} Throws an error if the request fails. 45 | * @see {@link https://developer.zendesk.com/api-reference/ticketing/tickets/ticket_metrics/#show-ticket-metrics} 46 | * @example 47 | * const client = createClient({...}); 48 | * const metric = await client.ticketmetrics.show(12345); 49 | */ 50 | async show(ticketMetricId) { 51 | return this.get(['ticket_metrics', ticketMetricId]); 52 | } 53 | } 54 | 55 | exports.TicketMetrics = TicketMetrics; 56 | -------------------------------------------------------------------------------- /src/clients/custom-event-target.js: -------------------------------------------------------------------------------- 1 | class CustomEventTarget { 2 | constructor() { 3 | this.listeners = new Map(); 4 | } 5 | 6 | addEventListener(type, callback) { 7 | if (!this.listeners.has(type)) { 8 | this.listeners.set(type, []); 9 | } 10 | 11 | this.listeners.get(type).push(callback); 12 | } 13 | 14 | removeEventListener(type, callback) { 15 | if (this.listeners.has(type)) { 16 | const callbacks = this.listeners.get(type); 17 | const index = callbacks.indexOf(callback); 18 | if (index !== -1) { 19 | callbacks.splice(index, 1); 20 | } 21 | } 22 | } 23 | 24 | dispatchEvent(event) { 25 | if (this.listeners.has(event.type)) { 26 | const callbacks = this.listeners.get(event.type); 27 | for (const callback of callbacks) { 28 | callback(event); 29 | } 30 | } 31 | } 32 | } 33 | 34 | exports.CustomEventTarget = CustomEventTarget; 35 | -------------------------------------------------------------------------------- /src/clients/helpcenter/accesspolicies.js: -------------------------------------------------------------------------------- 1 | // AccessPolicies.js: Client for the zendesk help center API. 2 | 3 | const {Client} = require('../client'); 4 | const {ApiTypes} = require('../../constants'); 5 | 6 | class AccessPolicies extends Client { 7 | constructor(options) { 8 | super(options, ApiTypes.helpcenter); 9 | this.jsonAPINames = ['accesspplicies', 'accesspolicy']; 10 | } 11 | 12 | // AccessPolicies 13 | // Showing Access Policies 14 | async show(sectionID) { 15 | return this.get(['sections', sectionID, 'access_policy']); 16 | } 17 | 18 | // Updating Access Policies 19 | async update(sectionID, accessPolicy) { 20 | return this.put(['sections', sectionID, 'access_policy'], accessPolicy); 21 | } 22 | } 23 | 24 | exports.AccessPolicies = AccessPolicies; 25 | -------------------------------------------------------------------------------- /src/clients/helpcenter/articleattachments.js: -------------------------------------------------------------------------------- 1 | // ArticleAttachments.js: Client for the zendesk help center API. 2 | const {Client} = require('../client'); 3 | const {ApiTypes} = require('../../constants'); 4 | 5 | class ArticleAttachments extends Client { 6 | constructor(options) { 7 | super(options, ApiTypes.helpcenter); 8 | this.jsonAPINames = ['articleattachments', 'articleattachment']; 9 | } 10 | 11 | // Article Attachments 12 | // Listing Article Attachments 13 | async list(articleID) { 14 | return this.get(['articles', articleID, 'attachments']); 15 | } 16 | 17 | // Listing Article Inline Attachments 18 | async listInline(articleID) { 19 | return this.get(['articles', articleID, 'attachments', 'inline']); 20 | } 21 | 22 | // Listing Article Block Attachments 23 | async listBlock(articleID) { 24 | return this.get(['articles', articleID, 'attachments', 'block']); 25 | } 26 | 27 | // Showing Article Attachments 28 | async show(attachmentID) { 29 | return this.get(['articles', 'attachments', attachmentID]); 30 | } 31 | 32 | // Creating Article Attachments 33 | async create(/* articleID */) { 34 | return new Error('not implemented'); 35 | } 36 | 37 | // Creating Unassociated Article Attachments 38 | async createUnassociated(/* articleID */) { 39 | return new Error('not implemented'); 40 | } 41 | 42 | // Deleting Article Attachments 43 | async delete(attachmentID) { 44 | return super.delete(['articles', 'attachments', attachmentID]); 45 | } 46 | } 47 | 48 | exports.ArticleAttachments = ArticleAttachments; 49 | -------------------------------------------------------------------------------- /src/clients/helpcenter/articlecomments.js: -------------------------------------------------------------------------------- 1 | // ArticleComment.js: Client for the zendesk help center API. 2 | const {Client} = require('../client'); 3 | const {ApiTypes} = require('../../constants'); 4 | 5 | class ArticleComments extends Client { 6 | constructor(options) { 7 | super(options, ApiTypes.helpcenter); 8 | this.jsonAPINames = ['articlecomments', 'articlecomment']; 9 | this.sideLoadMap = [{field: 'author_id', name: 'user', dataset: 'users'}]; 10 | } 11 | 12 | // Article Comments 13 | 14 | // Listing Article Comments by UserID 15 | async listByUser(userID) { 16 | return this.getAll(['users', userID, 'comments']); 17 | } 18 | 19 | // Listing Article Comments by ArticleID 20 | async listByArticle(articleID) { 21 | return this.getAll(['articles', articleID, 'comments']); 22 | } 23 | 24 | // Showing an Article Comment 25 | async show(articleID, commentID) { 26 | return this.get(['articles', articleID, 'comments', commentID]); 27 | } 28 | 29 | // Creating an Article Comment 30 | async create(articleID, comment) { 31 | return this.post(['articles', articleID, 'comments'], comment); 32 | } 33 | 34 | // Updating an Article Comment 35 | async update(articleID, commentID, comment) { 36 | return this.put(['articles', articleID, 'comments', commentID], comment); 37 | } 38 | 39 | // Deleting an Article Comment 40 | async delete(articleID, commentID) { 41 | return super.delete(['articles', articleID, 'comments', commentID]); 42 | } 43 | } 44 | 45 | exports.ArticleComments = ArticleComments; 46 | -------------------------------------------------------------------------------- /src/clients/helpcenter/articlelabels.js: -------------------------------------------------------------------------------- 1 | // ArticleLabels.js: Client for the zendesk help center API. 2 | const {Client} = require('../client'); 3 | const {ApiTypes} = require('../../constants'); 4 | 5 | class ArticleLabels extends Client { 6 | constructor(options) { 7 | super(options, ApiTypes.helpcenter); 8 | this.jsonAPINames = ['articlelabels', 'articlelabel']; 9 | } 10 | 11 | // Listing Article Labels 12 | async list() { 13 | return this.get(['articles', 'labels']); 14 | } 15 | 16 | // Listing Article Labels 17 | async listByArticle(articleID) { 18 | return this.get(['articles', articleID, 'labels']); 19 | } 20 | 21 | // Showing Article Labels 22 | async show(labelID) { 23 | return this.get(['articles', 'labels', labelID]); 24 | } 25 | 26 | // Creating Article Labels 27 | async create(articleID, label) { 28 | return this.post(['articles', articleID, 'labels'], label); 29 | } 30 | 31 | // Deleting Article Labels 32 | async delete(articleID, labelID) { 33 | return super.delete(['articles', articleID, 'labels', labelID]); 34 | } 35 | } 36 | 37 | exports.ArticleLabels = ArticleLabels; 38 | -------------------------------------------------------------------------------- /src/clients/helpcenter/articles.js: -------------------------------------------------------------------------------- 1 | // Articles.js: Client for the zendesk help center API. 2 | const {Client} = require('../client'); 3 | const {ApiTypes} = require('../../constants'); 4 | 5 | class Articles extends Client { 6 | constructor(options) { 7 | super(options, ApiTypes.helpcenter); 8 | this.jsonAPINames = ['articles', 'article']; 9 | 10 | this.sideLoadMap = [ 11 | {field: 'author_id', name: 'user', dataset: 'users'}, 12 | {field: 'section_id', name: 'section', dataset: 'sections'}, 13 | {field: 'category_id', name: 'category', dataset: 'categories'}, 14 | ]; 15 | } 16 | 17 | // Listing Articles 18 | async list() { 19 | return this.getAll(['articles']); 20 | } 21 | 22 | // Listing Articles By Locale 23 | 24 | async listByLocale(locale) { 25 | return this.getAll([locale, 'articles']); 26 | } 27 | 28 | // Listing Articles Under A Section 29 | 30 | async listBySection(sectionID) { 31 | return this.getAll(['sections', sectionID, 'articles']); 32 | } 33 | 34 | // Listing Articles Under A Section by Locale 35 | 36 | async listBySectionByLocale(locale, sectionID) { 37 | return this.getAll([locale, 'sections', sectionID, 'articles']); 38 | } 39 | 40 | // Listing Articles Under A Category 41 | 42 | async listByCategory(categoryID) { 43 | return this.getAll(['categories', categoryID, 'articles']); 44 | } 45 | 46 | // Listing Articles Under A Category by Locale 47 | 48 | async listByCategoryByLocale(locale, categoryID) { 49 | return this.getAll([locale, 'categories', categoryID, 'articles']); 50 | } 51 | 52 | // Listing Articles Belongs To A User 53 | 54 | async listByUser(userID) { 55 | return this.getAll(['users', userID, 'articles']); 56 | } 57 | 58 | // Listing Articles Since Start Time 59 | 60 | async listSinceStartTime(startTime) { 61 | return this.getAll(['incremental', 'articles', {start_time: startTime}]); 62 | } 63 | 64 | // Listing Articles By Label 65 | 66 | async listByLabelNames(labelNames) { 67 | return this.getAll(['articles', {label_names: labelNames.toString()}]); 68 | } 69 | 70 | // Viewing Articles 71 | async show(articleID) { 72 | return this.get(['articles', articleID]); 73 | } 74 | 75 | // Viewing Articles By Locale 76 | async showWithLocale(locale, articleID) { 77 | return this.get([locale, 'articles', articleID]); 78 | } 79 | 80 | // Creating Articles 81 | async create(sectionID, article) { 82 | return this.post(['sections', sectionID, 'articles'], article); 83 | } 84 | 85 | // Creating Articles With Specified Locale 86 | async createWithLocale(locale, sectionID, article) { 87 | return this.post([locale, 'sections', sectionID, 'articles'], article); 88 | } 89 | 90 | // Updating Articles 91 | async update(articleID, article) { 92 | return this.put(['articles', articleID], article); 93 | } 94 | 95 | // Updating Articles With Specified Locale 96 | async updateWithLocale(locale, articleID, article) { 97 | return this.put([locale, 'articles', articleID], article); 98 | } 99 | 100 | // Associating Attachments In Bulk 101 | async associateAttachmentsInBulk(articleID, attachmentIDsInBulk) { 102 | return this.post( 103 | ['articles', articleID, 'bulk_attachments'], 104 | attachmentIDsInBulk, 105 | ); 106 | } 107 | 108 | // Deleting Articles 109 | async delete(articleID) { 110 | return super.delete(['articles', articleID]); 111 | } 112 | } 113 | 114 | exports.Articles = Articles; 115 | -------------------------------------------------------------------------------- /src/clients/helpcenter/categories.js: -------------------------------------------------------------------------------- 1 | // Categories.js: Client for the zendesk API. 2 | const {Client} = require('../client'); 3 | const {ApiTypes} = require('../../constants'); 4 | 5 | class Categories extends Client { 6 | constructor(options) { 7 | super(options, ApiTypes.helpcenter); 8 | this.jsonAPINames = ['categories', 'category']; 9 | } 10 | 11 | // Listing Categories 12 | async list() { 13 | return this.getAll(['categories']); 14 | } 15 | 16 | // Listing Categories By Locale 17 | async listWithLocale(locale) { 18 | return this.getAll([locale, 'categories']); 19 | } 20 | 21 | // Viewing Categories 22 | async show(categoryID) { 23 | return this.get(['categories', categoryID]); 24 | } 25 | 26 | // Creating Categories 27 | async create(category) { 28 | return this.post(['categories'], category); 29 | } 30 | 31 | // Updating Categories 32 | async update(categoryID, category) { 33 | return this.put(['categories', categoryID], category); 34 | } 35 | 36 | // Updating Categories With Specified Locale 37 | async updateWithLocale(locale, categoryID, category) { 38 | return this.put([locale, 'categories', categoryID], category); 39 | } 40 | 41 | // Updating Categories' Source Locale 42 | async updateSourceLocale(categoryID, sourceLocale) { 43 | return this.put(['categories', categoryID, 'source_locale'], sourceLocale); 44 | } 45 | 46 | // Deleting Categories 47 | async delete(categoryID) { 48 | return super.delete(['categories', categoryID]); 49 | } 50 | } 51 | 52 | exports.Categories = Categories; 53 | -------------------------------------------------------------------------------- /src/clients/helpcenter/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Manages help center for the Zendesk client. 3 | * 4 | * This class provides access to various help center-related functionality within the Zendesk API. 5 | */ 6 | class ZendeskClientHelpcenter { 7 | /** 8 | * @param {import('../../index.js').ZendeskClient} client - The Zendesk client instance. 9 | */ 10 | constructor(client) { 11 | this.client = client; 12 | } 13 | 14 | /** 15 | * @template T 16 | * @param {new (options: import('../../index.js').ZendeskClientOptions) => T} className - The class to instantiate. 17 | * @returns {T} An instance of the provided class. 18 | * @private 19 | */ 20 | _instantiate(className) { 21 | return this.client._instantiate(className); 22 | } 23 | 24 | get accesspolicies() { 25 | const {AccessPolicies} = require('./accesspolicies'); 26 | return this._instantiate(AccessPolicies); 27 | } 28 | 29 | get articleattachments() { 30 | const {ArticleAttachments} = require('./articleattachments'); 31 | return this._instantiate(ArticleAttachments); 32 | } 33 | 34 | get articlecomments() { 35 | const {ArticleComments} = require('./articlecomments'); 36 | return this._instantiate(ArticleComments); 37 | } 38 | 39 | get articlelabels() { 40 | const {ArticleLabels} = require('./articlelabels'); 41 | return this._instantiate(ArticleLabels); 42 | } 43 | 44 | get articles() { 45 | const {Articles} = require('./articles'); 46 | return this._instantiate(Articles); 47 | } 48 | 49 | get categories() { 50 | const {Categories} = require('./categories'); 51 | return this._instantiate(Categories); 52 | } 53 | 54 | get search() { 55 | const {Search} = require('./search'); 56 | return this._instantiate(Search); 57 | } 58 | 59 | get sections() { 60 | const {Sections} = require('./sections'); 61 | return this._instantiate(Sections); 62 | } 63 | 64 | get subscriptions() { 65 | const {Subscriptions} = require('./subscriptions'); 66 | return this._instantiate(Subscriptions); 67 | } 68 | 69 | get translations() { 70 | const {Translations} = require('./translations'); 71 | return this._instantiate(Translations); 72 | } 73 | 74 | get usersegments() { 75 | const {UserSegments} = require('./usersegments'); 76 | return this._instantiate(UserSegments); 77 | } 78 | 79 | get votes() { 80 | const {Votes} = require('./votes'); 81 | return this._instantiate(Votes); 82 | } 83 | } 84 | 85 | module.exports = {ZendeskClientHelpcenter}; 86 | -------------------------------------------------------------------------------- /src/clients/helpcenter/search.js: -------------------------------------------------------------------------------- 1 | // Search.js: Client for the zendesk help center API. 2 | const {Client} = require('../client'); 3 | const {ApiTypes} = require('../../constants'); 4 | 5 | class Search extends Client { 6 | constructor(options) { 7 | super(options, ApiTypes.helpcenter); 8 | this.jsonAPINames = ['search', 'search']; 9 | } 10 | 11 | // Searching Articles 12 | async searchArticles(searchString) { 13 | const searchContent = 14 | typeof searchString === 'object' ? searchString : {query: searchString}; 15 | return this.get(['articles', 'search', searchContent]); 16 | } 17 | 18 | // Searching Articles In Locale 19 | async searchArticlesInLocale(searchString, locale) { 20 | const searchContent = {query: searchString, locale}; 21 | return this.get(['articles', 'search', searchContent]); 22 | } 23 | 24 | // Searching Articles By Labels 25 | async searchArticlesByLabels(labelNames) { 26 | const searchContent = 27 | typeof labelNames === 'object' ? labelNames : {label_names: labelNames}; 28 | return this.get(['articles', searchContent]); 29 | } 30 | 31 | // Searching Questions 32 | async searchQuestions(searchString) { 33 | // Do not need requesetAll 34 | const searchContent = 35 | typeof searchString === 'object' ? searchString : {query: searchString}; 36 | return this.get(['questions', 'search', searchContent]); 37 | } 38 | } 39 | 40 | exports.Search = Search; 41 | -------------------------------------------------------------------------------- /src/clients/helpcenter/sections.js: -------------------------------------------------------------------------------- 1 | // Sections.js: Client for the zendesk API. 2 | const {Client} = require('../client'); 3 | const {ApiTypes} = require('../../constants'); 4 | 5 | class Sections extends Client { 6 | constructor(options) { 7 | super(options, ApiTypes.helpcenter); 8 | this.jsonAPINames = ['sections', 'section']; 9 | this.sideLoadMap = [ 10 | { 11 | field: 'category_id', 12 | name: 'category', 13 | dataset: 'categories', 14 | }, 15 | ]; 16 | } 17 | 18 | // Sections 19 | // Listing Sections 20 | async list() { 21 | return this.getAll(['sections']); 22 | } 23 | 24 | // Listing Sections In A Category 25 | async listByCategory(categoryID) { 26 | return this.getAll(['categories', categoryID, 'sections']); 27 | } 28 | 29 | // Listing Sections By Locale 30 | async listWithLocale(locale) { 31 | return this.getAll([locale, 'sections']); 32 | } 33 | 34 | // Listing Sections By Locale In A Category 35 | async listByCategoryByLocale(locale, categoryID) { 36 | return this.getAll([locale, 'categories', categoryID, 'sections']); 37 | } 38 | 39 | // Viewing Sections 40 | async show(sectionID) { 41 | return this.get(['sections', sectionID]); 42 | } 43 | 44 | // Viewing Section by locale 45 | async showWithLocale(locale, sectionID) { 46 | return this.get([locale, 'sections', sectionID]); 47 | } 48 | 49 | // Creating Sections 50 | async create(categoryId, section) { 51 | return this.post(['categories', categoryId, 'sections'], section); 52 | } 53 | 54 | // Creating Sections With Specified Locale 55 | async createWithLocale(locale, categoryId, section) { 56 | return this.post([locale, 'categories', categoryId, 'sections'], section); 57 | } 58 | 59 | // Updating Sections 60 | async update(sectionID, section) { 61 | return this.put(['sections', sectionID], section); 62 | } 63 | 64 | // Updating Sections By Locale 65 | async updateWithLocale(locale, sectionID, section) { 66 | return this.put([locale, 'sections', sectionID], section); 67 | } 68 | 69 | // Updating Sections' Source Locale 70 | async updateSourceLocale(sectionID, sourceLocale) { 71 | return this.put(['sections', sectionID, 'source_locale'], sourceLocale); 72 | } 73 | 74 | // Deleting Sections 75 | async delete(sectionID) { 76 | return super.delete(['sections', sectionID]); 77 | } 78 | } 79 | 80 | exports.Sections = Sections; 81 | -------------------------------------------------------------------------------- /src/clients/helpcenter/subscriptions.js: -------------------------------------------------------------------------------- 1 | // Subscriptions.js: Client for the zendesk API. 2 | const {Client} = require('../client'); 3 | const {ApiTypes} = require('../../constants'); 4 | 5 | class Subscriptions extends Client { 6 | constructor(options) { 7 | super(options, ApiTypes.helpcenter); 8 | this.jsonAPINames = ['subscriptions', 'subscription']; 9 | } 10 | 11 | // Listing subscriptions by user 12 | async listByUser(userID) { 13 | return this.getAll(['users', userID, 'subscriptions']); 14 | } 15 | 16 | // Listing subscriptions by article 17 | async listByArticle(articleID) { 18 | return this.getAll(['articles', articleID, 'subscriptions']); 19 | } 20 | 21 | // Listing subscriptions by section 22 | async listBySection(sectionID) { 23 | return this.getAll(['sections', sectionID, 'subscriptions']); 24 | } 25 | 26 | // Showing subscriptions by article 27 | async showbyArticle(articleID, subscriptionID) { 28 | return this.get(['articles', articleID, 'subscriptions', subscriptionID]); 29 | } 30 | 31 | // Showing subscriptions by section 32 | async showbySection(sectionID, subscriptionID) { 33 | return this.get(['sections', sectionID, 'subscriptions', subscriptionID]); 34 | } 35 | 36 | // Creating subscriptions by article 37 | async createbyArticle(articleID, subscription) { 38 | return this.post(['articles', articleID, 'subscriptions'], subscription); 39 | } 40 | 41 | // Creating subscriptions by section 42 | async createbySection(sectionID, subscription) { 43 | return this.post(['sections', sectionID, 'subscriptions'], subscription); 44 | } 45 | 46 | // Deleting subscriptions by article 47 | async deletebyArticle(articleID, subscriptionID) { 48 | return super.delete([ 49 | 'articles', 50 | articleID, 51 | 'subscriptions', 52 | subscriptionID, 53 | ]); 54 | } 55 | 56 | // Deleting subscriptions by section 57 | async deletebySection(sectionID, subscriptionID) { 58 | return super.delete([ 59 | 'articles', 60 | sectionID, 61 | 'subscriptions', 62 | subscriptionID, 63 | ]); 64 | } 65 | } 66 | 67 | exports.Subscriptions = Subscriptions; 68 | -------------------------------------------------------------------------------- /src/clients/helpcenter/translations.js: -------------------------------------------------------------------------------- 1 | // Translation.js: Client for the zendesk API. 2 | const {Client} = require('../client'); 3 | const {ApiTypes} = require('../../constants'); 4 | 5 | class Translations extends Client { 6 | constructor(options) { 7 | super(options, ApiTypes.helpcenter); 8 | this.jsonAPINames = ['translations', 'translation']; 9 | } 10 | 11 | // Viewing Translations 12 | async show(articleID, locale) { 13 | return this.get(['articles', articleID, 'translations', locale]); 14 | } 15 | 16 | // Listing Translations Belongs To An Article 17 | // Parameters allowed: 18 | // locales=en-us,en-uk 19 | // outdated=true 20 | async listByArticle(articleID, filterParameters) { 21 | return this.getAll([ 22 | 'articles', 23 | articleID, 24 | 'translations', 25 | filterParameters, 26 | ]); 27 | } 28 | 29 | // Listing Translations Belongs To A Section 30 | async listBySection(sectionID) { 31 | return this.getAll(['sections', sectionID, 'translations']); 32 | } 33 | 34 | // Listing Translations Belongs To A Category 35 | async listByCategory(categoryID) { 36 | return this.getAll(['categories', categoryID, 'translations']); 37 | } 38 | 39 | // Listing Translations Belongs To An Article 40 | async listMissingLocalesByArticle(articleID) { 41 | return this.get(['articles', articleID, 'translations', 'missing']); 42 | } 43 | 44 | // Listing Translations Belongs To A Section 45 | async listMissingLocalesBySection(sectionID) { 46 | return this.get(['sections', sectionID, 'translations', 'missing']); 47 | } 48 | 49 | // Listing Translations Belongs To A Category 50 | async listMissingLocalesByCategory(categoryID) { 51 | return this.get(['categories', categoryID, 'translations', 'missing']); 52 | } 53 | 54 | // Creating Translations For An Article 55 | async createForArticle(articleID, translation) { 56 | return this.post(['articles', articleID, 'translations'], translation); 57 | } 58 | 59 | // Creating Translations For A Section 60 | async createForSection(sectionID, translation) { 61 | return this.post(['sections', sectionID, 'translations'], translation); 62 | } 63 | 64 | // Creating Translations For A Category 65 | async createForCategory(categoryID, translation) { 66 | return this.post(['categories', categoryID, 'translations'], translation); 67 | } 68 | 69 | // Updating Translations For An Article 70 | async updateForArticle(articleID, locale, translation) { 71 | return this.put( 72 | ['articles', articleID, 'translations', locale], 73 | translation, 74 | ); 75 | } 76 | 77 | // Updating Translations For A Section 78 | async updateForSection(sectionID, locale, translation) { 79 | return this.put( 80 | ['sections', sectionID, 'translations', locale], 81 | translation, 82 | ); 83 | } 84 | 85 | // Updating Translations For A Category 86 | async updateForCategory(categoryID, locale, translation) { 87 | return this.put( 88 | ['categories', categoryID, 'translations', locale], 89 | translation, 90 | ); 91 | } 92 | 93 | // Deleting Translations 94 | async delete(translationID) { 95 | return super.delete(['translations', translationID]); 96 | } 97 | 98 | // Listing All Enabled Locales And Default Locale 99 | async listLocales() { 100 | return this.get(['locales']); 101 | } 102 | } 103 | 104 | exports.Translations = Translations; 105 | -------------------------------------------------------------------------------- /src/clients/helpcenter/usersegments.js: -------------------------------------------------------------------------------- 1 | // Usersegments.js: Client for the zendesk help center API.. 2 | const {Client} = require('../client'); 3 | const {ApiTypes} = require('../../constants'); 4 | 5 | class UserSegments extends Client { 6 | constructor(options) { 7 | super(options, ApiTypes.helpcenter); 8 | this.jsonAPINames = ['usersegments', 'usersegment']; 9 | } 10 | 11 | // Listing User Segments 12 | async list() { 13 | return this.getAll(['user_segments']); 14 | } 15 | 16 | // Listing only User Segments applicable to the current account 17 | async listApplicable() { 18 | return this.getAll(['user_segments', 'applicable']); 19 | } 20 | 21 | // Listing Segment accessible for the specified user 22 | async listByUser(userID) { 23 | return this.getAll(['users', userID, 'user_segments']); 24 | } 25 | 26 | // Get User Segment By Id 27 | async show(userSegmentID) { 28 | return this.get(['user_segments', userSegmentID]); 29 | } 30 | 31 | // List Sections using a User Segment 32 | async listSections(userSegmentID) { 33 | return this.getAll(['user_segments', userSegmentID, 'sections']); 34 | } 35 | 36 | // List Sections using a User Segment 37 | async listTopics(userSegmentID) { 38 | return this.getAll(['user_segments', userSegmentID, 'topics']); 39 | } 40 | 41 | // Creating User Segment 42 | async create(userSegment) { 43 | return this.post(['user_segments'], userSegment); 44 | } 45 | 46 | // Updating User Segment 47 | async update(userSegmentID, userSegment) { 48 | return this.put(['user_segments', userSegmentID], userSegment); 49 | } 50 | 51 | // Deleting User Segment 52 | async delete(userSegmentID) { 53 | return super.delete(['user_segments', userSegmentID]); 54 | } 55 | } 56 | 57 | exports.UserSegments = UserSegments; 58 | -------------------------------------------------------------------------------- /src/clients/helpcenter/votes.js: -------------------------------------------------------------------------------- 1 | // Votes.js: Client for the zendesk help center API. 2 | const {Client} = require('../client'); 3 | const {ApiTypes} = require('../../constants'); 4 | 5 | class Votes extends Client { 6 | constructor(options) { 7 | super(options, ApiTypes.helpcenter); 8 | this.jsonAPINames = ['votes', 'vote']; 9 | } 10 | 11 | // Listing Votes By User 12 | async listByUser(userID) { 13 | return this.get(['users', userID, 'votes']); 14 | } 15 | 16 | // Listing Votes By Article 17 | async listByArticle(articleID) { 18 | return this.get(['articles', articleID, 'votes']); 19 | } 20 | 21 | // Viewing Votes 22 | async show(voteID) { 23 | return this.get(['votes', voteID]); 24 | } 25 | 26 | // Vote Up For Article 27 | async createUpVoteForArticle(articleID) { 28 | return this.post(['articles', articleID, 'up']); 29 | } 30 | 31 | // Vote Down For Article 32 | async createDownVoteForArticle(articleID) { 33 | return this.post(['articles', articleID, 'down']); 34 | } 35 | 36 | // Vote Up For Question 37 | async createUpVoteForQuestion(questionID) { 38 | return this.post(['questions', questionID, 'up']); 39 | } 40 | 41 | // Vote Down For Question 42 | async createDownVoteForQuestion(questionID) { 43 | return this.post(['questions', questionID, 'down']); 44 | } 45 | 46 | // Vote Up For Answer 47 | async createUpVoteForAnswer(answerID) { 48 | return this.post(['answers', answerID, 'up']); 49 | } 50 | 51 | // Vote Down For Answer 52 | async createDownVoteForAnswer(answerID) { 53 | return this.post(['answers', answerID, 'down']); 54 | } 55 | 56 | // Deleting Votes 57 | async delete(voteID) { 58 | return super.delete(['votes', voteID]); 59 | } 60 | } 61 | 62 | exports.Votes = Votes; 63 | -------------------------------------------------------------------------------- /src/clients/job-monitor.js: -------------------------------------------------------------------------------- 1 | const TERMINAL_STATUSES = new Set(['completed', 'failed', 'killed']); 2 | 3 | class JobMonitor { 4 | constructor(options) { 5 | this.client = require('../index').createClient(options); 6 | } 7 | 8 | /** 9 | * Checks the status of a job. 10 | * @param {string} jobID - The ID of the job to monitor. 11 | * @returns {Promise} - Promise resolving to the job status. 12 | */ 13 | async checkJobStatus(jobID) { 14 | const {result} = await this.client.jobstatuses.show(jobID); 15 | const {job_status} = result; 16 | return job_status; 17 | } 18 | 19 | /** 20 | * Continuously checks the status of a job using intervals and invokes a callback when the job status changes. 21 | * @param {string} jobID - The ID of the job to monitor. 22 | * @param {number} [interval=500] - The interval in milliseconds at which to check the job status. 23 | * @param {number} [maxAttempts=5] - The maximum number of attempts to check the job status. 24 | * @returns {Promise} - Promise resolving to the job result. 25 | */ 26 | async monitorJobStatus(jobID, interval = 500, maxAttempts = 5) { 27 | let attempts = 0; 28 | 29 | return new Promise((resolve, reject) => { 30 | const nIntervId = setInterval(async () => { 31 | try { 32 | const jobStatus = await this.checkJobStatus(jobID); 33 | 34 | if (TERMINAL_STATUSES.has(jobStatus.status)) { 35 | clearInterval(nIntervId); 36 | // This.client.emit('debug::result', `Job ${jobID} completed!`); 37 | resolve(jobStatus); 38 | } else { 39 | // This.client.emit( 40 | // 'debug::result', 41 | // `[${jobStatus.message || 'pending'}] Job progress: ${ 42 | // jobStatus.progress || 0 43 | // } out of ${jobStatus.total}`, 44 | // ); 45 | } 46 | } catch (error) { 47 | if (error && error.statusCode === 404 && attempts < maxAttempts) { 48 | ++attempts; 49 | // This.client.emit( 50 | // 'debug::result', 51 | // `Waiting for job to become available(attempt: ${attempts})...`, 52 | // ); 53 | } else { 54 | clearInterval(nIntervId); 55 | reject(error); 56 | } 57 | } 58 | }, interval); 59 | }); 60 | } 61 | } 62 | 63 | module.exports = JobMonitor; 64 | -------------------------------------------------------------------------------- /src/clients/services/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Manages services for the Zendesk client. 3 | * 4 | * This class provides access to various service-related functionality within the Zendesk API. 5 | */ 6 | class ZendeskClientServices { 7 | /** 8 | * Creates a new instance of ZendeskClientServices. 9 | * @param {import('../../index.js').ZendeskClient} client - The Zendesk client instance. 10 | */ 11 | constructor(client) { 12 | this.client = client; 13 | } 14 | 15 | /** 16 | * Instantiates a new service class. 17 | * @template T 18 | * @param {new (options: import('../../index.js').ZendeskClientOptions) => T} className - The class to instantiate. 19 | * @returns {T} An instance of the provided class. 20 | */ 21 | _instantiate(className) { 22 | return this.client._instantiate(className); 23 | } 24 | 25 | get links() { 26 | const {Links} = require('./links'); 27 | return this._instantiate(Links); 28 | } 29 | } 30 | 31 | module.exports = {ZendeskClientServices}; 32 | -------------------------------------------------------------------------------- /src/clients/services/links.js: -------------------------------------------------------------------------------- 1 | // Links.js: Client for the zendesk services API. 2 | const {Client} = require('../client'); 3 | const {ApiTypes} = require('../../constants'); 4 | 5 | class Links extends Client { 6 | constructor(options) { 7 | super(options, ApiTypes.services); 8 | this.jsonAPINames = ['links']; 9 | this.sideLoadMap = [ 10 | {field: 'ticket_id', name: 'ticket', dataset: 'tickets'}, 11 | ]; 12 | } 13 | 14 | // Listing Links 15 | async list() { 16 | this.getAll(['links']); 17 | } 18 | 19 | // Viewing Links 20 | async show(ticket_ids) { 21 | this.get(['links', '?ticket_id=' + ticket_ids.toString()]); 22 | } 23 | } 24 | 25 | exports.Links = Links; 26 | -------------------------------------------------------------------------------- /src/clients/throttle.js: -------------------------------------------------------------------------------- 1 | module.exports = throttle; 2 | 3 | /** 4 | * Creates a throttled function that limits the rate of execution of the provided function. 5 | * The throttled function ensures that the wrapped function is not invoked more frequently 6 | * than a specified time interval. 7 | * @param {...any} arguments_ - The arguments for the throttled function. This can include: 8 | * - `fn` (Function): The function to be throttled. 9 | * - `options` (object, optional): Throttling options. 10 | * - `options.interval` (number|string, optional): The time interval in milliseconds between function calls. 11 | * - `options.window` (number, default=1): The sliding window duration in which 'limit' number of calls are allowed. 12 | * - `options.limit` (number, default=1): The maximum number of function calls allowed in the specified window. 13 | * - `additionalArgs` (...any): Additional arguments to be passed to the throttled function. 14 | * @returns {Function} - A throttled function that queues and limits the execution of the original function. 15 | * @example 16 | * const throttledLog = throttle(console.log, 1000); // Throttle to at most 1 call per second 17 | * throttledLog('Message 1'); // Logs 'Message 1' 18 | * throttledLog('Message 2'); // Queues 'Message 2' to be logged after the throttle interval 19 | * @example 20 | * const throttledFetch = throttle(fetch, { window: 5, limit: 2 }); // Throttle to at most 2 calls in every 5 seconds 21 | * throttledFetch('https://api.example.com/data1'); // Fetches data1 22 | * throttledFetch('https://api.example.com/data2'); // Fetches data2 23 | * throttledFetch('https://api.example.com/data3'); // Queues data3 to be fetched after the throttle interval 24 | * 25 | * Credit: Original inspiration from https://github.com/brianloveswords/throttle-function "Brian J Brennan" 26 | */ 27 | function throttle(...arguments_) { 28 | const [thisArgument, function_, options = {}] = 29 | arguments_.length > 1 ? arguments_ : [null, ...arguments_]; 30 | const msBetweenCalls = getMsBetweenCalls(options); 31 | const queue = []; 32 | let timer; 33 | 34 | /** 35 | * Determines the milliseconds between calls based on the provided options. 36 | * @param {object|number|string} options - Throttling options or interval. 37 | * @returns {number} - Milliseconds between calls. 38 | */ 39 | function getMsBetweenCalls(options) { 40 | if (typeof options === 'number') return options; 41 | if (typeof options === 'string') return Number(options); 42 | return Math.ceil(((options.window || 1) / (options.limit || 1)) * 1000); 43 | } 44 | 45 | /** 46 | Executes the next function in the queue. 47 | * @returns {Function|null} - The executed function or null if the queue is empty. 48 | */ 49 | function runQueue() { 50 | if (queue.length === 0) clearInterval(timer); 51 | return queue.shift() ? function_.apply(thisArgument, queue.shift()) : null; 52 | } 53 | 54 | return function (...arguments_) { 55 | queue.push(arguments_); 56 | timer ||= setInterval(runQueue, msBetweenCalls); 57 | 58 | return { 59 | position: queue.length, 60 | queuedAt: Date.now(), 61 | timeUntilCall: queue.length * msBetweenCalls, 62 | }; 63 | }; 64 | } 65 | -------------------------------------------------------------------------------- /src/clients/voice/agentactivity.js: -------------------------------------------------------------------------------- 1 | // AgentActivity.js: Client for the Zendesk Voice API. 2 | const {Client} = require('../client'); 3 | const {ApiTypes} = require('../../constants'); 4 | 5 | class AgentActivity extends Client { 6 | constructor(options) { 7 | super(options, ApiTypes.voice); 8 | this.jsonAPINames = ['agent activity']; 9 | } 10 | 11 | // Showing Agent Activity 12 | async show() { 13 | return this.get(['stats', 'agents_activity']); 14 | } 15 | } 16 | 17 | exports.AgentActivity = AgentActivity; 18 | -------------------------------------------------------------------------------- /src/clients/voice/availabilities.js: -------------------------------------------------------------------------------- 1 | // Availabilities.js: Client for the Zendesk Voice API. 2 | const {Client} = require('../client'); 3 | const {ApiTypes} = require('../../constants'); 4 | 5 | class Availabilities extends Client { 6 | constructor(options) { 7 | super(options, ApiTypes.voice); 8 | this.jsonAPINames = ['availabilities', 'availability']; 9 | } 10 | 11 | // Update Availabilities 12 | async update(agentID, availability) { 13 | return this.put(['availabilities', agentID], availability); 14 | } 15 | 16 | // Get Availabilities by ID 17 | async show(agentID) { 18 | return this.get(['availabilities', agentID]); 19 | } 20 | } 21 | 22 | exports.Availabilities = Availabilities; 23 | -------------------------------------------------------------------------------- /src/clients/voice/currentqueueactivity.js: -------------------------------------------------------------------------------- 1 | // CurrentQueueActivity.js: Client for the Zendesk Voice API. 2 | const {Client} = require('../client'); 3 | const {ApiTypes} = require('../../constants'); 4 | 5 | class CurrentQueueActivity extends Client { 6 | constructor(options) { 7 | super(options, ApiTypes.voice); 8 | this.jsonAPINames = ['current_queue_activity', 'current_queue_activities']; 9 | } 10 | 11 | // Get Current Queue Activity 12 | async show() { 13 | return this.get(['stats', 'current_queue_activity']); 14 | } 15 | } 16 | 17 | exports.CurrentQueueActivity = CurrentQueueActivity; 18 | -------------------------------------------------------------------------------- /src/clients/voice/greetingcategories.js: -------------------------------------------------------------------------------- 1 | // GreetingCategories.js: Client for the zendesk API. 2 | const {Client} = require('../client'); 3 | const {ApiTypes} = require('../../constants'); 4 | 5 | class GreetingCategories extends Client { 6 | constructor(options) { 7 | super(options, ApiTypes.voice); 8 | this.jsonAPINames = ['greeting_categories', 'greeting_category']; 9 | } 10 | 11 | // List Greetings Categories 12 | async list() { 13 | return this.get(['greeting_categories']); 14 | } 15 | 16 | // Get Greetings Category by ID 17 | async show(greetingCategoryID) { 18 | return this.get(['greeting_category', greetingCategoryID]); 19 | } 20 | } 21 | 22 | exports.GreetingCategories = GreetingCategories; 23 | -------------------------------------------------------------------------------- /src/clients/voice/greetings.js: -------------------------------------------------------------------------------- 1 | // Greetings.js: Client for the zendesk API. 2 | const {Client} = require('../client'); 3 | const {ApiTypes} = require('../../constants'); 4 | 5 | class Greetings extends Client { 6 | constructor(options) { 7 | super(options, ApiTypes.voice); 8 | this.jsonAPINames = ['greetings', 'greetings']; 9 | } 10 | 11 | // List Greetings 12 | async list() { 13 | return this.get(['greetings']); 14 | } 15 | 16 | // List Greetings by ID 17 | async show(greetingID) { 18 | return this.get(['greetings', greetingID]); 19 | } 20 | 21 | // Create Greeting 22 | async create(greeting) { 23 | return this.post('POST', ['greetings'], greeting); 24 | } 25 | 26 | // Update Greeting 27 | async update(greeting, greetingID) { 28 | return this.put('PUT', ['greetings', greetingID], greeting); 29 | } 30 | 31 | // Delete Greeting 32 | async delete(greetingID) { 33 | return super.delete('DELETE', ['greetings', greetingID]); 34 | } 35 | } 36 | 37 | exports.Greetings = Greetings; 38 | -------------------------------------------------------------------------------- /src/clients/voice/historicalqueueactivity.js: -------------------------------------------------------------------------------- 1 | // HistoricalQueueActivity.js: Client for the zendesk API. 2 | const {Client} = require('../client'); 3 | const {ApiTypes} = require('../../constants'); 4 | 5 | class HistoricalQueueActivity extends Client { 6 | constructor(options) { 7 | super(options, ApiTypes.voice); 8 | this.jsonAPINames = [ 9 | 'historical_queue_activity', 10 | 'historical_queue_activities', 11 | ]; 12 | } 13 | 14 | // Showing HistoricalQueueActivity 15 | async show() { 16 | return this.get(['stats', 'historical_queue_activity']); 17 | } 18 | } 19 | 20 | exports.HistoricalQueueActivity = HistoricalQueueActivity; 21 | -------------------------------------------------------------------------------- /src/clients/voice/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Manages voice for the Zendesk client. 3 | * 4 | * This class provides access to various voice-related functionality within the Zendesk API. 5 | */ 6 | class ZendeskClientVoice { 7 | /** 8 | * @param {import('../../index.js').ZendeskClient} client - The Zendesk client instance. 9 | */ 10 | constructor(client) { 11 | this.client = client; 12 | } 13 | 14 | /** 15 | * @template T 16 | * @param {new (options: import('../../index.js').ZendeskClientOptions) => T} className - The class to instantiate. 17 | * @returns {T} An instance of the provided class. 18 | * @private 19 | */ 20 | _instantiate(className) { 21 | return this.client._instantiate(className); 22 | } 23 | 24 | get currentqueueactivity() { 25 | const {CurrentQueueActivity} = require('./currentqueueactivity'); 26 | return this._instantiate(CurrentQueueActivity); 27 | } 28 | 29 | get greetingcategories() { 30 | const {GreetingCategories} = require('./greetingcategories'); 31 | return this._instantiate(GreetingCategories); 32 | } 33 | 34 | get greetings() { 35 | const {Greetings} = require('./greetings'); 36 | return this._instantiate(Greetings); 37 | } 38 | 39 | get historicalqueueactivity() { 40 | const {HistoricalQueueActivity} = require('./historicalqueueactivity'); 41 | return this._instantiate(HistoricalQueueActivity); 42 | } 43 | 44 | get phonenumbers() { 45 | const {PhoneNumbers} = require('./phonenumbers'); 46 | return this._instantiate(PhoneNumbers); 47 | } 48 | } 49 | 50 | module.exports = {ZendeskClientVoice}; 51 | -------------------------------------------------------------------------------- /src/clients/voice/phonenumbers.js: -------------------------------------------------------------------------------- 1 | // PhoneNumbers.js: Client for the Zendesk Voice API. 2 | const {Client} = require('../client'); 3 | const {ApiTypes} = require('../../constants'); 4 | 5 | class PhoneNumbers extends Client { 6 | constructor(options) { 7 | super(options, ApiTypes.voice); 8 | this.jsonAPINames = ['phone numbers', 'phone number']; 9 | } 10 | 11 | // Searching Available PhoneNumbers 12 | async search(searchTerm) { 13 | return this.get(['phone_numbers', 'search', {query: searchTerm}]); 14 | } 15 | 16 | // List PhoneNumbers 17 | async list() { 18 | return this.get(['phone_numbers']); 19 | } 20 | 21 | // Create PhoneNumbers 22 | async create(phone_number) { 23 | return this.post(['phone_numbers'], phone_number); 24 | } 25 | 26 | // Update PhoneNumbers 27 | async update(phoneID, phone_number) { 28 | return this.put(['phone_numbers', phoneID], phone_number); 29 | } 30 | 31 | // Get PhoneNumbers by ID 32 | async show(phoneID) { 33 | return this.get(['phone_numbers', phoneID]); 34 | } 35 | 36 | // Delete PhoneNumbers 37 | async delete(phoneID) { 38 | return super.delete(['phone_numbers', phoneID]); 39 | } 40 | } 41 | 42 | exports.PhoneNumbers = PhoneNumbers; 43 | -------------------------------------------------------------------------------- /src/constants.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @readonly 3 | * @enum {string} 4 | */ 5 | const ApiTypes = { 6 | core: 'core', 7 | helpcenter: 'helpcenter', 8 | services: 'services', 9 | voice: 'voice', 10 | }; 11 | 12 | /** 13 | * @type {Record} 14 | * @readonly 15 | */ 16 | const Endpoints = { 17 | core: '.zendesk.com/api/v2', 18 | helpcenter: '.zendesk.com/api/v2/help_center', 19 | services: '.zendesk.com/api/services/jira', 20 | voice: '.zendesk.com/api/v2/channels/voice', 21 | }; 22 | 23 | module.exports = {ApiTypes, Endpoints}; 24 | -------------------------------------------------------------------------------- /src/logger.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | class LoggerInterface { 4 | fatal(message) { 5 | console.error(message); 6 | } 7 | 8 | error(message) { 9 | console.error(message); 10 | } 11 | 12 | warn(message) { 13 | console.warn(message); 14 | } 15 | 16 | info(message) { 17 | console.info(message); 18 | } 19 | 20 | debug(message) { 21 | console.log(message); 22 | } 23 | 24 | trace(message) { 25 | console.trace(message); 26 | } 27 | } 28 | 29 | class ConsoleLogger extends LoggerInterface {} 30 | 31 | module.exports = ConsoleLogger; 32 | -------------------------------------------------------------------------------- /test/endpoint-checker.test.js: -------------------------------------------------------------------------------- 1 | import {describe, expect, it} from 'vitest'; 2 | import {EndpointChecker} from '../src/clients/endpoint-checker.js'; 3 | 4 | describe('Zendesk Client Endpoint Checker', () => { 5 | const checker = new EndpointChecker(); 6 | 7 | it('should recognize a URL pattern with a locale placeholder', () => { 8 | const endpoint = 'help_center/en-us/articles'; 9 | const isSupported = checker.supportsCursorPagination(endpoint); 10 | 11 | expect(isSupported).toBe(true); 12 | }); 13 | 14 | it('should recognize a URL pattern containing the wildcard `.*`', () => { 15 | const endpointWithCursor = 'incremental/tickets/cursor'; 16 | const isSupportedWithCursor = 17 | checker.supportsCursorPagination(endpointWithCursor); 18 | 19 | expect(isSupportedWithCursor).toBe(true); 20 | }); 21 | 22 | it('should not recognize a URL pattern missing the wildcard segment', () => { 23 | const endpointWithoutCursor = 'incremental/tickets'; 24 | const isSupportedWithoutCursor = checker.supportsCursorPagination( 25 | endpointWithoutCursor, 26 | ); 27 | 28 | expect(isSupportedWithoutCursor).toBe(false); 29 | }); 30 | 31 | it('should recognize a complex endpoint pattern containing multiple placeholders', () => { 32 | const complexEndpoint = 33 | 'help_center/en-us/articles/12345/comments/67890/votes'; 34 | const isSupportedForComplex = 35 | checker.supportsCursorPagination(complexEndpoint); 36 | 37 | expect(isSupportedForComplex).toBe(true); 38 | }); 39 | }); 40 | -------------------------------------------------------------------------------- /test/exceptionshandling.test.js: -------------------------------------------------------------------------------- 1 | import process from 'node:process'; 2 | import dotenv from 'dotenv'; 3 | import {describe, expect, it} from 'vitest'; 4 | import {initializeClient} from './setup.js'; 5 | 6 | dotenv.config(); 7 | 8 | const username = process.env.ZENDESK_USERNAME; 9 | const token = process.env.ZENDESK_TOKEN; 10 | 11 | describe('Zendesk Exceptions Handling', () => { 12 | it('should throw an error for an invalid subdomain', async () => { 13 | const error = new Error('My Custom Error'); 14 | error.details = 'Custom Details'; 15 | 16 | const client = initializeClient({ 17 | username, 18 | token, 19 | subdomain: 'any', 20 | throwOriginalException: true, 21 | transportConfig: { 22 | transportFn() { 23 | throw error; 24 | }, 25 | }, 26 | }); 27 | 28 | await expect(() => client.users.me()).rejects.toThrowError(error); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /test/fixtures/authentication_test_correct_oauthtoken.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "scope": "https://nodejsapi.zendesk.com:443", 4 | "method": "GET", 5 | "path": "/api/v2/users/me.json", 6 | "body": "", 7 | "status": 200, 8 | "response": { 9 | "user": { 10 | "name": "TEST USER" 11 | } 12 | }, 13 | "responseIsBinary": false 14 | } 15 | ] -------------------------------------------------------------------------------- /test/fixtures/authentication_test_correct_u_token.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "scope": "https://nodejsapi.zendesk.com:443", 4 | "method": "GET", 5 | "path": "/api/v2/users/me.json", 6 | "body": "", 7 | "status": 200, 8 | "response": { 9 | "user": { 10 | "name": "TEST USER" 11 | } 12 | }, 13 | "responseIsBinary": false 14 | } 15 | ] -------------------------------------------------------------------------------- /test/fixtures/authentication_test_endpoint_uri.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "scope": "https://nodejsapi.zendesk.com:443", 4 | "method": "GET", 5 | "path": "/api/v2/users/me.json", 6 | "body": "", 7 | "status": 200, 8 | "response": { 9 | "user": { 10 | "name": "TEST USER" 11 | } 12 | }, 13 | "responseIsBinary": false 14 | } 15 | ] -------------------------------------------------------------------------------- /test/fixtures/authentication_test_incorrect_sans_token.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /test/fixtures/authentication_test_incorrect_subdomain.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "scope": "https://invalidSubdomain.zendesk.com:443", 4 | "method": "GET", 5 | "path": "/api/v2/users/me.json", 6 | "body": "", 7 | "status": 404, 8 | "response": { 9 | }, 10 | "responseIsBinary": false 11 | } 12 | ] -------------------------------------------------------------------------------- /test/fixtures/authentication_test_incorrect_token.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "scope": "https://nodejsapi.zendesk.com:443", 4 | "method": "GET", 5 | "path": "/api/v2/users/me.json", 6 | "body": "", 7 | "status": 200, 8 | "response": { 9 | "user": { 10 | "name": "Anonymous user" 11 | } 12 | }, 13 | "responseIsBinary": false 14 | } 15 | ] -------------------------------------------------------------------------------- /test/fixtures/authentication_test_incorrect_u_p.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "scope": "https://nodejsapi.zendesk.com:443", 4 | "method": "GET", 5 | "path": "/api/v2/users/me.json", 6 | "body": "", 7 | "status": 200, 8 | "response": { 9 | "user": { 10 | "name": "Anonymous user" 11 | } 12 | }, 13 | "responseIsBinary": false 14 | } 15 | ] -------------------------------------------------------------------------------- /test/fixtures/authentication_test_no_creds.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "scope": "https://nodejsapi.zendesk.com:443", 4 | "method": "GET", 5 | "path": "/api/v2/users/me.json", 6 | "body": "", 7 | "status": 200, 8 | "response": { 9 | "user": { 10 | "name": "Anonymous user" 11 | } 12 | }, 13 | "responseIsBinary": false 14 | } 15 | ] -------------------------------------------------------------------------------- /test/fixtures/authentication_test_user_pass.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "scope": "https://nodejsapi.zendesk.com:443", 4 | "method": "GET", 5 | "path": "/api/v2/users/me.json", 6 | "body": "", 7 | "status": 200, 8 | "response": { 9 | "user": { 10 | "name": "TEST USER" 11 | } 12 | }, 13 | "responseIsBinary": false 14 | } 15 | ] -------------------------------------------------------------------------------- /test/fixtures/organizations_test_autocomplete_organization.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "scope": "https://nodejsapi.zendesk.com:443", 4 | "method": "GET", 5 | "path": "/api/v2/organizations/autocomplete.json?name=xTes", 6 | "body": "", 7 | "status": 200, 8 | "response": [ 9 | "1f8b0800000000000003ab56ca2f4a4fcccbac4a2cc9cccf2b56b28a8ed551ca4bad28892f484c4f55b2ca2bcdc9d1512a284a2dcbcc2f2d46114cce2fcd2b51b232a805002842d5b244000000" 10 | ], 11 | "rawHeaders": [ 12 | "Date", 13 | "Sun, 08 Oct 2023 17:18:00 GMT", 14 | "Content-Type", 15 | "application/json; charset=utf-8", 16 | "Transfer-Encoding", 17 | "chunked", 18 | "Connection", 19 | "close", 20 | "x-zendesk-api-version", 21 | "v2", 22 | "x-zendesk-application-version", 23 | "v18586", 24 | "x-frame-options", 25 | "SAMEORIGIN", 26 | "x-rate-limit", 27 | "700", 28 | "rate-limit", 29 | "700", 30 | "x-rate-limit-remaining", 31 | "695", 32 | "rate-limit-remaining", 33 | "695", 34 | "rate-limit-reset", 35 | "60", 36 | "strict-transport-security", 37 | "max-age=31536000; includeSubDomains", 38 | "etag", 39 | "W/\"59a18f90e776ea29df3949752102ecfe\"", 40 | "cache-control", 41 | "max-age=0, private, must-revalidate", 42 | "set-cookie", 43 | "_zendesk_cookie=BAhJIhl7ImRldmljZV90b2tlbnMiOnt9fQY6BkVU--0bf2100788cb010d0183feca16aaf88ccaf719ca; path=/; expires=Mon, 07 Oct 2024 16:03:48 GMT; secure; HttpOnly; SameSite=None", 44 | "x-zendesk-origin-server", 45 | "classic-app-server-5d6b8cb99d-9d9dd", 46 | "x-request-id", 47 | "81300a650e47ec74-SEA", 48 | "X-Request-ID", 49 | "81300a650e47ec74-SEA", 50 | "x-runtime", 51 | "0.106503", 52 | "X-Zendesk-Zorg", 53 | "yes", 54 | "Content-Encoding", 55 | "gzip", 56 | "CF-Cache-Status", 57 | "DYNAMIC", 58 | "Report-To", 59 | "{\"endpoints\":[{\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v3?s=0gLpypucHDIUBx7mLs1Q4TM%2BTb9LkZ7vmdE%2BIQGRLGQfAeChSg9%2FXY9VMqtzvO%2FbLgmD8Q0NwbvZ%2BKiWGo3KBRyDQ9Mo0AStmxCTmcSp%2BhW6ZRvI%2FRkIm6RIPqMtaRpBmlplM2zDlw%3D%3D\"}],\"group\":\"cf-nel\",\"max_age\":604800}", 60 | "NEL", 61 | "{\"success_fraction\":0.01,\"report_to\":\"cf-nel\",\"max_age\":604800}", 62 | "Set-Cookie", 63 | "__cfruid=61e5bdec06c74ed3b43af0edd3efe6b764d2ada5-1696785480; path=/; domain=.nodejsapi.zendesk.com; HttpOnly; Secure; SameSite=None", 64 | "Server", 65 | "cloudflare", 66 | "CF-RAY", 67 | "81300a650e47ec74-SEA" 68 | ], 69 | "responseIsBinary": false 70 | } 71 | ] -------------------------------------------------------------------------------- /test/fixtures/organizations_test_create.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "scope": "https://nodejsapi.zendesk.com:443", 4 | "method": "POST", 5 | "path": "/api/v2/organizations.json", 6 | "body": { 7 | "organization": { 8 | "name": "xTestx Organization node-zendesk" 9 | } 10 | }, 11 | "status": 201, 12 | "response": { 13 | "organization": { 14 | "url": "https://nodejsapi.zendesk.com/api/v2/organizations/19442893058196.json", 15 | "id": 19442893058196, 16 | "name": "xTestx Organization node-zendesk", 17 | "shared_tickets": false, 18 | "shared_comments": false, 19 | "external_id": null, 20 | "created_at": "2023-09-23T00:16:16Z", 21 | "updated_at": "2023-09-23T00:16:16Z", 22 | "domain_names": [], 23 | "details": null, 24 | "notes": null, 25 | "group_id": null, 26 | "tags": [], 27 | "organization_fields": {} 28 | } 29 | }, 30 | "rawHeaders": [ 31 | "Date", 32 | "Sat, 23 Sep 2023 00:16:17 GMT", 33 | "Content-Type", 34 | "application/json; charset=utf-8", 35 | "Content-Length", 36 | "394", 37 | "Connection", 38 | "close", 39 | "x-zendesk-api-version", 40 | "v2", 41 | "x-zendesk-application-version", 42 | "v18457", 43 | "x-frame-options", 44 | "SAMEORIGIN", 45 | "location", 46 | "https://nodejsapi.zendesk.com/api/v2/organizations/19442893058196.json", 47 | "x-rate-limit", 48 | "700", 49 | "rate-limit", 50 | "700", 51 | "x-rate-limit-remaining", 52 | "696", 53 | "rate-limit-remaining", 54 | "696", 55 | "rate-limit-reset", 56 | "43", 57 | "strict-transport-security", 58 | "max-age=31536000; includeSubDomains", 59 | "etag", 60 | "W/\"63ad5b78e8c602ac6573a8cf2fa664a9\"", 61 | "cache-control", 62 | "max-age=0, private, must-revalidate", 63 | "set-cookie", 64 | "_zendesk_cookie=BAhJIhl7ImRldmljZV90b2tlbnMiOnt9fQY6BkVU--0bf2100788cb010d0183feca16aaf88ccaf719ca; path=/; expires=Mon, 23 Sep 2024 00:02:20 GMT; secure; HttpOnly; SameSite=None", 65 | "x-zendesk-origin-server", 66 | "classic-app-server-59c5666bb9-cck25", 67 | "x-request-id", 68 | "80ae9918ce8c30a1-SEA", 69 | "X-Request-ID", 70 | "80ae9918ce8c30a1-SEA", 71 | "x-runtime", 72 | "0.117232", 73 | "X-Zendesk-Zorg", 74 | "yes", 75 | "CF-Cache-Status", 76 | "DYNAMIC", 77 | "Report-To", 78 | "{\"endpoints\":[{\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v3?s=oEqABAop2xiodkKGYnyZ3dx2hz5Va2fdGAfvJwnvan2GkKpfXdIZTE5PXsIYbDm00Mp3giIVsL4aPzx1pO6%2BGU9e8GjslWG%2F%2FjLP%2F0zpRL0EbWXjrIbObeD6hVK8HlYqhfG0rpgr1g%3D%3D\"}],\"group\":\"cf-nel\",\"max_age\":604800}", 79 | "NEL", 80 | "{\"success_fraction\":0.01,\"report_to\":\"cf-nel\",\"max_age\":604800}", 81 | "Set-Cookie", 82 | "__cfruid=80bf5f8d9a0826d36ceb162e1c4f6557c9e7cbaf-1695428177; path=/; domain=.nodejsapi.zendesk.com; HttpOnly; Secure; SameSite=None", 83 | "Server", 84 | "cloudflare", 85 | "CF-RAY", 86 | "80ae9918ce8c30a1-SEA" 87 | ], 88 | "responseIsBinary": false 89 | } 90 | ] -------------------------------------------------------------------------------- /test/fixtures/organizations_test_delete_not_found_organization.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "scope": "https://nodejsapi.zendesk.com:443", 4 | "method": "DELETE", 5 | "path": "/api/v2/organizations/4819136400.json", 6 | "body": "", 7 | "status": 404, 8 | "response": { 9 | "error": "RecordNotFound", 10 | "description": "Not found" 11 | }, 12 | "rawHeaders": [ 13 | "Date", 14 | "Sat, 23 Sep 2023 00:16:19 GMT", 15 | "Content-Type", 16 | "application/json; charset=utf-8", 17 | "Transfer-Encoding", 18 | "chunked", 19 | "Connection", 20 | "close", 21 | "x-zendesk-api-version", 22 | "v2", 23 | "x-zendesk-application-version", 24 | "v18457", 25 | "x-frame-options", 26 | "SAMEORIGIN", 27 | "x-rate-limit", 28 | "700", 29 | "rate-limit", 30 | "700", 31 | "x-rate-limit-remaining", 32 | "676", 33 | "rate-limit-remaining", 34 | "676", 35 | "rate-limit-reset", 36 | "41", 37 | "strict-transport-security", 38 | "max-age=31536000; includeSubDomains", 39 | "cache-control", 40 | "no-cache", 41 | "set-cookie", 42 | "_zendesk_cookie=BAhJIhl7ImRldmljZV90b2tlbnMiOnt9fQY6BkVU--0bf2100788cb010d0183feca16aaf88ccaf719ca; path=/; expires=Mon, 23 Sep 2024 00:14:11 GMT; secure; HttpOnly; SameSite=None", 43 | "x-zendesk-origin-server", 44 | "classic-app-server-59c5666bb9-xmlw6", 45 | "x-request-id", 46 | "80ae99284fd23082-SEA", 47 | "X-Request-ID", 48 | "80ae99284fd23082-SEA", 49 | "x-runtime", 50 | "0.077380", 51 | "X-Zendesk-Zorg", 52 | "yes", 53 | "CF-Cache-Status", 54 | "DYNAMIC", 55 | "Report-To", 56 | "{\"endpoints\":[{\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v3?s=Tb7PtJNa5AMnz4Mj1wsHNkTxZqPmNPs8VIjUPa14YZdxAQ8ksCTxBiCt5QuSk7q1MgxxCQPT9zcj%2B4%2BYOuFQxnL6k7F54qlktmII1T1WxZGbqCbc0ilYeHESITNRBb%2BNandtX3N8cw%3D%3D\"}],\"group\":\"cf-nel\",\"max_age\":604800}", 57 | "NEL", 58 | "{\"success_fraction\":0.01,\"report_to\":\"cf-nel\",\"max_age\":604800}", 59 | "Set-Cookie", 60 | "__cfruid=9fe0aa3da14661fa59e7fde17780f9489d980c47-1695428179; path=/; domain=.nodejsapi.zendesk.com; HttpOnly; Secure; SameSite=None", 61 | "Server", 62 | "cloudflare", 63 | "CF-RAY", 64 | "80ae99284fd23082-SEA" 65 | ], 66 | "responseIsBinary": false 67 | } 68 | ] -------------------------------------------------------------------------------- /test/fixtures/organizations_test_delete_organization.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "scope": "https://nodejsapi.zendesk.com:443", 4 | "method": "DELETE", 5 | "path": "/api/v2/organizations/19442893058196.json", 6 | "body": "", 7 | "status": 204, 8 | "response": "", 9 | "rawHeaders": [ 10 | "Date", 11 | "Sat, 23 Sep 2023 00:16:19 GMT", 12 | "Connection", 13 | "close", 14 | "x-zendesk-api-version", 15 | "v2", 16 | "x-zendesk-application-version", 17 | "v18457", 18 | "x-frame-options", 19 | "SAMEORIGIN", 20 | "x-rate-limit", 21 | "700", 22 | "rate-limit", 23 | "700", 24 | "x-rate-limit-remaining", 25 | "679", 26 | "rate-limit-remaining", 27 | "679", 28 | "rate-limit-reset", 29 | "41", 30 | "strict-transport-security", 31 | "max-age=31536000; includeSubDomains", 32 | "cache-control", 33 | "no-cache", 34 | "set-cookie", 35 | "_zendesk_cookie=BAhJIhl7ImRldmljZV90b2tlbnMiOnt9fQY6BkVU--0bf2100788cb010d0183feca16aaf88ccaf719ca; path=/; expires=Mon, 23 Sep 2024 00:03:31 GMT; secure; HttpOnly; SameSite=None", 36 | "x-zendesk-origin-server", 37 | "classic-app-server-59c5666bb9-qzpmv", 38 | "x-request-id", 39 | "80ae99268831279c-SEA", 40 | "X-Request-ID", 41 | "80ae99268831279c-SEA", 42 | "x-runtime", 43 | "0.130440", 44 | "X-Zendesk-Zorg", 45 | "yes", 46 | "CF-Cache-Status", 47 | "DYNAMIC", 48 | "Report-To", 49 | "{\"endpoints\":[{\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v3?s=KlEG1wItkPDMdIlCbprWKEzU4ZxHzGM%2Fu%2F7%2FOTUWGbb0iScUnaosOajdtri5DT8AcmnHkB6A%2B2%2FhtRaGkiWNrzoVNxuKHw2Mxe6LaKckasanSmAu6oOmIik%2BjwfahFNJ5k682p40iw%3D%3D\"}],\"group\":\"cf-nel\",\"max_age\":604800}", 50 | "NEL", 51 | "{\"success_fraction\":0.01,\"report_to\":\"cf-nel\",\"max_age\":604800}", 52 | "Set-Cookie", 53 | "__cfruid=9fe0aa3da14661fa59e7fde17780f9489d980c47-1695428179; path=/; domain=.nodejsapi.zendesk.com; HttpOnly; Secure; SameSite=None", 54 | "Server", 55 | "cloudflare", 56 | "CF-RAY", 57 | "80ae99268831279c-SEA" 58 | ], 59 | "responseIsBinary": false 60 | } 61 | ] -------------------------------------------------------------------------------- /test/fixtures/organizations_test_search_organization.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "scope": "https://nodejsapi.zendesk.com:443", 4 | "method": "GET", 5 | "path": "/api/v2/organizations/search.json?external_id=69420", 6 | "body": "", 7 | "status": 200, 8 | "response": { 9 | "organizations": [ 10 | { 11 | "url": "https://nodejsapi.zendesk.com/api/v2/organizations/19442893058196.json", 12 | "id": 19442893058196, 13 | "name": "xTestx Organization node-zendesk", 14 | "shared_tickets": false, 15 | "shared_comments": false, 16 | "external_id": "69420", 17 | "created_at": "2023-09-23T00:16:16Z", 18 | "updated_at": "2023-09-23T00:16:18Z", 19 | "domain_names": [], 20 | "details": null, 21 | "notes": "foo", 22 | "group_id": null, 23 | "tags": [], 24 | "organization_fields": {} 25 | } 26 | ], 27 | "next_page": null, 28 | "previous_page": null, 29 | "count": 1 30 | }, 31 | "rawHeaders": [ 32 | "Date", 33 | "Sat, 23 Sep 2023 00:16:18 GMT", 34 | "Content-Type", 35 | "application/json; charset=utf-8", 36 | "Transfer-Encoding", 37 | "chunked", 38 | "Connection", 39 | "close", 40 | "x-zendesk-api-version", 41 | "v2", 42 | "x-zendesk-application-version", 43 | "v18457", 44 | "x-frame-options", 45 | "SAMEORIGIN", 46 | "x-rate-limit", 47 | "700", 48 | "rate-limit", 49 | "700", 50 | "x-rate-limit-remaining", 51 | "683", 52 | "rate-limit-remaining", 53 | "683", 54 | "rate-limit-reset", 55 | "42", 56 | "strict-transport-security", 57 | "max-age=31536000; includeSubDomains", 58 | "etag", 59 | "W/\"e2378755ca72c07c855b1f0a1182df84\"", 60 | "cache-control", 61 | "max-age=0, private, must-revalidate", 62 | "set-cookie", 63 | "_zendesk_cookie=BAhJIhl7ImRldmljZV90b2tlbnMiOnt9fQY6BkVU--0bf2100788cb010d0183feca16aaf88ccaf719ca; path=/; expires=Mon, 23 Sep 2024 00:03:46 GMT; secure; HttpOnly; SameSite=None", 64 | "x-zendesk-origin-server", 65 | "classic-app-server-59c5666bb9-tvb76", 66 | "x-request-id", 67 | "80ae9922cbfbc6c5-SEA", 68 | "X-Request-ID", 69 | "80ae9922cbfbc6c5-SEA", 70 | "x-runtime", 71 | "0.104008", 72 | "X-Zendesk-Zorg", 73 | "yes", 74 | "CF-Cache-Status", 75 | "DYNAMIC", 76 | "Report-To", 77 | "{\"endpoints\":[{\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v3?s=WH7nlGoE%2BrXFJ6ANnEwOGyLimZqZu4UGpmUkovB6y9NWQUGx1fg7XtrAdJFOC86tIE8pJfrCp%2BPjeErOS1yqsKY1BGF6tO%2B%2BANezAli%2FSEEPhvC35jPEmjvOnU0VOsOvllEcD2nirA%3D%3D\"}],\"group\":\"cf-nel\",\"max_age\":604800}", 78 | "NEL", 79 | "{\"success_fraction\":0.01,\"report_to\":\"cf-nel\",\"max_age\":604800}", 80 | "Set-Cookie", 81 | "__cfruid=b0f212948dc69c5976618b752ed96a4ba426e1d0-1695428178; path=/; domain=.nodejsapi.zendesk.com; HttpOnly; Secure; SameSite=None", 82 | "Server", 83 | "cloudflare", 84 | "CF-RAY", 85 | "80ae9922cbfbc6c5-SEA" 86 | ], 87 | "responseIsBinary": false 88 | } 89 | ] -------------------------------------------------------------------------------- /test/fixtures/organizations_test_show_single.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "scope": "https://nodejsapi.zendesk.com:443", 4 | "method": "GET", 5 | "path": "/api/v2/organizations/19442893058196.json", 6 | "body": "", 7 | "status": 200, 8 | "response": { 9 | "organization": { 10 | "url": "https://nodejsapi.zendesk.com/api/v2/organizations/19442893058196.json", 11 | "id": 19442893058196, 12 | "name": "xTestx Organization node-zendesk", 13 | "shared_tickets": false, 14 | "shared_comments": false, 15 | "external_id": null, 16 | "created_at": "2023-09-23T00:16:16Z", 17 | "updated_at": "2023-09-23T00:16:16Z", 18 | "domain_names": [], 19 | "details": null, 20 | "notes": null, 21 | "group_id": null, 22 | "tags": [], 23 | "organization_fields": {} 24 | } 25 | }, 26 | "rawHeaders": [ 27 | "Date", 28 | "Sat, 23 Sep 2023 00:16:17 GMT", 29 | "Content-Type", 30 | "application/json; charset=utf-8", 31 | "Transfer-Encoding", 32 | "chunked", 33 | "Connection", 34 | "close", 35 | "x-zendesk-api-version", 36 | "v2", 37 | "x-zendesk-application-version", 38 | "v18457", 39 | "x-frame-options", 40 | "SAMEORIGIN", 41 | "x-rate-limit", 42 | "700", 43 | "rate-limit", 44 | "700", 45 | "x-rate-limit-remaining", 46 | "690", 47 | "rate-limit-remaining", 48 | "690", 49 | "rate-limit-reset", 50 | "43", 51 | "strict-transport-security", 52 | "max-age=31536000; includeSubDomains", 53 | "etag", 54 | "W/\"63ad5b78e8c602ac6573a8cf2fa664a9\"", 55 | "cache-control", 56 | "max-age=0, private, must-revalidate", 57 | "set-cookie", 58 | "_zendesk_cookie=BAhJIhl7ImRldmljZV90b2tlbnMiOnt9fQY6BkVU--0bf2100788cb010d0183feca16aaf88ccaf719ca; path=/; expires=Mon, 23 Sep 2024 00:03:33 GMT; secure; HttpOnly; SameSite=None", 59 | "x-zendesk-origin-server", 60 | "classic-app-server-59c5666bb9-qmrqp", 61 | "x-request-id", 62 | "80ae991f6913ec54-SEA", 63 | "X-Request-ID", 64 | "80ae991f6913ec54-SEA", 65 | "x-runtime", 66 | "0.100362", 67 | "X-Zendesk-Zorg", 68 | "yes", 69 | "CF-Cache-Status", 70 | "DYNAMIC", 71 | "Report-To", 72 | "{\"endpoints\":[{\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v3?s=cemIwmpAhUL8EHR5wcsMCmKdzKlm4LuiSmgmRDTyPbRLTo5CJ64gBUpELaaiTb%2FLckDI1IhS%2BMmlkmCU7HzlAmyUib%2B6EAzCIKIn6vgbzV8YyTzpJ4NEjN3nsOekz6vSD1zvATAW3g%3D%3D\"}],\"group\":\"cf-nel\",\"max_age\":604800}", 73 | "NEL", 74 | "{\"success_fraction\":0.01,\"report_to\":\"cf-nel\",\"max_age\":604800}", 75 | "Set-Cookie", 76 | "__cfruid=80bf5f8d9a0826d36ceb162e1c4f6557c9e7cbaf-1695428177; path=/; domain=.nodejsapi.zendesk.com; HttpOnly; Secure; SameSite=None", 77 | "Server", 78 | "cloudflare", 79 | "CF-RAY", 80 | "80ae991f6913ec54-SEA" 81 | ], 82 | "responseIsBinary": false 83 | } 84 | ] -------------------------------------------------------------------------------- /test/fixtures/organizations_test_update_organization.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "scope": "https://nodejsapi.zendesk.com:443", 4 | "method": "PUT", 5 | "path": "/api/v2/organizations/19442893058196.json", 6 | "body": { 7 | "organization": { 8 | "notes": "foo", 9 | "external_id": "69420" 10 | } 11 | }, 12 | "status": 200, 13 | "response": { 14 | "organization": { 15 | "url": "https://nodejsapi.zendesk.com/api/v2/organizations/19442893058196.json", 16 | "id": 19442893058196, 17 | "name": "xTestx Organization node-zendesk", 18 | "shared_tickets": false, 19 | "shared_comments": false, 20 | "external_id": "69420", 21 | "created_at": "2023-09-23T00:16:16Z", 22 | "updated_at": "2023-09-23T00:16:18Z", 23 | "domain_names": [], 24 | "details": null, 25 | "notes": "foo", 26 | "group_id": null, 27 | "tags": [], 28 | "organization_fields": {} 29 | } 30 | }, 31 | "rawHeaders": [ 32 | "Date", 33 | "Sat, 23 Sep 2023 00:16:18 GMT", 34 | "Content-Type", 35 | "application/json; charset=utf-8", 36 | "Transfer-Encoding", 37 | "chunked", 38 | "Connection", 39 | "close", 40 | "x-zendesk-api-version", 41 | "v2", 42 | "x-zendesk-application-version", 43 | "v18457", 44 | "x-frame-options", 45 | "SAMEORIGIN", 46 | "x-rate-limit", 47 | "700", 48 | "rate-limit", 49 | "700", 50 | "x-rate-limit-remaining", 51 | "687", 52 | "rate-limit-remaining", 53 | "687", 54 | "rate-limit-reset", 55 | "42", 56 | "strict-transport-security", 57 | "max-age=31536000; includeSubDomains", 58 | "etag", 59 | "W/\"78912b012399d683537697c21e092cdd\"", 60 | "cache-control", 61 | "max-age=0, private, must-revalidate", 62 | "set-cookie", 63 | "_zendesk_cookie=BAhJIhl7ImRldmljZV90b2tlbnMiOnt9fQY6BkVU--0bf2100788cb010d0183feca16aaf88ccaf719ca; path=/; expires=Sun, 22 Sep 2024 07:06:30 GMT; secure; HttpOnly; SameSite=None", 64 | "x-zendesk-origin-server", 65 | "classic-app-server-59c5666bb9-tthft", 66 | "x-request-id", 67 | "80ae99210c61ec88-SEA", 68 | "X-Request-ID", 69 | "80ae99210c61ec88-SEA", 70 | "x-runtime", 71 | "0.096281", 72 | "X-Zendesk-Zorg", 73 | "yes", 74 | "CF-Cache-Status", 75 | "DYNAMIC", 76 | "Report-To", 77 | "{\"endpoints\":[{\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v3?s=mKmwHYlqXdZSGUe5xHdrDUAmdc6Ao3NQ4CiDBGhB0aX6d7NvAjgtS5%2BavYpvtg89ofY93Nm30xD30czonWPZweokSO%2FRnipBGfhsChYYatF67ExjxhyuuTZk13GBvGFZxKY4xIngAA%3D%3D\"}],\"group\":\"cf-nel\",\"max_age\":604800}", 78 | "NEL", 79 | "{\"success_fraction\":0.01,\"report_to\":\"cf-nel\",\"max_age\":604800}", 80 | "Set-Cookie", 81 | "__cfruid=b0f212948dc69c5976618b752ed96a4ba426e1d0-1695428178; path=/; domain=.nodejsapi.zendesk.com; HttpOnly; Secure; SameSite=None", 82 | "Server", 83 | "cloudflare", 84 | "CF-RAY", 85 | "80ae99210c61ec88-SEA" 86 | ], 87 | "responseIsBinary": false 88 | } 89 | ] -------------------------------------------------------------------------------- /test/fixtures/webhooks_endpoint.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "scope": "https://nodejsapi.zendesk.com:443", 4 | "method": "POST", 5 | "path": "/api/v2/webhooks", 6 | "status": 201, 7 | "response": { 8 | "id": 19442893058196 9 | }, 10 | "responseIsBinary": false 11 | } 12 | ] -------------------------------------------------------------------------------- /test/job-runner.js: -------------------------------------------------------------------------------- 1 | import {expect} from 'vitest'; 2 | 3 | class JobInitiator { 4 | async initiate(initiateFunction) { 5 | const {result} = await initiateFunction(); 6 | return result; 7 | } 8 | } 9 | 10 | class JobStatusVerifier { 11 | verifyInitialStatus(result) { 12 | expect(result.job_status).toHaveProperty('id'); 13 | expect(result.job_status.status).toBe('queued'); 14 | } 15 | 16 | verifyFinalStatus(finalJobResults) { 17 | expect(finalJobResults.status).toBe('completed'); 18 | } 19 | } 20 | 21 | class JobWatcher { 22 | constructor(client) { 23 | this.client = client; 24 | } 25 | 26 | async watch(jobStatusId) { 27 | return this.client.jobstatuses.watch(jobStatusId, 1000, 30); 28 | } 29 | } 30 | 31 | export class JobRunner { 32 | constructor(client) { 33 | this.client = client; 34 | this.initiator = new JobInitiator(); 35 | this.verifier = new JobStatusVerifier(); 36 | this.watcher = new JobWatcher(client); 37 | } 38 | 39 | async run(initiateFunction, validateJobDetails) { 40 | const result = await this.initiator.initiate(initiateFunction); 41 | 42 | this.verifier.verifyInitialStatus(result); 43 | 44 | const finalJobResults = await this.watcher.watch(result.job_status.id); 45 | 46 | this.verifier.verifyFinalStatus(finalJobResults); 47 | 48 | await validateJobDetails(finalJobResults); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /test/pagination.test.js: -------------------------------------------------------------------------------- 1 | import path from 'node:path'; 2 | import dotenv from 'dotenv'; 3 | import {beforeAll, afterAll, describe, expect, it} from 'vitest'; 4 | import {back as nockBack} from 'nock'; 5 | import {setupClient} from './setup.js'; 6 | 7 | dotenv.config(); 8 | 9 | describe('Zendesk Client Pagination', () => { 10 | const testOrganizations = []; 11 | 12 | const uniqueOrgName = (iteration) => 13 | `Test Organization ${('The Quick Brown Foxx' + iteration).toString('hex')}`; 14 | 15 | const defaultClient = setupClient(); 16 | 17 | /** 18 | * Creates a test organization based on the given iteration. 19 | * @param {number} iteration - The iteration number used to generate a unique organization name. 20 | */ 21 | async function createTestOrganization(iteration) { 22 | const {result: organization} = await defaultClient.organizations.create({ 23 | organization: {name: uniqueOrgName(iteration)}, 24 | }); 25 | testOrganizations.push(organization); 26 | } 27 | 28 | beforeAll(async () => { 29 | nockBack.setMode('record'); 30 | nockBack.fixtures = path.join(__dirname, '/fixtures'); 31 | const {nockDone} = await nockBack('pagination_test_setup.json'); 32 | await Promise.all([createTestOrganization(1), createTestOrganization(2)]); 33 | nockDone(); 34 | }); 35 | 36 | it( 37 | 'should fetch all test items even with pagination applied/forced', 38 | async () => { 39 | const {nockDone} = await nockBack('pagination_test_execute.json'); 40 | const paginatedClient = setupClient({query: {page: {size: 1}}}); 41 | const organizations = await paginatedClient.organizations.list(); 42 | const orgNames = organizations.map((org) => org.name); 43 | 44 | for (const testOrg of testOrganizations) { 45 | expect(orgNames).toContain(testOrg.name); 46 | } 47 | 48 | nockDone(); 49 | }, 50 | {timeout: 20_000}, 51 | ); 52 | 53 | afterAll(async () => { 54 | const {nockDone} = await nockBack('pagination_test_cleanup.json'); 55 | await Promise.all( 56 | testOrganizations.map((org) => 57 | defaultClient.organizations.delete(org.id), 58 | ), 59 | ); 60 | nockDone(); 61 | }); 62 | }); 63 | -------------------------------------------------------------------------------- /test/setup.js: -------------------------------------------------------------------------------- 1 | // Setup.js 2 | 3 | import process from 'node:process'; 4 | import dotenv from 'dotenv'; 5 | import {createClient} from '../src/index.js'; 6 | 7 | dotenv.config({ 8 | path: '.env.test', 9 | }); 10 | 11 | const {ZENDESK_USERNAME, ZENDESK_SUBDOMAIN, ZENDESK_PASSWORD, ZENDESK_TOKEN} = 12 | process.env; 13 | 14 | export const generateOrganizationName = (id) => { 15 | return `Test Organization ${id}`; 16 | }; 17 | 18 | export const generateMultipleOrganizations = (n) => { 19 | const organizations = []; 20 | for (let i = 0; i < n; i++) { 21 | organizations.push({ 22 | name: generateOrganizationName(i), 23 | }); 24 | } 25 | 26 | return organizations; 27 | }; 28 | 29 | export const initializeClient = (config) => { 30 | return createClient({ 31 | username: ZENDESK_USERNAME, 32 | subdomain: ZENDESK_SUBDOMAIN, 33 | ...config, 34 | }); 35 | }; 36 | 37 | /** 38 | * 39 | * @param {import('../src/clients/client').ClientOptions} config - The SetupClient config 40 | * @returns {import('../src/clients/client').ZendeskClient} - The Zendesk Client 41 | */ 42 | export const setupClient = (config = {}) => 43 | createClient({ 44 | username: ZENDESK_USERNAME, 45 | subdomain: ZENDESK_SUBDOMAIN, 46 | password: ZENDESK_PASSWORD, 47 | token: ZENDESK_TOKEN, 48 | ...config, 49 | }); 50 | -------------------------------------------------------------------------------- /test/webhooks.test.js: -------------------------------------------------------------------------------- 1 | import path from 'node:path'; 2 | import dotenv from 'dotenv'; 3 | import {back as nockBack} from 'nock'; 4 | import {beforeAll, describe, expect, it} from 'vitest'; 5 | import {setupClient} from './setup.js'; 6 | 7 | dotenv.config(); 8 | 9 | describe('Zendesk Client Webhooks', () => { 10 | const client = setupClient(); 11 | 12 | beforeAll(async () => { 13 | nockBack.setMode('record'); 14 | nockBack.fixtures = path.join(__dirname, '/fixtures'); 15 | }); 16 | 17 | it('should call endpoint without .json', async () => { 18 | const {nockDone} = await nockBack('webhooks_endpoint.json'); 19 | const {result} = await client.webhooks.create({ 20 | webhook: { 21 | name: `Web Hulk`, 22 | endpoint: 'noop://noop', 23 | http_method: 'POST', 24 | request_format: 'json', 25 | status: 'active', 26 | subscriptions: ['conditional_ticket_events'], 27 | }, 28 | }); 29 | nockDone(); 30 | 31 | expect(result.id).toBeDefined(); 32 | }); 33 | }); 34 | --------------------------------------------------------------------------------