Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions packages/edge/docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
- [ipAddress](README.md#ipaddress)
- [json](README.md#json)
- [next](README.md#next)
- [potentiallyLongRunningResponse](README.md#potentiallylongrunningresponse)
- [rewrite](README.md#rewrite)

## Variables
Expand Down Expand Up @@ -261,6 +262,43 @@ export default function middleware(_req: Request) {

---

### potentiallyLongRunningResponse

▸ **potentiallyLongRunningResponse**(`dataPromise`, `init?`): `Response`

Builds a response for returning data based on promise that take many seconds to resolve.
The response is returned immediately, but data is only written to it when the promise resolves.

**`Example`**

```ts
import { potentiallyLongRunningResponse } from '@vercel/edge';

export default () => {
const slowPromise = new Promise(resolve =>
setTimeout(() => resolve('Done'), 20000)
);
return potentiallyLongRunningResponse(slowPromise);
};
```

#### Parameters

| Name | Type | Description |
| :------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `dataPromise` | [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)<`string` \| [`Uint8Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array)\> | Promise for data to be sent as the response body. Note, that if this promise is rejected, then a plain text "ERROR" is returned to the cliet. Catch errors on the promise yourself to add custom error handling. |
| `init?` | `ResponseInit` | optional custom response status, statusText and headers |

#### Returns

`Response`

#### Defined in

[src/response.ts:43](https://github.com/vercel/vercel/blob/main/packages/edge/src/response.ts#L43)

---

### rewrite

▸ **rewrite**(`destination`, `init?`): `Response`
Expand Down
48 changes: 48 additions & 0 deletions packages/edge/src/response.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,51 @@ export function json(data: any, init?: ResponseInit): Response {
// @ts-expect-error This is not in lib/dom right now, and we can't augment it.
return Response.json(data, init);
}

/**
* Builds a response for returning data based on promise that take many seconds to resolve.
* The response is returned immediately, but data is only written to it when the promise resolves.
*
* @param dataPromise Promise for data to be sent as the response body. Note, that if this promise is
* rejected, then a plain text "ERROR" is returned to the cliet. Catch errors on the promise yourself
* to add custom error handling.
* @param init optional custom response status, statusText and headers
*
* @example
* ```ts
* import { potentiallyLongRunningResponse } from '@vercel/edge';
*
* export default () => {
* const slowPromise = new Promise((resolve) => setTimeout(() => resolve("Done"), 20000));
* return potentiallyLongRunningResponse(slowPromise);
* };
* ```
*/
export function potentiallyLongRunningResponse(
dataPromise: Promise<string | Uint8Array>,
init?: ResponseInit
): Response {
return new Response(
new ReadableStream({
start(controller) {
dataPromise
.then((data: string | Uint8Array) => {
if (typeof data === 'string') {
controller.enqueue(new TextEncoder().encode(data));
} else {
controller.enqueue(data);
}
controller.close();
})
.catch(error => {
console.log(
`Error in 'potentiallyLongRunningResponse' dataPromise: ${error}`
);
controller.enqueue(new TextEncoder().encode('ERROR'));
controller.close();
});
},
}),
init
);
}
49 changes: 48 additions & 1 deletion packages/edge/test/response.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* @jest-environment @edge-runtime/jest-environment
*/

import { json } from '../src/response';
import { json, potentiallyLongRunningResponse } from '../src/response';

describe('json', () => {
it('returns a response with JSON content', async () => {
Expand Down Expand Up @@ -32,3 +32,50 @@ describe('json', () => {
expect(await response.json()).toEqual(content);
});
});

describe('potentiallyLongRunningResponse', () => {
it('returns a response with immediate data', async () => {
const response = potentiallyLongRunningResponse(
new Promise(resolve => resolve('test'))
);
expect(await response.text()).toBe('test');
});

it('returns a response after a timeout', async () => {
const slowPromise: Promise<string> = new Promise(resolve =>
setTimeout(() => resolve('after timeout'), 1000)
);
const response = potentiallyLongRunningResponse(slowPromise);
expect(await response.text()).toBe('after timeout');
});

it('returns a response with custom init', async () => {
const response = potentiallyLongRunningResponse(
new Promise(resolve => resolve('test')),
{
status: 400,
headers: {
'content-type': 'text/custom',
},
}
);
expect(await response.text()).toBe('test');
expect(response.status).toBe(400);
expect(response.headers.get('content-type')).toBe('text/custom');
});

it('returns a response with Uint8Array data', async () => {
const data = new TextEncoder().encode('data');
const response = potentiallyLongRunningResponse(
new Promise(resolve => resolve(data))
);
expect(await response.text()).toBe('data');
});

it('returns ERROR on rejected promise', async () => {
const response = potentiallyLongRunningResponse(
new Promise((_, reject) => reject(new Error('test')))
);
expect(await response.text()).toBe('ERROR');
});
});