@bytecodealliance/preview3-shim 0.1.2 → 0.2.0

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.
Files changed (112) hide show
  1. package/dist/nodejs/cli.d.ts +51 -0
  2. package/dist/nodejs/cli.js +106 -0
  3. package/dist/nodejs/clocks.d.ts +55 -0
  4. package/dist/nodejs/clocks.js +83 -0
  5. package/dist/nodejs/filesystem/descriptor.d.ts +443 -0
  6. package/dist/nodejs/filesystem/descriptor.js +1010 -0
  7. package/dist/nodejs/filesystem/error.d.ts +61 -0
  8. package/dist/nodejs/filesystem/error.js +86 -0
  9. package/dist/nodejs/filesystem/utils.d.ts +8 -0
  10. package/dist/nodejs/filesystem/utils.js +25 -0
  11. package/dist/nodejs/filesystem.js +2 -0
  12. package/dist/nodejs/finalization.d.ts +2 -0
  13. package/{lib → dist}/nodejs/finalization.js +15 -21
  14. package/dist/nodejs/future.d.ts +98 -0
  15. package/dist/nodejs/future.js +176 -0
  16. package/dist/nodejs/http/client.d.ts +22 -0
  17. package/dist/nodejs/http/client.js +138 -0
  18. package/dist/nodejs/http/error.d.ts +18 -0
  19. package/dist/nodejs/http/error.js +62 -0
  20. package/dist/nodejs/http/fields.d.ts +144 -0
  21. package/dist/nodejs/http/fields.js +327 -0
  22. package/dist/nodejs/http/request.d.ts +256 -0
  23. package/dist/nodejs/http/request.js +606 -0
  24. package/dist/nodejs/http/response.d.ts +82 -0
  25. package/dist/nodejs/http/response.js +202 -0
  26. package/dist/nodejs/http/server.d.ts +13 -0
  27. package/dist/nodejs/http/server.js +127 -0
  28. package/dist/nodejs/http.d.ts +19 -0
  29. package/{lib → dist}/nodejs/http.js +13 -18
  30. package/dist/nodejs/index.js +8 -0
  31. package/dist/nodejs/random.d.ts +5 -0
  32. package/{lib → dist}/nodejs/random.js +2 -8
  33. package/dist/nodejs/sockets/address.d.ts +78 -0
  34. package/dist/nodejs/sockets/address.js +120 -0
  35. package/dist/nodejs/sockets/error.d.ts +83 -0
  36. package/dist/nodejs/sockets/error.js +120 -0
  37. package/dist/nodejs/sockets/ip-name-lookup.d.ts +18 -0
  38. package/dist/nodejs/sockets/ip-name-lookup.js +84 -0
  39. package/dist/nodejs/sockets/tcp.d.ts +333 -0
  40. package/dist/nodejs/sockets/tcp.js +723 -0
  41. package/dist/nodejs/sockets/udp.d.ts +224 -0
  42. package/dist/nodejs/sockets/udp.js +475 -0
  43. package/dist/nodejs/sockets.d.ts +11 -0
  44. package/{lib → dist}/nodejs/sockets.js +2 -5
  45. package/dist/nodejs/stream.d.ts +161 -0
  46. package/dist/nodejs/stream.js +388 -0
  47. package/dist/nodejs/workers/cli-worker.d.ts +1 -0
  48. package/dist/nodejs/workers/cli-worker.js +41 -0
  49. package/dist/nodejs/workers/filesystem-worker.d.ts +1 -0
  50. package/dist/nodejs/workers/filesystem-worker.js +102 -0
  51. package/dist/nodejs/workers/http-worker.d.ts +1 -0
  52. package/dist/nodejs/workers/http-worker.js +355 -0
  53. package/dist/nodejs/workers/resource-worker.d.ts +13 -0
  54. package/dist/nodejs/workers/resource-worker.js +152 -0
  55. package/dist/nodejs/workers/tcp-worker.d.ts +2 -0
  56. package/dist/nodejs/workers/tcp-worker.js +318 -0
  57. package/dist/nodejs/workers/udp-worker.d.ts +1 -0
  58. package/dist/nodejs/workers/udp-worker.js +156 -0
  59. package/package.json +20 -12
  60. package/types/interfaces/wasi-cli-environment.d.ts +3 -3
  61. package/types/interfaces/wasi-cli-exit.d.ts +12 -1
  62. package/types/interfaces/wasi-cli-run.d.ts +1 -1
  63. package/types/interfaces/wasi-cli-stderr.d.ts +3 -3
  64. package/types/interfaces/wasi-cli-stdin.d.ts +5 -5
  65. package/types/interfaces/wasi-cli-stdout.d.ts +3 -3
  66. package/types/interfaces/wasi-cli-terminal-input.d.ts +1 -1
  67. package/types/interfaces/wasi-cli-terminal-output.d.ts +1 -1
  68. package/types/interfaces/wasi-cli-terminal-stderr.d.ts +1 -1
  69. package/types/interfaces/wasi-cli-terminal-stdin.d.ts +1 -1
  70. package/types/interfaces/wasi-cli-terminal-stdout.d.ts +1 -1
  71. package/types/interfaces/wasi-cli-types.d.ts +5 -5
  72. package/types/interfaces/wasi-clocks-monotonic-clock.d.ts +3 -3
  73. package/types/interfaces/wasi-clocks-system-clock.d.ts +6 -6
  74. package/types/interfaces/wasi-clocks-types.d.ts +1 -1
  75. package/types/interfaces/wasi-filesystem-preopens.d.ts +1 -1
  76. package/types/interfaces/wasi-filesystem-types.d.ts +74 -74
  77. package/types/interfaces/wasi-http-client.d.ts +1 -1
  78. package/types/interfaces/wasi-http-handler.d.ts +1 -1
  79. package/types/interfaces/wasi-http-types.d.ts +34 -34
  80. package/types/interfaces/wasi-random-insecure-seed.d.ts +5 -5
  81. package/types/interfaces/wasi-random-insecure.d.ts +5 -5
  82. package/types/interfaces/wasi-random-random.d.ts +5 -5
  83. package/types/interfaces/wasi-sockets-ip-name-lookup.d.ts +11 -11
  84. package/types/interfaces/wasi-sockets-types.d.ts +121 -121
  85. package/types/wasi-cli-command.d.ts +23 -23
  86. package/types/wasi-http-service.d.ts +14 -14
  87. package/lib/nodejs/cli.js +0 -127
  88. package/lib/nodejs/clocks.js +0 -98
  89. package/lib/nodejs/filesystem/descriptor.js +0 -1093
  90. package/lib/nodejs/filesystem/error.js +0 -92
  91. package/lib/nodejs/filesystem/utils.js +0 -19
  92. package/lib/nodejs/future.js +0 -190
  93. package/lib/nodejs/http/client.js +0 -161
  94. package/lib/nodejs/http/error.js +0 -71
  95. package/lib/nodejs/http/fields.js +0 -373
  96. package/lib/nodejs/http/request.js +0 -691
  97. package/lib/nodejs/http/response.js +0 -227
  98. package/lib/nodejs/http/server.js +0 -157
  99. package/lib/nodejs/sockets/address.js +0 -146
  100. package/lib/nodejs/sockets/error.js +0 -123
  101. package/lib/nodejs/sockets/ip-name-lookup.js +0 -93
  102. package/lib/nodejs/sockets/tcp.js +0 -801
  103. package/lib/nodejs/sockets/udp.js +0 -516
  104. package/lib/nodejs/stream.js +0 -437
  105. package/lib/nodejs/workers/cli-worker.js +0 -49
  106. package/lib/nodejs/workers/filesystem-worker.js +0 -119
  107. package/lib/nodejs/workers/http-worker.js +0 -417
  108. package/lib/nodejs/workers/resource-worker.js +0 -195
  109. package/lib/nodejs/workers/tcp-worker.js +0 -370
  110. package/lib/nodejs/workers/udp-worker.js +0 -194
  111. /package/{lib/nodejs/filesystem.js → dist/nodejs/filesystem.d.ts} +0 -0
  112. /package/{lib/nodejs/index.js → dist/nodejs/index.d.ts} +0 -0
