@vercel/sandbox 0.0.4 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/.turbo/turbo-typecheck.log +1 -1
- package/CHANGELOG.md +16 -0
- package/README.md +3 -1
- package/dist/{client/client.d.ts → api-client/api-client.d.ts} +31 -17
- package/dist/{client/client.js → api-client/api-client.js} +50 -44
- package/dist/{client → api-client}/base-client.d.ts +1 -1
- package/dist/{client → api-client}/base-client.js +3 -3
- package/dist/api-client/index.d.ts +1 -0
- package/dist/api-client/index.js +5 -0
- package/dist/{client → api-client}/validators.d.ts +20 -1
- package/dist/{client → api-client}/validators.js +9 -2
- package/dist/command.d.ts +127 -0
- package/dist/command.js +137 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +6 -7
- package/dist/sandbox.d.ts +201 -0
- package/dist/sandbox.js +174 -0
- package/dist/utils/decode-base64-url.d.ts +7 -0
- package/dist/utils/decode-base64-url.js +12 -0
- package/dist/utils/get-credentials.d.ts +26 -0
- package/dist/utils/get-credentials.js +84 -0
- package/dist/utils/get-vercel-oidc-token.d.ts +6 -0
- package/dist/utils/get-vercel-oidc-token.js +21 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +10 -3
- package/src/api-client/api-client.ts +225 -0
- package/src/{client → api-client}/base-client.ts +1 -1
- package/src/api-client/index.ts +1 -0
- package/src/{client → api-client}/validators.ts +9 -1
- package/src/command.test.ts +51 -0
- package/src/command.ts +176 -0
- package/src/index.ts +2 -2
- package/src/sandbox.ts +309 -0
- package/src/utils/decode-base64-url.ts +14 -0
- package/src/utils/get-credentials.ts +113 -0
- package/src/utils/get-vercel-oidc-token.ts +31 -0
- package/src/version.ts +1 -1
- package/tsconfig.json +2 -1
- package/typedoc.json +7 -1
- package/vitest.config.ts +8 -0
- package/vitest.setup.ts +4 -0
- package/dist/create-sandbox.d.ts +0 -196
- package/dist/create-sandbox.js +0 -230
- package/dist/utils/deferred-generator.d.ts +0 -5
- package/dist/utils/deferred-generator.js +0 -32
- package/dist/utils/deferred.d.ts +0 -6
- package/dist/utils/deferred.js +0 -12
- package/src/client/client.ts +0 -186
- package/src/create-sandbox.ts +0 -294
- package/src/utils/deferred-generator.ts +0 -38
- package/src/utils/deferred.ts +0 -12
- /package/dist/{client → api-client}/api-error.d.ts +0 -0
- /package/dist/{client → api-client}/api-error.js +0 -0
- /package/dist/{client → api-client}/with-retry.d.ts +0 -0
- /package/dist/{client → api-client}/with-retry.js +0 -0
- /package/src/{client → api-client}/api-error.ts +0 -0
- /package/src/{client → api-client}/with-retry.ts +0 -0
package/dist/create-sandbox.js
DELETED
|
@@ -1,230 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Command = exports.Sandbox = exports.SDK = void 0;
|
|
4
|
-
const client_1 = require("./client/client");
|
|
5
|
-
/**
|
|
6
|
-
* SDK for interacting with the Sandbox API. Provides methods to create and
|
|
7
|
-
* manage sandboxes configured with specific source code and network ports.
|
|
8
|
-
*
|
|
9
|
-
* Example:
|
|
10
|
-
* ```ts
|
|
11
|
-
* const sdk = new SDK({
|
|
12
|
-
* teamId: process.env.VERCEL_TEAM_ID!,
|
|
13
|
-
* token: process.env.VERCEL_TOKEN!,
|
|
14
|
-
* });
|
|
15
|
-
* ```
|
|
16
|
-
*
|
|
17
|
-
* @see {@link SDK.createSandbox} to start a new sandbox.
|
|
18
|
-
*/
|
|
19
|
-
class SDK {
|
|
20
|
-
/**
|
|
21
|
-
* Create a new instance of `SDK`.
|
|
22
|
-
*
|
|
23
|
-
* @param config - Configuration options for the SDK.
|
|
24
|
-
* @param config.teamId - The Vercel team ID used to scope the Sandbox.
|
|
25
|
-
* @param config.token - The API token used for authentication.
|
|
26
|
-
*/
|
|
27
|
-
constructor({ teamId, token }) {
|
|
28
|
-
this.client = new client_1.SandboxClient({ teamId, token });
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* Creates a new sandbox instance using the provided Git repository and exposed ports.
|
|
32
|
-
*
|
|
33
|
-
* The repository must be public. On start, the sandbox will clone the repository
|
|
34
|
-
* and expose the specified ports for access.
|
|
35
|
-
*
|
|
36
|
-
* @param params - Configuration parameters for the sandbox.
|
|
37
|
-
* @param params.source - The source of the sandbox, currently supports Git repositories only.
|
|
38
|
-
* @param params.source.type - Type of source, must be `"git"`.
|
|
39
|
-
* @param params.source.url - The URL of the public Git repository to clone.
|
|
40
|
-
* @param config.projectId - The Vercel project ID used to link the Sandbox to.
|
|
41
|
-
* @param params.ports - Array of port numbers to expose from the sandbox.
|
|
42
|
-
* @param params.timeout - (Optional) Timeout in seconds before the sandbox auto-terminates.
|
|
43
|
-
*
|
|
44
|
-
* @returns A promise that resolves to a `Sandbox` instance.
|
|
45
|
-
*/
|
|
46
|
-
async createSandbox(params) {
|
|
47
|
-
const { client } = this;
|
|
48
|
-
const sandbox = await client.createSandbox({
|
|
49
|
-
source: params.source,
|
|
50
|
-
projectId: params.projectId,
|
|
51
|
-
ports: params.ports,
|
|
52
|
-
timeout: params.timeout,
|
|
53
|
-
});
|
|
54
|
-
return new Sandbox({
|
|
55
|
-
client,
|
|
56
|
-
sandboxId: sandbox.json.sandboxId,
|
|
57
|
-
routes: sandbox.json.routes,
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
/** @hidden */
|
|
61
|
-
async getSandbox({ routes, sandboxId, }) {
|
|
62
|
-
return new Sandbox({
|
|
63
|
-
client: this.client,
|
|
64
|
-
sandboxId: sandboxId,
|
|
65
|
-
routes: routes,
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
exports.SDK = SDK;
|
|
70
|
-
/**
|
|
71
|
-
* A Sandbox is an isolated Linux MicroVM that you can your experiments on.
|
|
72
|
-
*
|
|
73
|
-
* @see {@link SDK.createSandbox} to construct a Sandbox.
|
|
74
|
-
* @hideconstructor
|
|
75
|
-
*/
|
|
76
|
-
class Sandbox {
|
|
77
|
-
constructor({ client, routes, sandboxId, }) {
|
|
78
|
-
this.client = client;
|
|
79
|
-
this.routes = routes;
|
|
80
|
-
this.sandboxId = sandboxId;
|
|
81
|
-
}
|
|
82
|
-
/**
|
|
83
|
-
* Start executing a command in this sandbox.
|
|
84
|
-
* @param command
|
|
85
|
-
* @param args
|
|
86
|
-
* @returns
|
|
87
|
-
*/
|
|
88
|
-
async runCommand(command, args = []) {
|
|
89
|
-
const commandResponse = await this.client.runCommand({
|
|
90
|
-
sandboxId: this.sandboxId,
|
|
91
|
-
command,
|
|
92
|
-
args,
|
|
93
|
-
});
|
|
94
|
-
return new Command({
|
|
95
|
-
client: this.client,
|
|
96
|
-
sandboxId: this.sandboxId,
|
|
97
|
-
cmdId: commandResponse.json.cmdId,
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
/**
|
|
101
|
-
* Write files to the filesystem of this sandbox.
|
|
102
|
-
*/
|
|
103
|
-
async writeFiles(files) {
|
|
104
|
-
return this.client.writeFiles({
|
|
105
|
-
sandboxId: this.sandboxId,
|
|
106
|
-
files: files,
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
/**
|
|
110
|
-
* Get the public domain of a port of this sandbox.
|
|
111
|
-
*
|
|
112
|
-
* E.g. `2grza2l7imxe.vercel.run`
|
|
113
|
-
*/
|
|
114
|
-
domain(p) {
|
|
115
|
-
const route = this.routes.find(({ port }) => port == p);
|
|
116
|
-
if (route) {
|
|
117
|
-
return `https://${route.subdomain}.vercel.run`;
|
|
118
|
-
}
|
|
119
|
-
else {
|
|
120
|
-
throw new Error(`No route for port ${p}`);
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
exports.Sandbox = Sandbox;
|
|
125
|
-
/**
|
|
126
|
-
* A command executed in a Sandbox.
|
|
127
|
-
*
|
|
128
|
-
* You can {@link wait} on commands to access their {@link exitCode}, and
|
|
129
|
-
* iterate over their output with {@link logs}.
|
|
130
|
-
*
|
|
131
|
-
* @see {@link Sandbox.runCommand} to start a command.
|
|
132
|
-
*
|
|
133
|
-
* @hideconstructor
|
|
134
|
-
*/
|
|
135
|
-
class Command {
|
|
136
|
-
constructor({ client, sandboxId, cmdId, }) {
|
|
137
|
-
this.client = client;
|
|
138
|
-
this.sandboxId = sandboxId;
|
|
139
|
-
this.cmdId = cmdId;
|
|
140
|
-
this.exitCode = null;
|
|
141
|
-
}
|
|
142
|
-
/**
|
|
143
|
-
* Iterate over the output of this command.
|
|
144
|
-
*
|
|
145
|
-
* ```
|
|
146
|
-
* for await (const log of cmd.logs()) {
|
|
147
|
-
* if (log.stream === "stdout") {
|
|
148
|
-
* process.stdout.write(log.data);
|
|
149
|
-
* } else {
|
|
150
|
-
* process.stderr.write(log.data);
|
|
151
|
-
* }
|
|
152
|
-
* }
|
|
153
|
-
* ```
|
|
154
|
-
*
|
|
155
|
-
* @see {@link Command.stdout}, {@link Command.stderr}, and {@link Command.output}
|
|
156
|
-
* to access output as a string.
|
|
157
|
-
*/
|
|
158
|
-
logs() {
|
|
159
|
-
return this.client.getLogs({
|
|
160
|
-
sandboxId: this.sandboxId,
|
|
161
|
-
cmdId: this.cmdId,
|
|
162
|
-
});
|
|
163
|
-
}
|
|
164
|
-
/**
|
|
165
|
-
* Wait for a command to exit and populate it's exit code.
|
|
166
|
-
*
|
|
167
|
-
* ```
|
|
168
|
-
* await cmd.wait()
|
|
169
|
-
* if (cmd.exitCode != 0) {
|
|
170
|
-
* console.error("Something went wrong...")
|
|
171
|
-
* }
|
|
172
|
-
* ````
|
|
173
|
-
*/
|
|
174
|
-
async wait() {
|
|
175
|
-
const command = await this.client.getCommand({
|
|
176
|
-
sandboxId: this.sandboxId,
|
|
177
|
-
cmdId: this.cmdId,
|
|
178
|
-
wait: true,
|
|
179
|
-
});
|
|
180
|
-
this.exitCode = command.json.exitCode;
|
|
181
|
-
return this;
|
|
182
|
-
}
|
|
183
|
-
/**
|
|
184
|
-
* Print command logs to stdout/stderr
|
|
185
|
-
*/
|
|
186
|
-
async printLogs() {
|
|
187
|
-
for await (const log of this.logs()) {
|
|
188
|
-
if (log.stream === "stdout") {
|
|
189
|
-
process.stdout.write(log.data);
|
|
190
|
-
}
|
|
191
|
-
else {
|
|
192
|
-
process.stderr.write(log.data);
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
/**
|
|
197
|
-
* Get the output of `stdout` or `stderr` as a string.
|
|
198
|
-
*
|
|
199
|
-
* NOTE: This may error with string conversion errors if the command does
|
|
200
|
-
* not ouptut valid unicode.
|
|
201
|
-
*/
|
|
202
|
-
async output(stream = "both") {
|
|
203
|
-
let data = "";
|
|
204
|
-
for await (const log of this.logs()) {
|
|
205
|
-
if (log.stream === stream) {
|
|
206
|
-
data += log.data;
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
return data;
|
|
210
|
-
}
|
|
211
|
-
/**
|
|
212
|
-
* Get the output of `stdout` as a string.
|
|
213
|
-
*
|
|
214
|
-
* NOTE: This may error with string conversion errors if the command does
|
|
215
|
-
* not ouptut valid unicode.
|
|
216
|
-
*/
|
|
217
|
-
async stdout() {
|
|
218
|
-
return this.output("stdout");
|
|
219
|
-
}
|
|
220
|
-
/**
|
|
221
|
-
* Get the output of `stderr` as a string.
|
|
222
|
-
*
|
|
223
|
-
* NOTE: This may error with string conversion errors if the command does
|
|
224
|
-
* not ouptut valid unicode.
|
|
225
|
-
*/
|
|
226
|
-
async stderr() {
|
|
227
|
-
return this.output("stderr");
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
exports.Command = Command;
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createDeferredGenerator = createDeferredGenerator;
|
|
4
|
-
const deferred_1 = require("./deferred");
|
|
5
|
-
function createDeferredGenerator() {
|
|
6
|
-
const deferreds = [new deferred_1.Deferred()];
|
|
7
|
-
let currentIndex = 0;
|
|
8
|
-
const next = (value) => {
|
|
9
|
-
const currentDeferred = deferreds[currentIndex];
|
|
10
|
-
if (!value.done) {
|
|
11
|
-
deferreds.push(new deferred_1.Deferred());
|
|
12
|
-
currentIndex++;
|
|
13
|
-
}
|
|
14
|
-
currentDeferred.resolve(value);
|
|
15
|
-
};
|
|
16
|
-
function generator() {
|
|
17
|
-
let currentIndex = 0;
|
|
18
|
-
return (async function* () {
|
|
19
|
-
while (true) {
|
|
20
|
-
const result = await deferreds[currentIndex].promise;
|
|
21
|
-
if (result.done)
|
|
22
|
-
return result.value;
|
|
23
|
-
yield result.value;
|
|
24
|
-
currentIndex++;
|
|
25
|
-
}
|
|
26
|
-
})();
|
|
27
|
-
}
|
|
28
|
-
return {
|
|
29
|
-
generator,
|
|
30
|
-
next,
|
|
31
|
-
};
|
|
32
|
-
}
|
package/dist/utils/deferred.d.ts
DELETED
package/dist/utils/deferred.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Deferred = void 0;
|
|
4
|
-
class Deferred {
|
|
5
|
-
constructor() {
|
|
6
|
-
this.promise = new Promise((res, rej) => {
|
|
7
|
-
this.resolve = res;
|
|
8
|
-
this.reject = rej;
|
|
9
|
-
});
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
exports.Deferred = Deferred;
|
package/src/client/client.ts
DELETED
|
@@ -1,186 +0,0 @@
|
|
|
1
|
-
import FormData from "form-data";
|
|
2
|
-
import { APIClient, parseOrThrow, type RequestParams } from "./base-client";
|
|
3
|
-
import {
|
|
4
|
-
Command,
|
|
5
|
-
CreatedCommand,
|
|
6
|
-
CreatedSandbox,
|
|
7
|
-
LogLine,
|
|
8
|
-
WrittenFile,
|
|
9
|
-
} from "./validators";
|
|
10
|
-
import { Readable } from "stream";
|
|
11
|
-
import { APIError } from "./api-error";
|
|
12
|
-
import { createDeferredGenerator } from "../utils/deferred-generator";
|
|
13
|
-
import { VERSION } from "../version";
|
|
14
|
-
import { z } from "zod";
|
|
15
|
-
import jsonlines from "jsonlines";
|
|
16
|
-
import os from "os";
|
|
17
|
-
|
|
18
|
-
export class SandboxClient extends APIClient {
|
|
19
|
-
private teamId: string;
|
|
20
|
-
|
|
21
|
-
constructor(params: { host?: string; teamId: string; token: string }) {
|
|
22
|
-
super({
|
|
23
|
-
host: params.host ?? "https://api.vercel.com",
|
|
24
|
-
token: params.token,
|
|
25
|
-
debug: false,
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
this.teamId = params.teamId;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
protected async request(path: string, params?: RequestParams) {
|
|
32
|
-
return super.request(path, {
|
|
33
|
-
...params,
|
|
34
|
-
query: { teamId: this.teamId, ...params?.query },
|
|
35
|
-
headers: {
|
|
36
|
-
"content-type": "application/json",
|
|
37
|
-
"user-agent": `vercel/sandbox/${VERSION} (Node.js/${process.version}; ${os.platform()}/${os.arch()})`,
|
|
38
|
-
...params?.headers,
|
|
39
|
-
},
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
async createSandbox(params: {
|
|
44
|
-
ports: number[];
|
|
45
|
-
projectId: string;
|
|
46
|
-
source: { type: "git"; url: string };
|
|
47
|
-
timeout?: number;
|
|
48
|
-
}) {
|
|
49
|
-
return parseOrThrow(
|
|
50
|
-
CreatedSandbox,
|
|
51
|
-
await this.request("/v1/sandboxes", {
|
|
52
|
-
method: "POST",
|
|
53
|
-
body: JSON.stringify({
|
|
54
|
-
projectId: params.projectId,
|
|
55
|
-
ports: params.ports,
|
|
56
|
-
source: params.source,
|
|
57
|
-
timeout: params.timeout,
|
|
58
|
-
}),
|
|
59
|
-
}),
|
|
60
|
-
);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
async runCommand(params: {
|
|
64
|
-
sandboxId: string;
|
|
65
|
-
cwd?: string;
|
|
66
|
-
command: string;
|
|
67
|
-
args: string[];
|
|
68
|
-
}) {
|
|
69
|
-
return parseOrThrow(
|
|
70
|
-
CreatedCommand,
|
|
71
|
-
await this.request(`/v1/sandboxes/${params.sandboxId}/cmd`, {
|
|
72
|
-
method: "POST",
|
|
73
|
-
body: JSON.stringify({
|
|
74
|
-
command: params.command,
|
|
75
|
-
args: params.args,
|
|
76
|
-
cwd: params.cwd,
|
|
77
|
-
}),
|
|
78
|
-
}),
|
|
79
|
-
);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
async getCommand(params: {
|
|
83
|
-
sandboxId: string;
|
|
84
|
-
cmdId: string;
|
|
85
|
-
wait?: boolean;
|
|
86
|
-
}) {
|
|
87
|
-
return parseOrThrow(
|
|
88
|
-
Command,
|
|
89
|
-
await this.request(
|
|
90
|
-
`/v1/sandboxes/${params.sandboxId}/cmd/${params.cmdId}`,
|
|
91
|
-
{ query: { wait: params.wait ? "true" : undefined } },
|
|
92
|
-
),
|
|
93
|
-
);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
async writeFiles(params: {
|
|
97
|
-
sandboxId: string;
|
|
98
|
-
files: { path: string; stream: Readable | Buffer }[];
|
|
99
|
-
}) {
|
|
100
|
-
const formData = new FormData();
|
|
101
|
-
|
|
102
|
-
for (const file of params.files) {
|
|
103
|
-
formData.append(file.path, file.stream, file.path);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
await parseOrThrow(
|
|
107
|
-
WrittenFile,
|
|
108
|
-
await this.request(`/v1/sandboxes/${params.sandboxId}/fs/write`, {
|
|
109
|
-
method: "POST",
|
|
110
|
-
headers: { ...formData.getHeaders() },
|
|
111
|
-
body: formData,
|
|
112
|
-
}),
|
|
113
|
-
);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
async readFile(params: {
|
|
117
|
-
sandboxId: string;
|
|
118
|
-
path: string;
|
|
119
|
-
cwd?: string;
|
|
120
|
-
}): Promise<NodeJS.ReadableStream | null> {
|
|
121
|
-
const response = await this.request(
|
|
122
|
-
`/v1/sandboxes/${params.sandboxId}/fs/read`,
|
|
123
|
-
{
|
|
124
|
-
method: "POST",
|
|
125
|
-
body: JSON.stringify({ path: params.path, cwd: params.cwd }),
|
|
126
|
-
},
|
|
127
|
-
);
|
|
128
|
-
|
|
129
|
-
if (response.status === 404) {
|
|
130
|
-
return null;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
return response.body;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
getLogs(params: { sandboxId: string; cmdId: string }) {
|
|
137
|
-
const deferred = createDeferredGenerator<z.infer<typeof LogLine>, void>();
|
|
138
|
-
|
|
139
|
-
(async () => {
|
|
140
|
-
const response = await this.request(
|
|
141
|
-
`/v1/sandboxes/${params.sandboxId}/cmd/${params.cmdId}/logs`,
|
|
142
|
-
{ method: "GET" },
|
|
143
|
-
);
|
|
144
|
-
|
|
145
|
-
if (response.headers.get("content-type") !== "application/x-ndjson") {
|
|
146
|
-
throw new APIError(response, {
|
|
147
|
-
message: "Expected a stream of logs",
|
|
148
|
-
});
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
const parser = jsonlines.parse();
|
|
152
|
-
response.body.pipe(parser);
|
|
153
|
-
|
|
154
|
-
parser.on("data", (data) => {
|
|
155
|
-
const parsed = LogLine.safeParse(data);
|
|
156
|
-
if (parsed.success) {
|
|
157
|
-
deferred.next({
|
|
158
|
-
value: parsed.data,
|
|
159
|
-
done: false,
|
|
160
|
-
});
|
|
161
|
-
} else {
|
|
162
|
-
deferred.next({
|
|
163
|
-
value: Promise.reject(parsed.error),
|
|
164
|
-
done: false,
|
|
165
|
-
});
|
|
166
|
-
}
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
parser.on("error", (err) => {
|
|
170
|
-
deferred.next({
|
|
171
|
-
value: Promise.reject(err),
|
|
172
|
-
done: false,
|
|
173
|
-
});
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
parser.on("end", () => {
|
|
177
|
-
deferred.next({
|
|
178
|
-
value: undefined,
|
|
179
|
-
done: true,
|
|
180
|
-
});
|
|
181
|
-
});
|
|
182
|
-
})();
|
|
183
|
-
|
|
184
|
-
return deferred.generator();
|
|
185
|
-
}
|
|
186
|
-
}
|