├── .github ├── FUNDING.yml ├── dependabot.yml └── workflows │ ├── os-test.yml │ ├── check-dist.yml │ ├── codeql-analysis.yml │ └── test.yml ├── .prettierignore ├── .gitattributes ├── .eslintignore ├── __tests__ ├── data │ └── content-only.json └── webhook.test.ts ├── .prettierrc.json ├── jest.config.cjs ├── tsconfig.json ├── LICENSE ├── package.json ├── .gitignore ├── lib └── discord │ └── webhook.ts ├── .eslintrc.json ├── action.yml ├── src └── action.ts ├── README.md └── dist ├── licenses.txt └── sourcemap-register.js /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [tsickert] 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | lib/ 3 | node_modules/ -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | dist/** -diff linguist-generated=true -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | lib/ 3 | node_modules/ 4 | jest.config.cjs 5 | -------------------------------------------------------------------------------- /__tests__/data/content-only.json: -------------------------------------------------------------------------------- 1 | { 2 | "content": "Content-only `rawdata` test" 3 | } 4 | -------------------------------------------------------------------------------- /__tests__/webhook.test.ts: -------------------------------------------------------------------------------- 1 | import {expect, test} from '@jest/globals' 2 | 3 | test('fails with missing URL', async () => { 4 | expect(true).toBe(true) 5 | }) 6 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 80, 3 | "tabWidth": 2, 4 | "useTabs": false, 5 | "semi": false, 6 | "singleQuote": true, 7 | "trailingComma": "none", 8 | "bracketSpacing": false, 9 | "arrowParens": "avoid" 10 | } 11 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: github-actions 4 | directory: / 5 | schedule: 6 | interval: daily 7 | 8 | - package-ecosystem: npm 9 | directory: / 10 | schedule: 11 | interval: daily 12 | -------------------------------------------------------------------------------- /jest.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | clearMocks: true, 3 | moduleFileExtensions: ['js', 'ts'], 4 | testMatch: ['**/*.test.ts'], 5 | transform: { 6 | '^.+\\.ts$': 'ts-jest' 7 | }, 8 | transformIgnorePatterns: [ 9 | 'node_modules/(?!(axios)/)' 10 | ], 11 | verbose: true 12 | } 13 | -------------------------------------------------------------------------------- /.github/workflows/os-test.yml: -------------------------------------------------------------------------------- 1 | name: Runs on All Action Runners 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: 7 | - main 8 | - 'releases/*' 9 | workflow_dispatch: 10 | 11 | jobs: 12 | test: # make sure the action works on a clean machine without building 13 | strategy: 14 | max-parallel: 2 15 | matrix: 16 | os: 17 | - windows-latest 18 | - windows-2022 19 | - windows-2019 20 | - ubuntu-22.04 21 | - ubuntu-20.04 22 | - macos-12 23 | - macos-11 24 | runs-on: ${{ matrix.os }} 25 | steps: 26 | - uses: actions/checkout@v4 27 | - name: Upload File 28 | uses: ./ 29 | with: 30 | webhook-url: ${{ secrets.WEBHOOK_URL }} 31 | filename: __tests__/data/content-only.json 32 | username: OS Tester (${{ matrix.os }}) 33 | content: You should definitely be able to do this 34 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2017", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */ 4 | "module": "es2022", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ 5 | "moduleResolution": "node", 6 | "outDir": "./build", /* Redirect output structure to the directory. */ 7 | "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 8 | "strict": true, /* Enable all strict type-checking options. */ 9 | "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ 10 | "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ 11 | }, 12 | "include": ["./src/**/*", "./lib/**/*"] 13 | } 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2018 GitHub, Inc. and contributors 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "discord-webhook", 3 | "version": "6.0.0", 4 | "private": true, 5 | "description": "Send discord webhooks via GitHub Actions!", 6 | "main": "build/src/action.js", 7 | "scripts": { 8 | "build": "tsc", 9 | "watch": "tsc --watch", 10 | "format": "prettier --write '**/*.ts'", 11 | "format-check": "prettier --check '**/*.ts'", 12 | "lint": "eslint src/**/*.ts", 13 | "package": "ncc build --source-map --license licenses.txt", 14 | "test": "jest", 15 | "all": "npm run build && npm run format && npm run lint && npm run package && npm test" 16 | }, 17 | "repository": { 18 | "type": "git", 19 | "url": "git+https://github.com/actions/discord-webhook.git" 20 | }, 21 | "keywords": [ 22 | "actions", 23 | "node", 24 | "setup" 25 | ], 26 | "author": "", 27 | "license": "MIT", 28 | "dependencies": { 29 | "@actions/core": "^1.6.0", 30 | "@actions/http-client": "^2.0.1", 31 | "axios": "^1.6.8", 32 | "form-data": "^4.0.0" 33 | }, 34 | "devDependencies": { 35 | "@types/jest": "^27.5.2", 36 | "@types/node": "^18.7.8", 37 | "@typescript-eslint/eslint-plugin": "^5.33.1", 38 | "@typescript-eslint/parser": "^5.33.1", 39 | "@vercel/ncc": "^0.34.0", 40 | "eslint": "^7.32.0", 41 | "eslint-plugin-github": "^4.3.2", 42 | "eslint-plugin-jest": "^25.3.2", 43 | "jest": "^27.2.5", 44 | "js-yaml": "^4.1.0", 45 | "prettier": "2.7.1", 46 | "ts-jest": "^27.1.2", 47 | "typescript": "^4.7.4" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /.github/workflows/check-dist.yml: -------------------------------------------------------------------------------- 1 | # `dist/index.js` is a special file in Actions. 2 | # When you reference an action with `uses:` in a workflow, 3 | # `index.js` is the code that will run. 4 | # For our project, we generate this file through a build process from other source files. 5 | # We need to make sure the checked-in `index.js` actually matches what we expect it to be. 6 | name: Check dist/ 7 | 8 | on: 9 | push: 10 | branches: 11 | - main 12 | paths-ignore: 13 | - '**.md' 14 | pull_request: 15 | paths-ignore: 16 | - '**.md' 17 | workflow_dispatch: 18 | 19 | jobs: 20 | check-dist: 21 | runs-on: ubuntu-latest 22 | 23 | steps: 24 | - uses: actions/checkout@v4 25 | 26 | - name: Set Node.js 20.x 27 | uses: actions/setup-node@v4.0.2 28 | with: 29 | node-version: 20.x 30 | 31 | - name: Install dependencies 32 | run: npm ci 33 | 34 | - name: Rebuild the dist/ directory 35 | run: | 36 | npm run build 37 | npm run package 38 | 39 | - name: Compare the expected and actual dist/ directories 40 | run: | 41 | if [ "$(git diff --ignore-space-at-eol dist/ | wc -l)" -gt "0" ]; then 42 | echo "Detected uncommitted changes after build. See status below:" 43 | git diff 44 | exit 1 45 | fi 46 | id: diff 47 | 48 | # If index.js was different than expected, upload the expected version as an artifact 49 | - uses: actions/upload-artifact@v4 50 | if: ${{ failure() && steps.diff.conclusion == 'failure' }} 51 | with: 52 | name: dist 53 | path: dist/ 54 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Dependency directory 2 | node_modules 3 | 4 | # Rest pulled from https://github.com/github/gitignore/blob/master/Node.gitignore 5 | # Logs 6 | logs 7 | *.log 8 | npm-debug.log* 9 | yarn-debug.log* 10 | yarn-error.log* 11 | lerna-debug.log* 12 | 13 | # Diagnostic reports (https://nodejs.org/api/report.html) 14 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 15 | 16 | # Runtime data 17 | pids 18 | *.pid 19 | *.seed 20 | *.pid.lock 21 | 22 | # Directory for instrumented libs generated by jscoverage/JSCover 23 | lib-cov 24 | 25 | # Coverage directory used by tools like istanbul 26 | coverage 27 | *.lcov 28 | 29 | # nyc test coverage 30 | .nyc_output 31 | 32 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 33 | .grunt 34 | 35 | # Bower dependency directory (https://bower.io/) 36 | bower_components 37 | 38 | # node-waf configuration 39 | .lock-wscript 40 | 41 | # Compiled binary addons (https://nodejs.org/api/addons.html) 42 | build/Release 43 | 44 | # Dependency directories 45 | jspm_packages/ 46 | 47 | # TypeScript v1 declaration files 48 | typings/ 49 | 50 | # TypeScript cache 51 | *.tsbuildinfo 52 | 53 | # Optional npm cache directory 54 | .npm 55 | 56 | # Optional eslint cache 57 | .eslintcache 58 | 59 | # Optional REPL history 60 | .node_repl_history 61 | 62 | # Output of 'npm pack' 63 | *.tgz 64 | 65 | # Yarn Integrity file 66 | .yarn-integrity 67 | 68 | # dotenv environment variables file 69 | .env 70 | .env.test 71 | 72 | # parcel-bundler cache (https://parceljs.org/) 73 | .cache 74 | 75 | # next.js build output 76 | .next 77 | 78 | # nuxt.js build output 79 | .nuxt 80 | 81 | # vuepress build output 82 | .vuepress/dist 83 | 84 | # Serverless directories 85 | .serverless/ 86 | 87 | # FuseBox cache 88 | .fusebox/ 89 | 90 | # DynamoDB Local files 91 | .dynamodb/ 92 | 93 | # OS metadata 94 | .DS_Store 95 | Thumbs.db 96 | 97 | # Ignore built ts files 98 | __tests__/runner/* 99 | build 100 | 101 | # JetBrains 102 | .idea 103 | *.iml 104 | 105 | *.history 106 | -------------------------------------------------------------------------------- /lib/discord/webhook.ts: -------------------------------------------------------------------------------- 1 | import {blob} from 'node:stream/consumers' 2 | import {createReadStream} from 'fs' 3 | import axios from 'axios' 4 | import * as core from '@actions/core' 5 | import {TypedResponse} from '@actions/http-client/lib/interfaces' 6 | import {HttpClient} from '@actions/http-client' 7 | import path from 'node:path' 8 | 9 | const client = new HttpClient() 10 | 11 | async function handleResponse(response: TypedResponse): Promise { 12 | core.info( 13 | `Webhook returned ${response.statusCode} with message: ${response.result}. Please see discord documentation at https://discord.com/developers/docs/resources/webhook#execute-webhook for more information` 14 | ) 15 | if (response.statusCode >= 400) { 16 | core.error( 17 | 'Discord Webhook Action failed to execute webhook. Please see logs above for details. Error printed below:' 18 | ) 19 | core.error(JSON.stringify(response)) 20 | } 21 | } 22 | 23 | export async function executeWebhook( 24 | webhookUrl: string, 25 | threadId: string, 26 | filePath: string, 27 | wait: boolean, 28 | payload: unknown): Promise { 29 | 30 | if (threadId !== '') { 31 | webhookUrl = `${webhookUrl}?thread_id=${threadId}` 32 | } 33 | 34 | if (wait) { 35 | if (webhookUrl.includes('?')) { 36 | webhookUrl = `${webhookUrl}&wait=true` 37 | } else { 38 | webhookUrl = `${webhookUrl}?wait=true` 39 | } 40 | } 41 | 42 | if (filePath !== '') { 43 | const formData = new FormData() 44 | const fileName = path.basename(filePath); 45 | formData.append('upload-file', await blob(createReadStream(filePath)), fileName) 46 | formData.append('payload_json', JSON.stringify(payload)) 47 | 48 | const response = await axios({ 49 | method: 'POST', 50 | url: webhookUrl, 51 | data: formData, 52 | headers: { 53 | 'Content-Type': 'multipart/form-data' 54 | } 55 | }) 56 | 57 | if (response.status !== 200) { 58 | if (filePath !== '') { 59 | core.error(`failed to upload file: ${response.statusText}`) 60 | } 61 | } else if (filePath !== '') { 62 | core.info( 63 | `successfully uploaded file with status code: ${response.status}` 64 | ) 65 | } 66 | } else { 67 | const response = await client.postJson(webhookUrl, payload) 68 | await handleResponse(response) 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | workflow_dispatch: 16 | push: 17 | branches: [ main ] 18 | pull_request: 19 | # The branches below must be a subset of the branches above 20 | branches: [ main ] 21 | schedule: 22 | - cron: '31 7 * * 3' 23 | 24 | jobs: 25 | analyze: 26 | name: Analyze 27 | runs-on: ubuntu-latest 28 | permissions: 29 | actions: read 30 | contents: read 31 | security-events: write 32 | 33 | strategy: 34 | fail-fast: false 35 | matrix: 36 | language: [ 'TypeScript' ] 37 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 38 | # Learn more about CodeQL language support at https://git.io/codeql-language-support 39 | 40 | steps: 41 | - name: Checkout repository 42 | uses: actions/checkout@v4 43 | 44 | # Initializes the CodeQL tools for scanning. 45 | - name: Initialize CodeQL 46 | uses: github/codeql-action/init@v3 47 | with: 48 | languages: ${{ matrix.language }} 49 | source-root: src 50 | # If you wish to specify custom queries, you can do so here or in a config file. 51 | # By default, queries listed here will override any specified in a config file. 52 | # Prefix the list here with "+" to use these queries and those in the config file. 53 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 54 | 55 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 56 | # If this step fails, then you should remove it and run the build manually (see below) 57 | - name: Autobuild 58 | uses: github/codeql-action/autobuild@v3 59 | 60 | # ℹ️ Command-line programs to run using the OS shell. 61 | # 📚 https://git.io/JvXDl 62 | 63 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 64 | # and modify them (or add more) to build your code if your project 65 | # uses a compiled language 66 | 67 | #- run: | 68 | # make bootstrap 69 | # make release 70 | 71 | - name: Perform CodeQL Analysis 72 | uses: github/codeql-action/analyze@v3 73 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["jest", "@typescript-eslint"], 3 | "extends": ["plugin:github/recommended"], 4 | "parser": "@typescript-eslint/parser", 5 | "parserOptions": { 6 | "ecmaVersion": 9, 7 | "sourceType": "module", 8 | "project": "./tsconfig.json" 9 | }, 10 | "rules": { 11 | "i18n-text/no-en": "off", 12 | "eslint-comments/no-use": "off", 13 | "import/no-namespace": "off", 14 | "no-unused-vars": "off", 15 | "sort-imports": "off", 16 | "@typescript-eslint/no-unused-vars": "error", 17 | "@typescript-eslint/explicit-member-accessibility": ["error", {"accessibility": "no-public"}], 18 | "@typescript-eslint/no-require-imports": "error", 19 | "@typescript-eslint/array-type": "error", 20 | "@typescript-eslint/await-thenable": "error", 21 | "@typescript-eslint/ban-ts-comment": "error", 22 | "camelcase": "off", 23 | "@typescript-eslint/consistent-type-assertions": "error", 24 | "@typescript-eslint/explicit-function-return-type": ["error", {"allowExpressions": true}], 25 | "@typescript-eslint/func-call-spacing": ["error", "never"], 26 | "@typescript-eslint/no-array-constructor": "error", 27 | "@typescript-eslint/no-empty-interface": "error", 28 | "@typescript-eslint/no-explicit-any": "error", 29 | "@typescript-eslint/no-extraneous-class": "error", 30 | "@typescript-eslint/no-for-in-array": "error", 31 | "@typescript-eslint/no-inferrable-types": "error", 32 | "@typescript-eslint/no-misused-new": "error", 33 | "@typescript-eslint/no-namespace": "error", 34 | "@typescript-eslint/no-non-null-assertion": "warn", 35 | "@typescript-eslint/no-unnecessary-qualifier": "error", 36 | "@typescript-eslint/no-unnecessary-type-assertion": "error", 37 | "@typescript-eslint/no-useless-constructor": "error", 38 | "@typescript-eslint/no-var-requires": "error", 39 | "@typescript-eslint/prefer-for-of": "warn", 40 | "@typescript-eslint/prefer-function-type": "warn", 41 | "@typescript-eslint/prefer-includes": "error", 42 | "@typescript-eslint/prefer-string-starts-ends-with": "error", 43 | "@typescript-eslint/promise-function-async": "error", 44 | "@typescript-eslint/require-array-sort-compare": "error", 45 | "@typescript-eslint/restrict-plus-operands": "error", 46 | "semi": "off", 47 | "@typescript-eslint/semi": ["error", "never"], 48 | "@typescript-eslint/type-annotation-spacing": "error", 49 | "@typescript-eslint/unbound-method": "error" 50 | }, 51 | "env": { 52 | "node": true, 53 | "es6": true, 54 | "jest/globals": true 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | # action.yml 2 | name: 'Discord Webhook Action' 3 | description: 'Send custom messages or upload files to discord webhooks with simple action inputs.' 4 | branding: 5 | icon: message-square 6 | color: purple 7 | inputs: 8 | webhook-url: 9 | description: 'Webhook URL from discord. See: https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks for details' 10 | required: true 11 | content: 12 | description: 'Message that is sent via the webhook.' 13 | required: false 14 | thread-id: 15 | description: 'ID of the thread you want the webhook to send the message into (will automatically unarchive threads)' 16 | required: false 17 | thread-name: 18 | description: 'Name of the thread you want the webhook to create' 19 | required: false 20 | flags: 21 | description: 'Message flags' 22 | required: false 23 | wait: 24 | description: 'Whether Discord should wait for confirmation of message send before responding to the webhook request' 25 | required: false 26 | default: "true" 27 | username: 28 | description: 'The username that should appear to send the message. Note: username will have the "bot" badge next to their name.' 29 | required: false 30 | avatar-url: 31 | description: 'URL for the avatar that should appear with the message.' 32 | required: false 33 | tts: 34 | description: 'Boolean to indicate whether the webhook is text-to-speech' 35 | required: false 36 | raw-data: 37 | description: 'Name of a json file that will be sent as the data for the webhook' 38 | required: false 39 | filename: 40 | description: 'Name of a file that will be uploaded via the webhook' 41 | required: false 42 | embed-title: 43 | description: 'Embed title' 44 | required: false 45 | embed-url: 46 | description: 'Embed URL' 47 | required: false 48 | embed-description: 49 | description: 'Embed description' 50 | required: false 51 | embed-timestamp: 52 | description: 'Embed timestamp (ISO8601 format)' 53 | required: false 54 | embed-color: 55 | description: 'Embed color (integer)' 56 | required: false 57 | embed-footer-text: 58 | description: 'Embed footer text' 59 | required: false 60 | embed-footer-icon-url: 61 | description: 'Embed footer icon url' 62 | required: false 63 | embed-image-url: 64 | description: 'Embed image url' 65 | required: false 66 | embed-thumbnail-url: 67 | description: 'Embed thumbnail url' 68 | required: false 69 | embed-author-name: 70 | description: 'Embed embed author name' 71 | required: false 72 | embed-author-url: 73 | description: 'Embed author url' 74 | required: false 75 | embed-author-icon-url: 76 | description: 'Embed author icon' 77 | required: false 78 | runs: 79 | using: 'node20' 80 | main: 'dist/index.js' 81 | -------------------------------------------------------------------------------- /src/action.ts: -------------------------------------------------------------------------------- 1 | import * as core from '@actions/core' 2 | import {executeWebhook} from '../lib/discord/webhook' 3 | import {readFileSync} from 'fs' 4 | 5 | const WEBHOOK_URL = 'webhook-url' 6 | const CONTENT = 'content' 7 | const USERNAME = 'username' 8 | const AVATAR_URL = 'avatar-url' 9 | const RAW_DATA = 'raw-data' 10 | const TITLE = 'title' 11 | const DESCRIPTION = 'description' 12 | const TIMESTAMP = 'timestamp' 13 | const COLOR = 'color' 14 | const NAME = 'name' 15 | const URL = 'url' 16 | const ICON_URL = 'icon-url' 17 | const TEXT = 'text' 18 | const FILENAME = 'filename' 19 | const THREAD_ID = 'thread-id' 20 | const THREAD_NAME = 'thread-name' 21 | const FLAGS = 'flags' 22 | const WAIT = 'wait' 23 | 24 | const TOP_LEVEL_WEBHOOK_KEYS = [ 25 | CONTENT, 26 | USERNAME, 27 | AVATAR_URL, 28 | FLAGS, 29 | THREAD_NAME 30 | ] 31 | const EMBED_KEYS = [TITLE, DESCRIPTION, TIMESTAMP, COLOR, URL] 32 | const EMBED_AUTHOR_KEYS = [NAME, URL, ICON_URL] 33 | const EMBED_FOOTER_KEYS = [TEXT, ICON_URL] 34 | const EMBED_IMAGE_KEYS = [URL] 35 | const EMBED_THUMBNAIL_KEYS = [URL] 36 | 37 | const DESCRIPTION_LIMIT = 4096 38 | 39 | function createPayload(): Record { 40 | // If raw-data provided, load the file and ignore the other parameters 41 | const rawData = core.getInput(RAW_DATA) 42 | if (rawData.length > 0) { 43 | return JSON.parse(readFileSync(rawData, 'utf-8')) 44 | } 45 | 46 | const webhookPayloadMap = parseMapFromParameters(TOP_LEVEL_WEBHOOK_KEYS) 47 | const embedPayloadMap = createEmbedObject() 48 | if (embedPayloadMap.size > 0) { 49 | webhookPayloadMap.set('embeds', [Object.fromEntries(embedPayloadMap)]) 50 | } 51 | const webhookPayload = Object.fromEntries(webhookPayloadMap) 52 | core.info(JSON.stringify(webhookPayload)) 53 | return webhookPayload 54 | } 55 | 56 | function createEmbedObject(): Map { 57 | const embedPayloadMap = parseMapFromParameters(EMBED_KEYS, 'embed') 58 | 59 | if (embedPayloadMap.size > 0) { 60 | const embedAuthorMap = parseMapFromParameters( 61 | EMBED_AUTHOR_KEYS, 62 | 'embed-author' 63 | ) 64 | if (embedAuthorMap.size > 0) { 65 | embedPayloadMap.set('author', Object.fromEntries(embedAuthorMap)) 66 | } 67 | const embedFooterMap = parseMapFromParameters( 68 | EMBED_FOOTER_KEYS, 69 | 'embed-footer' 70 | ) 71 | if (embedFooterMap.size > 0) { 72 | embedPayloadMap.set('footer', Object.fromEntries(embedFooterMap)) 73 | } 74 | const embedImageMap = parseMapFromParameters( 75 | EMBED_IMAGE_KEYS, 76 | 'embed-image' 77 | ) 78 | if (embedImageMap.size > 0) { 79 | embedPayloadMap.set('image', Object.fromEntries(embedImageMap)) 80 | } 81 | const embedThumbnailMap = parseMapFromParameters( 82 | EMBED_THUMBNAIL_KEYS, 83 | 'embed-thumbnail' 84 | ) 85 | if (embedThumbnailMap.size > 0) { 86 | embedPayloadMap.set('thumbnail', Object.fromEntries(embedThumbnailMap)) 87 | } 88 | } 89 | 90 | return embedPayloadMap 91 | } 92 | 93 | function parseMapFromParameters( 94 | parameters: string[], 95 | inputObjectKey = '' 96 | ): Map { 97 | // Parse action inputs into discord webhook execute payload 98 | const parameterMap = new Map() 99 | core.info(`inputObjectKey: ${inputObjectKey}`) 100 | 101 | for (const parameter of parameters) { 102 | const inputKey = 103 | inputObjectKey !== '' ? `${inputObjectKey}-${parameter}` : parameter 104 | let value = core.getInput(inputKey) 105 | if (value === '') { 106 | continue 107 | } 108 | 109 | if (parameter === TIMESTAMP) { 110 | const parsedDate = new Date(value) 111 | value = parsedDate.toISOString() 112 | } 113 | 114 | if (parameter === DESCRIPTION) { 115 | if (value.length > DESCRIPTION_LIMIT) { 116 | value = value.substring(0, DESCRIPTION_LIMIT) 117 | } 118 | } 119 | 120 | core.info(`${inputKey}: ${value}`) 121 | if (value.length > 0) parameterMap.set(parameter.replace('-', '_'), value) 122 | } 123 | 124 | return parameterMap 125 | } 126 | 127 | async function run(): Promise { 128 | const webhookUrl = core.getInput(WEBHOOK_URL) 129 | const filename = core.getInput(FILENAME) 130 | const threadId = core.getInput(THREAD_ID) 131 | const wait = core.getBooleanInput(WAIT) 132 | const payload = createPayload() 133 | try { 134 | core.info('Running discord webhook action...') 135 | await executeWebhook(webhookUrl, threadId, filename, wait, payload) 136 | } catch (error) { 137 | if (error instanceof Error) core.setFailed(error.message) 138 | } 139 | } 140 | 141 | run() 142 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: "Build + Test" 2 | on: 3 | pull_request: 4 | push: 5 | branches: 6 | - main 7 | - 'releases/*' 8 | workflow_dispatch: 9 | 10 | jobs: 11 | build: # make sure build/ci work properly 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v4 15 | - run: | 16 | npm install 17 | - run: | 18 | npm run all 19 | test: # make sure the action works on a clean machine without building 20 | runs-on: ubuntu-latest 21 | steps: 22 | - uses: actions/checkout@v4 23 | - name: Basic Content Test 24 | uses: ./ 25 | with: 26 | webhook-url: ${{ secrets.WEBHOOK_URL }} 27 | content: test 28 | - name: Test `@ping` 29 | uses: ./ 30 | with: 31 | webhook-url: ${{ secrets.WEBHOOK_URL }} 32 | content: Hey there <@211894927997534208> 33 | - name: Test with JSON Payload Provided 34 | uses: ./ 35 | with: 36 | webhook-url: ${{ secrets.WEBHOOK_URL }} 37 | raw-data: __tests__/data/content-only.json 38 | - name: Upload File 39 | uses: ./ 40 | with: 41 | webhook-url: ${{ secrets.WEBHOOK_URL }} 42 | filename: __tests__/data/content-only.json 43 | username: Bill 44 | content: You should definitely be able to do this 45 | avatar-url: https://cdn.discordapp.com/avatars/742807869023322232/dd41912939ffccbea0276f70688fa0ec.webp?size=256 46 | - name: Discord Webhook Action With Embed 47 | uses: ./ 48 | with: 49 | webhook-url: ${{ secrets.WEBHOOK_URL }} 50 | username: Bill 51 | avatar-url: https://cdn.discordapp.com/avatars/742807869023322232/dd41912939ffccbea0276f70688fa0ec.webp?size=256 52 | embed-title: "Foo" 53 | embed-url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ" 54 | embed-description: "Bar [test](https://google.com)" 55 | embed-author-name: "Bill" 56 | embed-author-icon-url: "https://cdn.discordapp.com/avatars/742807869023322232/dd41912939ffccbea0276f70688fa0ec.webp?size=256" 57 | embed-author-url: "https://google.com" 58 | embed-thumbnail-url: "https://cdn.discordapp.com/avatars/742807869023322232/dd41912939ffccbea0276f70688fa0ec.webp?size=256" 59 | embed-image-url: "https://cdn.discordapp.com/avatars/742807869023322232/dd41912939ffccbea0276f70688fa0ec.webp?size=256" 60 | embed-footer-icon-url: "https://cdn.discordapp.com/avatars/742807869023322232/dd41912939ffccbea0276f70688fa0ec.webp?size=256" 61 | embed-footer-text: "Foot text [test](https://google.com)" 62 | embed-color: 15430476 63 | embed-timestamp: "2021-09-24T02:17:53+0000" 64 | - name: Sleep for a second 65 | run: sleep 1s 66 | - name: Discord Webhook Action With Embed Description That's Too Long 67 | uses: ./ 68 | with: 69 | webhook-url: ${{ secrets.WEBHOOK_URL }} 70 | username: Bill 71 | avatar-url: https://cdn.discordapp.com/avatars/742807869023322232/dd41912939ffccbea0276f70688fa0ec.webp?size=256 72 | embed-title: "Foo" 73 | embed-url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ" 74 | embed-description: "steaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteaksteak" 75 | embed-author-name: "Bill" 76 | embed-author-icon-url: "https://cdn.discordapp.com/avatars/742807869023322232/dd41912939ffccbea0276f70688fa0ec.webp?size=256" 77 | embed-author-url: "https://google.com" 78 | embed-thumbnail-url: "https://cdn.discordapp.com/avatars/742807869023322232/dd41912939ffccbea0276f70688fa0ec.webp?size=256" 79 | embed-image-url: "https://cdn.discordapp.com/avatars/742807869023322232/dd41912939ffccbea0276f70688fa0ec.webp?size=256" 80 | embed-footer-icon-url: "https://cdn.discordapp.com/avatars/742807869023322232/dd41912939ffccbea0276f70688fa0ec.webp?size=256" 81 | embed-footer-text: "Foot text [test](https://google.com)" 82 | embed-color: 15430476 83 | embed-timestamp: "2021-09-24T02:17:53+0000" 84 | - name: Discord Webhook Action to Thread 85 | uses: ./ 86 | with: 87 | webhook-url: ${{ secrets.WEBHOOK_URL }} 88 | username: Bill 89 | content: Threaded message 90 | avatar-url: https://cdn.discordapp.com/avatars/742807869023322232/dd41912939ffccbea0276f70688fa0ec.webp?size=256 91 | thread-id: ${{ secrets.TEST_THREAD_ID }} 92 | - name: Discord Webhook Action Confirm Message Sent 93 | uses: ./ 94 | with: 95 | webhook-url: ${{ secrets.WEBHOOK_URL }} 96 | username: Bill 97 | content: Discord will not confirm this was sent successfully before replying. 98 | avatar-url: https://cdn.discordapp.com/avatars/742807869023322232/dd41912939ffccbea0276f70688fa0ec.webp?size=256 99 | wait: false 100 | - name: Do not embed 101 | uses: ./ 102 | with: 103 | webhook-url: ${{ secrets.WEBHOOK_URL }} 104 | content: Don't embed link https://github.com/tsickert/discord-webhook 105 | flags: 4 106 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Discord Webhook Action 2 | 3 | [![Runs on All Action Runners](https://github.com/tsickert/discord-webhook/actions/workflows/os-test.yml/badge.svg?branch=master)](https://github.com/tsickert/discord-webhook/actions/workflows/os-test.yml) 4 | 5 | This action allows users to set up a GitHub Action that calls Discord webhooks with content message and, optionally, a custom username and avatar url. 6 | 7 | Want to know more about Discord Webhooks? Check out the [intro](https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks) and [documentation](https://discord.com/developers/docs/resources/webhook#execute-webhook) from Discord. 8 | 9 | ## Recent Updates 10 | - Support for message flags (v7.0.0) 11 | - Support for `wait` (v6.0.0) 12 | - Node 20 upgrade (v6.0.0) 13 | - Support for Thread ID added (v5.3.0) 14 | - Add Description Character limit truncation (v5.2.0) 15 | - Support for embed URL (v5.1.0) 16 | - Support for multiple operating systems (v5.0.0) 17 | - Improved performance (v5.0.0) 18 | - Changed to TypeScript Action (v5.0.0) 19 | - Support for embeds (v4.0.0) 20 | - Support for file uploads (v3.0.0) 21 | 22 | ## Inputs 23 | 24 | | Name | Required | Description | 25 | |-----------------------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------| 26 | | webhook-url | `true` | Webhook URL from discord. See: the [intro to webhook docs](https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks) for details | 27 | | content | `false` | Message that is sent via the webhook | 28 | | thread-id | `false` | ID of the thread you want the webhook to send the message into (will automatically unarchive threads) | 29 | | thread-name | `false` | Name of the thread you want the webhook to create | 30 | | flags | `false` | Message flags | 31 | | wait | `false` | Whether Discord should confirm the message was successfully sent before responding to the request (boolean) | 32 | | username | `false` | The username that should appear to send the message. Note: username will have the "bot" badge next to their name | 33 | | avatar-url | `false` | URL for the avatar that should appear with the message | 34 | | tts | `false` | Whether the message is text-to-speech | 35 | | raw-data | `false` | Filename of raw JSON body to send. **If this is provided, all other inputs (except `webhook-url`) are ignored** | 36 | | filename | `false` | Filename of file to upload. **This input is overridden by `raw-data`. If this is provided, `username` and `avatar-url` are still honored** | 37 | | embed-title | `false` | Title for embed | 38 | | embed-url | `false` | URL for embed | 39 | | embed-description | `false` | Description for embed | 40 | | embed-timestamp | `false` | Timestamp for embed (ISO8601 format) | 41 | | embed-color | `false` | Color for embed (integer) | 42 | | embed-footer-text | `false` | Text content for embed footer | 43 | | embed-footer-icon-url | `false` | Icon URL for embed footer | 44 | | embed-image-url | `false` | Embed image URL. | 45 | | embed-thumbnail-url | `false` | Embed Thumbnail URL | 46 | | embed-author-name | `false` | Embed Author Name | 47 | | embed-author-url | `false` | Embed Author URL | 48 | | embed-author-icon-url | `false` | Embed Author Icon URL | 49 | 50 | ## Usage 51 | 52 | Want to see some full examples? Check out the [`test`](https://github.com/tsickert/discord-webhook/blob/4543a29f31afb1608487e8d9cb3d380975669316/.github/workflows/test.yml) workflow! 53 | 54 | ### Secrets 55 | 56 | _PSA_: Do not commit your webhook URL to a public repository. Webhooks do not require authentication, so anyone who has the webhook can use it. 57 | GitHub repositories support [secrets](https://docs.github.com/en/actions/configuring-and-managing-workflows/creating-and-storing-encrypted-secrets) (under `settings->secrets`). Encrypt your webhook URLs. 58 | 59 | ### Scheduling 60 | 61 | GitHub Actions allow users to set up various triggers. One of the triggers is `schedule`. This allows users to set a POSIX cron timer to run the action. 62 | 63 | Below is an example that sends the message `"Test"` to the provided webhook. 64 | 65 | ```yaml 66 | on: 67 | schedule: 68 | - cron: '0 12 * * *' 69 | 70 | jobs: 71 | message: 72 | runs-on: ubuntu-latest 73 | steps: 74 | - name: Discord Webhook Action 75 | uses: tsickert/discord-webhook@v7.0.0 76 | with: 77 | webhook-url: ${{ secrets.WEBHOOK_URL }} 78 | content: "Test" 79 | ``` 80 | 81 | _Disclaimer_: GitHub Actions don't seem to always respect the cron job precisely. My experience has been that crons run about 15 minutes after they're scheduled to and crons that should run per minute will likely only run once every 7-10 minutes. 82 | 83 | ### Manual Trigger 84 | 85 | ```yaml 86 | on: 87 | workflow_dispatch: 88 | 89 | jobs: 90 | message: 91 | runs-on: ubuntu-latest 92 | steps: 93 | - name: Discord Webhook Action 94 | uses: tsickert/discord-webhook@v7.0.0 95 | with: 96 | webhook-url: ${{ secrets.WEBHOOK_URL }} 97 | content: "Test" 98 | ``` 99 | 100 | #### Note 101 | 102 | Multiple triggers are allowed for actions, so the action can have a manual trigger and a cron trigger: 103 | 104 | ```yaml 105 | on: 106 | workflow_dispatch: 107 | schedule: 108 | - cron: '0 12 * * *' 109 | ``` 110 | 111 | ### Advanced Use Cases 112 | 113 | #### Sending Raw JSON 114 | 115 | Do you need to send more than just some basic content? Things like embeds, for example? That's supported in `v2.0.0` and above. 116 | 117 | Instead of providing content inputs, you can override the 118 | `raw-data` input with the path to a JSON file in your repository that contains your webhook message. 119 | 120 | _(Note that all inputs except for `webhook-url` are ignored when `raw-data` is provided)_ 121 | 122 | ##### Example 123 | 124 | Let's say we want to send a message with an embed. 125 | 126 | Add a JSON file to your repository with the content you want (for this example, this file is called `hi.json`). 127 | 128 | ```json 129 | { 130 | "content": "See greeting below", 131 | "embeds": [{"title":"Hello","description":"World"}] 132 | } 133 | ``` 134 | 135 | **IMPORTANT**: Then, in the yaml where you define this action, you need to do one very important step, and that's adding a step 136 | to pull in the files from your repository. 137 | 138 | ``` 139 | - uses: actions/checkout@v2 140 | ``` 141 | 142 | This will allow the action to read the JSON that we added to the repository. 143 | 144 | The final action will look something like this: 145 | 146 | ```yaml 147 | name: Hi 148 | 149 | on: 150 | workflow_dispatch: 151 | 152 | jobs: 153 | build: 154 | runs-on: ubuntu-latest 155 | steps: 156 | - uses: actions/checkout@v2 157 | - name: Discord Webhook Action 158 | uses: tsickert/discord-webhook@v7.0.0 159 | with: 160 | webhook-url: ${{ secrets.WEBHOOK_URL }} 161 | raw-data: hi.json 162 | ``` 163 | 164 | #### Uploading Files 165 | 166 | Do you need to upload a file? Maybe you have a build artifact that you want to share or a daily update on progress 167 | that's tracked in a file. That's supported in `v3.0.0` and above. 168 | 169 | Instead of providing content inputs, you can override the `filename` input with the path to file in your workspace. 170 | 171 | _(Note that all inputs except for `webhook-url` are ignored when `raw-data` is provided)_ 172 | _(Note `raw-data` overrides this input if it also provided)_ 173 | 174 | ##### Example 175 | 176 | Let's say we want upload a file. 177 | 178 | Add file to your repository or workspace via an action (for this example, this file is called `test.txt`). 179 | 180 | **IMPORTANT**: If you added the file to your respoitory, don't forget to pull in the files from your repository. 181 | 182 | ``` 183 | - uses: actions/checkout@v2 184 | ``` 185 | 186 | This will allow the action see any files from the repository in the workspace. 187 | 188 | The final action will look something like this: 189 | 190 | ```yaml 191 | name: Hi 192 | 193 | on: 194 | workflow_dispatch: 195 | 196 | jobs: 197 | build: 198 | runs-on: ubuntu-latest 199 | steps: 200 | - uses: actions/checkout@v2 201 | - name: Discord Webhook Action 202 | uses: tsickert/discord-webhook@v7.0.0 203 | with: 204 | webhook-url: ${{ secrets.WEBHOOK_URL }} 205 | filename: test.txt 206 | ``` 207 | 208 | ## FAQ 209 | 210 | #### Can I use `@` pings with this? They just show up as plain text. 211 | 212 | Yes! Plaintext discord messages use the following syntax for `@`s: `<@{user-id}>` for users (example: `<@123456790>`) and `<#{channel-id}>` for channels (example: `<#123456790>`). The easiest way to find your user ID or channel ID is to enable developer mode and then right click on a user or channel and select `Copy ID`. To enable developer mode, go to `settings(cog wheel)` -> `Advanced (under App Settings header)` -> `Developer Mode`. 213 | 214 | #### How can I include multiline texts? 215 | 216 | You can achieve that using YAML's [block scalar literal style](https://yaml.org/spec/1.2.2/#literal-style), using a pipe `|` to tell YAML to keep the newlines in your text. 217 | 218 | For example, this is how you can write a multiline `embed-description`: 219 | 220 | ```yaml 221 | embed-description: | 222 | As we used the pipe, 223 | YAML will keep the newlines on our text. 224 | Awesome! 225 | ``` 226 | 227 | #### Help, something is wrong, my webhook isn't sending! 228 | 229 | Sorry to hear that! The discord webhook API is complicated and has a long list of conditions and restrictions. 230 | The implementation of the webhook provides a few guard rails against misuse, but does not protect against them all. 231 | Restrictions are set by Discord and may change--therefore the Discord API should ultimately be the source of truth for 232 | those restrictions. If you run into issues, please be sure to check the action outputs. The payload is printed there, 233 | so feel free to use it with curl or postman to first validate that the issue is not with the payload. If it's not, 234 | please open an issue in this repository and I'll take a look! 235 | 236 | #### What does "Near-full" support of the webhook API mean? 237 | 238 | The Discord API supports up to 10 embeds per webhook and also offers additional `fields` in the embed. Due to the input format for actions, I decided to limit it to one embed and I decided not to support fields. (`fields` seem to be bold text above non-bold text, so they seem reproducable without the explicit field). If you need to have multiple embeds, I would suggest invoking the action multiple times. If requested, I can explore providing the additional embeds and fields, but based on feedback I was getting during dev, the fields provided currently suited most needs. 239 | 240 | -------------------------------------------------------------------------------- /dist/licenses.txt: -------------------------------------------------------------------------------- 1 | @actions/core 2 | MIT 3 | The MIT License (MIT) 4 | 5 | Copyright 2019 GitHub 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 10 | 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 12 | 13 | @actions/http-client 14 | MIT 15 | Actions Http Client for Node.js 16 | 17 | Copyright (c) GitHub, Inc. 18 | 19 | All rights reserved. 20 | 21 | MIT License 22 | 23 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 24 | associated documentation files (the "Software"), to deal in the Software without restriction, 25 | including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 26 | and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 27 | subject to the following conditions: 28 | 29 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 30 | 31 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 32 | LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 33 | NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 34 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 35 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 36 | 37 | 38 | asynckit 39 | MIT 40 | The MIT License (MIT) 41 | 42 | Copyright (c) 2016 Alex Indigo 43 | 44 | Permission is hereby granted, free of charge, to any person obtaining a copy 45 | of this software and associated documentation files (the "Software"), to deal 46 | in the Software without restriction, including without limitation the rights 47 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 48 | copies of the Software, and to permit persons to whom the Software is 49 | furnished to do so, subject to the following conditions: 50 | 51 | The above copyright notice and this permission notice shall be included in all 52 | copies or substantial portions of the Software. 53 | 54 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 55 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 56 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 57 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 58 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 59 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 60 | SOFTWARE. 61 | 62 | 63 | axios 64 | MIT 65 | # Copyright (c) 2014-present Matt Zabriskie & Collaborators 66 | 67 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 68 | 69 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 70 | 71 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 72 | 73 | 74 | combined-stream 75 | MIT 76 | Copyright (c) 2011 Debuggable Limited 77 | 78 | Permission is hereby granted, free of charge, to any person obtaining a copy 79 | of this software and associated documentation files (the "Software"), to deal 80 | in the Software without restriction, including without limitation the rights 81 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 82 | copies of the Software, and to permit persons to whom the Software is 83 | furnished to do so, subject to the following conditions: 84 | 85 | The above copyright notice and this permission notice shall be included in 86 | all copies or substantial portions of the Software. 87 | 88 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 89 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 90 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 91 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 92 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 93 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 94 | THE SOFTWARE. 95 | 96 | 97 | debug 98 | MIT 99 | (The MIT License) 100 | 101 | Copyright (c) 2014-2017 TJ Holowaychuk 102 | Copyright (c) 2018-2021 Josh Junon 103 | 104 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software 105 | and associated documentation files (the 'Software'), to deal in the Software without restriction, 106 | including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 107 | and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 108 | subject to the following conditions: 109 | 110 | The above copyright notice and this permission notice shall be included in all copies or substantial 111 | portions of the Software. 112 | 113 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 114 | LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 115 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 116 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 117 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 118 | 119 | 120 | 121 | delayed-stream 122 | MIT 123 | Copyright (c) 2011 Debuggable Limited 124 | 125 | Permission is hereby granted, free of charge, to any person obtaining a copy 126 | of this software and associated documentation files (the "Software"), to deal 127 | in the Software without restriction, including without limitation the rights 128 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 129 | copies of the Software, and to permit persons to whom the Software is 130 | furnished to do so, subject to the following conditions: 131 | 132 | The above copyright notice and this permission notice shall be included in 133 | all copies or substantial portions of the Software. 134 | 135 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 136 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 137 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 138 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 139 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 140 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 141 | THE SOFTWARE. 142 | 143 | 144 | follow-redirects 145 | MIT 146 | Copyright 2014–present Olivier Lalonde , James Talmage , Ruben Verborgh 147 | 148 | Permission is hereby granted, free of charge, to any person obtaining a copy of 149 | this software and associated documentation files (the "Software"), to deal in 150 | the Software without restriction, including without limitation the rights to 151 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 152 | of the Software, and to permit persons to whom the Software is furnished to do 153 | so, subject to the following conditions: 154 | 155 | The above copyright notice and this permission notice shall be included in all 156 | copies or substantial portions of the Software. 157 | 158 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 159 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 160 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 161 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 162 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 163 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 164 | 165 | 166 | form-data 167 | MIT 168 | Copyright (c) 2012 Felix Geisendörfer (felix@debuggable.com) and contributors 169 | 170 | Permission is hereby granted, free of charge, to any person obtaining a copy 171 | of this software and associated documentation files (the "Software"), to deal 172 | in the Software without restriction, including without limitation the rights 173 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 174 | copies of the Software, and to permit persons to whom the Software is 175 | furnished to do so, subject to the following conditions: 176 | 177 | The above copyright notice and this permission notice shall be included in 178 | all copies or substantial portions of the Software. 179 | 180 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 181 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 182 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 183 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 184 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 185 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 186 | THE SOFTWARE. 187 | 188 | 189 | has-flag 190 | MIT 191 | MIT License 192 | 193 | Copyright (c) Sindre Sorhus (sindresorhus.com) 194 | 195 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 196 | 197 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 198 | 199 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 200 | 201 | 202 | mime-db 203 | MIT 204 | 205 | The MIT License (MIT) 206 | 207 | Copyright (c) 2014 Jonathan Ong me@jongleberry.com 208 | 209 | Permission is hereby granted, free of charge, to any person obtaining a copy 210 | of this software and associated documentation files (the "Software"), to deal 211 | in the Software without restriction, including without limitation the rights 212 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 213 | copies of the Software, and to permit persons to whom the Software is 214 | furnished to do so, subject to the following conditions: 215 | 216 | The above copyright notice and this permission notice shall be included in 217 | all copies or substantial portions of the Software. 218 | 219 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 220 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 221 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 222 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 223 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 224 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 225 | THE SOFTWARE. 226 | 227 | 228 | mime-types 229 | MIT 230 | (The MIT License) 231 | 232 | Copyright (c) 2014 Jonathan Ong 233 | Copyright (c) 2015 Douglas Christopher Wilson 234 | 235 | Permission is hereby granted, free of charge, to any person obtaining 236 | a copy of this software and associated documentation files (the 237 | 'Software'), to deal in the Software without restriction, including 238 | without limitation the rights to use, copy, modify, merge, publish, 239 | distribute, sublicense, and/or sell copies of the Software, and to 240 | permit persons to whom the Software is furnished to do so, subject to 241 | the following conditions: 242 | 243 | The above copyright notice and this permission notice shall be 244 | included in all copies or substantial portions of the Software. 245 | 246 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 247 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 248 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 249 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 250 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 251 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 252 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 253 | 254 | 255 | ms 256 | MIT 257 | The MIT License (MIT) 258 | 259 | Copyright (c) 2016 Zeit, Inc. 260 | 261 | Permission is hereby granted, free of charge, to any person obtaining a copy 262 | of this software and associated documentation files (the "Software"), to deal 263 | in the Software without restriction, including without limitation the rights 264 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 265 | copies of the Software, and to permit persons to whom the Software is 266 | furnished to do so, subject to the following conditions: 267 | 268 | The above copyright notice and this permission notice shall be included in all 269 | copies or substantial portions of the Software. 270 | 271 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 272 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 273 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 274 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 275 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 276 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 277 | SOFTWARE. 278 | 279 | 280 | proxy-from-env 281 | MIT 282 | The MIT License 283 | 284 | Copyright (C) 2016-2018 Rob Wu 285 | 286 | Permission is hereby granted, free of charge, to any person obtaining a copy of 287 | this software and associated documentation files (the "Software"), to deal in 288 | the Software without restriction, including without limitation the rights to 289 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 290 | of the Software, and to permit persons to whom the Software is furnished to do 291 | so, subject to the following conditions: 292 | 293 | The above copyright notice and this permission notice shall be included in all 294 | copies or substantial portions of the Software. 295 | 296 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 297 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 298 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 299 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 300 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 301 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 302 | 303 | 304 | supports-color 305 | MIT 306 | MIT License 307 | 308 | Copyright (c) Sindre Sorhus (sindresorhus.com) 309 | 310 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 311 | 312 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 313 | 314 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 315 | 316 | 317 | tunnel 318 | MIT 319 | The MIT License (MIT) 320 | 321 | Copyright (c) 2012 Koichi Kobayashi 322 | 323 | Permission is hereby granted, free of charge, to any person obtaining a copy 324 | of this software and associated documentation files (the "Software"), to deal 325 | in the Software without restriction, including without limitation the rights 326 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 327 | copies of the Software, and to permit persons to whom the Software is 328 | furnished to do so, subject to the following conditions: 329 | 330 | The above copyright notice and this permission notice shall be included in 331 | all copies or substantial portions of the Software. 332 | 333 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 334 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 335 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 336 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 337 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 338 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 339 | THE SOFTWARE. 340 | 341 | 342 | uuid 343 | MIT 344 | The MIT License (MIT) 345 | 346 | Copyright (c) 2010-2020 Robert Kieffer and other contributors 347 | 348 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 349 | 350 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 351 | 352 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 353 | -------------------------------------------------------------------------------- /dist/sourcemap-register.js: -------------------------------------------------------------------------------- 1 | (()=>{var e={650:e=>{var r=Object.prototype.toString;var n=typeof Buffer.alloc==="function"&&typeof Buffer.allocUnsafe==="function"&&typeof Buffer.from==="function";function isArrayBuffer(e){return r.call(e).slice(8,-1)==="ArrayBuffer"}function fromArrayBuffer(e,r,t){r>>>=0;var o=e.byteLength-r;if(o<0){throw new RangeError("'offset' is out of bounds")}if(t===undefined){t=o}else{t>>>=0;if(t>o){throw new RangeError("'length' is out of bounds")}}return n?Buffer.from(e.slice(r,r+t)):new Buffer(new Uint8Array(e.slice(r,r+t)))}function fromString(e,r){if(typeof r!=="string"||r===""){r="utf8"}if(!Buffer.isEncoding(r)){throw new TypeError('"encoding" must be a valid string encoding')}return n?Buffer.from(e,r):new Buffer(e,r)}function bufferFrom(e,r,t){if(typeof e==="number"){throw new TypeError('"value" argument must not be a number')}if(isArrayBuffer(e)){return fromArrayBuffer(e,r,t)}if(typeof e==="string"){return fromString(e,r)}return n?Buffer.from(e):new Buffer(e)}e.exports=bufferFrom},274:(e,r,n)=>{var t=n(339);var o=Object.prototype.hasOwnProperty;var i=typeof Map!=="undefined";function ArraySet(){this._array=[];this._set=i?new Map:Object.create(null)}ArraySet.fromArray=function ArraySet_fromArray(e,r){var n=new ArraySet;for(var t=0,o=e.length;t=0){return r}}else{var n=t.toSetString(e);if(o.call(this._set,n)){return this._set[n]}}throw new Error('"'+e+'" is not in the set.')};ArraySet.prototype.at=function ArraySet_at(e){if(e>=0&&e{var t=n(190);var o=5;var i=1<>1;return r?-n:n}r.encode=function base64VLQ_encode(e){var r="";var n;var i=toVLQSigned(e);do{n=i&a;i>>>=o;if(i>0){n|=u}r+=t.encode(n)}while(i>0);return r};r.decode=function base64VLQ_decode(e,r,n){var i=e.length;var s=0;var l=0;var c,p;do{if(r>=i){throw new Error("Expected more digits in base 64 VLQ value.")}p=t.decode(e.charCodeAt(r++));if(p===-1){throw new Error("Invalid base64 digit: "+e.charAt(r-1))}c=!!(p&u);p&=a;s=s+(p<{var n="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".split("");r.encode=function(e){if(0<=e&&e{r.GREATEST_LOWER_BOUND=1;r.LEAST_UPPER_BOUND=2;function recursiveSearch(e,n,t,o,i,a){var u=Math.floor((n-e)/2)+e;var s=i(t,o[u],true);if(s===0){return u}else if(s>0){if(n-u>1){return recursiveSearch(u,n,t,o,i,a)}if(a==r.LEAST_UPPER_BOUND){return n1){return recursiveSearch(e,u,t,o,i,a)}if(a==r.LEAST_UPPER_BOUND){return u}else{return e<0?-1:e}}}r.search=function search(e,n,t,o){if(n.length===0){return-1}var i=recursiveSearch(-1,n.length,e,n,t,o||r.GREATEST_LOWER_BOUND);if(i<0){return-1}while(i-1>=0){if(t(n[i],n[i-1],true)!==0){break}--i}return i}},680:(e,r,n)=>{var t=n(339);function generatedPositionAfter(e,r){var n=e.generatedLine;var o=r.generatedLine;var i=e.generatedColumn;var a=r.generatedColumn;return o>n||o==n&&a>=i||t.compareByGeneratedPositionsInflated(e,r)<=0}function MappingList(){this._array=[];this._sorted=true;this._last={generatedLine:-1,generatedColumn:0}}MappingList.prototype.unsortedForEach=function MappingList_forEach(e,r){this._array.forEach(e,r)};MappingList.prototype.add=function MappingList_add(e){if(generatedPositionAfter(this._last,e)){this._last=e;this._array.push(e)}else{this._sorted=false;this._array.push(e)}};MappingList.prototype.toArray=function MappingList_toArray(){if(!this._sorted){this._array.sort(t.compareByGeneratedPositionsInflated);this._sorted=true}return this._array};r.H=MappingList},758:(e,r)=>{function swap(e,r,n){var t=e[r];e[r]=e[n];e[n]=t}function randomIntInRange(e,r){return Math.round(e+Math.random()*(r-e))}function doQuickSort(e,r,n,t){if(n{var t;var o=n(339);var i=n(345);var a=n(274).I;var u=n(449);var s=n(758).U;function SourceMapConsumer(e,r){var n=e;if(typeof e==="string"){n=o.parseSourceMapInput(e)}return n.sections!=null?new IndexedSourceMapConsumer(n,r):new BasicSourceMapConsumer(n,r)}SourceMapConsumer.fromSourceMap=function(e,r){return BasicSourceMapConsumer.fromSourceMap(e,r)};SourceMapConsumer.prototype._version=3;SourceMapConsumer.prototype.__generatedMappings=null;Object.defineProperty(SourceMapConsumer.prototype,"_generatedMappings",{configurable:true,enumerable:true,get:function(){if(!this.__generatedMappings){this._parseMappings(this._mappings,this.sourceRoot)}return this.__generatedMappings}});SourceMapConsumer.prototype.__originalMappings=null;Object.defineProperty(SourceMapConsumer.prototype,"_originalMappings",{configurable:true,enumerable:true,get:function(){if(!this.__originalMappings){this._parseMappings(this._mappings,this.sourceRoot)}return this.__originalMappings}});SourceMapConsumer.prototype._charIsMappingSeparator=function SourceMapConsumer_charIsMappingSeparator(e,r){var n=e.charAt(r);return n===";"||n===","};SourceMapConsumer.prototype._parseMappings=function SourceMapConsumer_parseMappings(e,r){throw new Error("Subclasses must implement _parseMappings")};SourceMapConsumer.GENERATED_ORDER=1;SourceMapConsumer.ORIGINAL_ORDER=2;SourceMapConsumer.GREATEST_LOWER_BOUND=1;SourceMapConsumer.LEAST_UPPER_BOUND=2;SourceMapConsumer.prototype.eachMapping=function SourceMapConsumer_eachMapping(e,r,n){var t=r||null;var i=n||SourceMapConsumer.GENERATED_ORDER;var a;switch(i){case SourceMapConsumer.GENERATED_ORDER:a=this._generatedMappings;break;case SourceMapConsumer.ORIGINAL_ORDER:a=this._originalMappings;break;default:throw new Error("Unknown order of iteration.")}var u=this.sourceRoot;a.map((function(e){var r=e.source===null?null:this._sources.at(e.source);r=o.computeSourceURL(u,r,this._sourceMapURL);return{source:r,generatedLine:e.generatedLine,generatedColumn:e.generatedColumn,originalLine:e.originalLine,originalColumn:e.originalColumn,name:e.name===null?null:this._names.at(e.name)}}),this).forEach(e,t)};SourceMapConsumer.prototype.allGeneratedPositionsFor=function SourceMapConsumer_allGeneratedPositionsFor(e){var r=o.getArg(e,"line");var n={source:o.getArg(e,"source"),originalLine:r,originalColumn:o.getArg(e,"column",0)};n.source=this._findSourceIndex(n.source);if(n.source<0){return[]}var t=[];var a=this._findMapping(n,this._originalMappings,"originalLine","originalColumn",o.compareByOriginalPositions,i.LEAST_UPPER_BOUND);if(a>=0){var u=this._originalMappings[a];if(e.column===undefined){var s=u.originalLine;while(u&&u.originalLine===s){t.push({line:o.getArg(u,"generatedLine",null),column:o.getArg(u,"generatedColumn",null),lastColumn:o.getArg(u,"lastGeneratedColumn",null)});u=this._originalMappings[++a]}}else{var l=u.originalColumn;while(u&&u.originalLine===r&&u.originalColumn==l){t.push({line:o.getArg(u,"generatedLine",null),column:o.getArg(u,"generatedColumn",null),lastColumn:o.getArg(u,"lastGeneratedColumn",null)});u=this._originalMappings[++a]}}}return t};r.SourceMapConsumer=SourceMapConsumer;function BasicSourceMapConsumer(e,r){var n=e;if(typeof e==="string"){n=o.parseSourceMapInput(e)}var t=o.getArg(n,"version");var i=o.getArg(n,"sources");var u=o.getArg(n,"names",[]);var s=o.getArg(n,"sourceRoot",null);var l=o.getArg(n,"sourcesContent",null);var c=o.getArg(n,"mappings");var p=o.getArg(n,"file",null);if(t!=this._version){throw new Error("Unsupported version: "+t)}if(s){s=o.normalize(s)}i=i.map(String).map(o.normalize).map((function(e){return s&&o.isAbsolute(s)&&o.isAbsolute(e)?o.relative(s,e):e}));this._names=a.fromArray(u.map(String),true);this._sources=a.fromArray(i,true);this._absoluteSources=this._sources.toArray().map((function(e){return o.computeSourceURL(s,e,r)}));this.sourceRoot=s;this.sourcesContent=l;this._mappings=c;this._sourceMapURL=r;this.file=p}BasicSourceMapConsumer.prototype=Object.create(SourceMapConsumer.prototype);BasicSourceMapConsumer.prototype.consumer=SourceMapConsumer;BasicSourceMapConsumer.prototype._findSourceIndex=function(e){var r=e;if(this.sourceRoot!=null){r=o.relative(this.sourceRoot,r)}if(this._sources.has(r)){return this._sources.indexOf(r)}var n;for(n=0;n1){v.source=l+_[1];l+=_[1];v.originalLine=i+_[2];i=v.originalLine;v.originalLine+=1;v.originalColumn=a+_[3];a=v.originalColumn;if(_.length>4){v.name=c+_[4];c+=_[4]}}m.push(v);if(typeof v.originalLine==="number"){d.push(v)}}}s(m,o.compareByGeneratedPositionsDeflated);this.__generatedMappings=m;s(d,o.compareByOriginalPositions);this.__originalMappings=d};BasicSourceMapConsumer.prototype._findMapping=function SourceMapConsumer_findMapping(e,r,n,t,o,a){if(e[n]<=0){throw new TypeError("Line must be greater than or equal to 1, got "+e[n])}if(e[t]<0){throw new TypeError("Column must be greater than or equal to 0, got "+e[t])}return i.search(e,r,o,a)};BasicSourceMapConsumer.prototype.computeColumnSpans=function SourceMapConsumer_computeColumnSpans(){for(var e=0;e=0){var t=this._generatedMappings[n];if(t.generatedLine===r.generatedLine){var i=o.getArg(t,"source",null);if(i!==null){i=this._sources.at(i);i=o.computeSourceURL(this.sourceRoot,i,this._sourceMapURL)}var a=o.getArg(t,"name",null);if(a!==null){a=this._names.at(a)}return{source:i,line:o.getArg(t,"originalLine",null),column:o.getArg(t,"originalColumn",null),name:a}}}return{source:null,line:null,column:null,name:null}};BasicSourceMapConsumer.prototype.hasContentsOfAllSources=function BasicSourceMapConsumer_hasContentsOfAllSources(){if(!this.sourcesContent){return false}return this.sourcesContent.length>=this._sources.size()&&!this.sourcesContent.some((function(e){return e==null}))};BasicSourceMapConsumer.prototype.sourceContentFor=function SourceMapConsumer_sourceContentFor(e,r){if(!this.sourcesContent){return null}var n=this._findSourceIndex(e);if(n>=0){return this.sourcesContent[n]}var t=e;if(this.sourceRoot!=null){t=o.relative(this.sourceRoot,t)}var i;if(this.sourceRoot!=null&&(i=o.urlParse(this.sourceRoot))){var a=t.replace(/^file:\/\//,"");if(i.scheme=="file"&&this._sources.has(a)){return this.sourcesContent[this._sources.indexOf(a)]}if((!i.path||i.path=="/")&&this._sources.has("/"+t)){return this.sourcesContent[this._sources.indexOf("/"+t)]}}if(r){return null}else{throw new Error('"'+t+'" is not in the SourceMap.')}};BasicSourceMapConsumer.prototype.generatedPositionFor=function SourceMapConsumer_generatedPositionFor(e){var r=o.getArg(e,"source");r=this._findSourceIndex(r);if(r<0){return{line:null,column:null,lastColumn:null}}var n={source:r,originalLine:o.getArg(e,"line"),originalColumn:o.getArg(e,"column")};var t=this._findMapping(n,this._originalMappings,"originalLine","originalColumn",o.compareByOriginalPositions,o.getArg(e,"bias",SourceMapConsumer.GREATEST_LOWER_BOUND));if(t>=0){var i=this._originalMappings[t];if(i.source===n.source){return{line:o.getArg(i,"generatedLine",null),column:o.getArg(i,"generatedColumn",null),lastColumn:o.getArg(i,"lastGeneratedColumn",null)}}}return{line:null,column:null,lastColumn:null}};t=BasicSourceMapConsumer;function IndexedSourceMapConsumer(e,r){var n=e;if(typeof e==="string"){n=o.parseSourceMapInput(e)}var t=o.getArg(n,"version");var i=o.getArg(n,"sections");if(t!=this._version){throw new Error("Unsupported version: "+t)}this._sources=new a;this._names=new a;var u={line:-1,column:0};this._sections=i.map((function(e){if(e.url){throw new Error("Support for url field in sections not implemented.")}var n=o.getArg(e,"offset");var t=o.getArg(n,"line");var i=o.getArg(n,"column");if(t{var t=n(449);var o=n(339);var i=n(274).I;var a=n(680).H;function SourceMapGenerator(e){if(!e){e={}}this._file=o.getArg(e,"file",null);this._sourceRoot=o.getArg(e,"sourceRoot",null);this._skipValidation=o.getArg(e,"skipValidation",false);this._sources=new i;this._names=new i;this._mappings=new a;this._sourcesContents=null}SourceMapGenerator.prototype._version=3;SourceMapGenerator.fromSourceMap=function SourceMapGenerator_fromSourceMap(e){var r=e.sourceRoot;var n=new SourceMapGenerator({file:e.file,sourceRoot:r});e.eachMapping((function(e){var t={generated:{line:e.generatedLine,column:e.generatedColumn}};if(e.source!=null){t.source=e.source;if(r!=null){t.source=o.relative(r,t.source)}t.original={line:e.originalLine,column:e.originalColumn};if(e.name!=null){t.name=e.name}}n.addMapping(t)}));e.sources.forEach((function(t){var i=t;if(r!==null){i=o.relative(r,t)}if(!n._sources.has(i)){n._sources.add(i)}var a=e.sourceContentFor(t);if(a!=null){n.setSourceContent(t,a)}}));return n};SourceMapGenerator.prototype.addMapping=function SourceMapGenerator_addMapping(e){var r=o.getArg(e,"generated");var n=o.getArg(e,"original",null);var t=o.getArg(e,"source",null);var i=o.getArg(e,"name",null);if(!this._skipValidation){this._validateMapping(r,n,t,i)}if(t!=null){t=String(t);if(!this._sources.has(t)){this._sources.add(t)}}if(i!=null){i=String(i);if(!this._names.has(i)){this._names.add(i)}}this._mappings.add({generatedLine:r.line,generatedColumn:r.column,originalLine:n!=null&&n.line,originalColumn:n!=null&&n.column,source:t,name:i})};SourceMapGenerator.prototype.setSourceContent=function SourceMapGenerator_setSourceContent(e,r){var n=e;if(this._sourceRoot!=null){n=o.relative(this._sourceRoot,n)}if(r!=null){if(!this._sourcesContents){this._sourcesContents=Object.create(null)}this._sourcesContents[o.toSetString(n)]=r}else if(this._sourcesContents){delete this._sourcesContents[o.toSetString(n)];if(Object.keys(this._sourcesContents).length===0){this._sourcesContents=null}}};SourceMapGenerator.prototype.applySourceMap=function SourceMapGenerator_applySourceMap(e,r,n){var t=r;if(r==null){if(e.file==null){throw new Error("SourceMapGenerator.prototype.applySourceMap requires either an explicit source file, "+'or the source map\'s "file" property. Both were omitted.')}t=e.file}var a=this._sourceRoot;if(a!=null){t=o.relative(a,t)}var u=new i;var s=new i;this._mappings.unsortedForEach((function(r){if(r.source===t&&r.originalLine!=null){var i=e.originalPositionFor({line:r.originalLine,column:r.originalColumn});if(i.source!=null){r.source=i.source;if(n!=null){r.source=o.join(n,r.source)}if(a!=null){r.source=o.relative(a,r.source)}r.originalLine=i.line;r.originalColumn=i.column;if(i.name!=null){r.name=i.name}}}var l=r.source;if(l!=null&&!u.has(l)){u.add(l)}var c=r.name;if(c!=null&&!s.has(c)){s.add(c)}}),this);this._sources=u;this._names=s;e.sources.forEach((function(r){var t=e.sourceContentFor(r);if(t!=null){if(n!=null){r=o.join(n,r)}if(a!=null){r=o.relative(a,r)}this.setSourceContent(r,t)}}),this)};SourceMapGenerator.prototype._validateMapping=function SourceMapGenerator_validateMapping(e,r,n,t){if(r&&typeof r.line!=="number"&&typeof r.column!=="number"){throw new Error("original.line and original.column are not numbers -- you probably meant to omit "+"the original mapping entirely and only map the generated position. If so, pass "+"null for the original mapping instead of an object with empty or null values.")}if(e&&"line"in e&&"column"in e&&e.line>0&&e.column>=0&&!r&&!n&&!t){return}else if(e&&"line"in e&&"column"in e&&r&&"line"in r&&"column"in r&&e.line>0&&e.column>=0&&r.line>0&&r.column>=0&&n){return}else{throw new Error("Invalid mapping: "+JSON.stringify({generated:e,source:n,original:r,name:t}))}};SourceMapGenerator.prototype._serializeMappings=function SourceMapGenerator_serializeMappings(){var e=0;var r=1;var n=0;var i=0;var a=0;var u=0;var s="";var l;var c;var p;var f;var g=this._mappings.toArray();for(var h=0,d=g.length;h0){if(!o.compareByGeneratedPositionsInflated(c,g[h-1])){continue}l+=","}}l+=t.encode(c.generatedColumn-e);e=c.generatedColumn;if(c.source!=null){f=this._sources.indexOf(c.source);l+=t.encode(f-u);u=f;l+=t.encode(c.originalLine-1-i);i=c.originalLine-1;l+=t.encode(c.originalColumn-n);n=c.originalColumn;if(c.name!=null){p=this._names.indexOf(c.name);l+=t.encode(p-a);a=p}}s+=l}return s};SourceMapGenerator.prototype._generateSourcesContent=function SourceMapGenerator_generateSourcesContent(e,r){return e.map((function(e){if(!this._sourcesContents){return null}if(r!=null){e=o.relative(r,e)}var n=o.toSetString(e);return Object.prototype.hasOwnProperty.call(this._sourcesContents,n)?this._sourcesContents[n]:null}),this)};SourceMapGenerator.prototype.toJSON=function SourceMapGenerator_toJSON(){var e={version:this._version,sources:this._sources.toArray(),names:this._names.toArray(),mappings:this._serializeMappings()};if(this._file!=null){e.file=this._file}if(this._sourceRoot!=null){e.sourceRoot=this._sourceRoot}if(this._sourcesContents){e.sourcesContent=this._generateSourcesContent(e.sources,e.sourceRoot)}return e};SourceMapGenerator.prototype.toString=function SourceMapGenerator_toString(){return JSON.stringify(this.toJSON())};r.h=SourceMapGenerator},351:(e,r,n)=>{var t;var o=n(591).h;var i=n(339);var a=/(\r?\n)/;var u=10;var s="$$$isSourceNode$$$";function SourceNode(e,r,n,t,o){this.children=[];this.sourceContents={};this.line=e==null?null:e;this.column=r==null?null:r;this.source=n==null?null:n;this.name=o==null?null:o;this[s]=true;if(t!=null)this.add(t)}SourceNode.fromStringWithSourceMap=function SourceNode_fromStringWithSourceMap(e,r,n){var t=new SourceNode;var o=e.split(a);var u=0;var shiftNextLine=function(){var e=getNextLine();var r=getNextLine()||"";return e+r;function getNextLine(){return u=0;r--){this.prepend(e[r])}}else if(e[s]||typeof e==="string"){this.children.unshift(e)}else{throw new TypeError("Expected a SourceNode, string, or an array of SourceNodes and strings. Got "+e)}return this};SourceNode.prototype.walk=function SourceNode_walk(e){var r;for(var n=0,t=this.children.length;n0){r=[];for(n=0;n{function getArg(e,r,n){if(r in e){return e[r]}else if(arguments.length===3){return n}else{throw new Error('"'+r+'" is a required argument.')}}r.getArg=getArg;var n=/^(?:([\w+\-.]+):)?\/\/(?:(\w+:\w+)@)?([\w.-]*)(?::(\d+))?(.*)$/;var t=/^data:.+\,.+$/;function urlParse(e){var r=e.match(n);if(!r){return null}return{scheme:r[1],auth:r[2],host:r[3],port:r[4],path:r[5]}}r.urlParse=urlParse;function urlGenerate(e){var r="";if(e.scheme){r+=e.scheme+":"}r+="//";if(e.auth){r+=e.auth+"@"}if(e.host){r+=e.host}if(e.port){r+=":"+e.port}if(e.path){r+=e.path}return r}r.urlGenerate=urlGenerate;function normalize(e){var n=e;var t=urlParse(e);if(t){if(!t.path){return e}n=t.path}var o=r.isAbsolute(n);var i=n.split(/\/+/);for(var a,u=0,s=i.length-1;s>=0;s--){a=i[s];if(a==="."){i.splice(s,1)}else if(a===".."){u++}else if(u>0){if(a===""){i.splice(s+1,u);u=0}else{i.splice(s,2);u--}}}n=i.join("/");if(n===""){n=o?"/":"."}if(t){t.path=n;return urlGenerate(t)}return n}r.normalize=normalize;function join(e,r){if(e===""){e="."}if(r===""){r="."}var n=urlParse(r);var o=urlParse(e);if(o){e=o.path||"/"}if(n&&!n.scheme){if(o){n.scheme=o.scheme}return urlGenerate(n)}if(n||r.match(t)){return r}if(o&&!o.host&&!o.path){o.host=r;return urlGenerate(o)}var i=r.charAt(0)==="/"?r:normalize(e.replace(/\/+$/,"")+"/"+r);if(o){o.path=i;return urlGenerate(o)}return i}r.join=join;r.isAbsolute=function(e){return e.charAt(0)==="/"||n.test(e)};function relative(e,r){if(e===""){e="."}e=e.replace(/\/$/,"");var n=0;while(r.indexOf(e+"/")!==0){var t=e.lastIndexOf("/");if(t<0){return r}e=e.slice(0,t);if(e.match(/^([^\/]+:\/)?\/*$/)){return r}++n}return Array(n+1).join("../")+r.substr(e.length+1)}r.relative=relative;var o=function(){var e=Object.create(null);return!("__proto__"in e)}();function identity(e){return e}function toSetString(e){if(isProtoString(e)){return"$"+e}return e}r.toSetString=o?identity:toSetString;function fromSetString(e){if(isProtoString(e)){return e.slice(1)}return e}r.fromSetString=o?identity:fromSetString;function isProtoString(e){if(!e){return false}var r=e.length;if(r<9){return false}if(e.charCodeAt(r-1)!==95||e.charCodeAt(r-2)!==95||e.charCodeAt(r-3)!==111||e.charCodeAt(r-4)!==116||e.charCodeAt(r-5)!==111||e.charCodeAt(r-6)!==114||e.charCodeAt(r-7)!==112||e.charCodeAt(r-8)!==95||e.charCodeAt(r-9)!==95){return false}for(var n=r-10;n>=0;n--){if(e.charCodeAt(n)!==36){return false}}return true}function compareByOriginalPositions(e,r,n){var t=strcmp(e.source,r.source);if(t!==0){return t}t=e.originalLine-r.originalLine;if(t!==0){return t}t=e.originalColumn-r.originalColumn;if(t!==0||n){return t}t=e.generatedColumn-r.generatedColumn;if(t!==0){return t}t=e.generatedLine-r.generatedLine;if(t!==0){return t}return strcmp(e.name,r.name)}r.compareByOriginalPositions=compareByOriginalPositions;function compareByGeneratedPositionsDeflated(e,r,n){var t=e.generatedLine-r.generatedLine;if(t!==0){return t}t=e.generatedColumn-r.generatedColumn;if(t!==0||n){return t}t=strcmp(e.source,r.source);if(t!==0){return t}t=e.originalLine-r.originalLine;if(t!==0){return t}t=e.originalColumn-r.originalColumn;if(t!==0){return t}return strcmp(e.name,r.name)}r.compareByGeneratedPositionsDeflated=compareByGeneratedPositionsDeflated;function strcmp(e,r){if(e===r){return 0}if(e===null){return 1}if(r===null){return-1}if(e>r){return 1}return-1}function compareByGeneratedPositionsInflated(e,r){var n=e.generatedLine-r.generatedLine;if(n!==0){return n}n=e.generatedColumn-r.generatedColumn;if(n!==0){return n}n=strcmp(e.source,r.source);if(n!==0){return n}n=e.originalLine-r.originalLine;if(n!==0){return n}n=e.originalColumn-r.originalColumn;if(n!==0){return n}return strcmp(e.name,r.name)}r.compareByGeneratedPositionsInflated=compareByGeneratedPositionsInflated;function parseSourceMapInput(e){return JSON.parse(e.replace(/^\)]}'[^\n]*\n/,""))}r.parseSourceMapInput=parseSourceMapInput;function computeSourceURL(e,r,n){r=r||"";if(e){if(e[e.length-1]!=="/"&&r[0]!=="/"){e+="/"}r=e+r}if(n){var t=urlParse(n);if(!t){throw new Error("sourceMapURL could not be parsed")}if(t.path){var o=t.path.lastIndexOf("/");if(o>=0){t.path=t.path.substring(0,o+1)}}r=join(urlGenerate(t),r)}return normalize(r)}r.computeSourceURL=computeSourceURL},997:(e,r,n)=>{n(591).h;r.SourceMapConsumer=n(952).SourceMapConsumer;n(351)},284:(e,r,n)=>{e=n.nmd(e);var t=n(997).SourceMapConsumer;var o=n(17);var i;try{i=n(147);if(!i.existsSync||!i.readFileSync){i=null}}catch(e){}var a=n(650);function dynamicRequire(e,r){return e.require(r)}var u=false;var s=false;var l=false;var c="auto";var p={};var f={};var g=/^data:application\/json[^,]+base64,/;var h=[];var d=[];function isInBrowser(){if(c==="browser")return true;if(c==="node")return false;return typeof window!=="undefined"&&typeof XMLHttpRequest==="function"&&!(window.require&&window.module&&window.process&&window.process.type==="renderer")}function hasGlobalProcessEventEmitter(){return typeof process==="object"&&process!==null&&typeof process.on==="function"}function globalProcessVersion(){if(typeof process==="object"&&process!==null){return process.version}else{return""}}function globalProcessStderr(){if(typeof process==="object"&&process!==null){return process.stderr}}function globalProcessExit(e){if(typeof process==="object"&&process!==null&&typeof process.exit==="function"){return process.exit(e)}}function handlerExec(e){return function(r){for(var n=0;n"}var n=this.getLineNumber();if(n!=null){r+=":"+n;var t=this.getColumnNumber();if(t){r+=":"+t}}}var o="";var i=this.getFunctionName();var a=true;var u=this.isConstructor();var s=!(this.isToplevel()||u);if(s){var l=this.getTypeName();if(l==="[object Object]"){l="null"}var c=this.getMethodName();if(i){if(l&&i.indexOf(l)!=0){o+=l+"."}o+=i;if(c&&i.indexOf("."+c)!=i.length-c.length-1){o+=" [as "+c+"]"}}else{o+=l+"."+(c||"")}}else if(u){o+="new "+(i||"")}else if(i){o+=i}else{o+=r;a=false}if(a){o+=" ("+r+")"}return o}function cloneCallSite(e){var r={};Object.getOwnPropertyNames(Object.getPrototypeOf(e)).forEach((function(n){r[n]=/^(?:is|get)/.test(n)?function(){return e[n].call(e)}:e[n]}));r.toString=CallSiteToString;return r}function wrapCallSite(e,r){if(r===undefined){r={nextPosition:null,curPosition:null}}if(e.isNative()){r.curPosition=null;return e}var n=e.getFileName()||e.getScriptNameOrSourceURL();if(n){var t=e.getLineNumber();var o=e.getColumnNumber()-1;var i=/^v(10\.1[6-9]|10\.[2-9][0-9]|10\.[0-9]{3,}|1[2-9]\d*|[2-9]\d|\d{3,}|11\.11)/;var a=i.test(globalProcessVersion())?0:62;if(t===1&&o>a&&!isInBrowser()&&!e.isEval()){o-=a}var u=mapSourcePosition({source:n,line:t,column:o});r.curPosition=u;e=cloneCallSite(e);var s=e.getFunctionName;e.getFunctionName=function(){if(r.nextPosition==null){return s()}return r.nextPosition.name||s()};e.getFileName=function(){return u.source};e.getLineNumber=function(){return u.line};e.getColumnNumber=function(){return u.column+1};e.getScriptNameOrSourceURL=function(){return u.source};return e}var l=e.isEval()&&e.getEvalOrigin();if(l){l=mapEvalOrigin(l);e=cloneCallSite(e);e.getEvalOrigin=function(){return l};return e}return e}function prepareStackTrace(e,r){if(l){p={};f={}}var n=e.name||"Error";var t=e.message||"";var o=n+": "+t;var i={nextPosition:null,curPosition:null};var a=[];for(var u=r.length-1;u>=0;u--){a.push("\n at "+wrapCallSite(r[u],i));i.nextPosition=i.curPosition}i.curPosition=i.nextPosition=null;return o+a.reverse().join("")}function getErrorSource(e){var r=/\n at [^(]+ \((.*):(\d+):(\d+)\)/.exec(e.stack);if(r){var n=r[1];var t=+r[2];var o=+r[3];var a=p[n];if(!a&&i&&i.existsSync(n)){try{a=i.readFileSync(n,"utf8")}catch(e){a=""}}if(a){var u=a.split(/(?:\r\n|\r|\n)/)[t-1];if(u){return n+":"+t+"\n"+u+"\n"+new Array(o).join(" ")+"^"}}}return null}function printErrorAndExit(e){var r=getErrorSource(e);var n=globalProcessStderr();if(n&&n._handle&&n._handle.setBlocking){n._handle.setBlocking(true)}if(r){console.error();console.error(r)}console.error(e.stack);globalProcessExit(1)}function shimEmitUncaughtException(){var e=process.emit;process.emit=function(r){if(r==="uncaughtException"){var n=arguments[1]&&arguments[1].stack;var t=this.listeners(r).length>0;if(n&&!t){return printErrorAndExit(arguments[1])}}return e.apply(this,arguments)}}var S=h.slice(0);var _=d.slice(0);r.wrapCallSite=wrapCallSite;r.getErrorSource=getErrorSource;r.mapSourcePosition=mapSourcePosition;r.retrieveSourceMap=v;r.install=function(r){r=r||{};if(r.environment){c=r.environment;if(["node","browser","auto"].indexOf(c)===-1){throw new Error("environment "+c+" was unknown. Available options are {auto, browser, node}")}}if(r.retrieveFile){if(r.overrideRetrieveFile){h.length=0}h.unshift(r.retrieveFile)}if(r.retrieveSourceMap){if(r.overrideRetrieveSourceMap){d.length=0}d.unshift(r.retrieveSourceMap)}if(r.hookRequire&&!isInBrowser()){var n=dynamicRequire(e,"module");var t=n.prototype._compile;if(!t.__sourceMapSupport){n.prototype._compile=function(e,r){p[r]=e;f[r]=undefined;return t.call(this,e,r)};n.prototype._compile.__sourceMapSupport=true}}if(!l){l="emptyCacheBetweenOperations"in r?r.emptyCacheBetweenOperations:false}if(!u){u=true;Error.prepareStackTrace=prepareStackTrace}if(!s){var o="handleUncaughtExceptions"in r?r.handleUncaughtExceptions:true;try{var i=dynamicRequire(e,"worker_threads");if(i.isMainThread===false){o=false}}catch(e){}if(o&&hasGlobalProcessEventEmitter()){s=true;shimEmitUncaughtException()}}};r.resetRetrieveHandlers=function(){h.length=0;d.length=0;h=S.slice(0);d=_.slice(0);v=handlerExec(d);m=handlerExec(h)}},147:e=>{"use strict";e.exports=require("fs")},17:e=>{"use strict";e.exports=require("path")}};var r={};function __webpack_require__(n){var t=r[n];if(t!==undefined){return t.exports}var o=r[n]={id:n,loaded:false,exports:{}};var i=true;try{e[n](o,o.exports,__webpack_require__);i=false}finally{if(i)delete r[n]}o.loaded=true;return o.exports}(()=>{__webpack_require__.nmd=e=>{e.paths=[];if(!e.children)e.children=[];return e}})();if(typeof __webpack_require__!=="undefined")__webpack_require__.ab=__dirname+"/";var n={};(()=>{__webpack_require__(284).install()})();module.exports=n})(); --------------------------------------------------------------------------------