mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-09 16:13:31 +01:00
feat: @discordjs/proxy (#7925)
Co-authored-by: Parbez <imranbarbhuiya.fsd@gmail.com>
This commit is contained in:
1
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
1
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -15,6 +15,7 @@ body:
|
||||
- builders
|
||||
- collection
|
||||
- rest
|
||||
- proxy
|
||||
- voice
|
||||
validations:
|
||||
required: true
|
||||
|
||||
1
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
1
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
@@ -17,6 +17,7 @@ body:
|
||||
- builders
|
||||
- collection
|
||||
- rest
|
||||
- proxy
|
||||
- voice
|
||||
validations:
|
||||
required: true
|
||||
|
||||
4
.github/labeler.yml
vendored
4
.github/labeler.yml
vendored
@@ -14,6 +14,10 @@ chore:
|
||||
- packages/discord.js/*
|
||||
- packages/discord.js/**/*
|
||||
|
||||
'packages:proxy':
|
||||
- packages/proxy/*
|
||||
- packages/proxy/**/*
|
||||
|
||||
'packages:rest':
|
||||
- packages/rest/*
|
||||
- packages/rest/**/*
|
||||
|
||||
2
.github/labels.yml
vendored
2
.github/labels.yml
vendored
@@ -50,6 +50,8 @@
|
||||
color: 'fbca04'
|
||||
- name: 'packages:discord.js'
|
||||
color: 'fbca04'
|
||||
- name: 'packages:proxy'
|
||||
color: 'fbca04'
|
||||
- name: 'packages:rest'
|
||||
color: 'fbca04'
|
||||
- name: 'packages:voice'
|
||||
|
||||
2
.github/workflows/documentation.yml
vendored
2
.github/workflows/documentation.yml
vendored
@@ -62,7 +62,7 @@ jobs:
|
||||
max-parallel: 1
|
||||
fail-fast: false
|
||||
matrix:
|
||||
package: ['builders', 'collection', 'discord.js', 'rest', 'voice']
|
||||
package: ['builders', 'collection', 'discord.js', 'proxy', 'rest', 'voice']
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
BRANCH_NAME: ${{ needs.build.outputs.BRANCH_NAME }}
|
||||
|
||||
2
.github/workflows/publish-dev.yml
vendored
2
.github/workflows/publish-dev.yml
vendored
@@ -16,6 +16,8 @@ jobs:
|
||||
folder: 'collection'
|
||||
- package: 'discord.js'
|
||||
folder: 'discord.js'
|
||||
- package: '@discordjs/proxy'
|
||||
folder: 'proxy'
|
||||
- package: '@discordjs/rest'
|
||||
folder: 'rest'
|
||||
- package: '@discordjs/voice'
|
||||
|
||||
11
packages/proxy/.eslintrc.json
Normal file
11
packages/proxy/.eslintrc.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"root": true,
|
||||
"extends": "marine/prettier/node",
|
||||
"parserOptions": {
|
||||
"project": "./tsconfig.eslint.json"
|
||||
},
|
||||
"ignorePatterns": ["**/dist/*"],
|
||||
"env": {
|
||||
"jest": true
|
||||
}
|
||||
}
|
||||
32
packages/proxy/.gitignore
vendored
Normal file
32
packages/proxy/.gitignore
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
# Packages
|
||||
node_modules/
|
||||
|
||||
# Log files
|
||||
logs/
|
||||
*.log
|
||||
npm-debug.log*
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
|
||||
# Env
|
||||
.env
|
||||
|
||||
# Dist
|
||||
dist/
|
||||
typings/
|
||||
docs/**/*
|
||||
!docs/index.yml
|
||||
!docs/README.md
|
||||
|
||||
# Miscellaneous
|
||||
.tmp/
|
||||
coverage/
|
||||
tsconfig.tsbuildinfo
|
||||
.turbo
|
||||
|
||||
# Yarn files
|
||||
.yarn/install-state.gz
|
||||
.yarn/build-state.yml
|
||||
8
packages/proxy/.prettierrc.json
Normal file
8
packages/proxy/.prettierrc.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"printWidth": 120,
|
||||
"useTabs": true,
|
||||
"singleQuote": true,
|
||||
"quoteProps": "as-needed",
|
||||
"trailingComma": "all",
|
||||
"endOfLine": "lf"
|
||||
}
|
||||
191
packages/proxy/LICENSE
Normal file
191
packages/proxy/LICENSE
Normal file
@@ -0,0 +1,191 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Copyright 2022 Noel Buechler
|
||||
Copyright 2022 Charlotte Cristea
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
46
packages/proxy/README.md
Normal file
46
packages/proxy/README.md
Normal file
@@ -0,0 +1,46 @@
|
||||
<div align="center">
|
||||
<br />
|
||||
<p>
|
||||
<a href="https://discord.js.org"><img src="https://discord.js.org/static/logo.svg" width="546" alt="discord.js" /></a>
|
||||
</p>
|
||||
<br />
|
||||
<p>
|
||||
<a href="https://discord.gg/djs"><img src="https://img.shields.io/discord/222078108977594368?color=5865F2&logo=discord&logoColor=white" alt="Discord server" /></a>
|
||||
<a href="https://www.npmjs.com/package/@discordjs/proxy"><img src="https://img.shields.io/npm/v/@discordjs/proxy.svg?maxAge=3600" alt="npm version" /></a>
|
||||
<a href="https://www.npmjs.com/package/@discordjs/proxy"><img src="https://img.shields.io/npm/dt/@discordjs/proxy.svg?maxAge=3600" alt="npm downloads" /></a>
|
||||
<a href="https://github.com/discordjs/discord.js/actions"><img src="https://github.com/discordjs/discord.js/actions/workflows/test.yml/badge.svg" alt="Build status" /></a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
## About
|
||||
|
||||
`@discordjs/proxy` is a powerful wrapper around `@discordjs/rest` for running an HTTP proxy in front of Discord's API
|
||||
|
||||
## Installation
|
||||
|
||||
**Node.js 16.9.0 or newer is required.**
|
||||
|
||||
```sh-session
|
||||
npm install @discordjs/proxy
|
||||
yarn add @discordjs/proxy
|
||||
pnpm add @discordjs/proxy
|
||||
```
|
||||
|
||||
## Links
|
||||
|
||||
- [Website](https://discord.js.org/) ([source](https://github.com/discordjs/website))
|
||||
- [Documentation](https://discord.js.org/#/docs/proxy)
|
||||
- [discord.js Discord server](https://discord.gg/djs)
|
||||
- [GitHub](https://github.com/discordjs/discord.js/tree/main/packages/proxy)
|
||||
- [npm](https://www.npmjs.com/package/@discordjs/proxy)
|
||||
|
||||
## Contributing
|
||||
|
||||
Before creating an issue, please ensure that it hasn't already been reported/suggested, and double-check the
|
||||
[documentation](https://discord.js.org/#/docs/proxy).
|
||||
See [the contribution guide](https://github.com/discordjs/discord.js/blob/main/.github/CONTRIBUTING.md) if you'd like to submit a PR.
|
||||
|
||||
## Help
|
||||
|
||||
If you don't understand something in the documentation, you are experiencing problems, or you just need a gentle
|
||||
nudge in the right direction, please don't hesitate to join our official [discord.js Server](https://discord.gg/djs).
|
||||
83
packages/proxy/__tests__/proxyRequests.test.ts
Normal file
83
packages/proxy/__tests__/proxyRequests.test.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
import { createServer } from 'node:http';
|
||||
import { REST } from '@discordjs/rest';
|
||||
import supertest from 'supertest';
|
||||
import { MockAgent, Interceptable, setGlobalDispatcher } from 'undici';
|
||||
import type { MockInterceptor } from 'undici/types/mock-interceptor';
|
||||
import { proxyRequests } from '../src';
|
||||
|
||||
let mockAgent: MockAgent;
|
||||
let mockPool: Interceptable;
|
||||
|
||||
const responseOptions: MockInterceptor.MockResponseOptions = {
|
||||
headers: {
|
||||
'content-type': 'application/json',
|
||||
},
|
||||
};
|
||||
|
||||
const api = new REST().setToken('A-Very-Fake-Token');
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||
const server = createServer(proxyRequests(api));
|
||||
|
||||
beforeEach(() => {
|
||||
mockAgent = new MockAgent();
|
||||
mockAgent.disableNetConnect(); // prevent actual requests to Discord
|
||||
setGlobalDispatcher(mockAgent); // enabled the mock client to intercept requests
|
||||
|
||||
mockPool = mockAgent.get('https://discord.com');
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await mockAgent.close();
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
server.close();
|
||||
});
|
||||
|
||||
test('simple GET', async () => {
|
||||
mockPool
|
||||
.intercept({
|
||||
path: '/api/v10/simpleGet',
|
||||
method: 'GET',
|
||||
})
|
||||
.reply(() => ({
|
||||
data: { test: true },
|
||||
statusCode: 200,
|
||||
responseOptions: {
|
||||
...responseOptions,
|
||||
headers: {
|
||||
...responseOptions.headers,
|
||||
'x-ratelimit-limit': '10',
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
const res = await supertest(server).get('/api/v10/simpleGet');
|
||||
const headers = res.headers as Record<string, string>;
|
||||
|
||||
expect(headers['content-type']).toEqual(expect.stringMatching(/^application\/json/));
|
||||
// Ratelimit headers should be dropped
|
||||
expect(headers).not.toHaveProperty('x-ratelimit-limit');
|
||||
expect(res.statusCode).toBe(200);
|
||||
expect(res.body).toStrictEqual({ test: true });
|
||||
});
|
||||
|
||||
test('failed request', async () => {
|
||||
mockPool
|
||||
.intercept({
|
||||
path: '/api/v10/simpleGet',
|
||||
method: 'GET',
|
||||
})
|
||||
.reply(() => ({
|
||||
data: { code: 404, message: 'Not Found' },
|
||||
statusCode: 404,
|
||||
responseOptions,
|
||||
}));
|
||||
|
||||
const res = await supertest(server).get('/api/v10/simpleGet');
|
||||
const headers = res.headers as Record<string, string>;
|
||||
|
||||
expect(headers['content-type']).toEqual(expect.stringMatching(/^application\/json/));
|
||||
expect(res.statusCode).toBe(404);
|
||||
expect(res.body).toStrictEqual({ code: 404, message: 'Not Found' });
|
||||
});
|
||||
17
packages/proxy/babel.config.js
Normal file
17
packages/proxy/babel.config.js
Normal file
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* @type {import('@babel/core').TransformOptions}
|
||||
*/
|
||||
module.exports = {
|
||||
parserOpts: { strictMode: true },
|
||||
sourceMaps: 'inline',
|
||||
presets: [
|
||||
[
|
||||
'@babel/preset-env',
|
||||
{
|
||||
targets: { node: 'current' },
|
||||
modules: 'commonjs',
|
||||
},
|
||||
],
|
||||
'@babel/preset-typescript',
|
||||
],
|
||||
};
|
||||
65
packages/proxy/cliff.toml
Normal file
65
packages/proxy/cliff.toml
Normal file
@@ -0,0 +1,65 @@
|
||||
[changelog]
|
||||
header = """
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.\n
|
||||
"""
|
||||
body = """
|
||||
{% if version %}\
|
||||
# [{{ version | trim_start_matches(pat="v") }}]\
|
||||
{% if previous %}\
|
||||
{% if previous.version %}\
|
||||
(https://github.com/discordjs/discord.js/compare/{{ previous.version }}...{{ version }})\
|
||||
{% else %}
|
||||
(https://github.com/discordjs/discord.js/tree/{{ version }})\
|
||||
{% endif %}\
|
||||
{% endif %} \
|
||||
- ({{ timestamp | date(format="%Y-%m-%d") }})
|
||||
{% else %}\
|
||||
# [unreleased]
|
||||
{% endif %}\
|
||||
{% for group, commits in commits | group_by(attribute="group") %}
|
||||
## {{ group | upper_first }}
|
||||
{% for commit in commits %}
|
||||
- {% if commit.scope %}\
|
||||
**{{commit.scope}}:** \
|
||||
{% endif %}\
|
||||
{{ commit.message | upper_first }} ([{{ commit.id | truncate(length=7, end="") }}](https://github.com/discordjs/discord.js/commit/{{ commit.id }}))\
|
||||
{% if commit.breaking %}\
|
||||
\n\n {% raw %} {% endraw %} ### Breaking Changes:\n \
|
||||
{% for breakingChange in commit.footers %}\
|
||||
{% raw %} {% endraw %} - {{ breakingChange }}\n\
|
||||
{% endfor %}\
|
||||
{% endif %}\
|
||||
{% endfor %}
|
||||
{% endfor %}\n
|
||||
"""
|
||||
trim = true
|
||||
footer = ""
|
||||
|
||||
[git]
|
||||
conventional_commits = true
|
||||
filter_unconventional = true
|
||||
commit_parsers = [
|
||||
{ message = "^feat", group = "Features"},
|
||||
{ message = "^fix", group = "Bug Fixes"},
|
||||
{ message = "^docs", group = "Documentation"},
|
||||
{ message = "^perf", group = "Performance"},
|
||||
{ message = "^refactor", group = "Refactor"},
|
||||
{ message = "^typings", group = "Typings"},
|
||||
{ message = "^types", group = "Typings"},
|
||||
{ message = ".*deprecated", body = ".*deprecated", group = "Deprecation"},
|
||||
{ message = "^revert", skip = true},
|
||||
{ message = "^style", group = "Styling"},
|
||||
{ message = "^test", group = "Testing"},
|
||||
{ message = "^chore", skip = true},
|
||||
{ message = "^ci", skip = true},
|
||||
{ message = "^build", skip = true},
|
||||
{ body = ".*security", group = "Security"},
|
||||
]
|
||||
filter_commits = true
|
||||
tag_pattern = "@discordjs\\/proxy@.*"
|
||||
skip_tags = "v[0-9]*|11|12"
|
||||
ignore_tags = ""
|
||||
topo_order = false
|
||||
sort_commits = "newest"
|
||||
1
packages/proxy/docs/README.md
Normal file
1
packages/proxy/docs/README.md
Normal file
@@ -0,0 +1 @@
|
||||
## [View the documentation here.](https://discord.js.org/#/docs/proxy)
|
||||
5
packages/proxy/docs/index.yml
Normal file
5
packages/proxy/docs/index.yml
Normal file
@@ -0,0 +1,5 @@
|
||||
- name: General
|
||||
files:
|
||||
- name: Welcome
|
||||
id: welcome
|
||||
path: ../../README.md
|
||||
11
packages/proxy/jest.config.js
Normal file
11
packages/proxy/jest.config.js
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* @type {import('@jest/types').Config.InitialOptions}
|
||||
*/
|
||||
module.exports = {
|
||||
testMatch: ['**/+(*.)+(spec|test).+(ts|js)?(x)'],
|
||||
testEnvironment: 'node',
|
||||
collectCoverage: true,
|
||||
collectCoverageFrom: ['src/**/*.ts'],
|
||||
coverageDirectory: 'coverage',
|
||||
coverageReporters: ['text', 'lcov', 'clover'],
|
||||
};
|
||||
89
packages/proxy/package.json
Normal file
89
packages/proxy/package.json
Normal file
@@ -0,0 +1,89 @@
|
||||
{
|
||||
"name": "@discordjs/proxy",
|
||||
"version": "0.1.0-dev",
|
||||
"description": "Tools for running an HTTP proxy for Discord's API",
|
||||
"scripts": {
|
||||
"build": "tsup && tsc --emitDeclarationOnly --incremental",
|
||||
"test": "jest --pass-with-no-tests --collect-coverage",
|
||||
"lint": "prettier --check . && eslint src __tests__ --ext mjs,js,ts",
|
||||
"format": "prettier --write . && eslint src __tests__ --ext mjs,js,ts --fix",
|
||||
"docs": "typedoc --json docs/typedoc-out.json src/index.ts && node scripts/docs.mjs",
|
||||
"prepublishOnly": "yarn build && yarn lint && yarn test",
|
||||
"changelog": "git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'packages/proxy/*'"
|
||||
},
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.mjs",
|
||||
"typings": "./dist/index.d.ts",
|
||||
"exports": {
|
||||
"import": "./dist/index.mjs",
|
||||
"require": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts"
|
||||
},
|
||||
"directories": {
|
||||
"lib": "src",
|
||||
"test": "__tests__"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"contributors": [
|
||||
"Crawl <icrawltogo@gmail.com>",
|
||||
"Amish Shah <amishshah.2k@gmail.com>",
|
||||
"SpaceEEC <spaceeec@yahoo.com>",
|
||||
"Vlad Frangu <kingdgrizzle@gmail.com>",
|
||||
"Antonio Roman <kyradiscord@gmail.com>",
|
||||
"DD <didinele.dev@gmail.com>"
|
||||
],
|
||||
"license": "Apache-2.0",
|
||||
"keywords": [
|
||||
"discord",
|
||||
"api",
|
||||
"rest",
|
||||
"proxy",
|
||||
"discordapp",
|
||||
"discordjs"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/discordjs/discord.js.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/discordjs/discord.js/issues"
|
||||
},
|
||||
"homepage": "https://discord.js.org",
|
||||
"dependencies": {
|
||||
"@discordjs/rest": "workspace:^",
|
||||
"tslib": "^2.4.0",
|
||||
"undici": "^5.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.18.2",
|
||||
"@babel/plugin-proposal-decorators": "^7.18.2",
|
||||
"@babel/preset-env": "^7.18.2",
|
||||
"@babel/preset-typescript": "^7.17.12",
|
||||
"@discordjs/ts-docgen": "^0.4.1",
|
||||
"@types/jest": "^28.1.0",
|
||||
"@types/node": "^16.11.38",
|
||||
"@types/supertest": "^2.0.12",
|
||||
"@typescript-eslint/eslint-plugin": "^5.27.0",
|
||||
"@typescript-eslint/parser": "^5.27.0",
|
||||
"babel-plugin-const-enum": "^1.2.0",
|
||||
"babel-plugin-transform-typescript-metadata": "^0.3.2",
|
||||
"eslint": "^8.17.0",
|
||||
"eslint-config-marine": "^9.4.1",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"jest": "^28.1.0",
|
||||
"prettier": "^2.6.2",
|
||||
"supertest": "^6.2.3",
|
||||
"tsup": "^6.0.1",
|
||||
"typedoc": "^0.22.17",
|
||||
"typescript": "^4.7.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.9.0"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
}
|
||||
55
packages/proxy/src/handlers/proxyRequests.ts
Normal file
55
packages/proxy/src/handlers/proxyRequests.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
import { URL } from 'node:url';
|
||||
import { DiscordAPIError, HTTPError, RateLimitError, RequestMethod, REST, RouteLike } from '@discordjs/rest';
|
||||
import {
|
||||
populateAbortErrorResponse,
|
||||
populateGeneralErrorResponse,
|
||||
populateSuccessfulResponse,
|
||||
populateRatelimitErrorResponse,
|
||||
} from '../util/responseHelpers';
|
||||
import type { RequestHandler } from '../util/util';
|
||||
|
||||
/**
|
||||
* Creates an HTTP handler used to forward requests to Discord
|
||||
* @param rest REST instance to use for the requests
|
||||
*/
|
||||
export function proxyRequests(rest: REST): RequestHandler {
|
||||
return async (req, res) => {
|
||||
const { method, url } = req;
|
||||
|
||||
if (!method || !url) {
|
||||
throw new TypeError(
|
||||
'Invalid request. Missing method and/or url, implying that this is not a Server IncomingMesage',
|
||||
);
|
||||
}
|
||||
|
||||
// The 2nd parameter is here so the URL constructor doesn't complain about an "invalid url" when the origin is missing
|
||||
// we don't actually care about the origin and the value passed is irrelevant
|
||||
const fullRoute = new URL(url, 'http://noop').pathname.replace(/^\/api(\/v\d+)?/, '') as RouteLike;
|
||||
|
||||
try {
|
||||
const discordResponse = await rest.raw({
|
||||
body: req,
|
||||
fullRoute,
|
||||
// This type cast is technically incorrect, but we want Discord to throw Method Not Allowed for us
|
||||
method: method as RequestMethod,
|
||||
passThroughBody: true,
|
||||
});
|
||||
|
||||
await populateSuccessfulResponse(res, discordResponse);
|
||||
} catch (error) {
|
||||
if (error instanceof DiscordAPIError || error instanceof HTTPError) {
|
||||
populateGeneralErrorResponse(res, error);
|
||||
} else if (error instanceof RateLimitError) {
|
||||
populateRatelimitErrorResponse(res, error);
|
||||
} else if (error instanceof Error && error.name === 'AbortError') {
|
||||
populateAbortErrorResponse(res);
|
||||
} else {
|
||||
// Unclear if there's better course of action here for unknown erorrs. Any web framework allows to pass in an error handler for something like this
|
||||
// at which point the user could dictate what to do with the error - otherwise we could just 500
|
||||
throw error;
|
||||
}
|
||||
} finally {
|
||||
res.end();
|
||||
}
|
||||
};
|
||||
}
|
||||
3
packages/proxy/src/index.ts
Normal file
3
packages/proxy/src/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export * from './handlers/proxyRequests';
|
||||
export * from './util/responseHelpers';
|
||||
export { RequestHandler } from './util/util';
|
||||
54
packages/proxy/src/util/responseHelpers.ts
Normal file
54
packages/proxy/src/util/responseHelpers.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import type { ServerResponse } from 'node:http';
|
||||
import { pipeline } from 'node:stream/promises';
|
||||
import type { DiscordAPIError, HTTPError, RateLimitError } from '@discordjs/rest';
|
||||
import type { Dispatcher } from 'undici';
|
||||
|
||||
/**
|
||||
* Populates a server response with the data from a Discord 2xx REST response
|
||||
* @param res The server response to populate
|
||||
* @param data The data to populate the response with
|
||||
*/
|
||||
export async function populateSuccessfulResponse(res: ServerResponse, data: Dispatcher.ResponseData): Promise<void> {
|
||||
res.statusCode = data.statusCode;
|
||||
|
||||
for (const header of Object.keys(data.headers)) {
|
||||
// Strip ratelimit headers
|
||||
if (header.startsWith('x-ratelimit')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
res.setHeader(header, data.headers[header]!);
|
||||
}
|
||||
|
||||
await pipeline(data.body, res);
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates a server response with the data from a Discord non-2xx REST response that is NOT a 429
|
||||
* @param res The server response to populate
|
||||
* @param error The error to populate the response with
|
||||
*/
|
||||
export function populateGeneralErrorResponse(res: ServerResponse, error: DiscordAPIError | HTTPError): void {
|
||||
res.statusCode = error.status;
|
||||
res.statusMessage = error.message;
|
||||
|
||||
if ('rawError' in error) {
|
||||
res.setHeader('Content-Type', 'application/json');
|
||||
res.write(JSON.stringify(error.rawError));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates a server response with the data from a Discord 429 REST response
|
||||
* @param res The server response to populate
|
||||
* @param error The error to populate the response with
|
||||
*/
|
||||
export function populateRatelimitErrorResponse(res: ServerResponse, error: RateLimitError): void {
|
||||
res.statusCode = 429;
|
||||
res.setHeader('Retry-After', error.timeToReset / 1000);
|
||||
}
|
||||
|
||||
export function populateAbortErrorResponse(res: ServerResponse): void {
|
||||
res.statusCode = 504;
|
||||
res.statusMessage = 'Upstream timed out';
|
||||
}
|
||||
10
packages/proxy/src/util/util.ts
Normal file
10
packages/proxy/src/util/util.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import type { IncomingMessage, ServerResponse } from 'node:http';
|
||||
|
||||
/**
|
||||
* Represents a potentially awaitable value
|
||||
*/
|
||||
export type Awaitable<T> = T | PromiseLike<T>;
|
||||
/**
|
||||
* Represents a simple HTTP request handler
|
||||
*/
|
||||
export type RequestHandler = (req: IncomingMessage, res: ServerResponse) => Awaitable<void>;
|
||||
20
packages/proxy/tsconfig.eslint.json
Normal file
20
packages/proxy/tsconfig.eslint.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"allowJs": true
|
||||
},
|
||||
"include": [
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
"**/*.js",
|
||||
"**/*.mjs",
|
||||
"**/*.jsx",
|
||||
"**/*.test.ts",
|
||||
"**/*.test.js",
|
||||
"**/*.test.mjs",
|
||||
"**/*.spec.ts",
|
||||
"**/*.spec.js",
|
||||
"**/*.spec.mjs"
|
||||
],
|
||||
"exclude": []
|
||||
}
|
||||
4
packages/proxy/tsconfig.json
Normal file
4
packages/proxy/tsconfig.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"include": ["src/**/*.ts"]
|
||||
}
|
||||
20
packages/proxy/tsup.config.ts
Normal file
20
packages/proxy/tsup.config.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { defineConfig } from 'tsup';
|
||||
|
||||
export default defineConfig({
|
||||
clean: true,
|
||||
dts: true,
|
||||
entryPoints: ['src/index.ts'],
|
||||
format: ['esm', 'cjs'],
|
||||
minify: false,
|
||||
keepNames: true,
|
||||
skipNodeModulesBundle: true,
|
||||
sourcemap: true,
|
||||
target: 'es2021',
|
||||
esbuildOptions: (options, context) => {
|
||||
if (context.format === 'cjs') {
|
||||
options.banner = {
|
||||
js: '"use strict";',
|
||||
};
|
||||
}
|
||||
},
|
||||
});
|
||||
191
yarn.lock
191
yarn.lock
@@ -1947,6 +1947,38 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@discordjs/proxy@workspace:packages/proxy":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@discordjs/proxy@workspace:packages/proxy"
|
||||
dependencies:
|
||||
"@babel/core": ^7.18.2
|
||||
"@babel/plugin-proposal-decorators": ^7.18.2
|
||||
"@babel/preset-env": ^7.18.2
|
||||
"@babel/preset-typescript": ^7.17.12
|
||||
"@discordjs/rest": "workspace:^"
|
||||
"@discordjs/ts-docgen": ^0.4.1
|
||||
"@types/jest": ^28.1.0
|
||||
"@types/node": ^16.11.38
|
||||
"@types/supertest": ^2.0.12
|
||||
"@typescript-eslint/eslint-plugin": ^5.27.0
|
||||
"@typescript-eslint/parser": ^5.27.0
|
||||
babel-plugin-const-enum: ^1.2.0
|
||||
babel-plugin-transform-typescript-metadata: ^0.3.2
|
||||
eslint: ^8.17.0
|
||||
eslint-config-marine: ^9.4.1
|
||||
eslint-config-prettier: ^8.5.0
|
||||
eslint-plugin-import: ^2.26.0
|
||||
jest: ^28.1.0
|
||||
prettier: ^2.6.2
|
||||
supertest: ^6.2.3
|
||||
tslib: ^2.4.0
|
||||
tsup: ^6.0.1
|
||||
typedoc: ^0.22.17
|
||||
typescript: ^4.7.3
|
||||
undici: ^5.4.0
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@discordjs/rest@workspace:^, @discordjs/rest@workspace:packages/rest":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@discordjs/rest@workspace:packages/rest"
|
||||
@@ -2640,6 +2672,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/cookiejar@npm:*":
|
||||
version: 2.1.2
|
||||
resolution: "@types/cookiejar@npm:2.1.2"
|
||||
checksum: f6e1903454007f86edd6c3520cbb4d553e1d4e17eaf1f77f6f75e3270f48cc828d74397a113a36942f5fe52f9fa71067bcfa738f53ad468fcca0bc52cb1cbd28
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/eslint@npm:^7.2.13":
|
||||
version: 7.29.0
|
||||
resolution: "@types/eslint@npm:7.29.0"
|
||||
@@ -2785,6 +2824,25 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/superagent@npm:*":
|
||||
version: 4.1.15
|
||||
resolution: "@types/superagent@npm:4.1.15"
|
||||
dependencies:
|
||||
"@types/cookiejar": "*"
|
||||
"@types/node": "*"
|
||||
checksum: 347cd74ef0a29e6b9c6d32253c3fb0dd39a31618b50752f84d36b6a9246237bb6b68c9b436c1f94adabc2df89d9f1939e4782f4c850f98b9c2fe431ad4e565a4
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/supertest@npm:^2.0.12":
|
||||
version: 2.0.12
|
||||
resolution: "@types/supertest@npm:2.0.12"
|
||||
dependencies:
|
||||
"@types/superagent": "*"
|
||||
checksum: f0e2b44f86bec2f708d6a3d0cb209055b487922040773049b0f8c6b557af52d4b5fa904e17dfaa4ce6e610172206bbec7b62420d158fa57b6ffc2de37b1730d3
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/ws@npm:^8.5.3":
|
||||
version: 8.5.3
|
||||
resolution: "@types/ws@npm:8.5.3"
|
||||
@@ -3269,6 +3327,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"asap@npm:^2.0.0":
|
||||
version: 2.0.6
|
||||
resolution: "asap@npm:2.0.6"
|
||||
checksum: b296c92c4b969e973260e47523207cd5769abd27c245a68c26dc7a0fe8053c55bb04360237cb51cab1df52be939da77150ace99ad331fb7fb13b3423ed73ff3d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"asn1@npm:~0.2.3":
|
||||
version: 0.2.6
|
||||
resolution: "asn1@npm:0.2.6"
|
||||
@@ -3988,7 +4053,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"combined-stream@npm:^1.0.6, combined-stream@npm:~1.0.6":
|
||||
"combined-stream@npm:^1.0.6, combined-stream@npm:^1.0.8, combined-stream@npm:~1.0.6":
|
||||
version: 1.0.8
|
||||
resolution: "combined-stream@npm:1.0.8"
|
||||
dependencies:
|
||||
@@ -4079,6 +4144,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"component-emitter@npm:^1.3.0":
|
||||
version: 1.3.0
|
||||
resolution: "component-emitter@npm:1.3.0"
|
||||
checksum: b3c46de38ffd35c57d1c02488355be9f218e582aec72d72d1b8bbec95a3ac1b38c96cd6e03ff015577e68f550fbb361a3bfdbd9bb248be9390b7b3745691be6b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"concat-map@npm:0.0.1":
|
||||
version: 0.0.1
|
||||
resolution: "concat-map@npm:0.0.1"
|
||||
@@ -4316,6 +4388,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"cookiejar@npm:^2.1.3":
|
||||
version: 2.1.3
|
||||
resolution: "cookiejar@npm:2.1.3"
|
||||
checksum: 88259983ebc52ceb23cdacfa48762b6a518a57872eff1c7ed01d214fff5cf492e2660d7d5c04700a28f1787a76811df39e8639f8e17670b3cf94ecd86e161f07
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"core-js-compat@npm:^3.20.0":
|
||||
version: 3.20.2
|
||||
resolution: "core-js-compat@npm:3.20.2"
|
||||
@@ -4564,6 +4643,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"dezalgo@npm:1.0.3":
|
||||
version: 1.0.3
|
||||
resolution: "dezalgo@npm:1.0.3"
|
||||
dependencies:
|
||||
asap: ^2.0.0
|
||||
wrappy: 1
|
||||
checksum: 8b26238db91423b2702a7a6d9629d0019c37c415e7b6e75d4b3e8d27e9464e21cac3618dd145f4d4ee96c70cc6ff034227b5b8a0e9c09015a8bdbe6dace3cfb9
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"diff-sequences@npm:^27.4.0":
|
||||
version: 27.4.0
|
||||
resolution: "diff-sequences@npm:27.4.0"
|
||||
@@ -5558,6 +5647,13 @@ dts-critic@latest:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"fast-safe-stringify@npm:^2.1.1":
|
||||
version: 2.1.1
|
||||
resolution: "fast-safe-stringify@npm:2.1.1"
|
||||
checksum: a851cbddc451745662f8f00ddb622d6766f9bd97642dabfd9a405fb0d646d69fc0b9a1243cbf67f5f18a39f40f6fa821737651ff1bceeba06c9992ca2dc5bd3d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"fastq@npm:^1.6.0":
|
||||
version: 1.13.0
|
||||
resolution: "fastq@npm:1.13.0"
|
||||
@@ -5721,6 +5817,17 @@ dts-critic@latest:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"form-data@npm:^4.0.0":
|
||||
version: 4.0.0
|
||||
resolution: "form-data@npm:4.0.0"
|
||||
dependencies:
|
||||
asynckit: ^0.4.0
|
||||
combined-stream: ^1.0.8
|
||||
mime-types: ^2.1.12
|
||||
checksum: 01135bf8675f9d5c61ff18e2e2932f719ca4de964e3be90ef4c36aacfc7b9cb2fceb5eca0b7e0190e3383fe51c5b37f4cb80b62ca06a99aaabfcfd6ac7c9328c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"form-data@npm:~2.3.2":
|
||||
version: 2.3.3
|
||||
resolution: "form-data@npm:2.3.3"
|
||||
@@ -5732,6 +5839,18 @@ dts-critic@latest:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"formidable@npm:^2.0.1":
|
||||
version: 2.0.1
|
||||
resolution: "formidable@npm:2.0.1"
|
||||
dependencies:
|
||||
dezalgo: 1.0.3
|
||||
hexoid: 1.0.0
|
||||
once: 1.4.0
|
||||
qs: 6.9.3
|
||||
checksum: b35445444e7b6f6f3cacbadd5e6fadd6b5b2e83162e7c41fa22586df584cc515bbd1ee0dc2b701ce031fcb000d71769bc77bd0958db8a89a0ceb8b2227bdc695
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"fs-constants@npm:^1.0.0":
|
||||
version: 1.0.0
|
||||
resolution: "fs-constants@npm:1.0.0"
|
||||
@@ -6230,6 +6349,13 @@ dts-critic@latest:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"hexoid@npm:1.0.0":
|
||||
version: 1.0.0
|
||||
resolution: "hexoid@npm:1.0.0"
|
||||
checksum: 27a148ca76a2358287f40445870116baaff4a0ed0acc99900bf167f0f708ffd82e044ff55e9949c71963852b580fc024146d3ac6d5d76b508b78d927fa48ae2d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"hosted-git-info@npm:^2.1.4":
|
||||
version: 2.8.9
|
||||
resolution: "hosted-git-info@npm:2.8.9"
|
||||
@@ -7983,6 +8109,13 @@ dts-critic@latest:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"methods@npm:^1.1.2":
|
||||
version: 1.1.2
|
||||
resolution: "methods@npm:1.1.2"
|
||||
checksum: 0917ff4041fa8e2f2fda5425a955fe16ca411591fbd123c0d722fcf02b73971ed6f764d85f0a6f547ce49ee0221ce2c19a5fa692157931cecb422984f1dcd13a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"micromatch@npm:^4.0.4":
|
||||
version: 4.0.4
|
||||
resolution: "micromatch@npm:4.0.4"
|
||||
@@ -8009,6 +8142,15 @@ dts-critic@latest:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"mime@npm:^2.5.0":
|
||||
version: 2.6.0
|
||||
resolution: "mime@npm:2.6.0"
|
||||
bin:
|
||||
mime: cli.js
|
||||
checksum: 1497ba7b9f6960694268a557eae24b743fd2923da46ec392b042469f4b901721ba0adcf8b0d3c2677839d0e243b209d76e5edcbd09cfdeffa2dfb6bb4df4b862
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"mimic-fn@npm:^2.1.0":
|
||||
version: 2.1.0
|
||||
resolution: "mimic-fn@npm:2.1.0"
|
||||
@@ -8499,7 +8641,7 @@ dts-critic@latest:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"once@npm:^1.3.0, once@npm:^1.4.0":
|
||||
"once@npm:1.4.0, once@npm:^1.3.0, once@npm:^1.4.0":
|
||||
version: 1.4.0
|
||||
resolution: "once@npm:1.4.0"
|
||||
dependencies:
|
||||
@@ -8959,6 +9101,22 @@ dts-critic@latest:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"qs@npm:6.9.3":
|
||||
version: 6.9.3
|
||||
resolution: "qs@npm:6.9.3"
|
||||
checksum: 89cd1b5e521c19a7e0a7a056ddc261c5c30889664608cf9ce6085f9f25606fc48568cf6a6249e641b4b5c04dac7889e3b82133142523abf397228eb4f488fc38
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"qs@npm:^6.10.3":
|
||||
version: 6.10.3
|
||||
resolution: "qs@npm:6.10.3"
|
||||
dependencies:
|
||||
side-channel: ^1.0.4
|
||||
checksum: 0fac5e6c7191d0295a96d0e83c851aeb015df7e990e4d3b093897d3ac6c94e555dbd0a599739c84d7fa46d7fee282d94ba76943983935cf33bba6769539b8019
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"qs@npm:~6.5.2":
|
||||
version: 6.5.2
|
||||
resolution: "qs@npm:6.5.2"
|
||||
@@ -10005,6 +10163,35 @@ dts-critic@latest:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"superagent@npm:^7.1.3":
|
||||
version: 7.1.3
|
||||
resolution: "superagent@npm:7.1.3"
|
||||
dependencies:
|
||||
component-emitter: ^1.3.0
|
||||
cookiejar: ^2.1.3
|
||||
debug: ^4.3.4
|
||||
fast-safe-stringify: ^2.1.1
|
||||
form-data: ^4.0.0
|
||||
formidable: ^2.0.1
|
||||
methods: ^1.1.2
|
||||
mime: ^2.5.0
|
||||
qs: ^6.10.3
|
||||
readable-stream: ^3.6.0
|
||||
semver: ^7.3.7
|
||||
checksum: 436045d555d35c282de7bcba85102b1421470bdc80781c9a0b7ab7c639675b4eca026a71301974935f3de0d33782a0392274e24f3915335b81a78a04b48eeee5
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"supertest@npm:^6.2.3":
|
||||
version: 6.2.3
|
||||
resolution: "supertest@npm:6.2.3"
|
||||
dependencies:
|
||||
methods: ^1.1.2
|
||||
superagent: ^7.1.3
|
||||
checksum: c1bed86c31723a4bc461153a58176fd80d675deb7d23ab7bd170213040673b35c38e3cbeab9a4eb8a325cf736176c08c6f6522e42f0293314f183e192a6681fa
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"supports-color@npm:^2.0.0":
|
||||
version: 2.0.0
|
||||
resolution: "supports-color@npm:2.0.0"
|
||||
|
||||
Reference in New Issue
Block a user