@bytecodealliance/preview3-shim 0.1.2 → 0.2.1

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 +332 -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 +109 -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
@@ -0,0 +1,62 @@
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
+ payload;
8
+ /**
9
+ * Create a new WASI http error
10
+ * @param {string} tag - The error tag/type
11
+ * @param {string} [message] - Human-readable error message
12
+ * @param {any} [val] - Optional value/data for the error
13
+ */
14
+ constructor(tag, message = undefined, val = undefined, opts = {}) {
15
+ super(message || `Error: ${tag}`, { cause: opts.cause });
16
+ this.name = "HttpError";
17
+ this.payload = val !== undefined ? { tag, val } : { tag };
18
+ }
19
+ static from(err) {
20
+ if (err instanceof HttpError) {
21
+ return err;
22
+ }
23
+ if (err?.tag) {
24
+ return new HttpError(err.tag, undefined, err.val);
25
+ }
26
+ const e = getFirstError(err);
27
+ let tag, val;
28
+ switch (e.code) {
29
+ case "ECONNRESET":
30
+ tag = "HTTP-protocol-error";
31
+ break;
32
+ case "ENOTFOUND":
33
+ tag = "DNS-error";
34
+ val = {
35
+ rcode: e.code,
36
+ infoCode: e.errno < 0 ? -e.errno : e.errno,
37
+ };
38
+ break;
39
+ case "ECONNREFUSED":
40
+ tag = "connection-refused";
41
+ break;
42
+ default:
43
+ tag = "internal-error";
44
+ val = e.toString();
45
+ }
46
+ const httpErr = new HttpError(tag, e.message, val, { cause: e });
47
+ Error.captureStackTrace(httpErr, HttpError.from);
48
+ return httpErr;
49
+ }
50
+ }
51
+ function getFirstError(e) {
52
+ if (typeof e !== "object" || e === null) {
53
+ return e;
54
+ }
55
+ if (e.cause) {
56
+ return getFirstError(e.cause);
57
+ }
58
+ if (e instanceof AggregateError) {
59
+ return getFirstError(e.errors[0]);
60
+ }
61
+ return e;
62
+ }
@@ -0,0 +1,144 @@
1
+ export declare const _forbiddenHeaders: {
2
+ readonly value: any;
3
+ };
4
+ /**
5
+ * Implements the WASI Preview3 fields resource for HTTP headers and trailers
6
+ */
7
+ export declare class Fields {
8
+ #private;
9
+ /**
10
+ * Constructs an empty HTTP Fields
11
+ * WIT:
12
+ * ```
13
+ * constructor();
14
+ * ```
15
+ */
16
+ constructor();
17
+ /**
18
+ * Constructs a Fields instance from a list of name-value pairs
19
+ * WIT:
20
+ * ```
21
+ * from-list: static func(entries: list<tuple<field-name,field-value>>) -> result<fields, header-error>;
22
+ * ```
23
+ *
24
+ * @param {[string, Uint8Array[]][]} entries - List of field name and value pairs
25
+ * @returns {Fields} A new Fields instance
26
+ * @throws {HttpError} With payload.tag 'invalid-syntax' if any name or value is invalid
27
+ * @throws {HttpError} With payload.tag 'forbidden' if any name is forbidden
28
+ */
29
+ static fromList(entries: any): Fields;
30
+ /**
31
+ * Get all values for a given field name
32
+ * WIT:
33
+ * ```
34
+ * get: func(name: field-name) -> list<field-value>;
35
+ * ```
36
+ *
37
+ * @param {string} name - The field name to get values for
38
+ * @returns {Uint8Array[]} List of values for the field
39
+ */
40
+ get(name: any): any;
41
+ /**
42
+ * Check if a field name exists in the collection
43
+ * WIT:
44
+ * ```
45
+ * has: func(name: field-name) -> bool;
46
+ * ```
47
+ *
48
+ * @param {string} name - The field name to check
49
+ * @returns {boolean} True if the field exists
50
+ */
51
+ has(name: any): boolean;
52
+ /**
53
+ * Set values for a field name, replacing any existing values
54
+ * WIT:
55
+ * ```
56
+ * set: func(name: field-name, value: list<field-value>) -> result<_, header-error>;
57
+ * ```
58
+ *
59
+ * @param {string} name - The field name
60
+ * @param {Uint8Array[]} values - The values to set
61
+ * @throws {HttpError} With payload.tag 'immutable' if the fields are immutable
62
+ * @throws {HttpError} With payload.tag 'invalid-syntax' if name or values are invalid
63
+ * @throws {HttpError} With payload.tag 'forbidden' if name is forbidden
64
+ */
65
+ set(name: any, values: any): void;
66
+ /**
67
+ * Delete all values for a field name
68
+ * WIT:
69
+ * ```
70
+ * delete: func(name: field-name) -> result<_, header-error>;
71
+ * ```
72
+ *
73
+ * @param {string} name - The field name to delete
74
+ * @throws {HttpError} With payload.tag 'immutable' if the fields are immutable
75
+ */
76
+ delete(name: any): void;
77
+ /**
78
+ * Get all values for a field name and then delete them
79
+ * WIT:
80
+ * ```
81
+ * get-and-delete: func(name: field-name) -> result<list<field-value>, header-error>;
82
+ * ```
83
+ *
84
+ * @param {string} name - The field name to get and delete
85
+ * @returns {Uint8Array[]} List of values that were deleted
86
+ * @throws {HttpError} With payload.tag 'immutable' if the fields are immutable
87
+ */
88
+ getAndDelete(name: any): any;
89
+ /**
90
+ * Append a value to a field name
91
+ * WIT:
92
+ * ```
93
+ * append: func(name: field-name, value: field-value) -> result<_, header-error>;
94
+ * ```
95
+ *
96
+ * @param {string} name - The field name
97
+ * @param {Uint8Array} value - The value to append
98
+ * @throws {HttpError} With payload.tag 'immutable' if the fields are immutable
99
+ * @throws {HttpError} With payload.tag 'invalid-syntax' if name or value is invalid
100
+ * @throws {HttpError} With payload.tag 'forbidden' if name is forbidden
101
+ */
102
+ append(name: any, value: any): void;
103
+ /**
104
+ * Get all entries as a list of name-value pairs
105
+ * WIT:
106
+ * ```
107
+ * copy-all: func() -> list<tuple<field-name,field-value>>;
108
+ * ```
109
+ *
110
+ * @returns {[string, Uint8Array][]} List of all entries
111
+ */
112
+ copyAll(): any[];
113
+ /**
114
+ * Create a deep copy of this Fields instance
115
+ * WIT:
116
+ * ```
117
+ * clone: func() -> fields;
118
+ * ```
119
+ *
120
+ * @returns {Fields} A new mutable Fields instance with the same entries
121
+ */
122
+ clone(): Fields;
123
+ /**
124
+ * Mark fields as immutable
125
+ *
126
+ * @param {Fields} fields - The Fields instance to mark as immutable
127
+ * @returns {Fields} The same instance, now immutable
128
+ */
129
+ static _lock(fields: any): any;
130
+ /**
131
+ * Create a Fields instance from pre-validated entries
132
+ *
133
+ * @param {[string, Uint8Array][]} entries - Validated entries to use
134
+ * @returns {Fields} A new Fields instance with the provided entries
135
+ */
136
+ static _fromEntriesChecked(entries: any): Fields;
137
+ }
138
+ export declare function _fieldsLock(fields: any): any;
139
+ export declare function _fieldsFromEntriesChecked(entries: any): Fields;
140
+ export declare function _readTrailersForTransport(trailers: any): Promise<any[]>;
141
+ export declare function _trailerResultFromEntries(entries: any): {
142
+ tag: string;
143
+ val: Fields;
144
+ };
@@ -0,0 +1,332 @@
1
+ import { HttpError } from "./error.js";
2
+ import * as http from "node:http";
3
+ const { validateHeaderName = () => { }, validateHeaderValue = () => { } } = http;
4
+ let FORBIDDEN_HEADERS = null;
5
+ export const _forbiddenHeaders = {
6
+ get value() {
7
+ return (FORBIDDEN_HEADERS ??= new Set([
8
+ "connection",
9
+ "http2-settings",
10
+ "host",
11
+ "keep-alive",
12
+ "proxy-authenticate",
13
+ "proxy-authorization",
14
+ "proxy-connection",
15
+ "transfer-encoding",
16
+ "upgrade",
17
+ ]));
18
+ },
19
+ };
20
+ /**
21
+ * Implements the WASI Preview3 fields resource for HTTP headers and trailers
22
+ */
23
+ export class Fields {
24
+ #immutable = false;
25
+ /** @type {[string, Uint8Array][]} */
26
+ #entries = [];
27
+ /** @type {Map<string, [string, Uint8Array[]][]>} */
28
+ #table = new Map();
29
+ /**
30
+ * Constructs an empty HTTP Fields
31
+ * WIT:
32
+ * ```
33
+ * constructor();
34
+ * ```
35
+ */
36
+ constructor() { }
37
+ /**
38
+ * Constructs a Fields instance from a list of name-value pairs
39
+ * WIT:
40
+ * ```
41
+ * from-list: static func(entries: list<tuple<field-name,field-value>>) -> result<fields, header-error>;
42
+ * ```
43
+ *
44
+ * @param {[string, Uint8Array[]][]} entries - List of field name and value pairs
45
+ * @returns {Fields} A new Fields instance
46
+ * @throws {HttpError} With payload.tag 'invalid-syntax' if any name or value is invalid
47
+ * @throws {HttpError} With payload.tag 'forbidden' if any name is forbidden
48
+ */
49
+ static fromList(entries) {
50
+ const fields = new Fields();
51
+ for (const [name, values] of entries) {
52
+ for (const value of Array.isArray(values) ? values : [values]) {
53
+ fields.append(name, value);
54
+ }
55
+ }
56
+ return fields;
57
+ }
58
+ /**
59
+ * Get all values for a given field name
60
+ * WIT:
61
+ * ```
62
+ * get: func(name: field-name) -> list<field-value>;
63
+ * ```
64
+ *
65
+ * @param {string} name - The field name to get values for
66
+ * @returns {Uint8Array[]} List of values for the field
67
+ */
68
+ get(name) {
69
+ const tableEntries = this.#table.get(name.toLowerCase());
70
+ if (!tableEntries) {
71
+ return [];
72
+ }
73
+ return tableEntries.flatMap(([, v]) => v);
74
+ }
75
+ /**
76
+ * Check if a field name exists in the collection
77
+ * WIT:
78
+ * ```
79
+ * has: func(name: field-name) -> bool;
80
+ * ```
81
+ *
82
+ * @param {string} name - The field name to check
83
+ * @returns {boolean} True if the field exists
84
+ */
85
+ has(name) {
86
+ return this.#table.has(name.toLowerCase());
87
+ }
88
+ /**
89
+ * Set values for a field name, replacing any existing values
90
+ * WIT:
91
+ * ```
92
+ * set: func(name: field-name, value: list<field-value>) -> result<_, header-error>;
93
+ * ```
94
+ *
95
+ * @param {string} name - The field name
96
+ * @param {Uint8Array[]} values - The values to set
97
+ * @throws {HttpError} With payload.tag 'immutable' if the fields are immutable
98
+ * @throws {HttpError} With payload.tag 'invalid-syntax' if name or values are invalid
99
+ * @throws {HttpError} With payload.tag 'forbidden' if name is forbidden
100
+ */
101
+ set(name, values) {
102
+ this.#ensureMutable();
103
+ this.#validateName(name);
104
+ for (const value of values) {
105
+ this.#validateValue(name, value);
106
+ }
107
+ const lowercased = name.toLowerCase();
108
+ let bucket = this.#table.get(lowercased);
109
+ if (bucket) {
110
+ this.#entries = this.#entries.filter((e) => !bucket.includes(e));
111
+ this.#table.delete(lowercased);
112
+ }
113
+ if (values.length === 0) {
114
+ return;
115
+ }
116
+ bucket = [];
117
+ this.#table.set(lowercased, bucket);
118
+ for (const value of values) {
119
+ const entry = [name, value];
120
+ this.#entries.push(entry);
121
+ bucket.push(entry);
122
+ }
123
+ }
124
+ /**
125
+ * Delete all values for a field name
126
+ * WIT:
127
+ * ```
128
+ * delete: func(name: field-name) -> result<_, header-error>;
129
+ * ```
130
+ *
131
+ * @param {string} name - The field name to delete
132
+ * @throws {HttpError} With payload.tag 'immutable' if the fields are immutable
133
+ */
134
+ delete(name) {
135
+ this.#ensureMutable();
136
+ this.#validateName(name);
137
+ const lowercased = name.toLowerCase();
138
+ const tableEntries = this.#table.get(lowercased);
139
+ if (tableEntries) {
140
+ this.#entries = this.#entries.filter((entry) => !tableEntries.includes(entry));
141
+ this.#table.delete(lowercased);
142
+ }
143
+ }
144
+ /**
145
+ * Get all values for a field name and then delete them
146
+ * WIT:
147
+ * ```
148
+ * get-and-delete: func(name: field-name) -> result<list<field-value>, header-error>;
149
+ * ```
150
+ *
151
+ * @param {string} name - The field name to get and delete
152
+ * @returns {Uint8Array[]} List of values that were deleted
153
+ * @throws {HttpError} With payload.tag 'immutable' if the fields are immutable
154
+ */
155
+ getAndDelete(name) {
156
+ this.#ensureMutable();
157
+ this.#validateName(name);
158
+ const values = this.get(name);
159
+ this.delete(name);
160
+ return values;
161
+ }
162
+ /**
163
+ * Append a value to a field name
164
+ * WIT:
165
+ * ```
166
+ * append: func(name: field-name, value: field-value) -> result<_, header-error>;
167
+ * ```
168
+ *
169
+ * @param {string} name - The field name
170
+ * @param {Uint8Array} value - The value to append
171
+ * @throws {HttpError} With payload.tag 'immutable' if the fields are immutable
172
+ * @throws {HttpError} With payload.tag 'invalid-syntax' if name or value is invalid
173
+ * @throws {HttpError} With payload.tag 'forbidden' if name is forbidden
174
+ */
175
+ append(name, value) {
176
+ this.#ensureMutable();
177
+ this.#validateName(name);
178
+ this.#validateValue(name, value);
179
+ const lowercased = name.toLowerCase();
180
+ const tableEntries = this.#table.get(lowercased);
181
+ const entryName = tableEntries?.[0]?.[0] ?? name;
182
+ const entry = [entryName, value];
183
+ this.#entries.push(entry);
184
+ if (tableEntries) {
185
+ tableEntries.push(entry);
186
+ }
187
+ else {
188
+ this.#table.set(lowercased, [entry]);
189
+ }
190
+ }
191
+ /**
192
+ * Get all entries as a list of name-value pairs
193
+ * WIT:
194
+ * ```
195
+ * copy-all: func() -> list<tuple<field-name,field-value>>;
196
+ * ```
197
+ *
198
+ * @returns {[string, Uint8Array][]} List of all entries
199
+ */
200
+ copyAll() {
201
+ return this.#entries.slice();
202
+ }
203
+ /**
204
+ * Create a deep copy of this Fields instance
205
+ * WIT:
206
+ * ```
207
+ * clone: func() -> fields;
208
+ * ```
209
+ *
210
+ * @returns {Fields} A new mutable Fields instance with the same entries
211
+ */
212
+ clone() {
213
+ const entries = this.#entries.slice();
214
+ return _fieldsFromEntriesChecked(entries);
215
+ }
216
+ /**
217
+ * Mark fields as immutable
218
+ *
219
+ * @param {Fields} fields - The Fields instance to mark as immutable
220
+ * @returns {Fields} The same instance, now immutable
221
+ */
222
+ static _lock(fields) {
223
+ fields.#immutable = true;
224
+ return fields;
225
+ }
226
+ /**
227
+ * Create a Fields instance from pre-validated entries
228
+ *
229
+ * @param {[string, Uint8Array][]} entries - Validated entries to use
230
+ * @returns {Fields} A new Fields instance with the provided entries
231
+ */
232
+ static _fromEntriesChecked(entries) {
233
+ const fields = new Fields();
234
+ fields.#entries = entries;
235
+ for (const entry of entries) {
236
+ const lowercase = entry[0].toLowerCase();
237
+ const existing = fields.#table.get(lowercase);
238
+ if (existing) {
239
+ existing.push(entry);
240
+ }
241
+ else {
242
+ fields.#table.set(lowercase, [entry]);
243
+ }
244
+ }
245
+ return fields;
246
+ }
247
+ #validateName(name) {
248
+ try {
249
+ validateHeaderName(name);
250
+ }
251
+ catch {
252
+ throw new HttpError("invalid-syntax", `Invalid header name: ${name}`);
253
+ }
254
+ if (_forbiddenHeaders.value.has(name.toLowerCase())) {
255
+ throw new HttpError("forbidden", `Header ${name} is forbidden`);
256
+ }
257
+ }
258
+ #validateValue(name, value) {
259
+ try {
260
+ validateHeaderValue(name, bytesToHeaderValueString(value));
261
+ }
262
+ catch {
263
+ throw new HttpError("invalid-syntax", `Invalid header value for ${name}`);
264
+ }
265
+ }
266
+ #ensureMutable() {
267
+ if (this.#immutable) {
268
+ throw new HttpError("immutable", "Cannot modify immutable fields");
269
+ }
270
+ }
271
+ }
272
+ function bytesToHeaderValueString(value) {
273
+ let result = "";
274
+ for (let i = 0; i < value.length; i += 0x8000) {
275
+ result += String.fromCharCode(...value.subarray(i, i + 0x8000));
276
+ }
277
+ return result;
278
+ }
279
+ export function _fieldsLock(fields) {
280
+ return Fields._lock(fields);
281
+ }
282
+ export function _fieldsFromEntriesChecked(entries) {
283
+ return Fields._fromEntriesChecked(entries);
284
+ }
285
+ export async function _readTrailersForTransport(trailers) {
286
+ const fields = _unwrapTrailersResult(await trailers.read());
287
+ if (fields == null) {
288
+ return undefined;
289
+ }
290
+ if (fields instanceof Fields) {
291
+ return fields.copyAll();
292
+ }
293
+ if (Array.isArray(fields)) {
294
+ return fields;
295
+ }
296
+ throw new HttpError("invalid-argument", "trailers must be Fields or a list of entries");
297
+ }
298
+ export function _trailerResultFromEntries(entries) {
299
+ return {
300
+ tag: "ok",
301
+ val: entries && entries.length ? _fieldsFromEntriesChecked(entries) : null,
302
+ };
303
+ }
304
+ function _unwrapTrailersResult(result) {
305
+ if (result == null) {
306
+ return undefined;
307
+ }
308
+ if (result instanceof Fields || Array.isArray(result)) {
309
+ return result;
310
+ }
311
+ if (typeof result === "object") {
312
+ if (result.tag === "ok") {
313
+ return _unwrapTrailersResult(result.val);
314
+ }
315
+ if (result.tag === "some") {
316
+ return _unwrapTrailersResult(result.val);
317
+ }
318
+ if (result.tag === "none") {
319
+ return undefined;
320
+ }
321
+ if (result.tag === "err") {
322
+ throw HttpError.from(result.val);
323
+ }
324
+ if (Object.hasOwn(result, "ok")) {
325
+ return _unwrapTrailersResult(result.ok);
326
+ }
327
+ if (Object.hasOwn(result, "err")) {
328
+ throw HttpError.from(result.err);
329
+ }
330
+ }
331
+ return result;
332
+ }