@@ -1,92 +0,0 @@
1
- export const ERROR_MAP = {
2
- EACCES: "access",
3
- EALREADY: "already",
4
- EBADF: "bad-descriptor",
5
- EBUSY: "busy",
6
- EDEADLK: "deadlock",
7
- EDQUOT: "quota",
8
- EEXIST: "exist",
9
- EFBIG: "file-too-large",
10
- EILSEQ: "illegal-byte-sequence",
11
- EINPROGRESS: "in-progress",
12
- EINTR: "interrupted",
13
- EINVAL: "invalid",
14
- EIO: "io",
15
- EISDIR: "is-directory",
16
- ELOOP: "loop",
17
- EMLINK: "too-many-links",
18
- EMSGSIZE: "message-size",
19
- ENAMETOOLONG: "name-too-long",
20
- ENODEV: "no-device",
21
- ENOENT: "no-entry",
22
- ENOLCK: "no-lock",
23
- ENOMEM: "insufficient-memory",
24
- ENOSPC: "insufficient-space",
25
- ENOTDIR: "not-directory",
26
- ERR_FS_EISDIR: "not-directory",
27
- ENOTEMPTY: "not-empty",
28
- ENOTRECOVERABLE: "not-recoverable",
29
- ENOTSUP: "unsupported",
30
- ENOTTY: "no-tty",
31
- ENXIO: "no-such-device",
32
- EOVERFLOW: "overflow",
33
- EPERM: "not-permitted",
34
- EPIPE: "pipe",
35
- EROFS: "read-only",
36
- ESPIPE: "invalid-seek",
37
- ETXTBSY: "text-file-busy",
38
- EXDEV: "cross-device",
39
- };
40
-
41
- function getErrorTag(e) {
42
- if (e.code in ERROR_MAP) {
43
- return ERROR_MAP[e.code];
44
- }
45
-
46
- // Windows gives this error for badly structured `//` reads, this seems like
47
- // a slightly better error than unknown given that it's a common footgun.
48
- if (e.code === -4094 || (e.code === "UNKNOWN" && e.errno === -4094)) {
49
- return "no-such-device";
50
- }
51
-
52
- throw e;
53
- }
54
-
55
- /**
56
- * Custom error for File operations with JCO compatible payload.
57
- */
58
- export class FSError extends Error {
59
- /**
60
- * @param {string} tag – machine‐readable error tag
61
- * @param {string} [message] – human‐readable message
62
- * @param {any} [val] – optional extra data
63
- * @param {object} [opts]
64
- * @param {Error} [opts.cause]
65
- */
66
- constructor(tag, message, val, opts = {}) {
67
- super(message ?? `Error: ${tag}`, { cause: opts.cause });
68
- this.name = "FSError";
69
- this.payload = val !== undefined ? { tag, val } : { tag };
70
- }
71
-
72
- /**
73
- * Create or rewrap an error into FSError
74
- * @param {any} err – number, string, Error, or FSError
75
- */
76
- static from(err) {
77
- if (err instanceof FSError) {
78
- return err;
79
- }
80
-
81
- const tag = getErrorTag(err);
82
- const message = err?.message;
83
- return new FSError(tag, message, undefined, { cause: err });
84
- }
85
- }
86
-
87
- export function filesystemErrorCode(err) {
88
- if (err?.payload?.tag) {
89
- return err.payload;
90
- }
91
- return { tag: getErrorTag(err) };
92
- }
@@ -1,19 +0,0 @@
1
- /** Map fs.Dirent -> WASI type */
2
- export function wasiTypeFromDirent(obj) {
3
- if (obj.isFile()) {
4
- return { tag: "regular-file" };
5
- } else if (obj.isSocket()) {
6
- return { tag: "socket" };
7
- } else if (obj.isSymbolicLink()) {
8
- return { tag: "symbolic-link" };
9
- } else if (obj.isFIFO()) {
10
- return { tag: "fifo" };
11
- } else if (obj.isDirectory()) {
12
- return { tag: "directory" };
13
- } else if (obj.isCharacterDevice()) {
14
- return { tag: "character-device" };
15
- } else if (obj.isBlockDevice()) {
16
- return { tag: "block-device" };
17
- }
18
- return { tag: "other", val: undefined };
19
- }
@@ -1,190 +0,0 @@
1
- /**
2
- * Creates a future with a reader and writer.
3
- *
4
- * @returns {Object} An object containing:
5
- * - `tx` {FutureWriter}: The writer for the future.
6
- * - `rx` {FutureReader}: The reader for the future.
7
- *
8
- * @example
9
- * // Basic usage - creating a communication channel
10
- * const { tx, rx } = future();
11
- *
12
- * const message = 'Hello world!';
13
- * await tx.write(message);
14
- *
15
- * // first read yields the message
16
- * const value = await rx.read();
17
- * expect(value).toBe(message);
18
- *
19
- * // subsequent reads yield null
20
- * const noValue = await rx.read();
21
- * expect(noValue).toBeNull();
22
- */
23
- export function future() {
24
- const def = deferred();
25
- const tx = new FutureWriter(def);
26
- const rx = new FutureReader(def.promise);
27
- return { tx, rx };
28
- }
29
-
30
- function deferred() {
31
- let resolve, reject;
32
- const promise = new Promise((res, rej) => {
33
- resolve = res;
34
- reject = rej;
35
- });
36
- return { promise, resolve, reject };
37
- }
38
-
39
- export class FutureReader {
40
- /** The underlying Promise to read from */
41
- #promise;
42
- /** Tracks if read() has been called (prevents multiple reads) */
43
- #consumed = false;
44
-
45
- /**
46
- * Constructs a FutureReader.
47
- *
48
- * @param {Promise} promise - The promise to be read.
49
- * @throws {Error} If the provided argument is not a promise.
50
- */
51
- constructor(promise) {
52
- if (!promise || typeof promise.then !== "function") {
53
- throw new Error("Provided future must be a Promise");
54
- }
55
- if (promise instanceof Promise) {
56
- promise.catch(() => {});
57
- }
58
- this.#promise = promise;
59
- }
60
-
61
- /**
62
- * Reads the value from the promise. Can only be called once.
63
- *
64
- * @returns {Promise<any>} Resolves with the value of the promise or null if already consumed.
65
- * @throws {Error} If the promise is rejected.
66
- */
67
- async read() {
68
- if (this.#consumed) {
69
- return null;
70
- }
71
- try {
72
- return await this.#promise;
73
- } catch (err) {
74
- throw err;
75
- } finally {
76
- this.#consumed = true;
77
- }
78
- }
79
-
80
- then(resolve, reject) {
81
- return this.read().then(resolve, reject);
82
- }
83
-
84
- /**
85
- * Cancels the future. Not supported for FutureReader.
86
- */
87
- async cancel() {
88
- throw new Error("FutureReader does not support cancel");
89
- }
90
-
91
- /**
92
- * Closes the reader. No resources are released in this implementation.
93
- */
94
- close() {
95
- // Nothing to release.
96
- }
97
-
98
- /**
99
- * Converts the reader back into a promise.
100
- *
101
- * @returns {Promise} The original promise.
102
- */
103
- intoPromise() {
104
- const promise = this.#promise;
105
- this.#promise = null;
106
- return promise;
107
- }
108
- }
109
-
110
- export class FutureWriter {
111
- /** Deferred object with resolve/reject methods for controlling promise state */
112
- #deferred;
113
- /** Tracks if writer has been used */
114
- #written = false;
115
-
116
- /**
117
- * Constructs a FutureWriter.
118
- *
119
- * @param {Object} deferred - A deferred object with `resolve` and `reject` methods.
120
- * @throws {Error} If the deferred object is invalid.
121
- */
122
- constructor(deferred) {
123
- if (!deferred || typeof deferred.resolve !== "function") {
124
- throw new Error("Provided deferred object must have a resolve method");
125
- }
126
- this.#deferred = deferred;
127
- }
128
-
129
- /**
130
- * Resolves the promise with the given value.
131
- *
132
- * @param {any} value - The value to resolve the promise with.
133
- * @throws {Error} If the writer is already closed.
134
- */
135
- async write(value) {
136
- this.#ensureState();
137
- this.#written = true;
138
- this.#deferred.resolve(value);
139
- }
140
-
141
- /**
142
- * Rejects the promise with the given reason.
143
- *
144
- * @param {any} reason - The reason for rejecting the promise.
145
- * @throws {Error} If the writer is already closed.
146
- */
147
- async abort(reason) {
148
- this.#ensureState();
149
- this.#written = true;
150
- this.#deferred.reject(reason);
151
- }
152
-
153
- /**
154
- * Resolves the promise with null and closes the writer.
155
- */
156
- async close() {
157
- this.#ensureState();
158
- this.#written = true;
159
- this.#deferred.resolve(null);
160
- }
161
-
162
- /**
163
- * Rejects the promise with the given error and closes the writer.
164
- *
165
- * @param {Error} error - The error to reject the promise with.
166
- */
167
- async closeWithError(error) {
168
- this.#ensureState();
169
- this.#written = true;
170
- this.#deferred.reject(error);
171
- }
172
-
173
- /**
174
- * Converts the writer back into a promise.
175
- *
176
- * @returns {Promise} The original promise.
177
- */
178
- intoPromise() {
179
- this.close();
180
- const promise = this.#deferred.promise;
181
- this.#deferred = null;
182
- return promise;
183
- }
184
-
185
- #ensureState() {
186
- if (this.#written) {
187
- throw new Error("FutureWriter is closed (already written)");
188
- }
189
- }
190
- }
@@ -1,161 +0,0 @@
1
- import { ResourceWorker } from "../workers/resource-worker.js";
2
- import { StreamReader, readableByteStreamFromReader } from "../stream.js";
3
- import { FutureReader, future } from "../future.js";
4
- import { HttpError } from "./error.js";
5
- import { _schemeToString, Request } from "./request.js";
6
- import { Response } from "./response.js";
7
- import {
8
- _fieldsFromEntriesChecked,
9
- _readTrailersForTransport,
10
- _trailerResultFromEntries,
11
- } from "./fields.js";
12
-
13
- let WORKER = null;
14
- function worker() {
15
- return (WORKER ??= new ResourceWorker(new URL("../workers/http-worker.js", import.meta.url)));
16
- }
17
-
18
- /**
19
- * HTTP client interface.
20
- *
21
- * WIT:
22
- * ```
23
- * interface client {
24
- * use types.{request, response, error-code};
25
- * send: async func(request) -> result<response, error-code>;
26
- * }
27
- * ```
28
- */
29
- export const client = {
30
- /**
31
- * Send an HTTP request and return a response.
32
- *
33
- * @param {Request} req
34
- * @returns {Promise<Response>}
35
- * @throws {HttpError}
36
- */
37
- async send(req) {
38
- const scheme = _schemeToString(req.getScheme()) ?? "http";
39
- const authority = req.getAuthority();
40
-
41
- if (!authority) {
42
- const err = new HttpError("internal-error", "Request.authority must be set for client.send");
43
- req._resolve({ tag: "err", val: err.payload });
44
- throw err;
45
- }
46
-
47
- const path = req.getPathWithQuery();
48
- if (path == null) {
49
- const err = new HttpError("HTTP-request-URI-invalid", "Request.pathWithQuery must be set");
50
- req._resolve({ tag: "err", val: err.payload });
51
- throw err;
52
- }
53
-
54
- const url = `${scheme}://${authority}${path}`;
55
-
56
- const opts = req.getOptions();
57
- const connectTimeoutNs = opts?.getConnectTimeout() ?? null;
58
- const firstByteTimeoutNs = opts?.getFirstByteTimeout() ?? null;
59
- const betweenBytesTimeoutNs = opts?.getBetweenBytesTimeout() ?? null;
60
-
61
- const { rx: resRx } = future();
62
- const [body, trailers] = Request.consumeBody(req, resRx);
63
- const { port1: tx, port2: rx } = new MessageChannel();
64
- const { port1: transmitRx, port2: transmitTx } = new MessageChannel();
65
-
66
- const transfer = [rx, transmitTx];
67
- const stream = body ? readableByteStreamFromReader(body, { name: "request body" }) : undefined;
68
- if (stream) {
69
- transfer.unshift(stream);
70
- }
71
-
72
- let transmitSettled = false;
73
- const settleTransmit = (result) => {
74
- if (transmitSettled) {
75
- return;
76
- }
77
- transmitSettled = true;
78
- transmitRx.close();
79
- req._resolve(result);
80
- };
81
-
82
- transmitRx.once("message", ({ val, err }) => {
83
- if (err) {
84
- settleTransmit({ tag: "err", val: err });
85
- } else {
86
- settleTransmit({ tag: "ok", val });
87
- }
88
- });
89
-
90
- _readTrailersForTransport(trailers)
91
- .then((val) => tx.postMessage({ val }))
92
- .catch((err) => tx.postMessage({ err: HttpError.from(err).payload }))
93
- .finally(() => tx.close());
94
-
95
- try {
96
- const method = req.getMethod();
97
- const parts = await worker().run(
98
- {
99
- op: "client-request",
100
- url,
101
- method: method.tag === "other" ? method.val : method.tag,
102
- headers: req.getHeaders().copyAll(),
103
- timeouts: {
104
- connectTimeoutNs,
105
- firstByteTimeoutNs,
106
- betweenBytesTimeoutNs,
107
- },
108
- trailers: rx,
109
- transmit: transmitTx,
110
- body: stream,
111
- },
112
- transfer,
113
- );
114
-
115
- return responseFromParts(parts);
116
- } catch (e) {
117
- const err = HttpError.from(e);
118
- settleTransmit({ tag: "err", val: err.payload });
119
- throw err;
120
- }
121
- },
122
- };
123
-
124
- const responseFromParts = (parts) => {
125
- const { headers, body, trailers, statusCode } = parts;
126
-
127
- // Create a promise that resolves when the worker sends a message with trailers
128
- const promise = new Promise((resolve, reject) => {
129
- trailers.once("message", ({ val, err }) => {
130
- trailers.close();
131
- if (err) {
132
- reject(err);
133
- } else {
134
- resolve(val);
135
- }
136
- });
137
- });
138
-
139
- const future = new TrailerFutureReader(promise.then(_trailerResultFromEntries), trailers);
140
- const contents = new StreamReader(body);
141
- const fields = _fieldsFromEntriesChecked(headers);
142
-
143
- const [res] = Response.new(fields, contents, future);
144
- res.setStatusCode(statusCode);
145
- return res;
146
- };
147
-
148
- class TrailerFutureReader extends FutureReader {
149
- #trailers;
150
-
151
- constructor(promise, trailers) {
152
- super(promise);
153
- this.#trailers = trailers;
154
- }
155
-
156
- close() {
157
- this.#trailers?.close();
158
- this.#trailers = null;
159
- super.close();
160
- }
161
- }
@@ -1,71 +0,0 @@
1
- /**
2
- * Custom error class for WASI http interface that properly formats payload for Jco compatibility
3
- *
4
- * https://bytecodealliance.github.io/jco/wit-type-representations.html#result-considerations-idiomatic-js-errors-for-host-implementations
5
- */
6
- export class HttpError extends Error {
7
- /**
8
- * Create a new WASI http error
9
- * @param {string} tag - The error tag/type
10
- * @param {string} [message] - Human-readable error message
11
- * @param {any} [val] - Optional value/data for the error
12
- */
13
- constructor(tag, message, val, opts = {}) {
14
- super(message || `Error: ${tag}`, { cause: opts.cause });
15
- this.name = "HttpError";
16
- this.payload = val !== undefined ? { tag, val } : { tag };
17
- }
18
-
19
- static from(err) {
20
- if (err instanceof HttpError) {
21
- return err;
22
- }
23
-
24
- if (err?.tag) {
25
- return new HttpError(err.tag, undefined, err.val);
26
- }
27
-
28
- const e = getFirstError(err);
29
- let tag, val;
30
-
31
- switch (e.code) {
32
- case "ECONNRESET":
33
- tag = "HTTP-protocol-error";
34
- break;
35
-
36
- case "ENOTFOUND":
37
- tag = "DNS-error";
38
- val = {
39
- rcode: e.code,
40
- infoCode: e.errno < 0 ? -e.errno : e.errno,
41
- };
42
- break;
43
-
44
- case "ECONNREFUSED":
45
- tag = "connection-refused";
46
- break;
47
-
48
- default:
49
- tag = "internal-error";
50
- val = e.toString();
51
- }
52
-
53
- const httpErr = new HttpError(tag, e.message, val, { cause: e });
54
- Error.captureStackTrace(httpErr, HttpError.from);
55
-
56
- return httpErr;
57
- }
58
- }
59
-
60
- function getFirstError(e) {
61
- if (typeof e !== "object" || e === null) {
62
- return e;
63
- }
64
- if (e.cause) {
65
- return getFirstError(e.cause);
66
- }
67
- if (e instanceof AggregateError) {
68
- return getFirstError(e.errors[0]);
69
- }
70
- return e;
71
- }