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