Compare commits

..

29 Commits

Author SHA1 Message Date
Sean Massa
e0f8bc9820 Publish Stable
- @vercel/build-utils@6.3.2
 - vercel@28.16.8
 - @vercel/client@12.4.2
 - @vercel/edge@0.3.1
 - @vercel/frameworks@1.3.2
 - @vercel/fs-detectors@3.8.2
 - @vercel/gatsby-plugin-vercel-builder@1.1.10
 - @vercel/go@2.3.9
 - @vercel/hydrogen@0.0.55
 - @vercel/next@3.6.2
 - @vercel/node-bridge@3.1.13
 - @vercel/node@2.9.9
 - @vercel/python@3.1.51
 - @vercel/redwood@1.1.7
 - @vercel/remix@1.4.2
 - @vercel/routing-utils@2.1.10
 - @vercel/ruby@1.3.68
 - @vercel/static-build@1.3.13
2023-02-28 10:26:29 -06:00
Chris Barber
ebd2e1822c [routing-utils] Add missing 'middlewareRawSrc' to route schema (#9564)
Need to add `middlewareRawSrc` to route schema so the build container will accept the new property.

This PR blocks https://github.com/vercel/vercel/pull/9435.

Linear: https://linear.app/vercel/issue/VCCLI-411/display-uncompressed-edge-middleware-matcher-show-the-list-of-matches
2023-02-28 03:59:06 +00:00
Steven
31bc2581f3 [cli] Remove unncessary warning when monorepo setting override (#9565)
This warning is not actionable by the user so this PR removes it.
2023-02-27 16:23:49 -05:00
Steven
96759a9fda [hydrogen] Add missing envPrefix (#9551)
- Follow up to #9326
2023-02-27 20:01:05 +00:00
Jimmy Lai
ad2864bca5 [next] add support for the integration hook file tracing (#9562)
Adds support for bundling properly the dependencies used by the experimental instrumentation hook file, `instrumentation.js`, by adding the generated nft file to the list of server deps

fixes NEXT-631
2023-02-27 18:58:12 +00:00
Sean Massa
40fbc993d7 [tests] extract noisey setup to make test clearer (#9509)
Clarify dev server tests with a small function extraction.
2023-02-27 17:05:27 +00:00
Sean Massa
1f30e56a6d [cli][dev] remove link to 404 FAQ (#9508) 2023-02-27 10:37:57 -06:00
Nathan Rajlich
58d6268899 [frameworks] Check for remix.config.mjs for "remix" auto-detection (#9558)
Moving this to a separate PR based on this comment:
https://github.com/vercel/vercel/pull/9556#discussion_r1117939290

This will need to be merged and released before the relevant E2E test in
#9556 will pass.

Co-authored-by: Steven <steven@ceriously.com>
2023-02-27 10:07:32 -05:00
Nathan Rajlich
4e6659ace7 [remix] Fix sending multiple response headers with the same name with Node.js (#9533)
i.e. `Set-Cookie`. Right now only one will be sent and others will be lost. This update matches the code being used in `@remix-run/vercel`.
2023-02-27 07:19:58 +00:00
Nathan Rajlich
769234b6a6 [remix] Inject Edge entrypoint into @remix-run/vercel during Edge Function creation (#9553)
There's [a PR](https://github.com/remix-run/remix/pull/5537) opened on
Remix to add an Edge compatible entrypoint to `@remix-run/vercel`. This
is only really needed specifically for projects that have a custom
server.js entrypoint file, which is not strictly necessary anymore, but
there are some edge cases where a project might still want to have one.
So this PR is necessary for those kinds of projects to be able to use
Edge runtime.

Even when they merge the PR, it would be good to leave this injection
code around for some time to continue support for older
`@remix-run/vercel` versions in existing projects.
2023-02-25 00:53:30 -08:00
JJ Kasper
53cab61e88 [next] Fix deploying with cached build (#9555)
This leverages the relative app dir field in the required files manifest when available so that we don't rely on absolute paths from a cached build since the cache can be restored in a separate context where the value no longer applies.

x-ref: https://github.com/vercel/next.js/pull/45864
x-ref: https://github.com/vercel/next.js/pull/46393
x-ref: https://github.com/vercel/next.js/discussions/39432#discussioncomment-4914549
x-ref: [slack thread](https://vercel.slack.com/archives/C03S8ED1DKM/p1675821643786319)
2023-02-25 02:46:06 +00:00
Nathan Rajlich
3a65acfb32 [remix] Don't create output for Pathless Layout Routes without any child routes at the root level (#9539)
Fixes https://github.com/vercel/community/discussions/1587.
2023-02-25 01:17:01 +00:00
Nathan Rajlich
48eed7532a [tests] Properly test for multiple headers with same name in probes (#9538)
Updates the `responseHeaders` probe checks to properly test for multiple headers with the same name.

Previously the probes were using `headers.get()` which concats multiple headers into a single string, which results in the test not really checking if there are in fact multiple headers with the same name. Using `headers.raw()` allows us to properly test for that.

A couple of Python tests that were already checking for multiple `set-cookie` headers needed to be updated to match the full value, since the check now properly validates the full string match of each header (before it was basically just doing a `string.includes()` check).

This is a precursor for https://github.com/vercel/vercel/pull/9533.
2023-02-24 22:07:00 +00:00
Cody Olsen
f09d6fce85 [frameworks] add envPrefix to hydrogen framework (#9326)
Hydrogen uses the `PUBLIC_` env prefix, [it also supports
`VITE_`](8168cd2dd8/packages/hydrogen/src/framework/plugins/vite-plugin-hydrogen-config.ts (L127))
but [the docs only talk about
`PUBLIC_`](https://shopify.dev/custom-storefronts/hydrogen/environment-variables#public-variables).
2023-02-24 15:40:55 -05:00
Chris Barber
cc82c499db [cli] Added fetch dist-tags http status validation (#9549)
If for some reason the `get-latest-worker.js` fails to get the dist-tags, it doesn't check the status code and proceeds to `JSON.parse()` the response. If for example npm returns 401 Unauthorized, you get a cryptic JSON parse error message.
2023-02-24 20:14:53 +00:00
Steven
f0bc207717 [build-utils] Handle error during readConfigFile() (#9542)
This fixes a confusing error:

```
$ vercel build
Vercel CLI 28.16.6
Error: duplicated mapping key in "/vercel/path0/pnpm-lock.yaml" at line 1215, column -164:
      /@react-dnd/asap/4.0.1:
      ^
```
2023-02-24 18:02:35 +00:00
Steven
151c7f99ee [tests] Pass token to cron github actions (#9544)
https://github.com/actions/github-script#using-a-separate-github-token
2023-02-24 11:14:17 -05:00
Steven
61c2c494bf Revert "[tests] Update cron with token in git checkout" (#9543)
Reverts vercel/vercel#9541
2023-02-24 11:07:29 -05:00
Steven
7f49816129 [tests] Update cron with token in git checkout (#9541)
Hopefully this will fix the issue where actions do not run against the
automated PR.
2023-02-24 10:51:03 -05:00
Nathan Rajlich
7845bef826 Publish Stable
- vercel@28.16.7
 - @vercel/edge@0.3.0
 - @vercel/gatsby-plugin-vercel-builder@1.1.9
 - @vercel/next@3.6.1
 - @vercel/node-bridge@3.1.12
 - @vercel/node@2.9.8
 - @vercel/static-build@1.3.12
2023-02-24 04:04:16 -08:00
github-actions[bot]
7acb2e4b07 [examples] Upgrade Next.js to version 13.2.1 (#9536)
This auto-generated PR updates Next.js to version 13.2.1
2023-02-24 11:55:18 +00:00
Gal Schlezinger
abea002e93 [edge] Add RequestContext type (#9526)
Co-authored-by: Kiko Beats <josefrancisco.verdu@gmail.com>
2023-02-24 03:07:16 -08:00
Nathan Rajlich
2db9678bd4 [node-bridge] Fix multiple Set-Cookie headers in streaming mode (#9520)
Multiple `Set-Cookie` headers are being concat'd instead of being sent individually when in streaming mode.

**Non-streaming:**

```
$ curl -v https://01-remix-basics-eqztqyq3y.vercel-support.app/set-cookie 2>&1 | grep cookie
* h2h3 [:path: /set-cookie]
> GET /set-cookie HTTP/2
< set-cookie: foo=bar
< set-cookie: sessionId=38afes7a8
```

**Streaming:**

```
$ curl -v https://01-remix-basics-9b18alizh.vercel-support.app/set-cookie 2>&1 | grep cookie
* h2h3 [:path: /set-cookie]
> GET /set-cookie HTTP/2
< set-cookie: foo=bar,sessionId=38afes7a8
```
2023-02-24 04:03:37 +00:00
JJ Kasper
05f942c53f [tests] Update app-dir integration test (#9532)
The cache heuristic changed so there are now two separate serverless functions expected.
2023-02-24 00:29:34 +00:00
Nathan Rajlich
6c5f0b7aa0 Publish Stable
- vercel@28.16.6
 - @vercel/remix@1.4.1
2023-02-23 15:53:45 -08:00
Nathan Rajlich
fea05383b9 [remix] Ignore serverBuildPath from Remix config (#9531)
We are explicitly overriding `serverBuildPath` so there is no need to use the value that `readConfig()` gives to us.

Fixes #9524.
2023-02-23 23:52:27 +00:00
github-actions[bot]
247f49f765 [examples] Upgrade Next.js to version 13.2.0 (#9529)
This auto-generated PR updates Next.js to version 13.2.0

Co-authored-by: vercel-release-bot <infra+release@vercel.com>
2023-02-23 15:28:38 -05:00
Nathan Rajlich
231714c71b [remix] cd to the project directory during readConfig() (#9518)
Sometimes the `cwd` needs to be properly set for some Remix configurations. This is problematic in monorepos because the default `cwd` is the root of the monorepo, and not the project directory.

So `cd` to the project directory when reading the Remix config file to account for that.

Fixes https://github.com/kiliman/remix-flat-routes/issues/42.
Fixes https://github.com/vercel/vercel/discussions/9478.
2023-02-23 19:18:40 +00:00
Nathan Rajlich
73d6f0d0fa [remix] Update @remix-run/dev dep to v1.13.0 (#9519)
There were some fixes to thier new v2 filesystem routing that this will help with.

Related to https://github.com/remix-run/remix/issues/5322 and https://github.com/remix-run/remix/pull/5228.
2023-02-23 03:44:37 +00:00
81 changed files with 1282 additions and 2577 deletions

View File

@@ -25,6 +25,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN_PULL_REQUESTS }} GITHUB_TOKEN: ${{ secrets.GH_TOKEN_PULL_REQUESTS }}
# See https://github.com/actions/github-script#run-a-separate-file-with-an-async-function # See https://github.com/actions/github-script#run-a-separate-file-with-an-async-function
with: with:
github-token: ${{ secrets.GH_TOKEN_PULL_REQUESTS }}
script: | script: |
const script = require('./utils/update-next.js') const script = require('./utils/update-next.js')
await script({ github, context }) await script({ github, context })

View File

@@ -25,6 +25,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN_PULL_REQUESTS }} GITHUB_TOKEN: ${{ secrets.GH_TOKEN_PULL_REQUESTS }}
# See https://github.com/actions/github-script#run-a-separate-file-with-an-async-function # See https://github.com/actions/github-script#run-a-separate-file-with-an-async-function
with: with:
github-token: ${{ secrets.GH_TOKEN_PULL_REQUESTS }}
script: | script: |
const script = require('./utils/update-turbo.js') const script = require('./utils/update-turbo.js')
await script({ github, context }) await script({ github, context })

File diff suppressed because it is too large Load Diff

View File

@@ -9,10 +9,9 @@
"lint": "next lint" "lint": "next lint"
}, },
"dependencies": { "dependencies": {
"@next/font": "13.1.6", "eslint": "8.34.0",
"eslint": "8.32.0", "eslint-config-next": "13.2.1",
"eslint-config-next": "13.1.6", "next": "13.2.1",
"next": "13.1.6",
"react": "18.2.0", "react": "18.2.0",
"react-dom": "18.2.0" "react-dom": "18.2.0"
} }

View File

@@ -1,6 +1,6 @@
import Head from 'next/head' import Head from 'next/head'
import Image from 'next/image' import Image from 'next/image'
import { Inter } from '@next/font/google' import { Inter } from 'next/font/google'
import styles from '@/styles/Home.module.css' import styles from '@/styles/Home.module.css'
const inter = Inter({ subsets: ['latin'] }) const inter = Inter({ subsets: ['latin'] })

View File

@@ -1,6 +1,6 @@
{ {
"name": "@vercel/build-utils", "name": "@vercel/build-utils",
"version": "6.3.1", "version": "6.3.2",
"license": "MIT", "license": "MIT",
"main": "./dist/index.js", "main": "./dist/index.js",
"types": "./dist/index.d.js", "types": "./dist/index.d.js",

View File

@@ -25,13 +25,17 @@ export async function readConfigFile<T>(
if (data) { if (data) {
const str = data.toString('utf8'); const str = data.toString('utf8');
try {
if (name.endsWith('.json')) { if (name.endsWith('.json')) {
return JSON.parse(str) as T; return JSON.parse(str) as T;
} else if (name.endsWith('.toml')) { } else if (name.endsWith('.toml')) {
return (toml.parse(str) as unknown) as T; return toml.parse(str) as unknown as T;
} else if (name.endsWith('.yaml') || name.endsWith('.yml')) { } else if (name.endsWith('.yaml') || name.endsWith('.yml')) {
return yaml.safeLoad(str, { filename: name }) as T; return yaml.safeLoad(str, { filename: name }) as T;
} }
} catch (error: unknown) {
console.log(`Error while parsing config file: "${name}"`);
}
} }
} }

View File

@@ -0,0 +1,77 @@
import { join } from 'path';
import { writeFile, rm } from 'fs/promises';
import { readConfigFile } from '../src';
describe('Test `readConfigFile()`', () => {
let logMessages: string[];
const originalConsoleLog = console.log;
beforeEach(() => {
logMessages = [];
console.log = m => {
logMessages.push(m);
};
});
afterEach(() => {
console.log = originalConsoleLog;
});
const doesnotexist = join(__dirname, 'does-not-exist.json');
const tsconfig = join(__dirname, '../tsconfig.json');
const invalid = join(__dirname, 'invalid.json');
it('should return null when file does not exist', async () => {
expect(await readConfigFile(doesnotexist)).toBeNull();
expect(logMessages).toEqual([]);
});
it('should return parsed object when file exists', async () => {
expect(await readConfigFile(tsconfig)).toMatchObject({
compilerOptions: {
strict: true,
},
});
expect(logMessages).toEqual([]);
});
it('should return parsed object when at least one file exists', async () => {
const files = [doesnotexist, tsconfig];
expect(await readConfigFile(files)).toMatchObject({
compilerOptions: {
strict: true,
},
});
expect(logMessages).toEqual([]);
});
it('should return null when parse fails', async () => {
try {
await writeFile(invalid, 'borked');
expect(await readConfigFile(invalid)).toBeNull();
} finally {
await rm(invalid);
}
expect(logMessages.length).toBe(1);
expect(logMessages[0]).toMatch(
/^Error while parsing config file.+invalid.json/
);
});
it('should return parsed object when at least one file is valid', async () => {
try {
await writeFile(invalid, 'borked');
expect(await readConfigFile([invalid, tsconfig])).toMatchObject({
compilerOptions: {
strict: true,
},
});
} finally {
await rm(invalid);
}
expect(logMessages.length).toBe(1);
expect(logMessages[0]).toMatch(
/^Error while parsing config file.+invalid.json/
);
});
});

View File

@@ -1,6 +1,6 @@
{ {
"name": "vercel", "name": "vercel",
"version": "28.16.5", "version": "28.16.8",
"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",
@@ -41,16 +41,16 @@
"node": ">= 14" "node": ">= 14"
}, },
"dependencies": { "dependencies": {
"@vercel/build-utils": "6.3.1", "@vercel/build-utils": "6.3.2",
"@vercel/go": "2.3.8", "@vercel/go": "2.3.9",
"@vercel/hydrogen": "0.0.54", "@vercel/hydrogen": "0.0.55",
"@vercel/next": "3.6.0", "@vercel/next": "3.6.2",
"@vercel/node": "2.9.7", "@vercel/node": "2.9.9",
"@vercel/python": "3.1.50", "@vercel/python": "3.1.51",
"@vercel/redwood": "1.1.6", "@vercel/redwood": "1.1.7",
"@vercel/remix": "1.4.0", "@vercel/remix": "1.4.2",
"@vercel/ruby": "1.3.67", "@vercel/ruby": "1.3.68",
"@vercel/static-build": "1.3.11" "@vercel/static-build": "1.3.13"
}, },
"devDependencies": { "devDependencies": {
"@alex_neo/jest-expect-message": "1.0.5", "@alex_neo/jest-expect-message": "1.0.5",
@@ -93,13 +93,13 @@
"@types/which": "1.3.2", "@types/which": "1.3.2",
"@types/write-json-file": "2.2.1", "@types/write-json-file": "2.2.1",
"@types/yauzl-promise": "2.1.0", "@types/yauzl-promise": "2.1.0",
"@vercel/client": "12.4.1", "@vercel/client": "12.4.2",
"@vercel/error-utils": "1.0.8", "@vercel/error-utils": "1.0.8",
"@vercel/frameworks": "1.3.1", "@vercel/frameworks": "1.3.2",
"@vercel/fs-detectors": "3.8.1", "@vercel/fs-detectors": "3.8.2",
"@vercel/fun": "1.0.4", "@vercel/fun": "1.0.4",
"@vercel/ncc": "0.24.0", "@vercel/ncc": "0.24.0",
"@vercel/routing-utils": "2.1.9", "@vercel/routing-utils": "2.1.10",
"@zeit/source-map-support": "0.6.2", "@zeit/source-map-support": "0.6.2",
"ajv": "6.12.2", "ajv": "6.12.2",
"alpha-sort": "2.0.1", "alpha-sort": "2.0.1",

View File

@@ -9,6 +9,7 @@ import { ProjectLinkAndSettings } from '../projects/project-settings';
import { Output } from '../output'; import { Output } from '../output';
import title from 'title'; import title from 'title';
import { PartialProjectSettings } from '../input/edit-project-settings'; import { PartialProjectSettings } from '../input/edit-project-settings';
import { debug } from '@vercel/build-utils';
export async function setMonorepoDefaultSettings( export async function setMonorepoDefaultSettings(
cwd: string, cwd: string,
@@ -26,8 +27,8 @@ export async function setMonorepoDefaultSettings(
value: string value: string
) => { ) => {
if (projectSettings[command]) { if (projectSettings[command]) {
output.warn( debug(
`Cannot automatically assign ${command} as it is already set via project settings or configuration overrides.` `Skipping auto-assignment of ${command} as it is already set via project settings or configuration overrides.`
); );
} else { } else {
projectSettings[command] = value; projectSettings[command] = value;

View File

@@ -6,6 +6,4 @@
{{?}} {{?}}
<span class="devinfo-line">ID: <code>{{! it.request_id }}</code> <span class="devinfo-line">ID: <code>{{! it.request_id }}</code>
</p> </p>
<a href="https://vercel.link/404"><div class="note">Click here to learn more about this error.</div></a>
</main> </main>

View File

@@ -247,6 +247,14 @@ async function fetchDistTags(name) {
}); });
res.on('end', () => { res.on('end', () => {
try { try {
if (res.statusCode && res.statusCode >= 400) {
return reject(
new Error(
`Fetch dist-tags failed ${res.statusCode} ${res.statusMessage}`
)
);
}
resolve(JSON.parse(buf)); resolve(JSON.parse(buf));
} catch (err) { } catch (err) {
reject(err); reject(err);

View File

@@ -1,6 +1,6 @@
{ {
"name": "@vercel/client", "name": "@vercel/client",
"version": "12.4.1", "version": "12.4.2",
"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",
@@ -43,8 +43,8 @@
] ]
}, },
"dependencies": { "dependencies": {
"@vercel/build-utils": "6.3.1", "@vercel/build-utils": "6.3.2",
"@vercel/routing-utils": "2.1.9", "@vercel/routing-utils": "2.1.10",
"@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",

View File

@@ -7,6 +7,7 @@
- [ExtraResponseInit](interfaces/ExtraResponseInit.md) - [ExtraResponseInit](interfaces/ExtraResponseInit.md)
- [Geo](interfaces/Geo.md) - [Geo](interfaces/Geo.md)
- [ModifiedRequest](interfaces/ModifiedRequest.md) - [ModifiedRequest](interfaces/ModifiedRequest.md)
- [RequestContext](interfaces/RequestContext.md)
### Variables ### Variables

View File

@@ -0,0 +1,79 @@
# Interface: RequestContext
An extension to the standard `Request` object that is passed to every Edge Function.
**`Example`**
```ts
import type { RequestContext } from '@vercel/edge';
export default async function handler(
request: Request,
ctx: RequestContext
): Promise<Response> {
// ctx is the RequestContext
}
```
## Table of contents
### Methods
- [waitUntil](RequestContext.md#waituntil)
## Methods
### waitUntil
**waitUntil**(`promise`): `void`
A method that can be used to keep the function running after a response has been sent.
This is useful when you have an async task that you want to keep running even after the
response has been sent and the request has ended.
**`Example`**
<caption>Sending an internal error to an error tracking service</caption>
```ts
import type { RequestContext } from '@vercel/edge';
export async function handleRequest(
request: Request,
ctx: RequestContext
): Promise<Response> {
try {
return await myFunctionThatReturnsResponse();
} catch (e) {
ctx.waitUntil(
(async () => {
// report this error to your error tracking service
await fetch('https://my-error-tracking-service.com', {
method: 'POST',
body: JSON.stringify({
stack: e.stack,
message: e.message,
name: e.name,
url: request.url,
}),
});
})()
);
return new Response('Internal Server Error', { status: 500 });
}
}
```
#### Parameters
| Name | Type | Description |
| :-------- | :---------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------- |
| `promise` | [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)<`unknown`\> | A promise that will be kept alive until it resolves or rejects. |
#### Returns
`void`
#### Defined in
[packages/edge/src/request.ts:47](https://github.com/vercel/vercel/blob/main/packages/edge/src/request.ts#L47)

View File

@@ -1,6 +1,6 @@
{ {
"name": "@vercel/edge", "name": "@vercel/edge",
"version": "0.2.7", "version": "0.3.1",
"license": "MIT", "license": "MIT",
"main": "dist/index.js", "main": "dist/index.js",
"module": "dist/index.mjs", "module": "dist/index.mjs",

View File

@@ -4,5 +4,6 @@ export * from './middleware-helpers';
export type { Geo } from './edge-headers'; export type { Geo } from './edge-headers';
export * from './edge-headers'; export * from './edge-headers';
export * from './response'; export * from './response';
export type { RequestContext } from './request';
import './published-types.d.ts'; import './published-types.d.ts';

View File

@@ -0,0 +1,52 @@
/**
* An extension to the standard `Request` object that is passed to every Edge Function.
*
* @example
* ```ts
* import type { RequestContext } from '@vercel/edge';
*
* export default async function handler(request: Request, ctx: RequestContext): Promise<Response> {
* // ctx is the RequestContext
* }
* ```
*/
export interface RequestContext {
/**
* A method that can be used to keep the function running after a response has been sent.
* This is useful when you have an async task that you want to keep running even after the
* response has been sent and the request has ended.
*
* @example
*
* <caption>Sending an internal error to an error tracking service</caption>
*
* ```ts
* import type { RequestContext } from '@vercel/edge';
*
* export async function handleRequest(request: Request, ctx: RequestContext): Promise<Response> {
* try {
* return await myFunctionThatReturnsResponse();
* } catch (e) {
* ctx.waitUntil((async () => {
* // report this error to your error tracking service
* await fetch('https://my-error-tracking-service.com', {
* method: 'POST',
* body: JSON.stringify({
* stack: e.stack,
* message: e.message,
* name: e.name,
* url: request.url,
* }),
* });
* })());
* return new Response('Internal Server Error', { status: 500 });
* }
* }
* ```
*/
waitUntil(
/**
* A promise that will be kept alive until it resolves or rejects.
*/ promise: Promise<unknown>
): void;
}

View File

@@ -1,6 +1,6 @@
{ {
"name": "@vercel/frameworks", "name": "@vercel/frameworks",
"version": "1.3.1", "version": "1.3.2",
"main": "./dist/frameworks.js", "main": "./dist/frameworks.js",
"types": "./dist/frameworks.d.ts", "types": "./dist/frameworks.d.ts",
"files": [ "files": [
@@ -21,7 +21,7 @@
"@types/js-yaml": "3.12.1", "@types/js-yaml": "3.12.1",
"@types/node": "14.18.33", "@types/node": "14.18.33",
"@types/node-fetch": "2.5.8", "@types/node-fetch": "2.5.8",
"@vercel/routing-utils": "2.1.9", "@vercel/routing-utils": "2.1.10",
"ajv": "6.12.2", "ajv": "6.12.2",
"typescript": "4.3.4" "typescript": "4.3.4"
} }

View File

@@ -202,12 +202,13 @@ export const frameworks = [
useRuntime: { src: 'package.json', use: '@vercel/remix' }, useRuntime: { src: 'package.json', use: '@vercel/remix' },
ignoreRuntimes: ['@vercel/node'], ignoreRuntimes: ['@vercel/node'],
detectors: { detectors: {
every: [ some: [
// Intentionally does not detect a package name
// https://github.com/vercel/vercel/pull/7761
{ {
path: 'remix.config.js', path: 'remix.config.js',
}, },
{
path: 'remix.config.mjs',
},
], ],
}, },
settings: { settings: {
@@ -1698,6 +1699,7 @@ export const frameworks = [
description: 'React framework for headless commerce', description: 'React framework for headless commerce',
website: 'https://hydrogen.shopify.dev', website: 'https://hydrogen.shopify.dev',
useRuntime: { src: 'package.json', use: '@vercel/hydrogen' }, useRuntime: { src: 'package.json', use: '@vercel/hydrogen' },
envPrefix: 'PUBLIC_',
detectors: { detectors: {
some: [ some: [
{ {

View File

@@ -1,6 +1,6 @@
{ {
"name": "@vercel/fs-detectors", "name": "@vercel/fs-detectors",
"version": "3.8.1", "version": "3.8.2",
"description": "Vercel filesystem detectors", "description": "Vercel filesystem detectors",
"main": "./dist/index.js", "main": "./dist/index.js",
"types": "./dist/index.d.ts", "types": "./dist/index.d.ts",
@@ -20,8 +20,8 @@
}, },
"dependencies": { "dependencies": {
"@vercel/error-utils": "1.0.8", "@vercel/error-utils": "1.0.8",
"@vercel/frameworks": "1.3.1", "@vercel/frameworks": "1.3.2",
"@vercel/routing-utils": "2.1.9", "@vercel/routing-utils": "2.1.10",
"glob": "8.0.3", "glob": "8.0.3",
"js-yaml": "4.1.0", "js-yaml": "4.1.0",
"json5": "2.2.2", "json5": "2.2.2",
@@ -35,7 +35,7 @@
"@types/minimatch": "3.0.5", "@types/minimatch": "3.0.5",
"@types/node": "14.18.33", "@types/node": "14.18.33",
"@types/semver": "7.3.10", "@types/semver": "7.3.10",
"@vercel/build-utils": "6.3.1", "@vercel/build-utils": "6.3.2",
"typescript": "4.3.4" "typescript": "4.3.4"
} }
} }

View File

@@ -1,6 +1,6 @@
{ {
"name": "@vercel/gatsby-plugin-vercel-builder", "name": "@vercel/gatsby-plugin-vercel-builder",
"version": "1.1.8", "version": "1.1.10",
"main": "dist/index.js", "main": "dist/index.js",
"files": [ "files": [
"dist", "dist",
@@ -14,9 +14,9 @@
"build:src": "tsc -p tsconfig.src.json" "build:src": "tsc -p tsconfig.src.json"
}, },
"dependencies": { "dependencies": {
"@vercel/build-utils": "6.3.1", "@vercel/build-utils": "6.3.2",
"@vercel/node": "2.9.7", "@vercel/node": "2.9.9",
"@vercel/routing-utils": "2.1.9", "@vercel/routing-utils": "2.1.10",
"ajv": "8.12.0", "ajv": "8.12.0",
"esbuild": "0.14.47", "esbuild": "0.14.47",
"etag": "1.8.1", "etag": "1.8.1",

View File

@@ -1,6 +1,6 @@
{ {
"name": "@vercel/go", "name": "@vercel/go",
"version": "2.3.8", "version": "2.3.9",
"license": "MIT", "license": "MIT",
"main": "./dist/index", "main": "./dist/index",
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/go", "homepage": "https://vercel.com/docs/runtimes#official-runtimes/go",
@@ -36,7 +36,7 @@
"@types/node": "14.18.33", "@types/node": "14.18.33",
"@types/node-fetch": "^2.3.0", "@types/node-fetch": "^2.3.0",
"@types/tar": "^4.0.0", "@types/tar": "^4.0.0",
"@vercel/build-utils": "6.3.1", "@vercel/build-utils": "6.3.2",
"@vercel/ncc": "0.24.0", "@vercel/ncc": "0.24.0",
"async-retry": "1.3.1", "async-retry": "1.3.1",
"execa": "^1.0.0", "execa": "^1.0.0",

View File

@@ -1,6 +1,6 @@
{ {
"name": "@vercel/hydrogen", "name": "@vercel/hydrogen",
"version": "0.0.54", "version": "0.0.55",
"license": "MIT", "license": "MIT",
"main": "./dist/index.js", "main": "./dist/index.js",
"homepage": "https://vercel.com/docs", "homepage": "https://vercel.com/docs",
@@ -21,7 +21,7 @@
"devDependencies": { "devDependencies": {
"@types/jest": "27.5.1", "@types/jest": "27.5.1",
"@types/node": "14.18.33", "@types/node": "14.18.33",
"@vercel/build-utils": "6.3.1", "@vercel/build-utils": "6.3.2",
"@vercel/static-config": "2.0.13", "@vercel/static-config": "2.0.13",
"execa": "3.2.0", "execa": "3.2.0",
"fs-extra": "11.1.0", "fs-extra": "11.1.0",

View File

@@ -7,6 +7,7 @@ import {
execCommand, execCommand,
getEnvForPackageManager, getEnvForPackageManager,
getNodeVersion, getNodeVersion,
getPrefixedEnvVars,
getSpawnOptions, getSpawnOptions,
glob, glob,
readConfigFile, readConfigFile,
@@ -29,6 +30,15 @@ export const build: BuildV2 = async ({
await download(files, workPath, meta); await download(files, workPath, meta);
const prefixedEnvs = getPrefixedEnvVars({
envPrefix: 'PUBLIC_',
envs: process.env,
});
for (const [key, value] of Object.entries(prefixedEnvs)) {
process.env[key] = value;
}
const mountpoint = dirname(entrypoint); const mountpoint = dirname(entrypoint);
const entrypointDir = join(workPath, mountpoint); const entrypointDir = join(workPath, mountpoint);

View File

@@ -1,6 +1,6 @@
{ {
"name": "@vercel/next", "name": "@vercel/next",
"version": "3.6.0", "version": "3.6.2",
"license": "MIT", "license": "MIT",
"main": "./dist/index", "main": "./dist/index",
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/next-js", "homepage": "https://vercel.com/docs/runtimes#official-runtimes/next-js",
@@ -45,9 +45,9 @@
"@types/semver": "6.0.0", "@types/semver": "6.0.0",
"@types/text-table": "0.2.1", "@types/text-table": "0.2.1",
"@types/webpack-sources": "3.2.0", "@types/webpack-sources": "3.2.0",
"@vercel/build-utils": "6.3.1", "@vercel/build-utils": "6.3.2",
"@vercel/nft": "0.22.5", "@vercel/nft": "0.22.5",
"@vercel/routing-utils": "2.1.9", "@vercel/routing-utils": "2.1.10",
"async-sema": "3.0.1", "async-sema": "3.0.1",
"buffer-crc32": "0.2.13", "buffer-crc32": "0.2.13",
"bytes": "3.1.2", "bytes": "3.1.2",

View File

@@ -150,6 +150,10 @@ export async function serverBuild({
nextVersion, nextVersion,
EMPTY_ALLOW_QUERY_FOR_PRERENDERED_VERSION EMPTY_ALLOW_QUERY_FOR_PRERENDERED_VERSION
); );
const projectDir = requiredServerFilesManifest.relativeAppDir
? path.join(baseDir, requiredServerFilesManifest.relativeAppDir)
: requiredServerFilesManifest.appDir || entryPath;
let appBuildTraces: UnwrapPromise<ReturnType<typeof glob>> = {}; let appBuildTraces: UnwrapPromise<ReturnType<typeof glob>> = {};
let appDir: string | null = null; let appDir: string | null = null;
@@ -269,9 +273,10 @@ export async function serverBuild({
let initialFileList: string[]; let initialFileList: string[];
let initialFileReasons: NodeFileTraceReasons; let initialFileReasons: NodeFileTraceReasons;
let nextServerBuildTrace; let nextServerBuildTrace;
let instrumentationHookBuildTrace;
const nextServerFile = resolveFrom( const nextServerFile = resolveFrom(
requiredServerFilesManifest.appDir || entryPath, projectDir,
`${getNextServerPath(nextVersion)}/next-server.js` `${getNextServerPath(nextVersion)}/next-server.js`
); );
@@ -287,6 +292,22 @@ export async function serverBuild({
// if the trace is unavailable we trace inside the runtime // if the trace is unavailable we trace inside the runtime
} }
try {
instrumentationHookBuildTrace = JSON.parse(
await fs.readFile(
path.join(
entryPath,
outputDirectory,
'server',
'instrumentation.js.nft.json'
),
'utf8'
)
);
} catch (_) {
// if the trace is unavailable it means `instrumentation.js` wasn't used
}
if (nextServerBuildTrace) { if (nextServerBuildTrace) {
initialFileList = nextServerBuildTrace.files.map((file: string) => { initialFileList = nextServerBuildTrace.files.map((file: string) => {
return path.relative( return path.relative(
@@ -321,6 +342,18 @@ export async function serverBuild({
initialFileReasons = result.reasons; initialFileReasons = result.reasons;
} }
if (instrumentationHookBuildTrace) {
initialFileList = initialFileList.concat(
instrumentationHookBuildTrace.files.map((file: string) => {
return path.relative(
baseDir,
path.join(entryPath, outputDirectory, 'server', file)
);
})
);
debug('Using instrumentation.js.nft.json trace from build');
}
debug('collecting initial Next.js server files'); debug('collecting initial Next.js server files');
await Promise.all( await Promise.all(
initialFileList.map( initialFileList.map(
@@ -437,8 +470,8 @@ export async function serverBuild({
file file
); );
if (requiredServerFilesManifest.appDir) { if (projectDir) {
fsPath = path.join(requiredServerFilesManifest.appDir, file); fsPath = path.join(projectDir, file);
} }
const relativePath = path.relative(baseDir, fsPath); const relativePath = path.relative(baseDir, fsPath);
@@ -516,7 +549,7 @@ export async function serverBuild({
`conf: ${JSON.stringify({ `conf: ${JSON.stringify({
...requiredServerFilesManifest.config, ...requiredServerFilesManifest.config,
distDir: path.relative( distDir: path.relative(
requiredServerFilesManifest.appDir || entryPath, projectDir,
path.join(entryPath, outputDirectory) path.join(entryPath, outputDirectory)
), ),
compress: false, compress: false,
@@ -543,10 +576,8 @@ export async function serverBuild({
} }
const launcherFiles: { [name: string]: FileFsRef | FileBlob } = { const launcherFiles: { [name: string]: FileFsRef | FileBlob } = {
[path.join( [path.join(path.relative(baseDir, projectDir), '___next_launcher.cjs')]:
path.relative(baseDir, requiredServerFilesManifest.appDir || entryPath), new FileBlob({ data: launcher }),
'___next_launcher.cjs'
)]: new FileBlob({ data: launcher }),
}; };
const pageTraces: { const pageTraces: {
[page: string]: { [key: string]: FileFsRef }; [page: string]: { [key: string]: FileFsRef };
@@ -594,7 +625,7 @@ export async function serverBuild({
traceResult = await nodeFileTrace(pathsToTrace, { traceResult = await nodeFileTrace(pathsToTrace, {
base: baseDir, base: baseDir,
cache: traceCache, cache: traceCache,
processCwd: requiredServerFilesManifest.appDir || entryPath, processCwd: projectDir,
}); });
traceResult.esmFileList.forEach(file => traceResult?.fileList.add(file)); traceResult.esmFileList.forEach(file => traceResult?.fileList.add(file));
parentFilesMap = getFilesMapFromReasons( parentFilesMap = getFilesMapFromReasons(
@@ -703,7 +734,7 @@ export async function serverBuild({
const pageExtensions = requiredServerFilesManifest.config?.pageExtensions; const pageExtensions = requiredServerFilesManifest.config?.pageExtensions;
const pageLambdaGroups = await getPageLambdaGroups({ const pageLambdaGroups = await getPageLambdaGroups({
entryPath: requiredServerFilesManifest.appDir || entryPath, entryPath: projectDir,
config, config,
pages: nonApiPages, pages: nonApiPages,
prerenderRoutes, prerenderRoutes,
@@ -718,7 +749,7 @@ export async function serverBuild({
}); });
const streamingPageLambdaGroups = await getPageLambdaGroups({ const streamingPageLambdaGroups = await getPageLambdaGroups({
entryPath: requiredServerFilesManifest.appDir || entryPath, entryPath: projectDir,
config, config,
pages: streamingPages, pages: streamingPages,
prerenderRoutes, prerenderRoutes,
@@ -739,7 +770,7 @@ export async function serverBuild({
} }
const apiLambdaGroups = await getPageLambdaGroups({ const apiLambdaGroups = await getPageLambdaGroups({
entryPath: requiredServerFilesManifest.appDir || entryPath, entryPath: projectDir,
config, config,
pages: apiPages, pages: apiPages,
prerenderRoutes, prerenderRoutes,
@@ -873,10 +904,7 @@ export async function serverBuild({
}, },
layers: [group.pseudoLayer, groupPageFiles], layers: [group.pseudoLayer, groupPageFiles],
handler: path.join( handler: path.join(
path.relative( path.relative(baseDir, projectDir),
baseDir,
requiredServerFilesManifest.appDir || entryPath
),
'___next_launcher.cjs' '___next_launcher.cjs'
), ),
operationType, operationType,

View File

@@ -811,6 +811,7 @@ export async function createLambdaFromPseudoLayers({
export type NextRequiredServerFilesManifest = { export type NextRequiredServerFilesManifest = {
appDir?: string; appDir?: string;
relativeAppDir?: string;
files: string[]; files: string[];
ignore: string[]; ignore: string[];
config: Record<string, any>; config: Record<string, any>;
@@ -954,6 +955,7 @@ export async function getRequiredServerFilesManifest(
ignore: [], ignore: [],
config: {}, config: {},
appDir: manifestData.appDir, appDir: manifestData.appDir,
relativeAppDir: manifestData.relativeAppDir,
}; };
switch (manifestData.version) { switch (manifestData.version) {

View File

@@ -0,0 +1 @@
.vercel

View File

@@ -0,0 +1,7 @@
{
"name": "web",
"private": true,
"scripts": {
"build": "next build && rm -rf .next/cache && node post-build.js"
}
}

View File

@@ -0,0 +1,3 @@
export default function Page() {
return <p>index page</p>;
}

View File

@@ -0,0 +1,12 @@
export default function Page() {
return <p>ssg page</p>;
}
export function getStaticProps() {
return {
props: {
now: Date.now(),
},
revalidate: 3,
};
}

View File

@@ -0,0 +1,11 @@
export default function Page() {
return <p>ssp page</p>;
}
export function getServerSideProps() {
return {
props: {
now: Date.now(),
},
};
}

View File

@@ -0,0 +1,19 @@
const fs = require('fs');
const path = require('path');
const requiredFilesManifestPath = path.join(
__dirname,
'.next/required-server-files.json'
);
const requiredFilesManifest = JSON.parse(
fs.readFileSync(requiredFilesManifestPath, 'utf8')
);
fs.writeFileSync(
requiredFilesManifestPath,
JSON.stringify({
...requiredFilesManifest,
appDir: '/non-existent/apps/web',
})
);

View File

@@ -0,0 +1,12 @@
/* eslint-env jest */
const path = require('path');
const { deployAndTest } = require('../../utils');
const ctx = {};
describe(`${__dirname.split(path.sep).pop()}`, () => {
it('should deploy and pass probe checks', async () => {
const info = await deployAndTest(__dirname, { skipForceNew: true });
Object.assign(ctx, info);
});
});

View File

@@ -0,0 +1,15 @@
{
"workspaces": [
"apps/*"
],
"private": true,
"dependencies": {
"next": "13.2.2-canary.0",
"react": "18.2.0",
"react-dom": "18.2.0",
"turbo": "1.8.2"
},
"scripts": {
"build": "turbo build --cache-dir=turbo-cache"
}
}

View File

@@ -0,0 +1 @@
{ "hash": "3d4a11a80ae91055", "duration": 5510 }

View File

@@ -0,0 +1,8 @@
{
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": [".next/**"]
}
}
}

View File

@@ -0,0 +1,30 @@
{
"builds": [
{
"src": "package.json",
"use": "@vercel/next",
"config": {
"rootDirectory": "apps/web",
"buildCommand": "cd ../../ && yarn build",
"installCommand": "yarn"
}
}
],
"probes": [
{
"path": "/",
"status": 200,
"mustContain": "index page"
},
{
"path": "/ssg",
"status": 200,
"mustContain": "ssg page"
},
{
"path": "/ssp",
"status": 200,
"mustContain": "ssp page"
}
]
}

View File

@@ -0,0 +1,227 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@next/env@13.2.2-canary.0":
version "13.2.2-canary.0"
resolved "https://registry.yarnpkg.com/@next/env/-/env-13.2.2-canary.0.tgz#0f843ef602ff25441f17f10d09a93942baa8232b"
integrity sha512-EDy4UF4oXGmWgMq9w8P7Wg7JoYbrGY7EVnZcNoyMDU8o9KeiviYjK2IR3yFBulG0/1I2UbVu2wIM1xPYsQIonQ==
"@next/swc-android-arm-eabi@13.2.2-canary.0":
version "13.2.2-canary.0"
resolved "https://registry.yarnpkg.com/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-13.2.2-canary.0.tgz#62510cc5b11b677a63363788848efdc8aeda9cf8"
integrity sha512-/si1jk3wtrarhdVPQloSubTJjLeuTpgT7V2R2w+acWzvBBsrs2ThhZodLz0fJRKcYKmeDZebhtYGUkxkcm48Tw==
"@next/swc-android-arm64@13.2.2-canary.0":
version "13.2.2-canary.0"
resolved "https://registry.yarnpkg.com/@next/swc-android-arm64/-/swc-android-arm64-13.2.2-canary.0.tgz#967fe8a63d59bdd22f57056ef83005242b559c1a"
integrity sha512-MKImVjggMFvPJju48fvz/KqjiqXaKoimGz3Vmc3c12WaSIEa5O1sevw0dQKPI6sv+1Mf5MuP7XlLQ9bWJo+72Q==
"@next/swc-darwin-arm64@13.2.2-canary.0":
version "13.2.2-canary.0"
resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.2.2-canary.0.tgz#1250cf70dc129b765ae11bc596cd4d298a129afe"
integrity sha512-Sj+hCut5c6K2lOIJpV9KDsDJNe1dVacAE8WWmvotoeu4ab1W0//axZOxksq0S3240oF9CJ8QPZo+q5lPV6Gn2Q==
"@next/swc-darwin-x64@13.2.2-canary.0":
version "13.2.2-canary.0"
resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-13.2.2-canary.0.tgz#13dde75f037194d46799542111608679c73dc8dc"
integrity sha512-/lv1J5ts5UhQ5V2V0PpIkQJw8kJywMgvPegZ/yf0fy9QOOdGCAw1dXtZsKUISrJmuzPcCZo0F56Zjbyb6lCLsw==
"@next/swc-freebsd-x64@13.2.2-canary.0":
version "13.2.2-canary.0"
resolved "https://registry.yarnpkg.com/@next/swc-freebsd-x64/-/swc-freebsd-x64-13.2.2-canary.0.tgz#f9709e88c60207fb17244895cfe23a4a2d40b099"
integrity sha512-ECQyYOYd1AKu/oTNeI5pWDXebgKTIWXCs84IN9rXsM7f+FOQmVU8V+gK6Oisw3jya68B1vmfMqLDGQClDDIMAg==
"@next/swc-linux-arm-gnueabihf@13.2.2-canary.0":
version "13.2.2-canary.0"
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-13.2.2-canary.0.tgz#bdcef78c71820ff64c1225796dc383c8d72fcaed"
integrity sha512-/UQf0yoIwJJhgV8dpDmgWq/Q3/IxqFRsUHfBiy2M6kGVYwB9CnsjZzHwUKmg7sASdv+atW+oc4PIXXN6W9CCgg==
"@next/swc-linux-arm64-gnu@13.2.2-canary.0":
version "13.2.2-canary.0"
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.2.2-canary.0.tgz#e77b30092c22eb0af16a7a6c150d51fa84f0ceb0"
integrity sha512-pv0m+4hnKyq0MwEVAvrJScoYme4GKoPieP0Tj32oRK6P1gafFK4uJxF6zMVPlO0D/tGI7EkoHZjv/7sU5pSYSA==
"@next/swc-linux-arm64-musl@13.2.2-canary.0":
version "13.2.2-canary.0"
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.2.2-canary.0.tgz#779514bb2d0e7feced48fac1da0bc344180c8511"
integrity sha512-Bpc7nLJoP6dVPG9lOqCGqWkfiMo143YRx7+cvxSl1FVupkGP7Ntldvl3zS/m2CnU/5egQEjC2C5jEgQRY92Zhw==
"@next/swc-linux-x64-gnu@13.2.2-canary.0":
version "13.2.2-canary.0"
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.2.2-canary.0.tgz#d9022f44e0b243d32d39eeac683b1f189ff41487"
integrity sha512-2RPr5AxawTUVaQGrkhWWpjVdExPiA8wEJL6E1itI2gNav8LU3FEsIr9juQURv47Xn2KE286fw8214D6+D0RExg==
"@next/swc-linux-x64-musl@13.2.2-canary.0":
version "13.2.2-canary.0"
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.2.2-canary.0.tgz#8868f650f11594862fa183e0a0dac66d9c72973b"
integrity sha512-gKr5tJoJKGSlmDdpmoO1fe6oUeVMz2TluspKPM4ulc0rqyXjrRmQ9pd/oqEoypUKTUkqL49lt4hTL98MkhvXWg==
"@next/swc-win32-arm64-msvc@13.2.2-canary.0":
version "13.2.2-canary.0"
resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.2.2-canary.0.tgz#29faaa4b760128c648f153964e94a8191bb0b2d7"
integrity sha512-0N7+lcV8ycqzgJIye40+Vl0iUk/mu3919T2kfnt20WU7gP+rpRJkPfP44yxBdt7U7XYtnqldM2Ox969y+0qJVw==
"@next/swc-win32-ia32-msvc@13.2.2-canary.0":
version "13.2.2-canary.0"
resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.2.2-canary.0.tgz#078350e676d1a146442dbc7b1f5c4e03cb1345a5"
integrity sha512-vqdsKfJcfvf37P7YcJeIaPP5E7iSR7yTaHwgBpvY6Q0tDRxPv0gr4nRXElBs/V1VcxMaSx9PyyiQkKYB6UzEhg==
"@next/swc-win32-x64-msvc@13.2.2-canary.0":
version "13.2.2-canary.0"
resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.2.2-canary.0.tgz#7ca59776b5440e6de3aee341d571a8a4f7cbb40a"
integrity sha512-Hf1XQaP/hpi9ddS128u8+npotRzX5EOt9y4nxzHRKn6BmjgAKY7CEBsFQMsjVHWqit2Jt3jXspgaCVIFOCE9Ng==
"@swc/helpers@0.4.14":
version "0.4.14"
resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.4.14.tgz#1352ac6d95e3617ccb7c1498ff019654f1e12a74"
integrity sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==
dependencies:
tslib "^2.4.0"
caniuse-lite@^1.0.30001406:
version "1.0.30001457"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001457.tgz#6af34bb5d720074e2099432aa522c21555a18301"
integrity sha512-SDIV6bgE1aVbK6XyxdURbUE89zY7+k1BBBaOwYwkNCglXlel/E7mELiHC64HQ+W0xSKlqWhV9Wh7iHxUjMs4fA==
client-only@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/client-only/-/client-only-0.0.1.tgz#38bba5d403c41ab150bff64a95c85013cf73bca1"
integrity sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==
"js-tokens@^3.0.0 || ^4.0.0":
version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
loose-envify@^1.1.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
dependencies:
js-tokens "^3.0.0 || ^4.0.0"
nanoid@^3.3.4:
version "3.3.4"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab"
integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==
next@13.2.2-canary.0:
version "13.2.2-canary.0"
resolved "https://registry.yarnpkg.com/next/-/next-13.2.2-canary.0.tgz#7b8c9e2391d947fb66636fe988af644f2e930db2"
integrity sha512-sAzQCPI06df+TY7NI6txOkc7sOC7sErnOGF7vXA28GcQ0r4V09s4GDe8XTlPckxJ7o2Ky4OU1eN4NJ3vnDCcZQ==
dependencies:
"@next/env" "13.2.2-canary.0"
"@swc/helpers" "0.4.14"
caniuse-lite "^1.0.30001406"
postcss "8.4.14"
styled-jsx "5.1.1"
optionalDependencies:
"@next/swc-android-arm-eabi" "13.2.2-canary.0"
"@next/swc-android-arm64" "13.2.2-canary.0"
"@next/swc-darwin-arm64" "13.2.2-canary.0"
"@next/swc-darwin-x64" "13.2.2-canary.0"
"@next/swc-freebsd-x64" "13.2.2-canary.0"
"@next/swc-linux-arm-gnueabihf" "13.2.2-canary.0"
"@next/swc-linux-arm64-gnu" "13.2.2-canary.0"
"@next/swc-linux-arm64-musl" "13.2.2-canary.0"
"@next/swc-linux-x64-gnu" "13.2.2-canary.0"
"@next/swc-linux-x64-musl" "13.2.2-canary.0"
"@next/swc-win32-arm64-msvc" "13.2.2-canary.0"
"@next/swc-win32-ia32-msvc" "13.2.2-canary.0"
"@next/swc-win32-x64-msvc" "13.2.2-canary.0"
picocolors@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
postcss@8.4.14:
version "8.4.14"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.14.tgz#ee9274d5622b4858c1007a74d76e42e56fd21caf"
integrity sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==
dependencies:
nanoid "^3.3.4"
picocolors "^1.0.0"
source-map-js "^1.0.2"
react-dom@18.2.0:
version "18.2.0"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d"
integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==
dependencies:
loose-envify "^1.1.0"
scheduler "^0.23.0"
react@18.2.0:
version "18.2.0"
resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5"
integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==
dependencies:
loose-envify "^1.1.0"
scheduler@^0.23.0:
version "0.23.0"
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.0.tgz#ba8041afc3d30eb206a487b6b384002e4e61fdfe"
integrity sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==
dependencies:
loose-envify "^1.1.0"
source-map-js@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
styled-jsx@5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-5.1.1.tgz#839a1c3aaacc4e735fed0781b8619ea5d0009d1f"
integrity sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==
dependencies:
client-only "0.0.1"
tslib@^2.4.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf"
integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==
turbo-darwin-64@1.8.2:
version "1.8.2"
resolved "https://registry.yarnpkg.com/turbo-darwin-64/-/turbo-darwin-64-1.8.2.tgz#14c52e97d128c63fd3c7b2f15963123f02b9aa0e"
integrity sha512-j77U0uOeppENexFsIvvzExADSqMBEeCHnm+6LSNQfaajHSrbUVSTsuD6ZMYHamT6bslc+ZZm21jdecWkwZFBbw==
turbo-darwin-arm64@1.8.2:
version "1.8.2"
resolved "https://registry.yarnpkg.com/turbo-darwin-arm64/-/turbo-darwin-arm64-1.8.2.tgz#ae5efdb89cbdd667feacd3fe8e9c8110691a4d95"
integrity sha512-1NoAvjlwt2wycsAFJouauy9epn9DptSMy6BoGqxJVc4jiibsLepp9qYc4f1/ln0zjd3FR1IvhGOiBfdpqMN7hg==
turbo-linux-64@1.8.2:
version "1.8.2"
resolved "https://registry.yarnpkg.com/turbo-linux-64/-/turbo-linux-64-1.8.2.tgz#02442a48104db83c1e53409c85744fdeacbded56"
integrity sha512-TcT3CRYnBYA46kLGGbGC2jDyCEAvMgVpUdpIZGTmod48EKpZaEfVgTkpa4GJde8W68yRFogPZjPVL3yJHFpXSA==
turbo-linux-arm64@1.8.2:
version "1.8.2"
resolved "https://registry.yarnpkg.com/turbo-linux-arm64/-/turbo-linux-arm64-1.8.2.tgz#890ad0691671cb252e756dcd56295895f61d369a"
integrity sha512-Mb9+KBy4YJzPMZ6WGoMzMVZ6EtueCSvOvgmNpVFgkwbtabfBuaBOvN+irtg4RRSWvJQTDTziLABieocEEXZImQ==
turbo-windows-64@1.8.2:
version "1.8.2"
resolved "https://registry.yarnpkg.com/turbo-windows-64/-/turbo-windows-64-1.8.2.tgz#a57b902cdccdb69d1efa18772bee9e277e079583"
integrity sha512-/+R5ikRrw2w2w38JtNPubGLIQHgUC70m783DI9aPgaM5c8P5D/Y0k6HgjuC/uXgiaz2h3R7p7YWlr+2/E0bqyA==
turbo-windows-arm64@1.8.2:
version "1.8.2"
resolved "https://registry.yarnpkg.com/turbo-windows-arm64/-/turbo-windows-arm64-1.8.2.tgz#0f976a2c6b8a46447fc277d5a9f7d8615792bdde"
integrity sha512-s07viz5nXSx4kyiksuPM4FGLRkoaGMaw0BpwFjdRQsl1p+WclUN1IPdokVPKOmFpu5pNCVYlG/raP/mXAEzDCg==
turbo@1.8.2:
version "1.8.2"
resolved "https://registry.yarnpkg.com/turbo/-/turbo-1.8.2.tgz#869e674a524cde4f449ae4458f4651818e2ffe00"
integrity sha512-G/uJx6bZK5RwTWHsRN/MP0MvXFznmCaL3MQXdSf+OG/q0o8GE7+yivyyWEplWI1Asc8AEN909A/wlIkoz2FKTg==
optionalDependencies:
turbo-darwin-64 "1.8.2"
turbo-darwin-arm64 "1.8.2"
turbo-linux-64 "1.8.2"
turbo-linux-arm64 "1.8.2"
turbo-windows-64 "1.8.2"
turbo-windows-arm64 "1.8.2"

View File

@@ -0,0 +1,8 @@
const path = require('path');
const { deployAndTest } = require('../../utils');
describe(`${__dirname.split(path.sep).pop()}`, () => {
it('should deploy and pass probe checks', async () => {
await deployAndTest(__dirname);
});
});

View File

@@ -0,0 +1,3 @@
export function register() {
globalThis.isOdd = require('is-odd');
}

View File

@@ -0,0 +1,5 @@
module.exports = {
experimental: {
instrumentationHook: true,
},
};

View File

@@ -0,0 +1,16 @@
{
"name": "instrumentation-hook",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
},
"dependencies": {
"next": "canary",
"react": "latest",
"react-dom": "latest",
"is-odd": "3.0.1"
}
}

View File

@@ -0,0 +1,5 @@
export default async (req, res) => {
res.status(200).json({
payload: `isOdd: ${globalThis.isOdd(3)}`,
});
};

View File

@@ -0,0 +1,11 @@
export default function Home(props) {
return `isOdd: ${props.isOdd}`;
}
export async function getServerSideProps() {
return {
props: {
isOdd: globalThis.isOdd(2),
},
};
}

View File

@@ -0,0 +1,14 @@
{
"probes": [
{
"path": "/",
"status": 200,
"mustContain": "isOdd: false"
},
{
"path": "/api/hello",
"status": 200,
"mustContain": "isOdd: true"
}
]
}

View File

@@ -26,7 +26,7 @@ if (parseInt(process.versions.node.split('.')[0], 10) >= 16) {
} }
} }
expect(lambdas.size).toBe(1); expect(lambdas.size).toBe(2);
expect(buildResult.output['dashboard']).toBeDefined(); expect(buildResult.output['dashboard']).toBeDefined();
expect(buildResult.output['dashboard/another']).toBeDefined(); expect(buildResult.output['dashboard/another']).toBeDefined();
expect(buildResult.output['dashboard/changelog']).toBeDefined(); expect(buildResult.output['dashboard/changelog']).toBeDefined();

View File

@@ -71,8 +71,11 @@ export const createLoggerServer = async (): Promise<LoggerServer> => {
process.env.NEXT_TELEMETRY_DISABLED = '1'; process.env.NEXT_TELEMETRY_DISABLED = '1';
export async function deployAndTest(fixtureDir) { export async function deployAndTest(fixtureDir, opts) {
const { deploymentId, deploymentUrl } = await testDeployment(fixtureDir); const { deploymentId, deploymentUrl } = await testDeployment(
fixtureDir,
opts
);
return { return {
deploymentId, deploymentId,

View File

@@ -435,7 +435,13 @@ function getStreamResponseCallback({ url, socket, cipher, resolve, reject }) {
headers += `x-vercel-status-code: ${response.statusCode || 200}${CRLF}`; headers += `x-vercel-status-code: ${response.statusCode || 200}${CRLF}`;
for (const [name, value] of getHeadersIterator(response.headers)) { for (const [name, value] of getHeadersIterator(response.headers)) {
if (!['connection', 'transfer-encoding'].includes(name)) { if (!['connection', 'transfer-encoding'].includes(name)) {
if (typeof value === 'string') {
headers += `x-vercel-header-${name}: ${value}${CRLF}`; headers += `x-vercel-header-${name}: ${value}${CRLF}`;
} else {
for (const val of value) {
headers += `x-vercel-header-${name}: ${val}${CRLF}`;
}
}
} }
} }

View File

@@ -1,6 +1,6 @@
{ {
"name": "@vercel/node-bridge", "name": "@vercel/node-bridge",
"version": "3.1.11", "version": "3.1.13",
"license": "MIT", "license": "MIT",
"main": "./index.js", "main": "./index.js",
"repository": { "repository": {

View File

@@ -1,6 +1,6 @@
{ {
"name": "@vercel/node", "name": "@vercel/node",
"version": "2.9.7", "version": "2.9.9",
"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",
@@ -31,8 +31,8 @@
"dependencies": { "dependencies": {
"@edge-runtime/vm": "2.0.0", "@edge-runtime/vm": "2.0.0",
"@types/node": "14.18.33", "@types/node": "14.18.33",
"@vercel/build-utils": "6.3.1", "@vercel/build-utils": "6.3.2",
"@vercel/node-bridge": "3.1.11", "@vercel/node-bridge": "3.1.13",
"@vercel/static-config": "2.0.13", "@vercel/static-config": "2.0.13",
"edge-runtime": "2.0.0", "edge-runtime": "2.0.0",
"esbuild": "0.14.47", "esbuild": "0.14.47",

View File

@@ -1,22 +1,29 @@
import { forkDevServer, readMessage } from '../src/fork-dev-server'; import { forkDevServer, readMessage } from '../src/fork-dev-server';
import { resolve } from 'path'; import { resolve, extname } from 'path';
import fetch from 'node-fetch'; import fetch from 'node-fetch';
jest.setTimeout(10 * 1000); jest.setTimeout(10 * 1000);
test('runs a mjs endpoint', async () => { function testForkDevServer(entrypoint: string) {
const child = forkDevServer({ const ext = extname(entrypoint);
const isTypeScript = ext === '.ts';
const isEsm = ext === '.mjs';
return forkDevServer({
maybeTranspile: true, maybeTranspile: true,
config: {}, config: {},
isEsm: true, isEsm,
isTypeScript: false, isTypeScript,
meta: {}, meta: {},
require_: require, require_: require,
tsConfig: undefined, tsConfig: undefined,
workPath: resolve(__dirname, './dev-fixtures'), workPath: resolve(__dirname, './dev-fixtures'),
entrypoint: './esm-module.mjs', entrypoint,
devServerPath: resolve(__dirname, '../dist/dev-server.js'), devServerPath: resolve(__dirname, '../dist/dev-server.js'),
}); });
}
test('runs a mjs endpoint', async () => {
const child = testForkDevServer('./esm-module.mjs');
try { try {
const result = await readMessage(child); const result = await readMessage(child);
@@ -44,18 +51,7 @@ test('runs a mjs endpoint', async () => {
}); });
test('runs a esm typescript endpoint', async () => { test('runs a esm typescript endpoint', async () => {
const child = forkDevServer({ const child = testForkDevServer('./esm-module.ts');
maybeTranspile: true,
config: {},
isEsm: true,
isTypeScript: true,
meta: {},
require_: require,
tsConfig: undefined,
workPath: resolve(__dirname, './dev-fixtures'),
entrypoint: './esm-module.ts',
devServerPath: resolve(__dirname, '../dist/dev-server.js'),
});
try { try {
const result = await readMessage(child); const result = await readMessage(child);

View File

@@ -1,6 +1,6 @@
{ {
"name": "@vercel/python", "name": "@vercel/python",
"version": "3.1.50", "version": "3.1.51",
"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",
@@ -23,7 +23,7 @@
"@types/execa": "^0.9.0", "@types/execa": "^0.9.0",
"@types/jest": "27.4.1", "@types/jest": "27.4.1",
"@types/node": "14.18.33", "@types/node": "14.18.33",
"@vercel/build-utils": "6.3.1", "@vercel/build-utils": "6.3.2",
"@vercel/ncc": "0.24.0", "@vercel/ncc": "0.24.0",
"execa": "^1.0.0", "execa": "^1.0.0",
"typescript": "4.3.4" "typescript": "4.3.4"

View File

@@ -17,7 +17,7 @@
{ {
"path": "/cookie_wsgi.py", "path": "/cookie_wsgi.py",
"responseHeaders": { "responseHeaders": {
"set-cookie": ["one=first", "two=second"] "set-cookie": ["one=first; Path=/", "two=second; Path=/"]
} }
} }
] ]

View File

@@ -1,6 +1,6 @@
{ {
"name": "@vercel/redwood", "name": "@vercel/redwood",
"version": "1.1.6", "version": "1.1.7",
"main": "./dist/index.js", "main": "./dist/index.js",
"license": "MIT", "license": "MIT",
"homepage": "https://vercel.com/docs", "homepage": "https://vercel.com/docs",
@@ -20,14 +20,14 @@
}, },
"dependencies": { "dependencies": {
"@vercel/nft": "0.22.5", "@vercel/nft": "0.22.5",
"@vercel/routing-utils": "2.1.9", "@vercel/routing-utils": "2.1.10",
"semver": "6.1.1" "semver": "6.1.1"
}, },
"devDependencies": { "devDependencies": {
"@types/aws-lambda": "8.10.19", "@types/aws-lambda": "8.10.19",
"@types/node": "14.18.33", "@types/node": "14.18.33",
"@types/semver": "6.0.0", "@types/semver": "6.0.0",
"@vercel/build-utils": "6.3.1", "@vercel/build-utils": "6.3.2",
"execa": "3.2.0", "execa": "3.2.0",
"fs-extra": "11.1.0", "fs-extra": "11.1.0",
"typescript": "4.3.4" "typescript": "4.3.4"

View File

@@ -1,6 +1,6 @@
{ {
"name": "@vercel/remix", "name": "@vercel/remix",
"version": "1.4.0", "version": "1.4.2",
"license": "MIT", "license": "MIT",
"main": "./dist/index.js", "main": "./dist/index.js",
"homepage": "https://vercel.com/docs", "homepage": "https://vercel.com/docs",
@@ -18,10 +18,11 @@
"files": [ "files": [
"dist", "dist",
"server-node.mjs", "server-node.mjs",
"server-edge.mjs" "server-edge.mjs",
"vercel-edge-entrypoint.js"
], ],
"dependencies": { "dependencies": {
"@remix-run/dev": "1.12.0", "@remix-run/dev": "1.13.0",
"@vercel/nft": "0.22.5", "@vercel/nft": "0.22.5",
"@vercel/static-config": "2.0.13", "@vercel/static-config": "2.0.13",
"path-to-regexp": "6.2.1", "path-to-regexp": "6.2.1",
@@ -30,7 +31,7 @@
"devDependencies": { "devDependencies": {
"@types/jest": "27.5.1", "@types/jest": "27.5.1",
"@types/node": "14.18.33", "@types/node": "14.18.33",
"@vercel/build-utils": "6.3.1", "@vercel/build-utils": "6.3.2",
"typescript": "4.9.4" "typescript": "4.9.4"
} }
} }

View File

@@ -54,11 +54,13 @@ function createRemixRequest(req, res) {
} }
async function sendRemixResponse(res, nodeResponse) { async function sendRemixResponse(res, nodeResponse) {
res.statusCode = nodeResponse.status;
res.statusMessage = nodeResponse.statusText; res.statusMessage = nodeResponse.statusText;
for (const [name, value] of nodeResponse.headers.entries()) { let multiValueHeaders = nodeResponse.headers.raw();
res.setHeader(name, value); res.writeHead(
} nodeResponse.status,
nodeResponse.statusText,
multiValueHeaders
);
if (nodeResponse.body) { if (nodeResponse.body) {
await writeReadableStreamToWritable(nodeResponse.body, res); await writeReadableStreamToWritable(nodeResponse.body, res);

View File

@@ -5,6 +5,7 @@ import {
debug, debug,
download, download,
execCommand, execCommand,
FileBlob,
FileFsRef, FileFsRef,
getEnvForPackageManager, getEnvForPackageManager,
getNodeVersion, getNodeVersion,
@@ -28,6 +29,7 @@ import type {
PackageJson, PackageJson,
BuildResultV2Typical, BuildResultV2Typical,
} from '@vercel/build-utils'; } from '@vercel/build-utils';
import type { RemixConfig } from '@remix-run/dev/dist/config';
import type { ConfigRoute } from '@remix-run/dev/dist/config/routes'; import type { ConfigRoute } from '@remix-run/dev/dist/config/routes';
import { import {
findConfig, findConfig,
@@ -94,8 +96,8 @@ export const build: BuildV2 = async ({
// Make `remix build` output production mode // Make `remix build` output production mode
spawnOpts.env.NODE_ENV = 'production'; spawnOpts.env.NODE_ENV = 'production';
let remixConfig = await readConfig(entrypointFsDirname); const remixConfig = await chdirAndReadConfig(entrypointFsDirname);
const { serverEntryPoint } = remixConfig; const remixRoutes = Object.values(remixConfig.routes);
// We need to patch the `remix.config.js` file to force some values necessary // We need to patch the `remix.config.js` file to force some values necessary
// for a build that works on either Node.js or the Edge runtime // for a build that works on either Node.js or the Edge runtime
@@ -103,6 +105,7 @@ export const build: BuildV2 = async ({
const renamedRemixConfigPath = remixConfigPath const renamedRemixConfigPath = remixConfigPath
? `${remixConfigPath}.original${extname(remixConfigPath)}` ? `${remixConfigPath}.original${extname(remixConfigPath)}`
: undefined; : undefined;
const serverBuildPath = 'build/index.js';
if (remixConfigPath && renamedRemixConfigPath) { if (remixConfigPath && renamedRemixConfigPath) {
await fs.rename(remixConfigPath, renamedRemixConfigPath); await fs.rename(remixConfigPath, renamedRemixConfigPath);
@@ -122,7 +125,7 @@ export const build: BuildV2 = async ({
config.serverBuildTarget = undefined; config.serverBuildTarget = undefined;
config.serverModuleFormat = 'cjs'; config.serverModuleFormat = 'cjs';
config.serverPlatform = 'node'; config.serverPlatform = 'node';
config.serverBuildPath = 'build/index.js'; config.serverBuildPath = ${JSON.stringify(serverBuildPath)}
export default config;`; export default config;`;
} else { } else {
patchedConfig = `const config = require('./${basename( patchedConfig = `const config = require('./${basename(
@@ -131,7 +134,7 @@ export default config;`;
config.serverBuildTarget = undefined; config.serverBuildTarget = undefined;
config.serverModuleFormat = 'cjs'; config.serverModuleFormat = 'cjs';
config.serverPlatform = 'node'; config.serverPlatform = 'node';
config.serverBuildPath = 'build/index.js'; config.serverBuildPath = ${JSON.stringify(serverBuildPath)}
module.exports = config;`; module.exports = config;`;
} }
await fs.writeFile(remixConfigPath, patchedConfig); await fs.writeFile(remixConfigPath, patchedConfig);
@@ -166,7 +169,6 @@ module.exports = config;`;
}); });
} }
} }
remixConfig = await readConfig(entrypointFsDirname);
} finally { } finally {
// Clean up our patched `remix.config.js` to be polite // Clean up our patched `remix.config.js` to be polite
if (remixConfigPath && renamedRemixConfigPath) { if (remixConfigPath && renamedRemixConfigPath) {
@@ -174,9 +176,6 @@ module.exports = config;`;
} }
} }
const { serverBuildPath } = remixConfig;
const remixRoutes = Object.values(remixConfig.routes);
// Figure out which pages should be edge functions // Figure out which pages should be edge functions
let hasEdgeRoute = false; let hasEdgeRoute = false;
const staticConfigsMap = new Map<ConfigRoute, BaseFunctionConfig>(); const staticConfigsMap = new Map<ConfigRoute, BaseFunctionConfig>();
@@ -207,16 +206,16 @@ module.exports = config;`;
createRenderNodeFunction( createRenderNodeFunction(
entrypointFsDirname, entrypointFsDirname,
repoRootPath, repoRootPath,
serverBuildPath, join(entrypointFsDirname, serverBuildPath),
serverEntryPoint, remixConfig.serverEntryPoint,
nodeVersion nodeVersion
), ),
hasEdgeRoute hasEdgeRoute
? createRenderEdgeFunction( ? createRenderEdgeFunction(
entrypointFsDirname, entrypointFsDirname,
repoRootPath, repoRootPath,
serverBuildPath, join(entrypointFsDirname, serverBuildPath),
serverEntryPoint remixConfig.serverEntryPoint
) )
: undefined, : undefined,
]); ]);
@@ -239,6 +238,12 @@ module.exports = config;`;
const path = getPathFromRoute(route, remixConfig.routes); const path = getPathFromRoute(route, remixConfig.routes);
// If the route is a pathless layout route (at the root level)
// and doesn't have any sub-routes, then a function should not be created.
if (!path) {
continue;
}
let isEdge = false; let isEdge = false;
for (const currentRoute of getRouteIterator(route, remixConfig.routes)) { for (const currentRoute of getRouteIterator(route, remixConfig.routes)) {
const staticConfig = staticConfigsMap.get(currentRoute); const staticConfig = staticConfigsMap.get(currentRoute);
@@ -357,6 +362,8 @@ async function createRenderEdgeFunction(
await fs.copyFile(sourceHandlerPath, handlerPath); await fs.copyFile(sourceHandlerPath, handlerPath);
} }
let remixRunVercelPkgJson: string | undefined;
// Trace the handler with `@vercel/nft` // Trace the handler with `@vercel/nft`
const trace = await nodeFileTrace([handlerPath], { const trace = await nodeFileTrace([handlerPath], {
base: rootDir, base: rootDir,
@@ -375,6 +382,35 @@ async function createRenderEdgeFunction(
if (basename(fsPath) === 'package.json') { if (basename(fsPath) === 'package.json') {
// For Edge Functions, patch "main" field to prefer "browser" or "module" // For Edge Functions, patch "main" field to prefer "browser" or "module"
const pkgJson = JSON.parse(source.toString()); const pkgJson = JSON.parse(source.toString());
// When `@remix-run/vercel` is detected, we need to modify the `package.json`
// to include the "browser" field so that the proper Edge entrypoint file
// is used. This is a temporary stop gap until this PR is merged:
// https://github.com/remix-run/remix/pull/5537
if (pkgJson.name === '@remix-run/vercel') {
pkgJson.browser = 'dist/edge.js';
pkgJson.dependencies['@remix-run/server-runtime'] =
pkgJson.dependencies['@remix-run/node'];
if (!remixRunVercelPkgJson) {
remixRunVercelPkgJson = JSON.stringify(pkgJson, null, 2) + '\n';
// Copy in the edge entrypoint so that NFT can properly resolve it
const vercelEdgeEntrypointPath = join(
__dirname,
'../vercel-edge-entrypoint.js'
);
const vercelEdgeEntrypointDest = join(
dirname(fsPath),
'dist/edge.js'
);
await fs.copyFile(
vercelEdgeEntrypointPath,
vercelEdgeEntrypointDest
);
}
}
for (const prop of ['browser', 'module']) { for (const prop of ['browser', 'module']) {
const val = pkgJson[prop]; const val = pkgJson[prop];
if (typeof val === 'string') { if (typeof val === 'string') {
@@ -395,8 +431,16 @@ async function createRenderEdgeFunction(
} }
for (const file of trace.fileList) { for (const file of trace.fileList) {
if (
remixRunVercelPkgJson &&
file.endsWith(`@remix-run${sep}vercel${sep}package.json`)
) {
// Use the modified `@remix-run/vercel` package.json which contains "browser" field
files[file] = new FileBlob({ data: remixRunVercelPkgJson });
} else {
files[file] = await FileFsRef.fromFsPath({ fsPath: join(rootDir, file) }); files[file] = await FileFsRef.fromFsPath({ fsPath: join(rootDir, file) });
} }
}
const fn = new EdgeFunction({ const fn = new EdgeFunction({
files, files,
@@ -482,3 +526,15 @@ async function ensureResolvable(start: string, base: string, pkgName: string) {
function isEdgeRuntime(runtime: string): boolean { function isEdgeRuntime(runtime: string): boolean {
return runtime === 'edge' || runtime === 'experimental-edge'; return runtime === 'edge' || runtime === 'experimental-edge';
} }
async function chdirAndReadConfig(dir: string) {
const originalCwd = process.cwd();
let remixConfig: RemixConfig;
try {
process.chdir(dir);
remixConfig = await readConfig(dir);
} finally {
process.chdir(originalCwd);
}
return remixConfig;
}

View File

@@ -41,9 +41,12 @@ export function getPathFromRoute(
route: ConfigRoute, route: ConfigRoute,
routes: RouteManifest routes: RouteManifest
): string { ): string {
if (route.id === 'root' || (route.parentId === 'root' && route.index)) {
return 'index';
}
const pathParts: string[] = []; const pathParts: string[] = [];
for (const currentRoute of getRouteIterator(route, routes)) { for (const currentRoute of getRouteIterator(route, routes)) {
if (currentRoute.index) pathParts.push('index');
if (currentRoute.path) pathParts.push(currentRoute.path); if (currentRoute.path) pathParts.push(currentRoute.path);
} }
const path = pathParts.reverse().join('/'); const path = pathParts.reverse().join('/');

View File

@@ -0,0 +1,4 @@
// This is a pathless layout route at the root level,
// but there are no child routes, so a function should
// not be created for this route.
export default () => <div>pathless layout route</div>;

View File

@@ -1,6 +1,4 @@
export const config = { export const config = { runtime: 'edge' };
runtime: 'edge'
};
export default function Edge() { export default function Edge() {
return ( return (

View File

@@ -0,0 +1,3 @@
// This is a pathless layout route without any child routes,
// but Remix will serve this since its not at the root level.
export default () => <div>nested2 pathless layout route</div>;

View File

@@ -0,0 +1,10 @@
import type { LoaderFunction } from '@remix-run/server-runtime';
export const config = { runtime: 'edge' };
export const loader: LoaderFunction = () => {
const headers = new Headers();
headers.append('Set-Cookie', 'hello=world');
headers.append('Set-Cookie', 'foo=bar');
return new Response(null, { headers });
};

View File

@@ -0,0 +1,8 @@
import type { LoaderFunction } from '@remix-run/server-runtime';
export const loader: LoaderFunction = () => {
const headers = new Headers();
headers.append('Set-Cookie', 'hello=world');
headers.append('Set-Cookie', 'foo=bar');
return new Response(null, { headers });
};

View File

@@ -15,10 +15,38 @@
{ "path": "/b", "mustContain": "B page" }, { "path": "/b", "mustContain": "B page" },
{ "path": "/nested", "mustContain": "Nested index page" }, { "path": "/nested", "mustContain": "Nested index page" },
{ "path": "/nested/another", "mustContain": "Nested another page" }, { "path": "/nested/another", "mustContain": "Nested another page" },
{ "path": "/nested/index", "mustContain": "Not Found" }, { "path": "/nested/index", "status": 404, "mustContain": "Not Found" },
{ "path": "/asdf", "mustContain": "Not Found" }, { "path": "/asdf", "status": 404, "mustContain": "Not Found" },
{ "path": "/instanceof", "mustContain": "InstanceOfRequest: true" }, { "path": "/instanceof", "mustContain": "InstanceOfRequest: true" },
{ "path": "/projects/edge", "mustContain": "\"isEdge\":true" }, { "path": "/projects/edge", "mustContain": "\"isEdge\":true" },
{ "path": "/projects/node", "mustContain": "\"isEdge\":false" } { "path": "/projects/node", "mustContain": "\"isEdge\":false" },
{
"path": "/__pathless",
"status": 404,
"mustContain": "Not Found"
},
{
"path": "/nested2",
"mustContain": "nested2 pathless layout route"
},
{
"path": "/nested2/__pathless",
"status": 404,
"mustContain": "Not Found"
},
{
"path": "/set-cookie-edge",
"status": 200,
"responseHeaders": {
"set-cookie": ["hello=world", "foo=bar"]
}
},
{
"path": "/set-cookie-node",
"status": 200,
"responseHeaders": {
"set-cookie": ["hello=world", "foo=bar"]
}
}
] ]
} }

View File

@@ -0,0 +1,9 @@
export const config = { runtime: 'edge' };
export default function Edge() {
return (
<div style={{ fontFamily: 'system-ui, sans-serif', lineHeight: '1.4' }}>
<h1>Welcome to Remix@Edge</h1>
</div>
);
}

View File

@@ -1,4 +1,4 @@
import { json, LoaderFunction } from "@remix-run/node"; import { json, LoaderFunction } from "@remix-run/server-runtime";
export const loader: LoaderFunction = ({ context }) => { export const loader: LoaderFunction = ({ context }) => {
return json(context); return json(context);

View File

@@ -3,6 +3,7 @@
*/ */
export default { export default {
ignoredRouteFiles: ["**/.*"], ignoredRouteFiles: ["**/.*"],
serverBuildTarget: "vercel",
// When running locally in development mode, we use the built-in remix // When running locally in development mode, we use the built-in remix
// server. This does not understand the vercel lambda module format, // server. This does not understand the vercel lambda module format,
// so we default back to the standard build output. // so we default back to the standard build output.

View File

@@ -11,6 +11,7 @@
], ],
"probes": [ "probes": [
{ "path": "/", "mustContain": "Welcome to Remix" }, { "path": "/", "mustContain": "Welcome to Remix" },
{ "path": "/edge", "mustContain": "Welcome to Remix@Edge" },
{ "path": "/load-context", "mustContain": "{\"nodeLoadContext\":true}" } { "path": "/load-context", "mustContain": "{\"nodeLoadContext\":true}" }
] ]
} }

View File

@@ -5,7 +5,7 @@
"src": "package.json", "src": "package.json",
"use": "@vercel/remix", "use": "@vercel/remix",
"config": { "config": {
"installCommand": "env | sort && npm install --install-strategy=linked", "installCommand": "npm install --install-strategy=linked",
"zeroConfig": true "zeroConfig": true
} }
} }

View File

@@ -4,6 +4,12 @@ import type { RouteManifest } from '@remix-run/dev/dist/config/routes';
describe('getPathFromRoute()', () => { describe('getPathFromRoute()', () => {
const routes: RouteManifest = { const routes: RouteManifest = {
root: { path: '', id: 'root', file: 'root.tsx' }, root: { path: '', id: 'root', file: 'root.tsx' },
'routes/__pathless': {
path: undefined,
id: 'routes/__pathless',
parentId: 'root',
file: 'routes/__pathless.tsx',
},
'routes/$foo.$bar.$baz': { 'routes/$foo.$bar.$baz': {
path: ':foo/:bar/:baz', path: ':foo/:bar/:baz',
id: 'routes/$foo.$bar.$baz', id: 'routes/$foo.$bar.$baz',
@@ -22,12 +28,24 @@ describe('getPathFromRoute()', () => {
parentId: 'root', parentId: 'root',
file: 'routes/projects.tsx', file: 'routes/projects.tsx',
}, },
'routes/projects/__pathless': {
path: undefined,
id: 'routes/projects/__pathless',
parentId: 'routes/projects',
file: 'routes/projects/__pathless.tsx',
},
'routes/projects/index': { 'routes/projects/index': {
path: undefined, path: undefined,
index: true, index: true,
id: 'routes/projects/indexx', id: 'routes/projects/index',
parentId: 'routes/projects', parentId: 'routes/projects',
file: 'routes/projects/indexx.tsx', file: 'routes/projects/index.tsx',
},
'routes/projects/create': {
path: 'create',
id: 'routes/projects/create',
parentId: 'routes/projects',
file: 'routes/projects/create.tsx',
}, },
'routes/projects/$': { 'routes/projects/$': {
path: '*', path: '*',
@@ -57,11 +75,14 @@ describe('getPathFromRoute()', () => {
}; };
it.each([ it.each([
{ id: 'root', expected: '' }, { id: 'root', expected: 'index' },
{ id: 'routes/__pathless', expected: '' },
{ id: 'routes/index', expected: 'index' }, { id: 'routes/index', expected: 'index' },
{ id: 'routes/api.hello', expected: 'api/hello' }, { id: 'routes/api.hello', expected: 'api/hello' },
{ id: 'routes/projects', expected: 'projects' }, { id: 'routes/projects', expected: 'projects' },
{ id: 'routes/projects/index', expected: 'projects/index' }, { id: 'routes/projects/__pathless', expected: 'projects' },
{ id: 'routes/projects/index', expected: 'projects' },
{ id: 'routes/projects/create', expected: 'projects/create' },
{ id: 'routes/projects/$', expected: 'projects/*' }, { id: 'routes/projects/$', expected: 'projects/*' },
{ id: 'routes/$foo.$bar.$baz', expected: ':foo/:bar/:baz' }, { id: 'routes/$foo.$bar.$baz', expected: ':foo/:bar/:baz' },
{ id: 'routes/node', expected: 'node' }, { id: 'routes/node', expected: 'node' },

View File

@@ -0,0 +1,21 @@
/**
* Edge runtime entrypoint for `@remix-run/vercel`.
*/
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var serverRuntime = require('@remix-run/server-runtime');
/**
* Returns a request handler for the Vercel Edge runtime that serves
* the Remix SSR response.
*/
function createRequestHandler({ build, mode }) {
let handleRequest = serverRuntime.createRequestHandler(build, mode);
return request => {
return handleRequest(request);
};
}
exports.createRequestHandler = createRequestHandler;

View File

@@ -1,6 +1,6 @@
{ {
"name": "@vercel/routing-utils", "name": "@vercel/routing-utils",
"version": "2.1.9", "version": "2.1.10",
"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",

View File

@@ -155,6 +155,12 @@ export const routesSchema = {
}, },
middleware: { type: 'number' }, middleware: { type: 'number' },
middlewarePath: { type: 'string' }, middlewarePath: { type: 'string' },
middlewareRawSrc: {
type: 'array',
items: {
type: 'string',
},
},
has: hasSchema, has: hasSchema,
missing: hasSchema, missing: hasSchema,
}, },

View File

@@ -1,7 +1,7 @@
{ {
"name": "@vercel/ruby", "name": "@vercel/ruby",
"author": "Nathan Cahill <nathan@nathancahill.com>", "author": "Nathan Cahill <nathan@nathancahill.com>",
"version": "1.3.67", "version": "1.3.68",
"license": "MIT", "license": "MIT",
"main": "./dist/index", "main": "./dist/index",
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/ruby", "homepage": "https://vercel.com/docs/runtimes#official-runtimes/ruby",
@@ -22,7 +22,7 @@
"devDependencies": { "devDependencies": {
"@types/fs-extra": "8.0.0", "@types/fs-extra": "8.0.0",
"@types/semver": "6.0.0", "@types/semver": "6.0.0",
"@vercel/build-utils": "6.3.1", "@vercel/build-utils": "6.3.2",
"@vercel/ncc": "0.24.0", "@vercel/ncc": "0.24.0",
"execa": "2.0.4", "execa": "2.0.4",
"fs-extra": "^7.0.1", "fs-extra": "^7.0.1",

View File

@@ -1,6 +1,6 @@
{ {
"name": "@vercel/static-build", "name": "@vercel/static-build",
"version": "1.3.11", "version": "1.3.13",
"license": "MIT", "license": "MIT",
"main": "./dist/index", "main": "./dist/index",
"homepage": "https://vercel.com/docs/build-step", "homepage": "https://vercel.com/docs/build-step",
@@ -30,7 +30,7 @@
}, },
"dependencies": { "dependencies": {
"@vercel/gatsby-plugin-vercel-analytics": "1.0.7", "@vercel/gatsby-plugin-vercel-analytics": "1.0.7",
"@vercel/gatsby-plugin-vercel-builder": "1.1.8" "@vercel/gatsby-plugin-vercel-builder": "1.1.10"
}, },
"devDependencies": { "devDependencies": {
"@types/aws-lambda": "8.10.64", "@types/aws-lambda": "8.10.64",
@@ -42,11 +42,11 @@
"@types/node-fetch": "2.5.4", "@types/node-fetch": "2.5.4",
"@types/promise-timeout": "1.3.0", "@types/promise-timeout": "1.3.0",
"@types/semver": "7.3.13", "@types/semver": "7.3.13",
"@vercel/build-utils": "6.3.1", "@vercel/build-utils": "6.3.2",
"@vercel/frameworks": "1.3.1", "@vercel/frameworks": "1.3.2",
"@vercel/fs-detectors": "3.8.1", "@vercel/fs-detectors": "3.8.2",
"@vercel/ncc": "0.24.0", "@vercel/ncc": "0.24.0",
"@vercel/routing-utils": "2.1.9", "@vercel/routing-utils": "2.1.10",
"@vercel/static-config": "2.0.13", "@vercel/static-config": "2.0.13",
"execa": "3.2.0", "execa": "3.2.0",
"fs-extra": "10.0.0", "fs-extra": "10.0.0",

144
pnpm-lock.yaml generated
View File

@@ -204,23 +204,23 @@ importers:
'@types/which': 1.3.2 '@types/which': 1.3.2
'@types/write-json-file': 2.2.1 '@types/write-json-file': 2.2.1
'@types/yauzl-promise': 2.1.0 '@types/yauzl-promise': 2.1.0
'@vercel/build-utils': 6.3.1 '@vercel/build-utils': 6.3.2
'@vercel/client': 12.4.1 '@vercel/client': 12.4.2
'@vercel/error-utils': 1.0.8 '@vercel/error-utils': 1.0.8
'@vercel/frameworks': 1.3.1 '@vercel/frameworks': 1.3.2
'@vercel/fs-detectors': 3.8.1 '@vercel/fs-detectors': 3.8.2
'@vercel/fun': 1.0.4 '@vercel/fun': 1.0.4
'@vercel/go': 2.3.8 '@vercel/go': 2.3.9
'@vercel/hydrogen': 0.0.54 '@vercel/hydrogen': 0.0.55
'@vercel/ncc': 0.24.0 '@vercel/ncc': 0.24.0
'@vercel/next': 3.6.0 '@vercel/next': 3.6.2
'@vercel/node': 2.9.7 '@vercel/node': 2.9.9
'@vercel/python': 3.1.50 '@vercel/python': 3.1.51
'@vercel/redwood': 1.1.6 '@vercel/redwood': 1.1.7
'@vercel/remix': 1.4.0 '@vercel/remix': 1.4.2
'@vercel/routing-utils': 2.1.9 '@vercel/routing-utils': 2.1.10
'@vercel/ruby': 1.3.67 '@vercel/ruby': 1.3.68
'@vercel/static-build': 1.3.11 '@vercel/static-build': 1.3.13
'@zeit/source-map-support': 0.6.2 '@zeit/source-map-support': 0.6.2
ajv: 6.12.2 ajv: 6.12.2
alpha-sort: 2.0.1 alpha-sort: 2.0.1
@@ -444,8 +444,8 @@ importers:
'@types/node-fetch': 2.5.4 '@types/node-fetch': 2.5.4
'@types/recursive-readdir': 2.2.0 '@types/recursive-readdir': 2.2.0
'@types/tar-fs': 1.16.1 '@types/tar-fs': 1.16.1
'@vercel/build-utils': 6.3.1 '@vercel/build-utils': 6.3.2
'@vercel/routing-utils': 2.1.9 '@vercel/routing-utils': 2.1.10
'@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
@@ -525,7 +525,7 @@ importers:
'@types/js-yaml': 3.12.1 '@types/js-yaml': 3.12.1
'@types/node': 14.18.33 '@types/node': 14.18.33
'@types/node-fetch': 2.5.8 '@types/node-fetch': 2.5.8
'@vercel/routing-utils': 2.1.9 '@vercel/routing-utils': 2.1.10
ajv: 6.12.2 ajv: 6.12.2
js-yaml: 3.13.1 js-yaml: 3.13.1
typescript: 4.3.4 typescript: 4.3.4
@@ -549,10 +549,10 @@ importers:
'@types/minimatch': 3.0.5 '@types/minimatch': 3.0.5
'@types/node': 14.18.33 '@types/node': 14.18.33
'@types/semver': 7.3.10 '@types/semver': 7.3.10
'@vercel/build-utils': 6.3.1 '@vercel/build-utils': 6.3.2
'@vercel/error-utils': 1.0.8 '@vercel/error-utils': 1.0.8
'@vercel/frameworks': 1.3.1 '@vercel/frameworks': 1.3.2
'@vercel/routing-utils': 2.1.9 '@vercel/routing-utils': 2.1.10
glob: 8.0.3 glob: 8.0.3
js-yaml: 4.1.0 js-yaml: 4.1.0
json5: 2.2.2 json5: 2.2.2
@@ -597,9 +597,9 @@ importers:
'@types/fs-extra': 11.0.1 '@types/fs-extra': 11.0.1
'@types/node': 14.18.33 '@types/node': 14.18.33
'@types/react': 18.0.26 '@types/react': 18.0.26
'@vercel/build-utils': 6.3.1 '@vercel/build-utils': 6.3.2
'@vercel/node': 2.9.7 '@vercel/node': 2.9.9
'@vercel/routing-utils': 2.1.9 '@vercel/routing-utils': 2.1.10
ajv: 8.12.0 ajv: 8.12.0
esbuild: 0.14.47 esbuild: 0.14.47
etag: 1.8.1 etag: 1.8.1
@@ -632,7 +632,7 @@ importers:
'@types/node': 14.18.33 '@types/node': 14.18.33
'@types/node-fetch': ^2.3.0 '@types/node-fetch': ^2.3.0
'@types/tar': ^4.0.0 '@types/tar': ^4.0.0
'@vercel/build-utils': 6.3.1 '@vercel/build-utils': 6.3.2
'@vercel/ncc': 0.24.0 '@vercel/ncc': 0.24.0
async-retry: 1.3.1 async-retry: 1.3.1
execa: ^1.0.0 execa: ^1.0.0
@@ -664,7 +664,7 @@ importers:
specifiers: specifiers:
'@types/jest': 27.5.1 '@types/jest': 27.5.1
'@types/node': 14.18.33 '@types/node': 14.18.33
'@vercel/build-utils': 6.3.1 '@vercel/build-utils': 6.3.2
'@vercel/static-config': 2.0.13 '@vercel/static-config': 2.0.13
execa: 3.2.0 execa: 3.2.0
fs-extra: 11.1.0 fs-extra: 11.1.0
@@ -695,9 +695,9 @@ importers:
'@types/semver': 6.0.0 '@types/semver': 6.0.0
'@types/text-table': 0.2.1 '@types/text-table': 0.2.1
'@types/webpack-sources': 3.2.0 '@types/webpack-sources': 3.2.0
'@vercel/build-utils': 6.3.1 '@vercel/build-utils': 6.3.2
'@vercel/nft': 0.22.5 '@vercel/nft': 0.22.5
'@vercel/routing-utils': 2.1.9 '@vercel/routing-utils': 2.1.10
async-sema: 3.0.1 async-sema: 3.0.1
buffer-crc32: 0.2.13 buffer-crc32: 0.2.13
bytes: 3.1.2 bytes: 3.1.2
@@ -774,10 +774,10 @@ importers:
'@types/node': 14.18.33 '@types/node': 14.18.33
'@types/node-fetch': ^2.6.1 '@types/node-fetch': ^2.6.1
'@types/test-listen': 1.1.0 '@types/test-listen': 1.1.0
'@vercel/build-utils': 6.3.1 '@vercel/build-utils': 6.3.2
'@vercel/ncc': 0.24.0 '@vercel/ncc': 0.24.0
'@vercel/nft': 0.22.5 '@vercel/nft': 0.22.5
'@vercel/node-bridge': 3.1.11 '@vercel/node-bridge': 3.1.13
'@vercel/static-config': 2.0.13 '@vercel/static-config': 2.0.13
content-type: 1.0.4 content-type: 1.0.4
cookie: 0.4.0 cookie: 0.4.0
@@ -858,7 +858,7 @@ importers:
'@types/execa': ^0.9.0 '@types/execa': ^0.9.0
'@types/jest': 27.4.1 '@types/jest': 27.4.1
'@types/node': 14.18.33 '@types/node': 14.18.33
'@vercel/build-utils': 6.3.1 '@vercel/build-utils': 6.3.2
'@vercel/ncc': 0.24.0 '@vercel/ncc': 0.24.0
execa: ^1.0.0 execa: ^1.0.0
typescript: 4.3.4 typescript: 4.3.4
@@ -876,9 +876,9 @@ importers:
'@types/aws-lambda': 8.10.19 '@types/aws-lambda': 8.10.19
'@types/node': 14.18.33 '@types/node': 14.18.33
'@types/semver': 6.0.0 '@types/semver': 6.0.0
'@vercel/build-utils': 6.3.1 '@vercel/build-utils': 6.3.2
'@vercel/nft': 0.22.5 '@vercel/nft': 0.22.5
'@vercel/routing-utils': 2.1.9 '@vercel/routing-utils': 2.1.10
execa: 3.2.0 execa: 3.2.0
fs-extra: 11.1.0 fs-extra: 11.1.0
semver: 6.1.1 semver: 6.1.1
@@ -898,17 +898,17 @@ importers:
packages/remix: packages/remix:
specifiers: specifiers:
'@remix-run/dev': 1.12.0 '@remix-run/dev': 1.13.0
'@types/jest': 27.5.1 '@types/jest': 27.5.1
'@types/node': 14.18.33 '@types/node': 14.18.33
'@vercel/build-utils': 6.3.1 '@vercel/build-utils': 6.3.2
'@vercel/nft': 0.22.5 '@vercel/nft': 0.22.5
'@vercel/static-config': 2.0.13 '@vercel/static-config': 2.0.13
path-to-regexp: 6.2.1 path-to-regexp: 6.2.1
ts-morph: 12.0.0 ts-morph: 12.0.0
typescript: 4.9.4 typescript: 4.9.4
dependencies: dependencies:
'@remix-run/dev': 1.12.0 '@remix-run/dev': 1.13.0
'@vercel/nft': 0.22.5 '@vercel/nft': 0.22.5
'@vercel/static-config': link:../static-config '@vercel/static-config': link:../static-config
path-to-regexp: 6.2.1 path-to-regexp: 6.2.1
@@ -958,7 +958,7 @@ importers:
specifiers: specifiers:
'@types/fs-extra': 8.0.0 '@types/fs-extra': 8.0.0
'@types/semver': 6.0.0 '@types/semver': 6.0.0
'@vercel/build-utils': 6.3.1 '@vercel/build-utils': 6.3.2
'@vercel/ncc': 0.24.0 '@vercel/ncc': 0.24.0
execa: 2.0.4 execa: 2.0.4
fs-extra: ^7.0.1 fs-extra: ^7.0.1
@@ -985,13 +985,13 @@ importers:
'@types/node-fetch': 2.5.4 '@types/node-fetch': 2.5.4
'@types/promise-timeout': 1.3.0 '@types/promise-timeout': 1.3.0
'@types/semver': 7.3.13 '@types/semver': 7.3.13
'@vercel/build-utils': 6.3.1 '@vercel/build-utils': 6.3.2
'@vercel/frameworks': 1.3.1 '@vercel/frameworks': 1.3.2
'@vercel/fs-detectors': 3.8.1 '@vercel/fs-detectors': 3.8.2
'@vercel/gatsby-plugin-vercel-analytics': 1.0.7 '@vercel/gatsby-plugin-vercel-analytics': 1.0.7
'@vercel/gatsby-plugin-vercel-builder': 1.1.8 '@vercel/gatsby-plugin-vercel-builder': 1.1.10
'@vercel/ncc': 0.24.0 '@vercel/ncc': 0.24.0
'@vercel/routing-utils': 2.1.9 '@vercel/routing-utils': 2.1.10
'@vercel/static-config': 2.0.13 '@vercel/static-config': 2.0.13
execa: 3.2.0 execa: 3.2.0
fs-extra: 10.0.0 fs-extra: 10.0.0
@@ -3888,7 +3888,7 @@ packages:
resolution: {integrity: sha512-TInJmbrsmYIwUyrRxytjO82KjJbRwm67F7LoZs1shAq6rMvNqi4NxSY9j+hT/939alFmEq1zssoy/caeLXHRfQ==} resolution: {integrity: sha512-TInJmbrsmYIwUyrRxytjO82KjJbRwm67F7LoZs1shAq6rMvNqi4NxSY9j+hT/939alFmEq1zssoy/caeLXHRfQ==}
engines: {node: ^14.15.0 || >=16.0.0} engines: {node: ^14.15.0 || >=16.0.0}
dependencies: dependencies:
node-fetch: 2.6.8 node-fetch: 2.6.7
npmlog: 6.0.2 npmlog: 6.0.2
transitivePeerDependencies: transitivePeerDependencies:
- encoding - encoding
@@ -4859,7 +4859,7 @@ packages:
'@octokit/request-error': 3.0.2 '@octokit/request-error': 3.0.2
'@octokit/types': 8.1.0 '@octokit/types': 8.1.0
is-plain-object: 5.0.0 is-plain-object: 5.0.0
node-fetch: 2.6.8 node-fetch: 2.6.7
universal-user-agent: 6.0.0 universal-user-agent: 6.0.0
transitivePeerDependencies: transitivePeerDependencies:
- encoding - encoding
@@ -5282,12 +5282,12 @@ packages:
webpack: 5.75.0_esbuild@0.14.47 webpack: 5.75.0_esbuild@0.14.47
dev: true dev: true
/@remix-run/dev/1.12.0: /@remix-run/dev/1.13.0:
resolution: {integrity: sha512-lBiA2FlDi+DjpOAE/vn93zFTSxudKag/FGpmbV6O+LQItDCpFARfbBMhTck/uKcc95nyhRd1GGhQ4ZDgQnyjaQ==} resolution: {integrity: sha512-hPqUjM9RRcz3inBOWqP3GKhggVz0a0ikWaRZpdKrhpQNCNiF6Hunbx876mJERj2YrmIzJ05eoeQmmdF6xcr4qg==}
engines: {node: '>=14'} engines: {node: '>=14'}
hasBin: true hasBin: true
peerDependencies: peerDependencies:
'@remix-run/serve': ^1.12.0 '@remix-run/serve': ^1.13.0
peerDependenciesMeta: peerDependenciesMeta:
'@remix-run/serve': '@remix-run/serve':
optional: true optional: true
@@ -5303,7 +5303,7 @@ packages:
'@babel/types': 7.20.7 '@babel/types': 7.20.7
'@esbuild-plugins/node-modules-polyfill': 0.1.4_esbuild@0.16.3 '@esbuild-plugins/node-modules-polyfill': 0.1.4_esbuild@0.16.3
'@npmcli/package-json': 2.0.0 '@npmcli/package-json': 2.0.0
'@remix-run/server-runtime': 1.12.0 '@remix-run/server-runtime': 1.13.0
'@vanilla-extract/integration': 6.0.3 '@vanilla-extract/integration': 6.0.3
arg: 5.0.2 arg: 5.0.2
cacache: 15.3.0 cacache: 15.3.0
@@ -5325,10 +5325,11 @@ packages:
lodash.debounce: 4.0.8 lodash.debounce: 4.0.8
lru-cache: 7.14.1 lru-cache: 7.14.1
minimatch: 3.1.2 minimatch: 3.1.2
node-fetch: 2.6.8 node-fetch: 2.6.7
ora: 5.4.1 ora: 5.4.1
postcss: 8.4.21 postcss: 8.4.21
postcss-discard-duplicates: 5.1.0_postcss@8.4.21 postcss-discard-duplicates: 5.1.0_postcss@8.4.21
postcss-load-config: 4.0.1_postcss@8.4.21
postcss-modules: 6.0.0_postcss@8.4.21 postcss-modules: 6.0.0_postcss@8.4.21
prettier: 2.7.1 prettier: 2.7.1
pretty-ms: 7.0.1 pretty-ms: 7.0.1
@@ -5347,6 +5348,7 @@ packages:
- bufferutil - bufferutil
- encoding - encoding
- supports-color - supports-color
- ts-node
- utf-8-validate - utf-8-validate
dev: false dev: false
@@ -5370,6 +5372,11 @@ packages:
engines: {node: '>=14'} engines: {node: '>=14'}
dev: false dev: false
/@remix-run/router/1.3.2:
resolution: {integrity: sha512-t54ONhl/h75X94SWsHGQ4G/ZrCEguKSRQr7DrjTciJXW0YU1QhlwYeycvK5JgkzlxmvrK7wq1NB/PLtHxoiDcA==}
engines: {node: '>=14'}
dev: false
/@remix-run/server-runtime/1.12.0: /@remix-run/server-runtime/1.12.0:
resolution: {integrity: sha512-7I0165Ns/ffPfCEfuiqD58lMderTn2s/sew1xJ34ONa21mG/7+5T7diHIgxKST8rS3816JPmlwSqUaHgwbmO6Q==} resolution: {integrity: sha512-7I0165Ns/ffPfCEfuiqD58lMderTn2s/sew1xJ34ONa21mG/7+5T7diHIgxKST8rS3816JPmlwSqUaHgwbmO6Q==}
engines: {node: '>=14'} engines: {node: '>=14'}
@@ -5383,6 +5390,19 @@ packages:
source-map: 0.7.4 source-map: 0.7.4
dev: false dev: false
/@remix-run/server-runtime/1.13.0:
resolution: {integrity: sha512-gjIW3XCeIlOt3rrOZMD6HixQydRgs1SwYjP99ZAVruG2+gNq/tL2OusMFYTLvtWrybt215tPROyF/6iTLsaO3g==}
engines: {node: '>=14'}
dependencies:
'@remix-run/router': 1.3.2
'@types/cookie': 0.4.1
'@types/react': 18.0.26
'@web3-storage/multipart-parser': 1.0.0
cookie: 0.4.2
set-cookie-parser: 2.5.1
source-map: 0.7.4
dev: false
/@remix-run/web-blob/3.0.4: /@remix-run/web-blob/3.0.4:
resolution: {integrity: sha512-AfegzZvSSDc+LwnXV+SwROTrDtoLiPxeFW+jxgvtDAnkuCX1rrzmVJ6CzqZ1Ai0bVfmJadkG5GxtAfYclpPmgw==} resolution: {integrity: sha512-AfegzZvSSDc+LwnXV+SwROTrDtoLiPxeFW+jxgvtDAnkuCX1rrzmVJ6CzqZ1Ai0bVfmJadkG5GxtAfYclpPmgw==}
dependencies: dependencies:
@@ -6082,7 +6102,7 @@ packages:
dependencies: dependencies:
'@types/http-cache-semantics': 4.0.1 '@types/http-cache-semantics': 4.0.1
'@types/keyv': 3.1.4 '@types/keyv': 3.1.4
'@types/node': 18.11.18 '@types/node': 14.18.33
'@types/responselike': 1.0.0 '@types/responselike': 1.0.0
/@types/chance/1.1.3: /@types/chance/1.1.3:
@@ -6309,7 +6329,7 @@ packages:
resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==} resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==}
dependencies: dependencies:
'@types/minimatch': 5.1.2 '@types/minimatch': 5.1.2
'@types/node': 18.11.18 '@types/node': 14.18.33
/@types/graceful-fs/4.1.6: /@types/graceful-fs/4.1.6:
resolution: {integrity: sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==} resolution: {integrity: sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==}
@@ -6424,7 +6444,7 @@ packages:
/@types/keyv/3.1.4: /@types/keyv/3.1.4:
resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==}
dependencies: dependencies:
'@types/node': 18.11.18 '@types/node': 14.18.33
/@types/load-json-file/2.0.7: /@types/load-json-file/2.0.7:
resolution: {integrity: sha512-NrH6jPlV77QCVPhAHofWeiOr77TgpKt82c2RVxSBChWBJqyY/u4ngl3CA4mcsAg/w7rNLrkR7dkObMV0ihLLXw==} resolution: {integrity: sha512-NrH6jPlV77QCVPhAHofWeiOr77TgpKt82c2RVxSBChWBJqyY/u4ngl3CA4mcsAg/w7rNLrkR7dkObMV0ihLLXw==}
@@ -6546,6 +6566,7 @@ packages:
/@types/node/18.11.18: /@types/node/18.11.18:
resolution: {integrity: sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==} resolution: {integrity: sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==}
dev: true
/@types/node/8.10.66: /@types/node/8.10.66:
resolution: {integrity: sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==} resolution: {integrity: sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==}
@@ -6631,7 +6652,7 @@ packages:
/@types/responselike/1.0.0: /@types/responselike/1.0.0:
resolution: {integrity: sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==} resolution: {integrity: sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==}
dependencies: dependencies:
'@types/node': 18.11.18 '@types/node': 14.18.33
/@types/retry/0.12.2: /@types/retry/0.12.2:
resolution: {integrity: sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==} resolution: {integrity: sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==}
@@ -16498,7 +16519,6 @@ packages:
/lilconfig/2.0.6: /lilconfig/2.0.6:
resolution: {integrity: sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg==} resolution: {integrity: sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg==}
engines: {node: '>=10'} engines: {node: '>=10'}
dev: true
/line-async-iterator/3.0.0: /line-async-iterator/3.0.0:
resolution: {integrity: sha512-IJwnVaX14dtWL2Za0B/qpuettNO3wtO2tb3NT37ffrz3ZOOkAFOpty5vysg7eLJ+QodMLRSROjR2csFB8ozYJg==} resolution: {integrity: sha512-IJwnVaX14dtWL2Za0B/qpuettNO3wtO2tb3NT37ffrz3ZOOkAFOpty5vysg7eLJ+QodMLRSROjR2csFB8ozYJg==}
@@ -19298,6 +19318,23 @@ packages:
yaml: 1.10.2 yaml: 1.10.2
dev: true dev: true
/postcss-load-config/4.0.1_postcss@8.4.21:
resolution: {integrity: sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==}
engines: {node: '>= 14'}
peerDependencies:
postcss: '>=8.0.9'
ts-node: '>=9.0.0'
peerDependenciesMeta:
postcss:
optional: true
ts-node:
optional: true
dependencies:
lilconfig: 2.0.6
postcss: 8.4.21
yaml: 2.2.1
dev: false
/postcss-loader/5.3.0_6jdsrmfenkuhhw3gx4zvjlznce: /postcss-loader/5.3.0_6jdsrmfenkuhhw3gx4zvjlznce:
resolution: {integrity: sha512-/+Z1RAmssdiSLgIZwnJHwBMnlABPgF7giYzTN2NOfr9D21IJZ4mQC1R2miwp80zno9M4zMD/umGI8cR+2EL5zw==} resolution: {integrity: sha512-/+Z1RAmssdiSLgIZwnJHwBMnlABPgF7giYzTN2NOfr9D21IJZ4mQC1R2miwp80zno9M4zMD/umGI8cR+2EL5zw==}
engines: {node: '>= 10.13.0'} engines: {node: '>= 10.13.0'}
@@ -23639,7 +23676,6 @@ packages:
/yaml/2.2.1: /yaml/2.2.1:
resolution: {integrity: sha512-e0WHiYql7+9wr4cWMx3TVQrNwejKaEe7/rHNmQmqRjazfOP5W8PB6Jpebb5o6fIapbz9o9+2ipcaTM2ZwDI6lw==} resolution: {integrity: sha512-e0WHiYql7+9wr4cWMx3TVQrNwejKaEe7/rHNmQmqRjazfOP5W8PB6Jpebb5o6fIapbz9o9+2ipcaTM2ZwDI6lw==}
engines: {node: '>= 14'} engines: {node: '>= 14'}
dev: true
/yargs-parser/10.1.0: /yargs-parser/10.1.0:
resolution: {integrity: sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==} resolution: {integrity: sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==}

View File

@@ -10,7 +10,7 @@ const ms = require('ms');
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms)); const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
async function nowDeploy(projectName, bodies, randomness, uploadNowJson) { async function nowDeploy(projectName, bodies, randomness, uploadNowJson, opts) {
const files = Object.keys(bodies) const files = Object.keys(bodies)
.filter(n => .filter(n =>
uploadNowJson uploadNowJson
@@ -68,7 +68,7 @@ async function nowDeploy(projectName, bodies, randomness, uploadNowJson) {
let deploymentUrl; let deploymentUrl;
{ {
const json = await deploymentPost(nowDeployPayload); const json = await deploymentPost(nowDeployPayload, opts);
if (json.error && json.error.code === 'missing_files') if (json.error && json.error.code === 'missing_files')
throw new Error('Missing files'); throw new Error('Missing files');
deploymentId = json.id; deploymentId = json.id;
@@ -137,8 +137,11 @@ async function filePost(body, digest) {
return json; return json;
} }
async function deploymentPost(payload) { async function deploymentPost(payload, opts = {}) {
const url = '/v13/deployments?skipAutoDetectionConfirmation=1&forceNew=1'; const url = `/v13/deployments?skipAutoDetectionConfirmation=1${
// skipForceNew allows turbo cache to be leveraged
!opts.skipForceNew ? `&forceNew=1` : ''
}`;
const resp = await fetchWithAuth(url, { const resp = await fetchWithAuth(url, {
method: 'POST', method: 'POST',
body: JSON.stringify(payload), body: JSON.stringify(payload),

View File

@@ -220,27 +220,48 @@ async function runProbe(probe, deploymentId, deploymentUrl, ctx) {
hadTest = true; hadTest = true;
} }
/**
* @type Record<string, string[]>
*/
const rawHeaders = resp.headers.raw();
if (probe.responseHeaders) { if (probe.responseHeaders) {
// eslint-disable-next-line no-loop-func // eslint-disable-next-line no-loop-func
Object.keys(probe.responseHeaders).forEach(header => { Object.keys(probe.responseHeaders).forEach(header => {
const actual = resp.headers.get(header); const actualArr = rawHeaders[header.toLowerCase()];
const expected = probe.responseHeaders[header]; let expectedArr = probe.responseHeaders[header];
const isEqual = Array.isArray(expected)
? expected.every(h => actual.includes(h)) // Header should not exist
: typeof expected === 'string' && if (expectedArr === null) {
expected.startsWith('/') && if (actualArr) {
expected.endsWith('/') throw new Error(
`Page ${probeUrl} contains response header "${header}", but probe says it should not.\n\nActual: ${formatHeaders(
rawHeaders
)}`
);
}
return;
}
if (!Array.isArray(expectedArr)) {
expectedArr = [expectedArr];
}
for (const expected of expectedArr) {
let isEqual = false;
for (const actual of actualArr) {
isEqual =
expected.startsWith('/') && expected.endsWith('/')
? new RegExp(expected.slice(1, -1)).test(actual) ? new RegExp(expected.slice(1, -1)).test(actual)
: expected === actual; : expected === actual;
if (isEqual) break;
}
if (!isEqual) { if (!isEqual) {
const headers = Array.from(resp.headers.entries())
.map(([k, v]) => ` ${k}=${v}`)
.join('\n');
throw new Error( throw new Error(
`Page ${probeUrl} does not have expected response header ${header}.\n\nExpected: ${expected}.\n\nActual: ${headers}` `Page ${probeUrl} does not have expected response header ${header}.\n\nExpected: ${expected}.\n\nActual: ${formatHeaders(
rawHeaders
)}`
); );
} }
}
}); });
hadTest = true; hadTest = true;
} else if (probe.notResponseHeaders) { } else if (probe.notResponseHeaders) {
@@ -249,12 +270,10 @@ async function runProbe(probe, deploymentId, deploymentUrl, ctx) {
const expected = probe.notResponseHeaders[header]; const expected = probe.notResponseHeaders[header];
if (headerValue === expected) { if (headerValue === expected) {
const headers = Array.from(resp.headers.entries())
.map(([k, v]) => ` ${k}=${v}`)
.join('\n');
throw new Error( throw new Error(
`Page ${probeUrl} has unexpected response header ${header}.\n\nDid not expect: ${header}=${expected}.\n\nAll: ${headers}` `Page ${probeUrl} has unexpected response header ${header}.\n\nDid not expect: ${header}=${expected}.\n\nAll: ${formatHeaders(
rawHeaders
)}`
); );
} }
}); });
@@ -264,7 +283,7 @@ async function runProbe(probe, deploymentId, deploymentUrl, ctx) {
assert(hadTest, 'probe must have a test condition'); assert(hadTest, 'probe must have a test condition');
} }
async function testDeployment(fixturePath) { async function testDeployment(fixturePath, opts) {
const projectName = path const projectName = path
.basename(fixturePath) .basename(fixturePath)
.toLowerCase() .toLowerCase()
@@ -329,7 +348,8 @@ async function testDeployment(fixturePath) {
projectName, projectName,
bodies, bodies,
randomness, randomness,
uploadNowJson uploadNowJson,
opts
); );
const probeCtx = {}; const probeCtx = {};
@@ -434,6 +454,15 @@ async function spawnAsync(...args) {
}); });
} }
/**
* @param {Record<string, string[]>} headers
*/
function formatHeaders(headers) {
return Object.entries(headers)
.flatMap(([name, values]) => values.map(v => ` ${name}: ${v}`))
.join('\n');
}
module.exports = { module.exports = {
packAndDeploy, packAndDeploy,
testDeployment, testDeployment,