mirror of
https://github.com/LukeHagar/vercel.git
synced 2025-12-11 21:07:47 +00:00
Compare commits
29 Commits
@vercel/py
...
@vercel/py
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e659eecf48 | ||
|
|
b428f7ff83 | ||
|
|
5eb133283d | ||
|
|
646c29600e | ||
|
|
469eb4315d | ||
|
|
6dc54d0d64 | ||
|
|
adc84d5148 | ||
|
|
88642b1ce8 | ||
|
|
4b8d207533 | ||
|
|
36fe5cc4d1 | ||
|
|
370b0dbed2 | ||
|
|
cc7a82fb0a | ||
|
|
6eea26c39e | ||
|
|
b8bfae7840 | ||
|
|
dc6a0a1cbb | ||
|
|
a6807c9d21 | ||
|
|
c628090d08 | ||
|
|
4e0b291ed1 | ||
|
|
ee0bc9b0c8 | ||
|
|
e516c1f49f | ||
|
|
01f53f36fc | ||
|
|
f2d396caae | ||
|
|
001f2f60b8 | ||
|
|
78ca930287 | ||
|
|
b03e18df12 | ||
|
|
3a6b8b072c | ||
|
|
d480cd6bbd | ||
|
|
181b624bf4 | ||
|
|
200495e4ce |
332
LICENSE
332
LICENSE
@@ -1,190 +1,202 @@
|
|||||||
Apache License
|
|
||||||
Version 2.0, January 2004
|
|
||||||
https://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
1. Definitions.
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction,
|
1. Definitions.
|
||||||
and distribution as defined by Sections 1 through 9 of this document.
|
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
the copyright owner that is granting the License.
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
"Legal Entity" shall mean the union of the acting entity and all
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
other entities that control, are controlled by, or are under common
|
the copyright owner that is granting the License.
|
||||||
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
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
exercising permissions granted by this License.
|
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.
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications,
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
including but not limited to software source code, documentation
|
exercising permissions granted by this License.
|
||||||
source, and configuration files.
|
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
transformation or translation of a Source form, including but
|
including but not limited to software source code, documentation
|
||||||
not limited to compiled object code, generated documentation,
|
source, and configuration files.
|
||||||
and conversions to other media types.
|
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or
|
"Object" form shall mean any form resulting from mechanical
|
||||||
Object form, made available under the License, as indicated by a
|
transformation or translation of a Source form, including but
|
||||||
copyright notice that is included in or attached to the work
|
not limited to compiled object code, generated documentation,
|
||||||
(an example is provided in the Appendix below).
|
and conversions to other media types.
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
form, that is based on (or derived from) the Work and for which the
|
Object form, made available under the License, as indicated by a
|
||||||
editorial revisions, annotations, elaborations, or other modifications
|
copyright notice that is included in or attached to the work
|
||||||
represent, as a whole, an original work of authorship. For the purposes
|
(an example is provided in the Appendix below).
|
||||||
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
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
the original version of the Work and any modifications or additions
|
form, that is based on (or derived from) the Work and for which the
|
||||||
to that Work or Derivative Works thereof, that is intentionally
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
or by an individual or Legal Entity authorized to submit on behalf of
|
of this License, Derivative Works shall not include works that remain
|
||||||
the copyright owner. For the purposes of this definition, "submitted"
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
means any form of electronic, verbal, or written communication sent
|
the Work and Derivative Works thereof.
|
||||||
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
|
"Contribution" shall mean any work of authorship, including
|
||||||
on behalf of whom a Contribution has been received by Licensor and
|
the original version of the Work and any modifications or additions
|
||||||
subsequently incorporated within the Work.
|
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."
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
subsequently incorporated within the Work.
|
||||||
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
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
(except as stated in this section) patent license to make, have made,
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
where such license applies only to those patent claims licensable
|
Work and such Derivative Works in Source or Object form.
|
||||||
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
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
Work or Derivative Works thereof in any medium, with or without
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
modifications, and in Source or Object form, provided that You
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
meet the following conditions:
|
(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.
|
||||||
|
|
||||||
(a) You must give any other recipients of the Work or
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
Derivative Works a copy of this License; and
|
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:
|
||||||
|
|
||||||
(b) You must cause any modified files to carry prominent notices
|
(a) You must give any other recipients of the Work or
|
||||||
stating that You changed the files; and
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
(c) You must retain, in the Source form of any Derivative Works
|
(b) You must cause any modified files to carry prominent notices
|
||||||
that You distribute, all copyright, patent, trademark, and
|
stating that You changed the files; 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
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
distribution, then any Derivative Works that You distribute must
|
that You distribute, all copyright, patent, trademark, and
|
||||||
include a readable copy of the attribution notices contained
|
attribution notices from the Source form of the Work,
|
||||||
within such NOTICE file, excluding those notices that do not
|
excluding those notices that do not pertain to any part of
|
||||||
pertain to any part of the Derivative Works, in at least one
|
the Derivative Works; and
|
||||||
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
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
may provide additional or different license terms and conditions
|
distribution, then any Derivative Works that You distribute must
|
||||||
for use, reproduction, or distribution of Your modifications, or
|
include a readable copy of the attribution notices contained
|
||||||
for any such Derivative Works as a whole, provided Your use,
|
within such NOTICE file, excluding those notices that do not
|
||||||
reproduction, and distribution of the Work otherwise complies with
|
pertain to any part of the Derivative Works, in at least one
|
||||||
the conditions stated in this License.
|
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.
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
You may add Your own copyright statement to Your modifications and
|
||||||
any Contribution intentionally submitted for inclusion in the Work
|
may provide additional or different license terms and conditions
|
||||||
by You to the Licensor shall be under the terms and conditions of
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
this License, without any additional terms or conditions.
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
the terms of any separate license agreement you may have executed
|
the conditions stated in this License.
|
||||||
with Licensor regarding such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
names, trademarks, service marks, or product names of the Licensor,
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
except as required for reasonable and customary use in describing the
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
origin of the Work and reproducing the content of the NOTICE file.
|
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.
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
agreed to in writing, Licensor provides the Work (and each
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
except as required for reasonable and customary use in describing the
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
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,
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
whether in tort (including negligence), contract, or otherwise,
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
unless required by applicable law (such as deliberate and grossly
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
negligent acts) or agreed to in writing, shall any Contributor be
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
liable to You for damages, including any direct, indirect, special,
|
implied, including, without limitation, any warranties or conditions
|
||||||
incidental, or consequential damages of any character arising as a
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
result of this License or out of the use or inability to use the
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
Work (including but not limited to damages for loss of goodwill,
|
appropriateness of using or redistributing the Work and assume any
|
||||||
work stoppage, computer failure or malfunction, or any and all
|
risks associated with Your exercise of permissions under this License.
|
||||||
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
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
the Work or Derivative Works thereof, You may choose to offer,
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
unless required by applicable law (such as deliberate and grossly
|
||||||
or other liability obligations and/or rights consistent with this
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
License. However, in accepting such obligations, You may act only
|
liable to You for damages, including any direct, indirect, special,
|
||||||
on Your own behalf and on Your sole responsibility, not on behalf
|
incidental, or consequential damages of any character arising as a
|
||||||
of any other Contributor, and only if You agree to indemnify,
|
result of this License or out of the use or inability to use the
|
||||||
defend, and hold each Contributor harmless for any liability
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
incurred by, or claims asserted against, such Contributor by reason
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
of your accepting any such warranty or additional liability.
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
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.
|
||||||
|
|
||||||
Copyright 2017 Vercel, Inc.
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
https://www.apache.org/licenses/LICENSE-2.0
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
Copyright 2017 Vercel, Inc.
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
See the License for the specific language governing permissions and
|
you may not use this file except in compliance with the License.
|
||||||
limitations under 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.
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"name": "vercel-monorepo",
|
"name": "vercel-monorepo",
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"license": "MIT",
|
"license": "Apache-2.0",
|
||||||
"workspaces": {
|
"workspaces": {
|
||||||
"packages": [
|
"packages": [
|
||||||
"packages/*"
|
"packages/*"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@vercel/build-utils",
|
"name": "@vercel/build-utils",
|
||||||
"version": "2.10.3-canary.4",
|
"version": "2.11.1",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/index.js",
|
||||||
"types": "./dist/index.d.js",
|
"types": "./dist/index.d.js",
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
"@types/node-fetch": "^2.1.6",
|
"@types/node-fetch": "^2.1.6",
|
||||||
"@types/semver": "6.0.0",
|
"@types/semver": "6.0.0",
|
||||||
"@types/yazl": "^2.4.1",
|
"@types/yazl": "^2.4.1",
|
||||||
"@vercel/frameworks": "0.3.3-canary.3",
|
"@vercel/frameworks": "0.4.1",
|
||||||
"@vercel/ncc": "0.24.0",
|
"@vercel/ncc": "0.24.0",
|
||||||
"aggregate-error": "3.0.1",
|
"aggregate-error": "3.0.1",
|
||||||
"async-retry": "1.2.3",
|
"async-retry": "1.2.3",
|
||||||
|
|||||||
1
packages/cgi/.gitignore
vendored
1
packages/cgi/.gitignore
vendored
@@ -1 +0,0 @@
|
|||||||
handler
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
#!/usr/bin/env node
|
|
||||||
const execa = require('execa');
|
|
||||||
const { join } = require('path');
|
|
||||||
const { homedir } = require('os');
|
|
||||||
|
|
||||||
async function main() {
|
|
||||||
process.env.GOOS = 'linux';
|
|
||||||
process.env.GOARCH = 'amd64';
|
|
||||||
process.env.GOPATH = join(homedir(), 'go');
|
|
||||||
|
|
||||||
await execa('go', ['get', 'github.com/aws/aws-lambda-go/events'], {
|
|
||||||
stdio: 'inherit',
|
|
||||||
});
|
|
||||||
await execa('go', ['get', 'github.com/aws/aws-lambda-go/lambda'], {
|
|
||||||
stdio: 'inherit',
|
|
||||||
});
|
|
||||||
await execa('go', ['build', '-o', 'handler', 'main.go'], {
|
|
||||||
stdio: 'inherit',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
main().catch(err => {
|
|
||||||
console.error(err);
|
|
||||||
process.exit(1);
|
|
||||||
});
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
const path = require('path');
|
|
||||||
const { mkdirp, copyFile } = require('fs-extra');
|
|
||||||
|
|
||||||
const {
|
|
||||||
glob,
|
|
||||||
download,
|
|
||||||
shouldServe,
|
|
||||||
createLambda,
|
|
||||||
getWritableDirectory,
|
|
||||||
} = require('@vercel/build-utils');
|
|
||||||
|
|
||||||
exports.analyze = ({ files, entrypoint }) => files[entrypoint].digest;
|
|
||||||
|
|
||||||
exports.version = 3;
|
|
||||||
|
|
||||||
exports.build = async ({ workPath, files, entrypoint, meta }) => {
|
|
||||||
const outDir = await getWritableDirectory();
|
|
||||||
|
|
||||||
await download(files, workPath, meta);
|
|
||||||
|
|
||||||
const handlerPath = path.join(__dirname, 'handler');
|
|
||||||
await copyFile(handlerPath, path.join(outDir, 'handler'));
|
|
||||||
|
|
||||||
const entrypointOutDir = path.join(outDir, path.dirname(entrypoint));
|
|
||||||
await mkdirp(entrypointOutDir);
|
|
||||||
|
|
||||||
// For now only the entrypoint file is copied into the lambda
|
|
||||||
await copyFile(
|
|
||||||
path.join(workPath, entrypoint),
|
|
||||||
path.join(outDir, entrypoint)
|
|
||||||
);
|
|
||||||
|
|
||||||
const lambda = await createLambda({
|
|
||||||
files: await glob('**', outDir),
|
|
||||||
handler: 'handler',
|
|
||||||
runtime: 'go1.x',
|
|
||||||
environment: {
|
|
||||||
SCRIPT_FILENAME: entrypoint,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return { output: lambda };
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.shouldServe = shouldServe;
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
now "../../utils/go/bridge"
|
|
||||||
"net/http"
|
|
||||||
"net/http/cgi"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
)
|
|
||||||
|
|
||||||
type CgiHandler struct {
|
|
||||||
http.Handler
|
|
||||||
Dir string
|
|
||||||
Script string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *CgiHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
||||||
handler := cgi.Handler{
|
|
||||||
Path: h.Script,
|
|
||||||
Root: "/" + h.Script,
|
|
||||||
Dir: h.Dir,
|
|
||||||
Env: []string{
|
|
||||||
"HTTPS=on",
|
|
||||||
"SERVER_PORT=443",
|
|
||||||
"SERVER_SOFTWARE=@vercel/cgi",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
handler.ServeHTTP(w, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
workdir, _ := filepath.Abs(".")
|
|
||||||
script := os.Getenv("SCRIPT_FILENAME")
|
|
||||||
handler := &CgiHandler{nil, workdir, script}
|
|
||||||
now.Start(handler)
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "@vercel/cgi",
|
|
||||||
"version": "1.0.7",
|
|
||||||
"license": "MIT",
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/vercel/vercel.git",
|
|
||||||
"directory": "packages/cgi"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"build": "node build",
|
|
||||||
"prepublishOnly": "node build"
|
|
||||||
},
|
|
||||||
"files": [
|
|
||||||
"index.js",
|
|
||||||
"handler"
|
|
||||||
],
|
|
||||||
"dependencies": {
|
|
||||||
"fs-extra": "7.0.0"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"rmfr": "2.0.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "vercel",
|
"name": "vercel",
|
||||||
"version": "22.0.2-canary.6",
|
"version": "23.0.1",
|
||||||
"preferGlobal": true,
|
"preferGlobal": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"description": "The command-line interface for Vercel",
|
"description": "The command-line interface for Vercel",
|
||||||
@@ -17,8 +17,8 @@
|
|||||||
"test-integration-dev": "ava test/dev/integration.js --serial --fail-fast --verbose",
|
"test-integration-dev": "ava test/dev/integration.js --serial --fail-fast --verbose",
|
||||||
"prepublishOnly": "yarn build",
|
"prepublishOnly": "yarn build",
|
||||||
"coverage": "nyc report --reporter=text-lcov > coverage.lcov && codecov",
|
"coverage": "nyc report --reporter=text-lcov > coverage.lcov && codecov",
|
||||||
"build": "ts-node ./scripts/build.ts",
|
"build": "node -r ts-eager/register ./scripts/build.ts",
|
||||||
"build-dev": "ts-node ./scripts/build.ts --dev"
|
"build-dev": "node -r ts-eager/register ./scripts/build.ts --dev"
|
||||||
},
|
},
|
||||||
"nyc": {
|
"nyc": {
|
||||||
"include": [
|
"include": [
|
||||||
@@ -61,10 +61,10 @@
|
|||||||
"node": ">= 12"
|
"node": ">= 12"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vercel/build-utils": "2.10.3-canary.4",
|
"@vercel/build-utils": "2.11.1",
|
||||||
"@vercel/go": "1.2.2",
|
"@vercel/go": "1.2.2",
|
||||||
"@vercel/node": "1.10.1-canary.2",
|
"@vercel/node": "1.11.1",
|
||||||
"@vercel/python": "2.0.2",
|
"@vercel/python": "2.0.4",
|
||||||
"@vercel/ruby": "1.2.6",
|
"@vercel/ruby": "1.2.6",
|
||||||
"update-notifier": "4.1.0"
|
"update-notifier": "4.1.0"
|
||||||
},
|
},
|
||||||
@@ -89,7 +89,7 @@
|
|||||||
"@types/mri": "1.1.0",
|
"@types/mri": "1.1.0",
|
||||||
"@types/ms": "0.7.30",
|
"@types/ms": "0.7.30",
|
||||||
"@types/node": "11.11.0",
|
"@types/node": "11.11.0",
|
||||||
"@types/node-fetch": "2.1.4",
|
"@types/node-fetch": "2.5.10",
|
||||||
"@types/npm-package-arg": "6.1.0",
|
"@types/npm-package-arg": "6.1.0",
|
||||||
"@types/pluralize": "0.0.29",
|
"@types/pluralize": "0.0.29",
|
||||||
"@types/progress": "2.0.3",
|
"@types/progress": "2.0.3",
|
||||||
@@ -100,7 +100,7 @@
|
|||||||
"@types/universal-analytics": "0.4.2",
|
"@types/universal-analytics": "0.4.2",
|
||||||
"@types/which": "1.3.2",
|
"@types/which": "1.3.2",
|
||||||
"@types/write-json-file": "2.2.1",
|
"@types/write-json-file": "2.2.1",
|
||||||
"@vercel/frameworks": "0.3.3-canary.3",
|
"@vercel/frameworks": "0.4.1",
|
||||||
"@vercel/ncc": "0.24.0",
|
"@vercel/ncc": "0.24.0",
|
||||||
"@zeit/fun": "0.11.2",
|
"@zeit/fun": "0.11.2",
|
||||||
"@zeit/source-map-support": "0.6.2",
|
"@zeit/source-map-support": "0.6.2",
|
||||||
@@ -117,7 +117,7 @@
|
|||||||
"chalk": "4.1.0",
|
"chalk": "4.1.0",
|
||||||
"chokidar": "3.3.1",
|
"chokidar": "3.3.1",
|
||||||
"clipboardy": "2.1.0",
|
"clipboardy": "2.1.0",
|
||||||
"codecov": "3.7.1",
|
"codecov": "3.8.2",
|
||||||
"cpy": "7.2.0",
|
"cpy": "7.2.0",
|
||||||
"credit-card": "3.0.1",
|
"credit-card": "3.0.1",
|
||||||
"date-fns": "1.29.0",
|
"date-fns": "1.29.0",
|
||||||
@@ -148,7 +148,7 @@
|
|||||||
"node-fetch": "2.6.1",
|
"node-fetch": "2.6.1",
|
||||||
"npm-package-arg": "6.1.0",
|
"npm-package-arg": "6.1.0",
|
||||||
"nyc": "13.2.0",
|
"nyc": "13.2.0",
|
||||||
"open": "8.0.2",
|
"open": "8.2.0",
|
||||||
"ora": "3.4.0",
|
"ora": "3.4.0",
|
||||||
"pcre-to-regexp": "1.0.0",
|
"pcre-to-regexp": "1.0.0",
|
||||||
"pluralize": "7.0.0",
|
"pluralize": "7.0.0",
|
||||||
@@ -169,6 +169,7 @@
|
|||||||
"title": "3.4.1",
|
"title": "3.4.1",
|
||||||
"tmp-promise": "1.0.3",
|
"tmp-promise": "1.0.3",
|
||||||
"tree-kill": "1.2.2",
|
"tree-kill": "1.2.2",
|
||||||
|
"ts-eager": "2.0.2",
|
||||||
"ts-node": "8.3.0",
|
"ts-node": "8.3.0",
|
||||||
"typescript": "3.9.3",
|
"typescript": "3.9.3",
|
||||||
"universal-analytics": "0.4.20",
|
"universal-analytics": "0.4.20",
|
||||||
|
|||||||
@@ -2,10 +2,11 @@ import chalk from 'chalk';
|
|||||||
|
|
||||||
import { handleError } from '../../util/error';
|
import { handleError } from '../../util/error';
|
||||||
|
|
||||||
|
import Client from '../../util/client';
|
||||||
import getArgs from '../../util/get-args';
|
import getArgs from '../../util/get-args';
|
||||||
import getSubcommand from '../../util/get-subcommand';
|
import getSubcommand from '../../util/get-subcommand';
|
||||||
import logo from '../../util/output/logo';
|
import logo from '../../util/output/logo';
|
||||||
import { getPkgName } from '../../util/pkg-name.ts';
|
import { getPkgName } from '../../util/pkg-name';
|
||||||
|
|
||||||
import ls from './ls';
|
import ls from './ls';
|
||||||
import rm from './rm';
|
import rm from './rm';
|
||||||
@@ -36,6 +37,7 @@ const help = () => {
|
|||||||
)} Login token
|
)} Login token
|
||||||
-S, --scope Set a custom scope
|
-S, --scope Set a custom scope
|
||||||
-N, --next Show next page of results
|
-N, --next Show next page of results
|
||||||
|
|
||||||
${chalk.dim('Examples:')}
|
${chalk.dim('Examples:')}
|
||||||
|
|
||||||
${chalk.gray('–')} Add a new alias to ${chalk.underline('my-api.vercel.app')}
|
${chalk.gray('–')} Add a new alias to ${chalk.underline('my-api.vercel.app')}
|
||||||
@@ -64,13 +66,13 @@ const help = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const COMMAND_CONFIG = {
|
const COMMAND_CONFIG = {
|
||||||
default: 'set',
|
default: ['set'],
|
||||||
ls: ['ls', 'list'],
|
ls: ['ls', 'list'],
|
||||||
rm: ['rm', 'remove'],
|
rm: ['rm', 'remove'],
|
||||||
set: ['set'],
|
set: ['set'],
|
||||||
};
|
};
|
||||||
|
|
||||||
export default async function main(client) {
|
export default async function main(client: Client) {
|
||||||
let argv;
|
let argv;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -1,21 +1,26 @@
|
|||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
import ms from 'ms';
|
import ms from 'ms';
|
||||||
import table from 'text-table';
|
import table from 'text-table';
|
||||||
import Now from '../../util';
|
import Client from '../../util/client';
|
||||||
import getAliases from '../../util/alias/get-aliases';
|
import getAliases from '../../util/alias/get-aliases';
|
||||||
import getScope from '../../util/get-scope.ts';
|
import getScope from '../../util/get-scope';
|
||||||
import stamp from '../../util/output/stamp.ts';
|
import stamp from '../../util/output/stamp';
|
||||||
import strlen from '../../util/strlen.ts';
|
import strlen from '../../util/strlen';
|
||||||
import getCommandFlags from '../../util/get-command-flags';
|
import getCommandFlags from '../../util/get-command-flags';
|
||||||
import { getCommandName } from '../../util/pkg-name.ts';
|
import { getCommandName } from '../../util/pkg-name';
|
||||||
|
|
||||||
export default async function ls(client, opts, args) {
|
import { Alias } from '../../types';
|
||||||
const {
|
|
||||||
apiUrl,
|
interface Options {
|
||||||
authConfig: { token },
|
'--next'?: number;
|
||||||
output,
|
}
|
||||||
config: { currentTeam },
|
|
||||||
} = client;
|
export default async function ls(
|
||||||
|
client: Client,
|
||||||
|
opts: Options,
|
||||||
|
args: string[]
|
||||||
|
) {
|
||||||
|
const { output } = client;
|
||||||
const { '--next': nextTimestamp } = opts;
|
const { '--next': nextTimestamp } = opts;
|
||||||
|
|
||||||
let contextName = null;
|
let contextName = null;
|
||||||
@@ -36,13 +41,6 @@ export default async function ls(client, opts, args) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
const now = new Now({
|
|
||||||
apiUrl,
|
|
||||||
token,
|
|
||||||
debug: client.output.isDebugEnabled(),
|
|
||||||
currentTeam,
|
|
||||||
output,
|
|
||||||
});
|
|
||||||
const lsStamp = stamp();
|
const lsStamp = stamp();
|
||||||
|
|
||||||
if (args.length > 0) {
|
if (args.length > 0) {
|
||||||
@@ -56,8 +54,9 @@ export default async function ls(client, opts, args) {
|
|||||||
|
|
||||||
output.spinner(`Fetching aliases under ${chalk.bold(contextName)}`);
|
output.spinner(`Fetching aliases under ${chalk.bold(contextName)}`);
|
||||||
|
|
||||||
|
// Get the list of alias
|
||||||
const { aliases, pagination } = await getAliases(
|
const { aliases, pagination } = await getAliases(
|
||||||
now,
|
client,
|
||||||
undefined,
|
undefined,
|
||||||
nextTimestamp
|
nextTimestamp
|
||||||
);
|
);
|
||||||
@@ -73,21 +72,20 @@ export default async function ls(client, opts, args) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
now.close();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function printAliasTable(aliases) {
|
function printAliasTable(aliases: Alias[]) {
|
||||||
return `${table(
|
return `${table(
|
||||||
[
|
[
|
||||||
['source', 'url', 'age'].map(h => chalk.gray(h)),
|
['source', 'url', 'age'].map(header => chalk.gray(header)),
|
||||||
...aliases.map(a => [
|
...aliases.map(a => [
|
||||||
// for legacy reasons, we might have situations
|
// for legacy reasons, we might have situations
|
||||||
// where the deployment was deleted and the alias
|
// where the deployment was deleted and the alias
|
||||||
// not collected appropriately, and we need to handle it
|
// not collected appropriately, and we need to handle it
|
||||||
a.deployment && a.deployment.url ? a.deployment.url : chalk.gray('–'),
|
a.deployment && a.deployment.url ? a.deployment.url : chalk.gray('–'),
|
||||||
a.alias,
|
a.alias,
|
||||||
ms(Date.now() - new Date(a.createdAt)),
|
ms(Date.now() - a.createdAt),
|
||||||
]),
|
]),
|
||||||
],
|
],
|
||||||
{
|
{
|
||||||
@@ -1,23 +1,29 @@
|
|||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
import ms from 'ms';
|
import ms from 'ms';
|
||||||
import table from 'text-table';
|
import table from 'text-table';
|
||||||
import Now from '../../util';
|
import Client from '../../util/client';
|
||||||
import getScope from '../../util/get-scope.ts';
|
import getScope from '../../util/get-scope';
|
||||||
import removeAliasById from '../../util/alias/remove-alias-by-id';
|
import removeAliasById from '../../util/alias/remove-alias-by-id';
|
||||||
import stamp from '../../util/output/stamp.ts';
|
import stamp from '../../util/output/stamp';
|
||||||
import strlen from '../../util/strlen.ts';
|
import strlen from '../../util/strlen';
|
||||||
import confirm from '../../util/input/confirm';
|
import confirm from '../../util/input/confirm';
|
||||||
import { isValidName } from '../../util/is-valid-name';
|
|
||||||
import findAliasByAliasOrId from '../../util/alias/find-alias-by-alias-or-id';
|
import findAliasByAliasOrId from '../../util/alias/find-alias-by-alias-or-id';
|
||||||
import { getCommandName } from '../../util/pkg-name.ts';
|
|
||||||
|
|
||||||
export default async function rm(client, opts, args) {
|
import { Alias } from '../../types';
|
||||||
const {
|
import { Output } from '../../util/output';
|
||||||
apiUrl,
|
import { isValidName } from '../../util/is-valid-name';
|
||||||
authConfig: { token },
|
import { getCommandName } from '../../util/pkg-name';
|
||||||
output,
|
|
||||||
config: { currentTeam },
|
type Options = {
|
||||||
} = client;
|
'--yes': boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default async function rm(
|
||||||
|
client: Client,
|
||||||
|
opts: Partial<Options>,
|
||||||
|
args: string[]
|
||||||
|
) {
|
||||||
|
const { output } = client;
|
||||||
|
|
||||||
let contextName = null;
|
let contextName = null;
|
||||||
|
|
||||||
@@ -32,13 +38,6 @@ export default async function rm(client, opts, args) {
|
|||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
|
|
||||||
const now = new Now({
|
|
||||||
apiUrl,
|
|
||||||
token,
|
|
||||||
debug: client.output.isDebugEnabled(),
|
|
||||||
currentTeam,
|
|
||||||
output,
|
|
||||||
});
|
|
||||||
const [aliasOrId] = args;
|
const [aliasOrId] = args;
|
||||||
|
|
||||||
if (args.length !== 1) {
|
if (args.length !== 1) {
|
||||||
@@ -61,7 +60,8 @@ export default async function rm(client, opts, args) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
const alias = await findAliasByAliasOrId(output, now, aliasOrId);
|
const alias = await findAliasByAliasOrId(output, client, aliasOrId);
|
||||||
|
|
||||||
if (!alias) {
|
if (!alias) {
|
||||||
output.error(
|
output.error(
|
||||||
`Alias not found by "${aliasOrId}" under ${chalk.bold(contextName)}`
|
`Alias not found by "${aliasOrId}" under ${chalk.bold(contextName)}`
|
||||||
@@ -76,7 +76,7 @@ export default async function rm(client, opts, args) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
await removeAliasById(now, alias.uid);
|
await removeAliasById(client, alias.uid);
|
||||||
console.log(
|
console.log(
|
||||||
`${chalk.cyan('> Success!')} Alias ${chalk.bold(
|
`${chalk.cyan('> Success!')} Alias ${chalk.bold(
|
||||||
alias.alias
|
alias.alias
|
||||||
@@ -85,7 +85,7 @@ export default async function rm(client, opts, args) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function confirmAliasRemove(output, alias) {
|
async function confirmAliasRemove(output: Output, alias: Alias) {
|
||||||
const srcUrl = alias.deployment
|
const srcUrl = alias.deployment
|
||||||
? chalk.underline(alias.deployment.url)
|
? chalk.underline(alias.deployment.url)
|
||||||
: null;
|
: null;
|
||||||
@@ -94,7 +94,7 @@ async function confirmAliasRemove(output, alias) {
|
|||||||
[
|
[
|
||||||
...(srcUrl ? [srcUrl] : []),
|
...(srcUrl ? [srcUrl] : []),
|
||||||
chalk.underline(alias.alias),
|
chalk.underline(alias.alias),
|
||||||
chalk.gray(`${ms(new Date() - new Date(alias.created))} ago`),
|
chalk.gray(`${ms(Date.now() - alias.createdAt)} ago`),
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
{
|
{
|
||||||
@@ -28,7 +28,7 @@ type Options = {
|
|||||||
|
|
||||||
export default async function set(
|
export default async function set(
|
||||||
client: Client,
|
client: Client,
|
||||||
opts: Options,
|
opts: Partial<Options>,
|
||||||
args: string[]
|
args: string[]
|
||||||
) {
|
) {
|
||||||
const { output, localConfig } = client;
|
const { output, localConfig } = client;
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import { getCommandName, getPkgName } from '../util/pkg-name';
|
|||||||
import getGlobalPathConfig from '../util/config/global-path';
|
import getGlobalPathConfig from '../util/config/global-path';
|
||||||
import { writeToAuthConfigFile, writeToConfigFile } from '../util/config/files';
|
import { writeToAuthConfigFile, writeToConfigFile } from '../util/config/files';
|
||||||
import Client from '../util/client';
|
import Client from '../util/client';
|
||||||
import { LoginParams } from '../util/login/types';
|
|
||||||
|
|
||||||
const help = () => {
|
const help = () => {
|
||||||
console.log(`
|
console.log(`
|
||||||
@@ -46,7 +45,7 @@ const help = () => {
|
|||||||
|
|
||||||
export default async function login(client: Client): Promise<number> {
|
export default async function login(client: Client): Promise<number> {
|
||||||
let argv;
|
let argv;
|
||||||
const { apiUrl, output } = client;
|
const { output } = client;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
argv = getArgs(client.argv.slice(2));
|
argv = getArgs(client.argv.slice(2));
|
||||||
@@ -68,18 +67,17 @@ export default async function login(client: Client): Promise<number> {
|
|||||||
const input = argv._[1];
|
const input = argv._[1];
|
||||||
|
|
||||||
let result: number | string = 1;
|
let result: number | string = 1;
|
||||||
const params: LoginParams = { output, apiUrl };
|
|
||||||
|
|
||||||
if (input) {
|
if (input) {
|
||||||
// Email or Team slug was provided via command line
|
// Email or Team slug was provided via command line
|
||||||
if (validateEmail(input)) {
|
if (validateEmail(input)) {
|
||||||
result = await doEmailLogin(input, params);
|
result = await doEmailLogin(client, input);
|
||||||
} else {
|
} else {
|
||||||
result = await doSsoLogin(input, params);
|
result = await doSsoLogin(client, input);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Interactive mode
|
// Interactive mode
|
||||||
result = await prompt(params);
|
result = await prompt(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The login function failed, so it returned an exit code
|
// The login function failed, so it returned an exit code
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
import logo from '../util/output/logo';
|
import logo from '../util/output/logo';
|
||||||
// @ts-ignore
|
|
||||||
import { handleError } from '../util/error';
|
import { handleError } from '../util/error';
|
||||||
import { writeToConfigFile, writeToAuthConfigFile } from '../util/config/files';
|
import { writeToConfigFile, writeToAuthConfigFile } from '../util/config/files';
|
||||||
import getArgs from '../util/get-args';
|
import getArgs from '../util/get-args';
|
||||||
@@ -62,6 +61,7 @@ export default async function main(client: Client): Promise<number> {
|
|||||||
try {
|
try {
|
||||||
await client.fetch(`/v3/user/tokens/current`, {
|
await client.fetch(`/v3/user/tokens/current`, {
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
|
useCurrentTeam: false,
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err.status === 403) {
|
if (err.status === 403) {
|
||||||
|
|||||||
@@ -187,25 +187,22 @@ async function run({ client, contextName }) {
|
|||||||
|
|
||||||
const name = args[0];
|
const name = args[0];
|
||||||
|
|
||||||
// Check the existence of the project
|
|
||||||
try {
|
|
||||||
await client.fetch(`/projects/info/${e(name)}`);
|
|
||||||
} catch (err) {
|
|
||||||
if (err.status === 404) {
|
|
||||||
console.error(error('No such project exists'));
|
|
||||||
return exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const yes = await readConfirmation(name);
|
const yes = await readConfirmation(name);
|
||||||
if (!yes) {
|
if (!yes) {
|
||||||
console.error(error('User abort'));
|
console.error(error('User abort'));
|
||||||
return exit(0);
|
return exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
await client.fetch(`/v2/projects/${name}`, {
|
try {
|
||||||
method: 'DELETE',
|
await client.fetch(`/v2/projects/${e(name)}`, {
|
||||||
});
|
method: 'DELETE',
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
if (err.status === 404) {
|
||||||
|
console.error(error('No such project exists'));
|
||||||
|
return exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
const elapsed = ms(new Date() - start);
|
const elapsed = ms(new Date() - start);
|
||||||
console.log(
|
console.log(
|
||||||
`${chalk.cyan('> Success!')} Project ${chalk.bold(
|
`${chalk.cyan('> Success!')} Project ${chalk.bold(
|
||||||
|
|||||||
@@ -115,8 +115,6 @@ export default async function main(client) {
|
|||||||
try {
|
try {
|
||||||
({ contextName } = await getScope(client));
|
({ contextName } = await getScope(client));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
client.close();
|
|
||||||
|
|
||||||
if (err.code === 'NOT_AUTHORIZED' || err.code === 'TEAM_DELETED') {
|
if (err.code === 'NOT_AUTHORIZED' || err.code === 'TEAM_DELETED') {
|
||||||
output.error(err.message);
|
output.error(err.message);
|
||||||
return 1;
|
return 1;
|
||||||
@@ -210,7 +208,6 @@ export default async function main(client) {
|
|||||||
.map(id => chalk.bold(`"${id}"`))
|
.map(id => chalk.bold(`"${id}"`))
|
||||||
.join(', ')}. Run ${getCommandName('ls')} to list.`
|
.join(', ')}. Run ${getCommandName('ls')} to list.`
|
||||||
);
|
);
|
||||||
client.close();
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,7 +230,6 @@ export default async function main(client) {
|
|||||||
|
|
||||||
if (confirmation !== 'y' && confirmation !== 'yes') {
|
if (confirmation !== 'y' && confirmation !== 'yes') {
|
||||||
output.log('Aborted');
|
output.log('Aborted');
|
||||||
client.close();
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -265,7 +261,6 @@ export default async function main(client) {
|
|||||||
console.log(`${chalk.gray('-')} ${chalk.bold(project.name)}`);
|
console.log(`${chalk.gray('-')} ${chalk.bold(project.name)}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
client.close();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,9 +3,10 @@ import chalk from 'chalk';
|
|||||||
|
|
||||||
// Utilities
|
// Utilities
|
||||||
import Client from '../../util/client';
|
import Client from '../../util/client';
|
||||||
import listInput from '../../util/input/list';
|
import { emoji } from '../../util/emoji';
|
||||||
import getUser from '../../util/get-user';
|
import getUser from '../../util/get-user';
|
||||||
import getTeams from '../../util/get-teams';
|
import getTeams from '../../util/get-teams';
|
||||||
|
import listInput from '../../util/input/list';
|
||||||
import { Team, GlobalConfig } from '../../types';
|
import { Team, GlobalConfig } from '../../types';
|
||||||
import { writeToConfigFile } from '../../util/config/files';
|
import { writeToConfigFile } from '../../util/config/files';
|
||||||
|
|
||||||
@@ -31,7 +32,7 @@ export default async function main(client: Client, desiredSlug?: string) {
|
|||||||
: teams.find(team => team.id === config.currentTeam);
|
: teams.find(team => team.id === config.currentTeam);
|
||||||
|
|
||||||
if (!personalScopeSelected && !currentTeam) {
|
if (!personalScopeSelected && !currentTeam) {
|
||||||
output.error(`You are not a part of the current team anymore.`);
|
output.error(`You are not a member of the current team anymore.`);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,30 +42,39 @@ export default async function main(client: Client, desiredSlug?: string) {
|
|||||||
.sort((a, b) => {
|
.sort((a, b) => {
|
||||||
return a.name.toLowerCase().localeCompare(b.name.toLowerCase());
|
return a.name.toLowerCase().localeCompare(b.name.toLowerCase());
|
||||||
})
|
})
|
||||||
.map(({ id, slug, name }) => {
|
.map(team => {
|
||||||
let title = `${name} (${slug})`;
|
let title = `${team.name} (${team.slug})`;
|
||||||
const selected = id === currentTeam?.id;
|
const selected = team.id === currentTeam?.id;
|
||||||
|
|
||||||
if (selected) {
|
if (selected) {
|
||||||
title += ` ${chalk.bold('(current)')}`;
|
title += ` ${chalk.bold('(current)')}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (team.limited) {
|
||||||
|
title += ` ${emoji('locked')}`;
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: title,
|
name: title,
|
||||||
value: slug,
|
value: team.slug,
|
||||||
short: slug,
|
short: team.slug,
|
||||||
selected,
|
selected,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add the User scope entry at the top
|
// Add the User scope entry at the top
|
||||||
const suffix = personalScopeSelected ? ` ${chalk.bold('(current)')}` : '';
|
let suffix = personalScopeSelected ? ` ${chalk.bold('(current)')}` : '';
|
||||||
|
|
||||||
|
// SAML tokens can not interact with the user scope
|
||||||
|
if (user.limited) {
|
||||||
|
suffix += ` ${emoji('locked')}`;
|
||||||
|
}
|
||||||
|
|
||||||
const choices = [
|
const choices = [
|
||||||
{ separator: 'Personal Account' },
|
{ separator: 'Personal Account' },
|
||||||
{
|
{
|
||||||
name: `${user.email} (${user.username})${suffix}`,
|
name: `${user.name || user.email} (${user.username})${suffix}`,
|
||||||
value: user.email,
|
value: user.username,
|
||||||
short: user.username,
|
short: user.username,
|
||||||
selected: personalScopeSelected,
|
selected: personalScopeSelected,
|
||||||
},
|
},
|
||||||
@@ -93,9 +103,18 @@ export default async function main(client: Client, desiredSlug?: string) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (user.limited) {
|
||||||
|
await client.reauthenticate({
|
||||||
|
scope: user.username,
|
||||||
|
teamId: null,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
updateCurrentTeam(config);
|
updateCurrentTeam(config);
|
||||||
|
|
||||||
output.success(`Your account (${chalk.bold(desiredSlug)}) is now active!`);
|
output.success(
|
||||||
|
`Your account (${chalk.bold(user.username)}) is now active!`
|
||||||
|
);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,6 +133,15 @@ export default async function main(client: Client, desiredSlug?: string) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (newTeam.limited) {
|
||||||
|
const samlEnabled = newTeam.saml?.connection?.state === 'active';
|
||||||
|
await client.reauthenticate({
|
||||||
|
teamId: samlEnabled ? newTeam.id : null,
|
||||||
|
scope: newTeam.slug,
|
||||||
|
enforced: samlEnabled && newTeam.saml?.enforced === true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
updateCurrentTeam(config, newTeam);
|
updateCurrentTeam(config, newTeam);
|
||||||
|
|
||||||
output.success(
|
output.success(
|
||||||
|
|||||||
@@ -1,5 +1,22 @@
|
|||||||
|
export type Primitive =
|
||||||
|
| bigint
|
||||||
|
| boolean
|
||||||
|
| null
|
||||||
|
| number
|
||||||
|
| string
|
||||||
|
| symbol
|
||||||
|
| undefined;
|
||||||
|
|
||||||
|
export type JSONArray = JSONValue[];
|
||||||
|
|
||||||
|
export type JSONValue = Primitive | JSONObject | JSONArray;
|
||||||
|
|
||||||
|
export interface JSONObject {
|
||||||
|
[key: string]: JSONValue;
|
||||||
|
}
|
||||||
|
|
||||||
export interface AuthConfig {
|
export interface AuthConfig {
|
||||||
token: string;
|
token?: string;
|
||||||
skipWrite?: boolean;
|
skipWrite?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,18 +62,26 @@ export type User = {
|
|||||||
updatedAt: number;
|
updatedAt: number;
|
||||||
};
|
};
|
||||||
name?: string;
|
name?: string;
|
||||||
|
limited?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Team = {
|
export interface Team {
|
||||||
id: string;
|
id: string;
|
||||||
avatar?: string;
|
avatar?: string | null;
|
||||||
billing: Billing;
|
billing: Billing;
|
||||||
created: string;
|
created: string;
|
||||||
creatorId: string;
|
creatorId: string;
|
||||||
membership: { uid: string; role: 'MEMBER' | 'OWNER'; created: number };
|
membership: { uid: string; role: 'MEMBER' | 'OWNER'; created: number };
|
||||||
name: string;
|
name: string;
|
||||||
slug: string;
|
slug: string;
|
||||||
};
|
limited?: boolean;
|
||||||
|
saml?: {
|
||||||
|
enforced: boolean;
|
||||||
|
connection?: {
|
||||||
|
state: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export type Domain = {
|
export type Domain = {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -120,7 +145,7 @@ export type Deployment = {
|
|||||||
export type Alias = {
|
export type Alias = {
|
||||||
uid: string;
|
uid: string;
|
||||||
alias: string;
|
alias: string;
|
||||||
created: string;
|
createdAt: number;
|
||||||
deployment: {
|
deployment: {
|
||||||
id: string;
|
id: string;
|
||||||
url: string;
|
url: string;
|
||||||
@@ -268,3 +293,13 @@ export type ProjectLinkResult =
|
|||||||
| { status: 'linked'; org: Org; project: Project }
|
| { status: 'linked'; org: Org; project: Project }
|
||||||
| { status: 'not_linked'; org: null; project: null }
|
| { status: 'not_linked'; org: null; project: null }
|
||||||
| { status: 'error'; exitCode: number };
|
| { status: 'error'; exitCode: number };
|
||||||
|
|
||||||
|
export interface Token {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
type: string;
|
||||||
|
origin?: string;
|
||||||
|
activeAt: number;
|
||||||
|
createdAt: number;
|
||||||
|
teamId?: string;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { Output } from '../output';
|
import { Output } from '../output';
|
||||||
import { Alias } from '../../types';
|
import { Alias } from '../../types';
|
||||||
|
|
||||||
import Client from '../client';
|
import Client from '../client';
|
||||||
|
|
||||||
export default async function findAliasByAliasOrId(
|
export default async function findAliasByAliasOrId(
|
||||||
@@ -11,7 +12,6 @@ export default async function findAliasByAliasOrId(
|
|||||||
`/now/aliases/${encodeURIComponent(getSafeAlias(aliasOrId))}`
|
`/now/aliases/${encodeURIComponent(getSafeAlias(aliasOrId))}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSafeAlias(alias: string) {
|
function getSafeAlias(alias: string) {
|
||||||
return alias
|
return alias
|
||||||
.replace(/^https:\/\//i, '')
|
.replace(/^https:\/\//i, '')
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import { Alias } from '../../types';
|
import { Alias, PaginationOptions } from '../../types';
|
||||||
import Client from '../client';
|
import Client from '../client';
|
||||||
|
|
||||||
type Response = {
|
type Response = {
|
||||||
aliases: Alias[];
|
aliases: Alias[];
|
||||||
|
pagination: PaginationOptions;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default async function getAliases(
|
export default async function getAliases(
|
||||||
|
|||||||
@@ -2,6 +2,6 @@ import Client from '../client';
|
|||||||
|
|
||||||
export default async function removeAliasById(client: Client, id: string) {
|
export default async function removeAliasById(client: Client, id: string) {
|
||||||
return client.fetch(`/now/aliases/${id}`, {
|
return client.fetch(`/now/aliases/${id}`, {
|
||||||
method: 'DELETE'
|
method: 'DELETE',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,28 @@
|
|||||||
import { URLSearchParams } from 'url';
|
|
||||||
import { EventEmitter } from 'events';
|
import { EventEmitter } from 'events';
|
||||||
|
import { URLSearchParams } from 'url';
|
||||||
import { parse as parseUrl } from 'url';
|
import { parse as parseUrl } from 'url';
|
||||||
import fetch, { RequestInit, Response } from 'node-fetch';
|
import { VercelConfig } from '@vercel/client';
|
||||||
import retry, { RetryFunction, Options as RetryOptions } from 'async-retry';
|
import retry, { RetryFunction, Options as RetryOptions } from 'async-retry';
|
||||||
|
import fetch, { BodyInit, Headers, RequestInit, Response } from 'node-fetch';
|
||||||
|
import ua from './ua';
|
||||||
import { Output } from './output/create-output';
|
import { Output } from './output/create-output';
|
||||||
import responseError from './response-error';
|
import responseError from './response-error';
|
||||||
import ua from './ua';
|
|
||||||
import printIndications from './print-indications';
|
import printIndications from './print-indications';
|
||||||
import { AuthConfig, GlobalConfig } from '../types';
|
import reauthenticate from './login/reauthenticate';
|
||||||
import { VercelConfig } from './dev/types';
|
import { SAMLError } from './login/types';
|
||||||
import doSsoLogin from './login/sso';
|
|
||||||
import { writeToAuthConfigFile } from './config/files';
|
import { writeToAuthConfigFile } from './config/files';
|
||||||
|
import { AuthConfig, GlobalConfig, JSONObject } from '../types';
|
||||||
|
import { sharedPromise } from './promise';
|
||||||
|
import { APIError } from './errors-ts';
|
||||||
|
import { bold } from 'chalk';
|
||||||
|
|
||||||
export interface FetchOptions {
|
const isSAMLError = (v: any): v is SAMLError => {
|
||||||
body?: NodeJS.ReadableStream | object | string;
|
return v && v.saml;
|
||||||
headers?: { [key: string]: string };
|
};
|
||||||
|
|
||||||
|
export interface FetchOptions extends Omit<RequestInit, 'body'> {
|
||||||
|
body?: BodyInit | JSONObject;
|
||||||
json?: boolean;
|
json?: boolean;
|
||||||
method?: 'GET' | 'POST' | 'PATCH' | 'PUT' | 'DELETE';
|
|
||||||
retry?: RetryOptions;
|
retry?: RetryOptions;
|
||||||
useCurrentTeam?: boolean;
|
useCurrentTeam?: boolean;
|
||||||
accountId?: string;
|
accountId?: string;
|
||||||
@@ -31,6 +37,10 @@ export interface ClientOptions {
|
|||||||
localConfig: VercelConfig;
|
localConfig: VercelConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isJSONObject = (v: any): v is JSONObject => {
|
||||||
|
return v && typeof v == 'object' && v.constructor === Object;
|
||||||
|
};
|
||||||
|
|
||||||
export default class Client extends EventEmitter {
|
export default class Client extends EventEmitter {
|
||||||
argv: string[];
|
argv: string[];
|
||||||
apiUrl: string;
|
apiUrl: string;
|
||||||
@@ -47,7 +57,6 @@ export default class Client extends EventEmitter {
|
|||||||
this.output = opts.output;
|
this.output = opts.output;
|
||||||
this.config = opts.config;
|
this.config = opts.config;
|
||||||
this.localConfig = opts.localConfig;
|
this.localConfig = opts.localConfig;
|
||||||
this._onRetry = this._onRetry.bind(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
retry<T>(fn: RetryFunction<T>, { retries = 3, maxTimeout = Infinity } = {}) {
|
retry<T>(fn: RetryFunction<T>, { retries = 3, maxTimeout = Infinity } = {}) {
|
||||||
@@ -78,34 +87,30 @@ export default class Client extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_url = `${apiUrl}${parsedUrl.pathname}?${query}`;
|
_url = `${apiUrl}${parsedUrl.pathname}?${query}`;
|
||||||
|
|
||||||
delete opts.useCurrentTeam;
|
|
||||||
delete opts.accountId;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opts.json !== false && opts.body && typeof opts.body === 'object') {
|
const headers = new Headers(opts.headers);
|
||||||
Object.assign(opts, {
|
headers.set('authorization', `Bearer ${this.authConfig.token}`);
|
||||||
body: JSON.stringify(opts.body),
|
headers.set('user-agent', ua);
|
||||||
headers: Object.assign({}, opts.headers, {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
opts.headers = opts.headers || {};
|
let body;
|
||||||
opts.headers.Authorization = `Bearer ${this.authConfig.token}`;
|
if (isJSONObject(opts.body)) {
|
||||||
opts.headers['user-agent'] = ua;
|
body = JSON.stringify(opts.body);
|
||||||
|
headers.set('content-type', 'application/json; charset=utf8');
|
||||||
|
} else {
|
||||||
|
body = opts.body;
|
||||||
|
}
|
||||||
|
|
||||||
const url = `${apiUrl ? '' : this.apiUrl}${_url}`;
|
const url = `${apiUrl ? '' : this.apiUrl}${_url}`;
|
||||||
return this.output.time(
|
return this.output.time(
|
||||||
`${opts.method || 'GET'} ${url} ${JSON.stringify(opts.body) || ''}`,
|
`${opts.method || 'GET'} ${url} ${JSON.stringify(opts.body) || ''}`,
|
||||||
fetch(url, opts as RequestInit)
|
fetch(url, { ...opts, headers, body })
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fetch(url: string, opts: { json: false }): Promise<Response>;
|
fetch(url: string, opts: { json: false }): Promise<Response>;
|
||||||
fetch<T>(url: string, opts?: FetchOptions): Promise<T>;
|
fetch<T>(url: string, opts?: FetchOptions): Promise<T>;
|
||||||
async fetch<T>(url: string, opts: FetchOptions = {}): Promise<T> {
|
fetch(url: string, opts: FetchOptions = {}) {
|
||||||
return this.retry(async bail => {
|
return this.retry(async bail => {
|
||||||
const res = await this._fetch(url, opts);
|
const res = await this._fetch(url, opts);
|
||||||
|
|
||||||
@@ -114,19 +119,11 @@ export default class Client extends EventEmitter {
|
|||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
const error = await responseError(res);
|
const error = await responseError(res);
|
||||||
|
|
||||||
if (error.saml && error.teamId) {
|
if (isSAMLError(error)) {
|
||||||
// If a SAML error is encountered then we re-trigger the SAML
|
// A SAML error means the token is expired, or is not
|
||||||
// authentication flow for the team specified in the error.
|
// designated for the requested team, so the user needs
|
||||||
const result = await doSsoLogin(error.teamId, this);
|
// to re-authenticate
|
||||||
|
await this.reauthenticate(error);
|
||||||
if (typeof result === 'number') {
|
|
||||||
this.output.prettyError(error);
|
|
||||||
process.exit(1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.authConfig.token = result;
|
|
||||||
writeToAuthConfigFile(this.authConfig);
|
|
||||||
} else if (res.status >= 400 && res.status < 500) {
|
} else if (res.status >= 400 && res.status < 500) {
|
||||||
// Any other 4xx should bail without retrying
|
// Any other 4xx should bail without retrying
|
||||||
return bail(error);
|
return bail(error);
|
||||||
@@ -140,19 +137,37 @@ export default class Client extends EventEmitter {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!res.headers.get('content-type')) {
|
const contentType = res.headers.get('content-type');
|
||||||
|
if (!contentType) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.headers.get('content-type').includes('application/json')
|
return contentType.includes('application/json') ? res.json() : res;
|
||||||
? res.json()
|
|
||||||
: res;
|
|
||||||
}, opts.retry);
|
}, opts.retry);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onRetry(error: Error) {
|
reauthenticate = sharedPromise(async function (
|
||||||
this.output.debug(`Retrying: ${error}\n${error.stack}`);
|
this: Client,
|
||||||
}
|
error: SAMLError
|
||||||
|
) {
|
||||||
|
const result = await reauthenticate(this, error);
|
||||||
|
|
||||||
close() {}
|
if (typeof result === 'number') {
|
||||||
|
if (error instanceof APIError) {
|
||||||
|
this.output.prettyError(error);
|
||||||
|
} else {
|
||||||
|
this.output.error(
|
||||||
|
`Failed to re-authenticate for ${bold(error.scope)} scope`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.authConfig.token = result;
|
||||||
|
writeToAuthConfigFile(this.authConfig);
|
||||||
|
});
|
||||||
|
|
||||||
|
_onRetry = (error: Error) => {
|
||||||
|
this.output.debug(`Retrying: ${error}\n${error.stack}`);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,9 @@ export default async function getDeploymentsByProjectId(
|
|||||||
query.set('from', options.from.toString());
|
query.set('from', options.from.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
const { deployments } = await client.fetch<Response>(`/v4/now/deployments?${query}`);
|
const { deployments } = await client.fetch<Response>(
|
||||||
|
`/v4/now/deployments?${query}`
|
||||||
|
);
|
||||||
total += deployments.length;
|
total += deployments.length;
|
||||||
|
|
||||||
if (options.max && total >= options.max) {
|
if (options.max && total >= options.max) {
|
||||||
@@ -49,15 +51,15 @@ export default async function getDeploymentsByProjectId(
|
|||||||
if (options.continue && deployments.length === limit) {
|
if (options.continue && deployments.length === limit) {
|
||||||
const nextFrom = deployments[deployments.length - 1].created;
|
const nextFrom = deployments[deployments.length - 1].created;
|
||||||
const nextOptions = Object.assign({}, options, { from: nextFrom });
|
const nextOptions = Object.assign({}, options, { from: nextFrom });
|
||||||
deployments.push(...(await getDeploymentsByProjectId(client, projectId, nextOptions, total)));
|
deployments.push(
|
||||||
|
...(await getDeploymentsByProjectId(
|
||||||
|
client,
|
||||||
|
projectId,
|
||||||
|
nextOptions,
|
||||||
|
total
|
||||||
|
))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return deployments;
|
return deployments;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getAllDeploymentsByProjectId(
|
|
||||||
client: Client,
|
|
||||||
projectId: string
|
|
||||||
) {
|
|
||||||
return getDeploymentsByProjectId(client, projectId, { from: null, limit: 100, continue: true });
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -145,6 +145,7 @@ export default class DevServer {
|
|||||||
private devServerPids: Set<number>;
|
private devServerPids: Set<number>;
|
||||||
private projectSettings?: ProjectSettings;
|
private projectSettings?: ProjectSettings;
|
||||||
|
|
||||||
|
private vercelConfigWarning: boolean;
|
||||||
private getVercelConfigPromise: Promise<VercelConfig> | null;
|
private getVercelConfigPromise: Promise<VercelConfig> | null;
|
||||||
private blockingBuildsPromise: Promise<void> | null;
|
private blockingBuildsPromise: Promise<void> | null;
|
||||||
private updateBuildersPromise: Promise<void> | null;
|
private updateBuildersPromise: Promise<void> | null;
|
||||||
@@ -181,6 +182,7 @@ export default class DevServer {
|
|||||||
this.inProgressBuilds = new Map();
|
this.inProgressBuilds = new Map();
|
||||||
this.devCacheDir = join(getVercelDirectory(cwd), 'cache');
|
this.devCacheDir = join(getVercelDirectory(cwd), 'cache');
|
||||||
|
|
||||||
|
this.vercelConfigWarning = false;
|
||||||
this.getVercelConfigPromise = null;
|
this.getVercelConfigPromise = null;
|
||||||
this.blockingBuildsPromise = null;
|
this.blockingBuildsPromise = null;
|
||||||
this.updateBuildersPromise = null;
|
this.updateBuildersPromise = null;
|
||||||
@@ -636,6 +638,20 @@ export default class DevServer {
|
|||||||
|
|
||||||
await this.validateVercelConfig(config);
|
await this.validateVercelConfig(config);
|
||||||
|
|
||||||
|
// TODO: temporarily strip and warn since `has` is not implemented yet
|
||||||
|
config.routes = (config.routes || []).filter(route => {
|
||||||
|
if ('has' in route) {
|
||||||
|
if (!this.vercelConfigWarning) {
|
||||||
|
this.vercelConfigWarning = true;
|
||||||
|
this.output.warn(
|
||||||
|
`The "has" property in ${config[fileNameSymbol]} will be ignored during development. Deployments will work as expected.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
this.caseSensitive = hasNewRoutingProperties(config);
|
this.caseSensitive = hasNewRoutingProperties(config);
|
||||||
this.apiDir = detectApiDirectory(config.builds || []);
|
this.apiDir = detectApiDirectory(config.builds || []);
|
||||||
this.apiExtensions = detectApiExtensions(config.builds || []);
|
this.apiExtensions = detectApiExtensions(config.builds || []);
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ export const emojiLabels = {
|
|||||||
link: '🔗',
|
link: '🔗',
|
||||||
inspect: '🔍',
|
inspect: '🔍',
|
||||||
success: '✅',
|
success: '✅',
|
||||||
|
locked: '🔒',
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export type EmojiLabel = keyof typeof emojiLabels;
|
export type EmojiLabel = keyof typeof emojiLabels;
|
||||||
|
|||||||
@@ -6,15 +6,12 @@ export default async function confirm(
|
|||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
require('./patch-inquirer');
|
require('./patch-inquirer');
|
||||||
|
|
||||||
const name = `${Date.now()}`;
|
|
||||||
|
|
||||||
const answers = await inquirer.prompt({
|
const answers = await inquirer.prompt({
|
||||||
type: 'confirm',
|
type: 'confirm',
|
||||||
name,
|
name: 'value',
|
||||||
message,
|
message,
|
||||||
default: preferred,
|
default: preferred,
|
||||||
});
|
});
|
||||||
|
|
||||||
const answer = answers[name] as boolean;
|
return answers.value;
|
||||||
return answer;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,5 +9,5 @@ export default function doBitbucketLogin(params: LoginParams) {
|
|||||||
// cookie that the OAuth callback URL depends on
|
// cookie that the OAuth callback URL depends on
|
||||||
'https://vercel.com'
|
'https://vercel.com'
|
||||||
);
|
);
|
||||||
return doOauthLogin(url, 'Bitbucket', params);
|
return doOauthLogin(params, url, 'Bitbucket');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ import executeLogin from './login';
|
|||||||
import { LoginParams } from './types';
|
import { LoginParams } from './types';
|
||||||
|
|
||||||
export default async function doEmailLogin(
|
export default async function doEmailLogin(
|
||||||
email: string,
|
params: LoginParams,
|
||||||
params: LoginParams
|
email: string
|
||||||
): Promise<number | string> {
|
): Promise<number | string> {
|
||||||
let securityCode;
|
let securityCode;
|
||||||
let verificationToken;
|
let verificationToken;
|
||||||
@@ -42,7 +42,7 @@ export default async function doEmailLogin(
|
|||||||
while (!token) {
|
while (!token) {
|
||||||
try {
|
try {
|
||||||
await sleep(ms('1s'));
|
await sleep(ms('1s'));
|
||||||
token = await verify(email, verificationToken, params);
|
token = await verify(email, verificationToken, 'Email', params);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err.message !== 'Confirmation incomplete') {
|
if (err.message !== 'Confirmation incomplete') {
|
||||||
output.error(err.message);
|
output.error(err.message);
|
||||||
|
|||||||
@@ -9,5 +9,5 @@ export default function doGithubLogin(params: LoginParams) {
|
|||||||
// cookie that the OAuth callback URL depends on
|
// cookie that the OAuth callback URL depends on
|
||||||
'https://vercel.com'
|
'https://vercel.com'
|
||||||
);
|
);
|
||||||
return doOauthLogin(url, 'GitHub', params);
|
return doOauthLogin(params, url, 'GitHub');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,5 +6,5 @@ export default function doGitlabLogin(params: LoginParams) {
|
|||||||
// Can't use `apiUrl` here because this URL sets a
|
// Can't use `apiUrl` here because this URL sets a
|
||||||
// cookie that the OAuth callback URL depends on
|
// cookie that the OAuth callback URL depends on
|
||||||
const url = new URL('/api/registration/gitlab/connect', 'https://vercel.com');
|
const url = new URL('/api/registration/gitlab/connect', 'https://vercel.com');
|
||||||
return doOauthLogin(url, 'GitLab', params);
|
return doOauthLogin(params, url, 'GitLab');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
import fetch from 'node-fetch';
|
import fetch from 'node-fetch';
|
||||||
import { hostname } from 'os';
|
|
||||||
import { InvalidEmail, AccountNotFound } from '../errors-ts';
|
import { InvalidEmail, AccountNotFound } from '../errors-ts';
|
||||||
import ua from '../ua';
|
import ua from '../ua';
|
||||||
import { getTitleName } from '../pkg-name';
|
|
||||||
import { LoginData } from './types';
|
import { LoginData } from './types';
|
||||||
|
|
||||||
export default async function login(
|
export default async function login(
|
||||||
@@ -10,20 +8,13 @@ export default async function login(
|
|||||||
email: string,
|
email: string,
|
||||||
mode: 'login' | 'signup' = 'login'
|
mode: 'login' | 'signup' = 'login'
|
||||||
): Promise<LoginData> {
|
): Promise<LoginData> {
|
||||||
const hyphens = new RegExp('-', 'g');
|
|
||||||
const host = hostname().replace(hyphens, ' ').replace('.local', '');
|
|
||||||
const tokenName = `${getTitleName()} CLI on ${host}`;
|
|
||||||
|
|
||||||
const response = await fetch(`${apiUrl}/now/registration?mode=${mode}`, {
|
const response = await fetch(`${apiUrl}/now/registration?mode=${mode}`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'User-Agent': ua,
|
'User-Agent': ua,
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({ email }),
|
||||||
tokenName,
|
|
||||||
email,
|
|
||||||
}),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const body = await response.json();
|
const body = await response.json();
|
||||||
|
|||||||
@@ -2,35 +2,29 @@ import http from 'http';
|
|||||||
import open from 'open';
|
import open from 'open';
|
||||||
import { URL } from 'url';
|
import { URL } from 'url';
|
||||||
import listen from 'async-listen';
|
import listen from 'async-listen';
|
||||||
import { hostname } from 'os';
|
|
||||||
import { LoginParams } from './types';
|
import { LoginParams } from './types';
|
||||||
import prompt from './prompt';
|
import prompt from './prompt';
|
||||||
import verify from './verify';
|
import verify from './verify';
|
||||||
import { getTitleName } from '../pkg-name';
|
|
||||||
import highlight from '../output/highlight';
|
import highlight from '../output/highlight';
|
||||||
|
import link from '../output/link';
|
||||||
|
import eraseLines from '../output/erase-lines';
|
||||||
|
|
||||||
export default async function doOauthLogin(
|
export default async function doOauthLogin(
|
||||||
|
params: LoginParams,
|
||||||
url: URL,
|
url: URL,
|
||||||
provider: string,
|
provider: string
|
||||||
params: LoginParams
|
|
||||||
): Promise<number | string> {
|
): Promise<number | string> {
|
||||||
const { output } = params;
|
const { output } = params;
|
||||||
|
|
||||||
output.spinner(
|
|
||||||
`Please complete the ${provider} authentication in your web browser`
|
|
||||||
);
|
|
||||||
|
|
||||||
const server = http.createServer();
|
const server = http.createServer();
|
||||||
const address = await listen(server, 0, '127.0.0.1');
|
const address = await listen(server, 0, '127.0.0.1');
|
||||||
const { port } = new URL(address);
|
const { port } = new URL(address);
|
||||||
url.searchParams.append('mode', 'login');
|
url.searchParams.set('mode', 'login');
|
||||||
url.searchParams.append('next', `http://localhost:${port}`);
|
url.searchParams.set('next', `http://localhost:${port}`);
|
||||||
|
|
||||||
// Append token name param
|
output.log(`Please visit the following URL in your web browser:`);
|
||||||
const hyphens = new RegExp('-', 'g');
|
output.log(link(url.href));
|
||||||
const host = hostname().replace(hyphens, ' ').replace('.local', '');
|
output.spinner(`Waiting for ${provider} authentication to be completed`);
|
||||||
const tokenName = `${getTitleName()} CLI on ${host} via ${provider}`;
|
|
||||||
url.searchParams.append('tokenName', tokenName);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const [query] = await Promise.all([
|
const [query] = await Promise.all([
|
||||||
@@ -78,6 +72,9 @@ export default async function doOauthLogin(
|
|||||||
open(url.href),
|
open(url.href),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
output.stopSpinner();
|
||||||
|
output.print(eraseLines(3));
|
||||||
|
|
||||||
const loginError = query.get('loginError');
|
const loginError = query.get('loginError');
|
||||||
if (loginError) {
|
if (loginError) {
|
||||||
const err = JSON.parse(loginError);
|
const err = JSON.parse(loginError);
|
||||||
@@ -106,7 +103,7 @@ export default async function doOauthLogin(
|
|||||||
}
|
}
|
||||||
|
|
||||||
output.spinner('Verifying authentication token');
|
output.spinner('Verifying authentication token');
|
||||||
const token = await verify(email, verificationToken, params);
|
const token = await verify(email, verificationToken, provider, params);
|
||||||
output.success(
|
output.success(
|
||||||
`${provider} authentication complete for ${highlight(email)}`
|
`${provider} authentication complete for ${highlight(email)}`
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -2,14 +2,17 @@ import inquirer from 'inquirer';
|
|||||||
import error from '../output/error';
|
import error from '../output/error';
|
||||||
import listInput from '../input/list';
|
import listInput from '../input/list';
|
||||||
import { getCommandName } from '../pkg-name';
|
import { getCommandName } from '../pkg-name';
|
||||||
import { LoginParams } from './types';
|
import { LoginParams, SAMLError } from './types';
|
||||||
import doSsoLogin from './sso';
|
import doSsoLogin from './sso';
|
||||||
import doEmailLogin from './email';
|
import doEmailLogin from './email';
|
||||||
import doGithubLogin from './github';
|
import doGithubLogin from './github';
|
||||||
import doGitlabLogin from './gitlab';
|
import doGitlabLogin from './gitlab';
|
||||||
import doBitbucketLogin from './bitbucket';
|
import doBitbucketLogin from './bitbucket';
|
||||||
|
|
||||||
export default async function prompt(params: LoginParams) {
|
export default async function prompt(
|
||||||
|
params: LoginParams,
|
||||||
|
error?: Pick<SAMLError, 'teamId'>
|
||||||
|
) {
|
||||||
let result: number | string = 1;
|
let result: number | string = 1;
|
||||||
|
|
||||||
const choices = [
|
const choices = [
|
||||||
@@ -17,11 +20,12 @@ export default async function prompt(params: LoginParams) {
|
|||||||
{ name: 'Continue with GitLab', value: 'gitlab', short: 'gitlab' },
|
{ name: 'Continue with GitLab', value: 'gitlab', short: 'gitlab' },
|
||||||
{ name: 'Continue with Bitbucket', value: 'bitbucket', short: 'bitbucket' },
|
{ name: 'Continue with Bitbucket', value: 'bitbucket', short: 'bitbucket' },
|
||||||
{ name: 'Continue with Email', value: 'email', short: 'email' },
|
{ name: 'Continue with Email', value: 'email', short: 'email' },
|
||||||
{ name: 'Continue with SAML Single Sign-On', value: 'saml', short: 'saml' },
|
{ name: 'Continue with SAML Single Sign-On', value: 'sso', short: 'sso' },
|
||||||
];
|
];
|
||||||
|
|
||||||
if (params.ssoUserId) {
|
if (params.ssoUserId || (error && !error.teamId)) {
|
||||||
// Remove SAML login option if we're connecting SAML Profile
|
// Remove SAML login option if we're connecting SAML Profile,
|
||||||
|
// or if this is a SAML error for a user / team without SAML
|
||||||
choices.pop();
|
choices.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,10 +42,10 @@ export default async function prompt(params: LoginParams) {
|
|||||||
result = await doBitbucketLogin(params);
|
result = await doBitbucketLogin(params);
|
||||||
} else if (choice === 'email') {
|
} else if (choice === 'email') {
|
||||||
const email = await readInput('Enter your email address');
|
const email = await readInput('Enter your email address');
|
||||||
result = await doEmailLogin(email, params);
|
result = await doEmailLogin(params, email);
|
||||||
} else if (choice === 'saml') {
|
} else if (choice === 'sso') {
|
||||||
const slug = await readInput('Enter your Team slug');
|
const slug = error?.teamId || (await readInput('Enter your Team slug'));
|
||||||
result = await doSsoLogin(slug, params);
|
result = await doSsoLogin(params, slug);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
28
packages/cli/src/util/login/reauthenticate.ts
Normal file
28
packages/cli/src/util/login/reauthenticate.ts
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import { bold } from 'chalk';
|
||||||
|
import doSsoLogin from './sso';
|
||||||
|
import showLoginPrompt from './prompt';
|
||||||
|
import { LoginParams, SAMLError } from './types';
|
||||||
|
import confirm from '../input/confirm';
|
||||||
|
|
||||||
|
export default async function reauthenticate(
|
||||||
|
params: LoginParams,
|
||||||
|
error: Pick<SAMLError, 'enforced' | 'scope' | 'teamId'>
|
||||||
|
): Promise<string | number> {
|
||||||
|
let result: string | number = 1;
|
||||||
|
if (error.teamId && error.enforced) {
|
||||||
|
// If team has SAML enforced then trigger the SSO login directly
|
||||||
|
params.output.log(
|
||||||
|
`You must re-authenticate with SAML to use ${bold(error.scope)} scope.`
|
||||||
|
);
|
||||||
|
if (await confirm(`Log in with SAML?`, true)) {
|
||||||
|
result = await doSsoLogin(params, error.teamId);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Personal account, or team that does not have SAML enforced
|
||||||
|
params.output.log(
|
||||||
|
`You must re-authenticate to use ${bold(error.scope)} scope.`
|
||||||
|
);
|
||||||
|
result = await showLoginPrompt(params, error);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
@@ -2,8 +2,8 @@ import { URL } from 'url';
|
|||||||
import { LoginParams } from './types';
|
import { LoginParams } from './types';
|
||||||
import doOauthLogin from './oauth';
|
import doOauthLogin from './oauth';
|
||||||
|
|
||||||
export default function doSsoLogin(teamIdOrSlug: string, params: LoginParams) {
|
export default function doSsoLogin(params: LoginParams, teamIdOrSlug: string) {
|
||||||
const url = new URL('/auth/sso', params.apiUrl);
|
const url = new URL('/auth/sso', params.apiUrl);
|
||||||
url.searchParams.append('teamId', teamIdOrSlug);
|
url.searchParams.set('teamId', teamIdOrSlug);
|
||||||
return doOauthLogin(url, 'SAML Single Sign-On', params);
|
return doOauthLogin(params, url, 'SAML Single Sign-On');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
|
import { AuthConfig } from '../../types';
|
||||||
import { Output } from '../output';
|
import { Output } from '../output';
|
||||||
|
|
||||||
export interface LoginParams {
|
export interface LoginParams {
|
||||||
|
authConfig: AuthConfig;
|
||||||
apiUrl: string;
|
apiUrl: string;
|
||||||
output: Output;
|
output: Output;
|
||||||
ssoUserId?: string;
|
ssoUserId?: string;
|
||||||
@@ -10,3 +12,10 @@ export interface LoginData {
|
|||||||
token: string;
|
token: string;
|
||||||
securityCode: string;
|
securityCode: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface SAMLError {
|
||||||
|
saml?: true;
|
||||||
|
teamId: string | null;
|
||||||
|
scope: string;
|
||||||
|
enforced?: boolean;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,24 +1,41 @@
|
|||||||
import { URL } from 'url';
|
import { URL } from 'url';
|
||||||
import fetch from 'node-fetch';
|
import fetch, { Headers } from 'node-fetch';
|
||||||
import ua from '../ua';
|
import ua from '../ua';
|
||||||
import { LoginParams } from './types';
|
import { LoginParams } from './types';
|
||||||
|
import { hostname } from 'os';
|
||||||
|
import { getTitleName } from '../pkg-name';
|
||||||
|
|
||||||
export default async function verify(
|
export default async function verify(
|
||||||
email: string,
|
email: string,
|
||||||
verificationToken: string,
|
verificationToken: string,
|
||||||
{ apiUrl, ssoUserId }: LoginParams
|
provider: string,
|
||||||
|
{ authConfig, apiUrl, ssoUserId }: LoginParams
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
const url = new URL('/registration/verify', apiUrl);
|
const url = new URL('/registration/verify', apiUrl);
|
||||||
url.searchParams.append('email', email);
|
url.searchParams.set('email', email);
|
||||||
url.searchParams.append('token', verificationToken);
|
url.searchParams.set('token', verificationToken);
|
||||||
if (ssoUserId) {
|
|
||||||
url.searchParams.append('ssoUserId', ssoUserId);
|
const headers = new Headers({ 'User-Agent': ua });
|
||||||
|
|
||||||
|
if (authConfig.token) {
|
||||||
|
// If there is already an auth token then it will be
|
||||||
|
// upgraded, rather than a new token being created
|
||||||
|
headers.set('Authorization', `Bearer ${authConfig.token}`);
|
||||||
|
} else {
|
||||||
|
// Set the "name" of the Token that will be created
|
||||||
|
const hyphens = new RegExp('-', 'g');
|
||||||
|
const host = hostname().replace(hyphens, ' ').replace('.local', '');
|
||||||
|
const tokenName = `${getTitleName()} CLI on ${host} via ${provider}`;
|
||||||
|
url.searchParams.set('tokenName', tokenName);
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await fetch(url.href, {
|
// If `ssoUserId` is defined then this verification
|
||||||
headers: { 'User-Agent': ua },
|
// will complete the SAML two-step login connection
|
||||||
});
|
if (ssoUserId) {
|
||||||
|
url.searchParams.set('ssoUserId', ssoUserId);
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await fetch(url.href, { headers });
|
||||||
const body = await res.json();
|
const body = await res.json();
|
||||||
|
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
|
|||||||
24
packages/cli/src/util/promise.ts
Normal file
24
packages/cli/src/util/promise.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
/**
|
||||||
|
* Wraps a function such that only one in-flight invocation is active at a time.
|
||||||
|
*
|
||||||
|
* That is, if the returned function is invoked more that one time before the
|
||||||
|
* promise returned from the initial invocation resolves, then the same promise
|
||||||
|
* is returned for subsequent invocations.
|
||||||
|
*
|
||||||
|
* Once the promise has resolved, the next invocation of the returned function
|
||||||
|
* will re-invoke the original function again.
|
||||||
|
*/
|
||||||
|
export function sharedPromise<P extends any[], V, T>(
|
||||||
|
fn: (this: T, ...args: P) => Promise<V>
|
||||||
|
) {
|
||||||
|
let promise: Promise<V> | null = null;
|
||||||
|
return function (this: T, ...args: P) {
|
||||||
|
if (!promise) {
|
||||||
|
promise = fn.apply(this, args);
|
||||||
|
promise.finally(() => {
|
||||||
|
promise = null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return promise;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -7,9 +7,9 @@ import { parse } from 'url';
|
|||||||
* google.com => google.com
|
* google.com => google.com
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function toHost(url: string) {
|
function toHost(url: string): string {
|
||||||
if (/^https?:\/\//.test(url)) {
|
if (/^https?:\/\//.test(url)) {
|
||||||
return parse(url).host;
|
return parse(url).host!;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove any path if present
|
// Remove any path if present
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 78 KiB |
@@ -1710,7 +1710,9 @@ test(
|
|||||||
expectHeader('image/svg+xml'),
|
expectHeader('image/svg+xml'),
|
||||||
fetchOpts('image/webp')
|
fetchOpts('image/webp')
|
||||||
);
|
);
|
||||||
// bmp should bypass: serve as-is
|
/* Disabled bmp because `next dev` bypasses
|
||||||
|
* and production will convert. Eventually
|
||||||
|
* we can enable once `next dev` supports it.
|
||||||
await testPath(
|
await testPath(
|
||||||
200,
|
200,
|
||||||
toUrl('/test.bmp', 64, 50),
|
toUrl('/test.bmp', 64, 50),
|
||||||
@@ -1718,6 +1720,7 @@ test(
|
|||||||
expectHeader('image/bmp'),
|
expectHeader('image/bmp'),
|
||||||
fetchOpts('image/webp')
|
fetchOpts('image/webp')
|
||||||
);
|
);
|
||||||
|
*/
|
||||||
// animated gif should bypass: serve as-is
|
// animated gif should bypass: serve as-is
|
||||||
await testPath(
|
await testPath(
|
||||||
200,
|
200,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@vercel/client",
|
"name": "@vercel/client",
|
||||||
"version": "10.0.1-canary.5",
|
"version": "10.1.1",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"typings": "dist/index.d.ts",
|
"typings": "dist/index.d.ts",
|
||||||
"homepage": "https://vercel.com",
|
"homepage": "https://vercel.com",
|
||||||
@@ -40,7 +40,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vercel/build-utils": "2.10.3-canary.4",
|
"@vercel/build-utils": "2.11.1",
|
||||||
"@zeit/fetch": "5.2.0",
|
"@zeit/fetch": "5.2.0",
|
||||||
"async-retry": "1.2.3",
|
"async-retry": "1.2.3",
|
||||||
"async-sema": "3.0.0",
|
"async-sema": "3.0.0",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@vercel/frameworks",
|
"name": "@vercel/frameworks",
|
||||||
"version": "0.3.3-canary.3",
|
"version": "0.4.1",
|
||||||
"main": "./dist/frameworks.js",
|
"main": "./dist/frameworks.js",
|
||||||
"types": "./dist/frameworks.d.ts",
|
"types": "./dist/frameworks.d.ts",
|
||||||
"files": [
|
"files": [
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
"@types/js-yaml": "3.12.1",
|
"@types/js-yaml": "3.12.1",
|
||||||
"@types/node": "12.0.4",
|
"@types/node": "12.0.4",
|
||||||
"@types/node-fetch": "2.5.8",
|
"@types/node-fetch": "2.5.8",
|
||||||
"@vercel/routing-utils": "1.11.1-canary.1",
|
"@vercel/routing-utils": "1.11.2",
|
||||||
"ajv": "6.12.2",
|
"ajv": "6.12.2",
|
||||||
"jest": "24.9.0",
|
"jest": "24.9.0",
|
||||||
"ts-jest": "24.1.0",
|
"ts-jest": "24.1.0",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@vercel/node",
|
"name": "@vercel/node",
|
||||||
"version": "1.10.1-canary.2",
|
"version": "1.11.1",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"main": "./dist/index",
|
"main": "./dist/index",
|
||||||
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/node-js",
|
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/node-js",
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
"@types/etag": "1.8.0",
|
"@types/etag": "1.8.0",
|
||||||
"@types/test-listen": "1.1.0",
|
"@types/test-listen": "1.1.0",
|
||||||
"@vercel/ncc": "0.24.0",
|
"@vercel/ncc": "0.24.0",
|
||||||
"@vercel/nft": "0.12.2",
|
"@vercel/nft": "0.13.1",
|
||||||
"content-type": "1.0.4",
|
"content-type": "1.0.4",
|
||||||
"cookie": "0.4.0",
|
"cookie": "0.4.0",
|
||||||
"etag": "1.8.1",
|
"etag": "1.8.1",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@vercel/python",
|
"name": "@vercel/python",
|
||||||
"version": "2.0.2",
|
"version": "2.0.4",
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/index.js",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/python",
|
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/python",
|
||||||
|
|||||||
@@ -82,14 +82,27 @@ elif 'app' in __vc_variables:
|
|||||||
not inspect.iscoroutinefunction(__vc_module.app.__call__)
|
not inspect.iscoroutinefunction(__vc_module.app.__call__)
|
||||||
):
|
):
|
||||||
print('using Web Server Gateway Interface (WSGI)')
|
print('using Web Server Gateway Interface (WSGI)')
|
||||||
|
from io import BytesIO
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
from werkzeug._compat import BytesIO
|
|
||||||
from werkzeug._compat import string_types
|
|
||||||
from werkzeug._compat import to_bytes
|
|
||||||
from werkzeug._compat import wsgi_encoding_dance
|
|
||||||
from werkzeug.datastructures import Headers
|
from werkzeug.datastructures import Headers
|
||||||
from werkzeug.wrappers import Response
|
from werkzeug.wrappers import Response
|
||||||
|
|
||||||
|
string_types = (str,)
|
||||||
|
|
||||||
|
def to_bytes(x, charset=sys.getdefaultencoding(), errors="strict"):
|
||||||
|
if x is None:
|
||||||
|
return None
|
||||||
|
if isinstance(x, (bytes, bytearray, memoryview)):
|
||||||
|
return bytes(x)
|
||||||
|
if isinstance(x, str):
|
||||||
|
return x.encode(charset, errors)
|
||||||
|
raise TypeError("Expected bytes")
|
||||||
|
|
||||||
|
def wsgi_encoding_dance(s, charset="utf-8", errors="replace"):
|
||||||
|
if isinstance(s, str):
|
||||||
|
s = s.encode(charset)
|
||||||
|
return s.decode("latin1", errors)
|
||||||
|
|
||||||
def vc_handler(event, context):
|
def vc_handler(event, context):
|
||||||
payload = json.loads(event['body'])
|
payload = json.loads(event['body'])
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@vercel/routing-utils",
|
"name": "@vercel/routing-utils",
|
||||||
"version": "1.11.1-canary.1",
|
"version": "1.11.2",
|
||||||
"description": "Vercel routing utilities",
|
"description": "Vercel routing utilities",
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/index.js",
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
|
|||||||
@@ -37,9 +37,9 @@ function getCheckAndContinue(
|
|||||||
route
|
route
|
||||||
)}`
|
)}`
|
||||||
);
|
);
|
||||||
} else if (route.check) {
|
} else if (route.check && !route.override) {
|
||||||
checks.push(route);
|
checks.push(route);
|
||||||
} else if (route.continue) {
|
} else if (route.continue && !route.override) {
|
||||||
continues.push(route);
|
continues.push(route);
|
||||||
} else {
|
} else {
|
||||||
others.push(route);
|
others.push(route);
|
||||||
|
|||||||
@@ -104,6 +104,9 @@ export const routesSchema = {
|
|||||||
continue: {
|
continue: {
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
},
|
},
|
||||||
|
override: {
|
||||||
|
type: 'boolean',
|
||||||
|
},
|
||||||
check: {
|
check: {
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -187,6 +187,10 @@ function collectHasSegments(has?: HasField) {
|
|||||||
const hasSegments = new Set<string>();
|
const hasSegments = new Set<string>();
|
||||||
|
|
||||||
for (const hasItem of has || []) {
|
for (const hasItem of has || []) {
|
||||||
|
if ('key' in hasItem && hasItem.type === 'header') {
|
||||||
|
hasItem.key = hasItem.key.toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
if (!hasItem.value && 'key' in hasItem) {
|
if (!hasItem.value && 'key' in hasItem) {
|
||||||
hasSegments.add(hasItem.key);
|
hasSegments.add(hasItem.key);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ export type Source = {
|
|||||||
headers?: { [name: string]: string };
|
headers?: { [name: string]: string };
|
||||||
methods?: string[];
|
methods?: string[];
|
||||||
continue?: boolean;
|
continue?: boolean;
|
||||||
|
override?: boolean;
|
||||||
check?: boolean;
|
check?: boolean;
|
||||||
important?: boolean;
|
important?: boolean;
|
||||||
status?: number;
|
status?: number;
|
||||||
|
|||||||
94
packages/routing-utils/test/merge.spec.js
vendored
94
packages/routing-utils/test/merge.spec.js
vendored
@@ -419,3 +419,97 @@ test('mergeRoutes ensure `handle: error` comes last', () => {
|
|||||||
];
|
];
|
||||||
deepStrictEqual(actual, expected);
|
deepStrictEqual(actual, expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('mergeRoutes ensure beforeFiles comes after redirects (continue)', () => {
|
||||||
|
const userRoutes = [];
|
||||||
|
const builds = [
|
||||||
|
{
|
||||||
|
use: '@vercel/next',
|
||||||
|
entrypoint: 'package.json',
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
src: '^/home$',
|
||||||
|
status: 301,
|
||||||
|
headers: {
|
||||||
|
Location: '/',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
src: '^/hello$',
|
||||||
|
dest: '/somewhere',
|
||||||
|
continue: true,
|
||||||
|
override: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
handle: 'filesystem',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
src: '^/404$',
|
||||||
|
dest: '/404',
|
||||||
|
status: 404,
|
||||||
|
check: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const actual = mergeRoutes({ userRoutes, builds });
|
||||||
|
const expected = [
|
||||||
|
{ src: '^/home$', status: 301, headers: { Location: '/' } },
|
||||||
|
{
|
||||||
|
src: '^/hello$',
|
||||||
|
dest: '/somewhere',
|
||||||
|
continue: true,
|
||||||
|
override: true,
|
||||||
|
},
|
||||||
|
{ handle: 'filesystem' },
|
||||||
|
{ src: '^/404$', dest: '/404', status: 404, check: true },
|
||||||
|
];
|
||||||
|
deepStrictEqual(actual, expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('mergeRoutes ensure beforeFiles comes after redirects (check)', () => {
|
||||||
|
const userRoutes = [];
|
||||||
|
const builds = [
|
||||||
|
{
|
||||||
|
use: '@vercel/next',
|
||||||
|
entrypoint: 'package.json',
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
src: '^/home$',
|
||||||
|
status: 301,
|
||||||
|
headers: {
|
||||||
|
Location: '/',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
src: '^/hello$',
|
||||||
|
dest: '/somewhere',
|
||||||
|
check: true,
|
||||||
|
override: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
handle: 'filesystem',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
src: '^/404$',
|
||||||
|
dest: '/404',
|
||||||
|
status: 404,
|
||||||
|
check: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const actual = mergeRoutes({ userRoutes, builds });
|
||||||
|
const expected = [
|
||||||
|
{ src: '^/home$', status: 301, headers: { Location: '/' } },
|
||||||
|
{
|
||||||
|
src: '^/hello$',
|
||||||
|
dest: '/somewhere',
|
||||||
|
check: true,
|
||||||
|
override: true,
|
||||||
|
},
|
||||||
|
{ handle: 'filesystem' },
|
||||||
|
{ src: '^/404$', dest: '/404', status: 404, check: true },
|
||||||
|
];
|
||||||
|
deepStrictEqual(actual, expected);
|
||||||
|
});
|
||||||
|
|||||||
@@ -247,7 +247,7 @@ test('convertRedirects', () => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'header',
|
type: 'header',
|
||||||
key: 'x-pathname',
|
key: 'X-Pathname',
|
||||||
value: '(?<another>hello|world)',
|
value: '(?<another>hello|world)',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -549,7 +549,7 @@ test('convertRewrites', () => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'header',
|
type: 'header',
|
||||||
key: 'x-pathname',
|
key: 'X-Pathname',
|
||||||
value: '(?<another>hello|world)',
|
value: '(?<another>hello|world)',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -893,7 +893,7 @@ test('convertHeaders', () => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'header',
|
type: 'header',
|
||||||
key: 'x-pathname',
|
key: 'X-Pathname',
|
||||||
value: '(?<another>hello|world)',
|
value: '(?<another>hello|world)',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -1,127 +0,0 @@
|
|||||||
package bridge
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding/base64"
|
|
||||||
"encoding/json"
|
|
||||||
"github.com/aws/aws-lambda-go/events"
|
|
||||||
"github.com/aws/aws-lambda-go/lambda"
|
|
||||||
"net/http"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Request struct {
|
|
||||||
Host string `json:"host"`
|
|
||||||
Path string `json:"path"`
|
|
||||||
Method string `json:"method"`
|
|
||||||
Headers map[string]string `json:"headers"`
|
|
||||||
Encoding string `json:"encoding,omitempty"`
|
|
||||||
Body string `json:"body"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Response struct {
|
|
||||||
StatusCode int `json:"statusCode"`
|
|
||||||
Headers map[string][]string `json:"headers"`
|
|
||||||
Encoding string `json:"encoding,omitemtpy"`
|
|
||||||
Body string `json:"body"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ResponseWriter struct {
|
|
||||||
http.ResponseWriter
|
|
||||||
statusCode int
|
|
||||||
headers http.Header
|
|
||||||
body *bytes.Buffer
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *ResponseWriter) Header() http.Header {
|
|
||||||
return w.headers
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *ResponseWriter) Write(p []byte) (n int, err error) {
|
|
||||||
n, err = w.body.Write(p)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *ResponseWriter) WriteHeader(statusCode int) {
|
|
||||||
w.statusCode = statusCode
|
|
||||||
}
|
|
||||||
|
|
||||||
var userHandler http.Handler
|
|
||||||
|
|
||||||
func Serve(handler http.Handler, req *Request) (res Response, err error) {
|
|
||||||
var body []byte
|
|
||||||
if req.Encoding == "base64" {
|
|
||||||
body, err = base64.StdEncoding.DecodeString(req.Body)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
body = []byte(req.Body)
|
|
||||||
}
|
|
||||||
|
|
||||||
r, err := http.NewRequest(req.Method, req.Path, bytes.NewReader(body))
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for k, v := range req.Headers {
|
|
||||||
r.Header.Add(k, v)
|
|
||||||
switch strings.ToLower(k) {
|
|
||||||
case "host":
|
|
||||||
// we need to set `Host` in the request
|
|
||||||
// because Go likes to ignore the `Host` header
|
|
||||||
// see https://github.com/golang/go/issues/7682
|
|
||||||
r.Host = v
|
|
||||||
case "content-length":
|
|
||||||
contentLength, _ := strconv.ParseInt(v, 10, 64)
|
|
||||||
r.ContentLength = contentLength
|
|
||||||
case "x-forwarded-for":
|
|
||||||
case "x-real-ip":
|
|
||||||
r.RemoteAddr = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var bodyBuf bytes.Buffer
|
|
||||||
w := &ResponseWriter{
|
|
||||||
nil,
|
|
||||||
http.StatusOK,
|
|
||||||
make(http.Header),
|
|
||||||
&bodyBuf,
|
|
||||||
}
|
|
||||||
|
|
||||||
handler.ServeHTTP(w, r)
|
|
||||||
defer r.Body.Close()
|
|
||||||
|
|
||||||
headers := make(map[string][]string)
|
|
||||||
for k, v := range w.headers {
|
|
||||||
for _, s := range v {
|
|
||||||
headers[k] = append(headers[k], s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
res = Response{
|
|
||||||
StatusCode: w.statusCode,
|
|
||||||
Headers: headers,
|
|
||||||
Encoding: "base64",
|
|
||||||
Body: base64.StdEncoding.EncodeToString(bodyBuf.Bytes()),
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Maps the `APIGatewayProxyRequest` to a `Request` instance and invokes `Serve()`
|
|
||||||
func handler(event events.APIGatewayProxyRequest) (res Response, err error) {
|
|
||||||
var req Request
|
|
||||||
err = json.Unmarshal([]byte(event.Body), &req)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
res, err = Serve(userHandler, &req)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Starts the Lambda
|
|
||||||
func Start(h http.Handler) {
|
|
||||||
userHandler = h
|
|
||||||
lambda.Start(handler)
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
package bridge
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/base64"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
type HttpHandler struct {
|
|
||||||
http.Handler
|
|
||||||
t *testing.T
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *HttpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
||||||
w.Header().Add("X-Foo", "bar")
|
|
||||||
w.WriteHeader(404)
|
|
||||||
w.Write([]byte("test"))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestServe(t *testing.T) {
|
|
||||||
h := &HttpHandler{nil, t}
|
|
||||||
req := &Request{
|
|
||||||
"test.com",
|
|
||||||
"/path?foo=bar",
|
|
||||||
"POST",
|
|
||||||
map[string]string{"Content-Length": "1", "X-Foo": "bar"},
|
|
||||||
"",
|
|
||||||
"a",
|
|
||||||
}
|
|
||||||
res, err := Serve(h, req)
|
|
||||||
if err != nil {
|
|
||||||
t.Fail()
|
|
||||||
}
|
|
||||||
if res.StatusCode != 404 {
|
|
||||||
t.Fail()
|
|
||||||
}
|
|
||||||
fmt.Printf("status code: %d\n", res.StatusCode)
|
|
||||||
fmt.Printf("header: %v\n", res.Headers)
|
|
||||||
fmt.Printf("base64 body: %s\n", res.Body)
|
|
||||||
body, err := base64.StdEncoding.DecodeString(res.Body)
|
|
||||||
fmt.Printf("body: %s\n", body)
|
|
||||||
}
|
|
||||||
1
utils/run.js
vendored
1
utils/run.js
vendored
@@ -6,7 +6,6 @@ const allPackages = [
|
|||||||
'routing-utils',
|
'routing-utils',
|
||||||
'frameworks',
|
'frameworks',
|
||||||
'build-utils',
|
'build-utils',
|
||||||
'cgi',
|
|
||||||
'client',
|
'client',
|
||||||
'node-bridge',
|
'node-bridge',
|
||||||
'node',
|
'node',
|
||||||
|
|||||||
104
yarn.lock
104
yarn.lock
@@ -1860,12 +1860,13 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@types/node" "*"
|
"@types/node" "*"
|
||||||
|
|
||||||
"@types/node-fetch@2.1.4":
|
"@types/node-fetch@2.5.10":
|
||||||
version "2.1.4"
|
version "2.5.10"
|
||||||
resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.1.4.tgz#093d1beae11541aef25999d70aa09286fd025b1a"
|
resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.10.tgz#9b4d4a0425562f9fcea70b12cb3fcdd946ca8132"
|
||||||
integrity sha512-tR1ekaXUGpmzOcDXWU9BW73YfA2/VW1DF1FH+wlJ82BbCSnWTbdX+JkqWQXWKIGsFPnPsYadbXfNgz28g+ccWg==
|
integrity sha512-IpkX0AasN44hgEad0gEF/V6EgR5n69VEqPEgnmoM8GsIGro3PowbWs4tR6IhxUTyPLpOn+fiGG6nrQhcmoCuIQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/node" "*"
|
"@types/node" "*"
|
||||||
|
form-data "^3.0.0"
|
||||||
|
|
||||||
"@types/node-fetch@2.5.4":
|
"@types/node-fetch@2.5.4":
|
||||||
version "2.5.4"
|
version "2.5.4"
|
||||||
@@ -2115,13 +2116,13 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@vercel/ncc/-/ncc-0.24.0.tgz#a2e8783a185caa99b5d8961a57dfc9665de16296"
|
resolved "https://registry.yarnpkg.com/@vercel/ncc/-/ncc-0.24.0.tgz#a2e8783a185caa99b5d8961a57dfc9665de16296"
|
||||||
integrity sha512-crqItMcIwCkvdXY/V3/TzrHJQx6nbIaRqE1cOopJhgGX6izvNov40SmD//nS5flfEvdK54YGjwVVq+zG6crjOg==
|
integrity sha512-crqItMcIwCkvdXY/V3/TzrHJQx6nbIaRqE1cOopJhgGX6izvNov40SmD//nS5flfEvdK54YGjwVVq+zG6crjOg==
|
||||||
|
|
||||||
"@vercel/nft@0.12.2":
|
"@vercel/nft@0.13.1":
|
||||||
version "0.12.2"
|
version "0.13.1"
|
||||||
resolved "https://registry.yarnpkg.com/@vercel/nft/-/nft-0.12.2.tgz#67ea9f231d24639b3783e3e69bef173659972d3b"
|
resolved "https://registry.yarnpkg.com/@vercel/nft/-/nft-0.13.1.tgz#98df07e04620069ba63fff92af490c5842a2f31f"
|
||||||
integrity sha512-H8n44GboVnJaVVX4+WfuOTAaNLDnUIYH4KpMZcXll7KMNIcg0JTd0IFRsIBe/uvuXisqm6nEANp8Tr3/1dlRQw==
|
integrity sha512-7pBTfSkwhhcPAeGVsFml5YX7LCZgtocP+zTAknnRK2u/RsV3GGqOD5yw7CtbgTpfjY8NfXWzwoxF1zOUEVsbww==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@mapbox/node-pre-gyp" "^1.0.5"
|
"@mapbox/node-pre-gyp" "^1.0.5"
|
||||||
acorn "^8.1.0"
|
acorn "^8.3.0"
|
||||||
acorn-class-fields "^1.0.0"
|
acorn-class-fields "^1.0.0"
|
||||||
acorn-static-class-features "^1.0.0"
|
acorn-static-class-features "^1.0.0"
|
||||||
bindings "^1.4.0"
|
bindings "^1.4.0"
|
||||||
@@ -2282,10 +2283,10 @@ acorn@^7.1.1:
|
|||||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.2.0.tgz#17ea7e40d7c8640ff54a694c889c26f31704effe"
|
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.2.0.tgz#17ea7e40d7c8640ff54a694c889c26f31704effe"
|
||||||
integrity sha512-apwXVmYVpQ34m/i71vrApRrRKCWQnZZF1+npOD0WV5xZFfwWOmKGQ2RWlfdy9vWITsenisM8M0Qeq8agcFHNiQ==
|
integrity sha512-apwXVmYVpQ34m/i71vrApRrRKCWQnZZF1+npOD0WV5xZFfwWOmKGQ2RWlfdy9vWITsenisM8M0Qeq8agcFHNiQ==
|
||||||
|
|
||||||
acorn@^8.1.0:
|
acorn@^8.3.0:
|
||||||
version "8.1.1"
|
version "8.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.1.1.tgz#fb0026885b9ac9f48bac1e185e4af472971149ff"
|
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.3.0.tgz#1193f9b96c4e8232f00b11a9edff81b2c8b98b88"
|
||||||
integrity sha512-xYiIVjNuqtKXMxlRMDc6mZUhXehod4a3gbZ1qRlM7icK4EbxUFNLhWoPblCvFtB2Y9CIqHP3CF/rdxLItaQv8g==
|
integrity sha512-tqPKHZ5CaBJw0Xmy0ZZvLs1qTV+BNFSyvn77ASXkpBNfIRk8ev26fKrD9iLGwGA9zedPao52GSHzq8lyZG0NUw==
|
||||||
|
|
||||||
agent-base@4, agent-base@^4.1.0, agent-base@^4.3.0:
|
agent-base@4, agent-base@^4.1.0, agent-base@^4.3.0:
|
||||||
version "4.3.0"
|
version "4.3.0"
|
||||||
@@ -2294,11 +2295,6 @@ agent-base@4, agent-base@^4.1.0, agent-base@^4.3.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
es6-promisify "^5.0.0"
|
es6-promisify "^5.0.0"
|
||||||
|
|
||||||
agent-base@5:
|
|
||||||
version "5.1.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-5.1.1.tgz#e8fb3f242959db44d63be665db7a8e739537a32c"
|
|
||||||
integrity sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g==
|
|
||||||
|
|
||||||
agent-base@6:
|
agent-base@6:
|
||||||
version "6.0.0"
|
version "6.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.0.tgz#5d0101f19bbfaed39980b22ae866de153b93f09a"
|
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.0.tgz#5d0101f19bbfaed39980b22ae866de153b93f09a"
|
||||||
@@ -3479,15 +3475,15 @@ code-point-at@^1.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
|
resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
|
||||||
integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=
|
integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=
|
||||||
|
|
||||||
codecov@3.7.1:
|
codecov@3.8.2:
|
||||||
version "3.7.1"
|
version "3.8.2"
|
||||||
resolved "https://registry.yarnpkg.com/codecov/-/codecov-3.7.1.tgz#434cb8d55f18ef01672e5739d3d266696bebc202"
|
resolved "https://registry.yarnpkg.com/codecov/-/codecov-3.8.2.tgz#ab24f18783998c39e809ea210af899f8dbcc790e"
|
||||||
integrity sha512-JHWxyPTkMLLJn9SmKJnwAnvY09kg2Os2+Ux+GG7LwZ9g8gzDDISpIN5wAsH1UBaafA/yGcd3KofMaorE8qd6Lw==
|
integrity sha512-6w/kt/xvmPsWMfDFPE/T054txA9RTgcJEw36PNa6MYX+YV29jCHCRFXwbQ3QZBTOgnex1J2WP8bo2AT8TWWz9g==
|
||||||
dependencies:
|
dependencies:
|
||||||
argv "0.0.2"
|
argv "0.0.2"
|
||||||
ignore-walk "3.0.3"
|
ignore-walk "3.0.3"
|
||||||
js-yaml "3.13.1"
|
js-yaml "3.14.1"
|
||||||
teeny-request "6.0.1"
|
teeny-request "7.0.1"
|
||||||
urlgrey "0.4.4"
|
urlgrey "0.4.4"
|
||||||
|
|
||||||
collection-visit@^1.0.0:
|
collection-visit@^1.0.0:
|
||||||
@@ -4474,6 +4470,11 @@ es6-promisify@^5.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
es6-promise "^4.0.3"
|
es6-promise "^4.0.3"
|
||||||
|
|
||||||
|
esbuild@^0.11.20:
|
||||||
|
version "0.11.23"
|
||||||
|
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.11.23.tgz#c42534f632e165120671d64db67883634333b4b8"
|
||||||
|
integrity sha512-iaiZZ9vUF5wJV8ob1tl+5aJTrwDczlvGP0JoMmnpC2B0ppiMCu8n8gmy5ZTGl5bcG081XBVn+U+jP+mPFm5T5Q==
|
||||||
|
|
||||||
escape-goat@^2.0.0:
|
escape-goat@^2.0.0:
|
||||||
version "2.1.1"
|
version "2.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-2.1.1.tgz#1b2dc77003676c457ec760b2dc68edb648188675"
|
resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-2.1.1.tgz#1b2dc77003676c457ec760b2dc68edb648188675"
|
||||||
@@ -5736,14 +5737,6 @@ https-proxy-agent@^2.2.3:
|
|||||||
agent-base "^4.3.0"
|
agent-base "^4.3.0"
|
||||||
debug "^3.1.0"
|
debug "^3.1.0"
|
||||||
|
|
||||||
https-proxy-agent@^4.0.0:
|
|
||||||
version "4.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz#702b71fb5520a132a66de1f67541d9e62154d82b"
|
|
||||||
integrity sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg==
|
|
||||||
dependencies:
|
|
||||||
agent-base "5"
|
|
||||||
debug "4"
|
|
||||||
|
|
||||||
https-proxy-agent@^5.0.0:
|
https-proxy-agent@^5.0.0:
|
||||||
version "5.0.0"
|
version "5.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2"
|
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2"
|
||||||
@@ -6830,6 +6823,14 @@ js-yaml@3.13.1:
|
|||||||
argparse "^1.0.7"
|
argparse "^1.0.7"
|
||||||
esprima "^4.0.0"
|
esprima "^4.0.0"
|
||||||
|
|
||||||
|
js-yaml@3.14.1:
|
||||||
|
version "3.14.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537"
|
||||||
|
integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==
|
||||||
|
dependencies:
|
||||||
|
argparse "^1.0.7"
|
||||||
|
esprima "^4.0.0"
|
||||||
|
|
||||||
js-yaml@^3.10.0, js-yaml@^3.13.1:
|
js-yaml@^3.10.0, js-yaml@^3.13.1:
|
||||||
version "3.14.0"
|
version "3.14.0"
|
||||||
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.0.tgz#a7a34170f26a21bb162424d8adacb4113a69e482"
|
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.0.tgz#a7a34170f26a21bb162424d8adacb4113a69e482"
|
||||||
@@ -7929,7 +7930,7 @@ node-fetch@2.6.0:
|
|||||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd"
|
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd"
|
||||||
integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==
|
integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==
|
||||||
|
|
||||||
node-fetch@2.6.1, node-fetch@^2.2.0, node-fetch@^2.2.1, node-fetch@^2.3.0, node-fetch@^2.5.0, node-fetch@^2.6.1:
|
node-fetch@2.6.1, node-fetch@^2.2.1, node-fetch@^2.3.0, node-fetch@^2.5.0, node-fetch@^2.6.1:
|
||||||
version "2.6.1"
|
version "2.6.1"
|
||||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
|
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
|
||||||
integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
|
integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
|
||||||
@@ -8292,10 +8293,10 @@ onetime@^5.1.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
mimic-fn "^2.1.0"
|
mimic-fn "^2.1.0"
|
||||||
|
|
||||||
open@8.0.2:
|
open@8.2.0:
|
||||||
version "8.0.2"
|
version "8.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/open/-/open-8.0.2.tgz#8c3e95cce93ba2fc8d99968ee8bfefecdb50b84f"
|
resolved "https://registry.yarnpkg.com/open/-/open-8.2.0.tgz#d6a4788b00009a9d60df471ecb89842a15fdcfc1"
|
||||||
integrity sha512-NV5QmWJrTaNBLHABJyrb+nd5dXI5zfea/suWawBhkHzAbVhLLiJdrqMgxMypGK9Eznp2Ltoh7SAVkQ3XAucX7Q==
|
integrity sha512-O8uInONB4asyY3qUcEytpgwxQG3O0fJ/hlssoUHsBboOIRVZzT6Wq+Rwj5nffbeUhOdMjpXeISpDDzHCMRDuOQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
define-lazy-prop "^2.0.0"
|
define-lazy-prop "^2.0.0"
|
||||||
is-docker "^2.1.1"
|
is-docker "^2.1.1"
|
||||||
@@ -9858,7 +9859,7 @@ source-map-support@0.5.12:
|
|||||||
buffer-from "^1.0.0"
|
buffer-from "^1.0.0"
|
||||||
source-map "^0.6.0"
|
source-map "^0.6.0"
|
||||||
|
|
||||||
source-map-support@^0.5.12, source-map-support@^0.5.17, source-map-support@^0.5.6:
|
source-map-support@^0.5.12, source-map-support@^0.5.17, source-map-support@^0.5.19, source-map-support@^0.5.6:
|
||||||
version "0.5.19"
|
version "0.5.19"
|
||||||
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61"
|
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61"
|
||||||
integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==
|
integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==
|
||||||
@@ -10384,16 +10385,16 @@ tar@^6.1.0:
|
|||||||
mkdirp "^1.0.3"
|
mkdirp "^1.0.3"
|
||||||
yallist "^4.0.0"
|
yallist "^4.0.0"
|
||||||
|
|
||||||
teeny-request@6.0.1:
|
teeny-request@7.0.1:
|
||||||
version "6.0.1"
|
version "7.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/teeny-request/-/teeny-request-6.0.1.tgz#9b1f512cef152945827ba7e34f62523a4ce2c5b0"
|
resolved "https://registry.yarnpkg.com/teeny-request/-/teeny-request-7.0.1.tgz#bdd41fdffea5f8fbc0d29392cb47bec4f66b2b4c"
|
||||||
integrity sha512-TAK0c9a00ELOqLrZ49cFxvPVogMUFaWY8dUsQc/0CuQPGF+BOxOQzXfE413BAk2kLomwNplvdtMpeaeGWmoc2g==
|
integrity sha512-sasJmQ37klOlplL4Ia/786M5YlOcoLGQyq2TE4WHSRupbAuDaQW0PfVxV4MtdBtRJ4ngzS+1qim8zP6Zp35qCw==
|
||||||
dependencies:
|
dependencies:
|
||||||
http-proxy-agent "^4.0.0"
|
http-proxy-agent "^4.0.0"
|
||||||
https-proxy-agent "^4.0.0"
|
https-proxy-agent "^5.0.0"
|
||||||
node-fetch "^2.2.0"
|
node-fetch "^2.6.1"
|
||||||
stream-events "^1.0.5"
|
stream-events "^1.0.5"
|
||||||
uuid "^3.3.2"
|
uuid "^8.0.0"
|
||||||
|
|
||||||
temp-dir@^1.0.0:
|
temp-dir@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
@@ -10637,6 +10638,14 @@ trim-right@^1.0.1:
|
|||||||
resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003"
|
resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003"
|
||||||
integrity sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=
|
integrity sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=
|
||||||
|
|
||||||
|
ts-eager@2.0.2:
|
||||||
|
version "2.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/ts-eager/-/ts-eager-2.0.2.tgz#2c1a4d37529effa321f3438793650a84028a87d5"
|
||||||
|
integrity sha512-xzFPL2z7mgLs0brZXaIHTm91Pjl/Cuu9AMKprgSuK+kIS2LjiG8fqqg4eqz3tgBy9OIdupb9w55pr7ea3JBB+Q==
|
||||||
|
dependencies:
|
||||||
|
esbuild "^0.11.20"
|
||||||
|
source-map-support "^0.5.19"
|
||||||
|
|
||||||
ts-jest@24.1.0:
|
ts-jest@24.1.0:
|
||||||
version "24.1.0"
|
version "24.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-24.1.0.tgz#2eaa813271a2987b7e6c3fefbda196301c131734"
|
resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-24.1.0.tgz#2eaa813271a2987b7e6c3fefbda196301c131734"
|
||||||
@@ -10992,6 +11001,11 @@ uuid@^3.0.0, uuid@^3.0.1, uuid@^3.3.2:
|
|||||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
|
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
|
||||||
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
|
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
|
||||||
|
|
||||||
|
uuid@^8.0.0:
|
||||||
|
version "8.3.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
|
||||||
|
integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
|
||||||
|
|
||||||
v8-compile-cache@^2.0.3:
|
v8-compile-cache@^2.0.3:
|
||||||
version "2.1.1"
|
version "2.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz#54bc3cdd43317bca91e35dcaf305b1a7237de745"
|
resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz#54bc3cdd43317bca91e35dcaf305b1a7237de745"
|
||||||
|
|||||||
Reference in New Issue
Block a user