goscript 0.2.2 → 0.2.3

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 (136) hide show
  1. package/compiler/gotest/testdata/browserapi/browserapi_test.go +36 -0
  2. package/compiler/lowering.go +223 -9
  3. package/compiler/override-registry_test.go +50 -0
  4. package/compiler/protobuf-ts-binding.go +154 -6
  5. package/compiler/protobuf-ts-binding_test.go +7 -2
  6. package/compiler/runtime-contract.go +2 -0
  7. package/compiler/runtime-contract_test.go +1 -0
  8. package/compiler/semantic-model.go +16 -0
  9. package/compiler/semantic-model_test.go +38 -0
  10. package/compiler/skeleton_test.go +473 -15
  11. package/compiler/typescript-emitter.go +4 -0
  12. package/dist/gs/builtin/builtin.js +7 -9
  13. package/dist/gs/builtin/builtin.js.map +1 -1
  14. package/dist/gs/builtin/defer.js +2 -2
  15. package/dist/gs/builtin/hostio.js +5 -5
  16. package/dist/gs/builtin/hostio.js.map +1 -1
  17. package/dist/gs/builtin/map.js +2 -1
  18. package/dist/gs/builtin/map.js.map +1 -1
  19. package/dist/gs/builtin/slice.d.ts +3 -0
  20. package/dist/gs/builtin/slice.js +39 -0
  21. package/dist/gs/builtin/slice.js.map +1 -1
  22. package/dist/gs/builtin/type.js +49 -0
  23. package/dist/gs/builtin/type.js.map +1 -1
  24. package/dist/gs/compress/zlib/index.js +5 -2
  25. package/dist/gs/compress/zlib/index.js.map +1 -1
  26. package/dist/gs/crypto/ecdh/index.js +27 -8
  27. package/dist/gs/crypto/ecdh/index.js.map +1 -1
  28. package/dist/gs/crypto/ed25519/index.js +3 -3
  29. package/dist/gs/crypto/ed25519/index.js.map +1 -1
  30. package/dist/gs/crypto/rand/index.js +6 -3
  31. package/dist/gs/crypto/rand/index.js.map +1 -1
  32. package/dist/gs/embed/index.js +9 -3
  33. package/dist/gs/embed/index.js.map +1 -1
  34. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.d.ts +1 -0
  35. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js +33 -0
  36. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js.map +1 -1
  37. package/dist/gs/github.com/mr-tron/base58/base58/index.js +4 -1
  38. package/dist/gs/github.com/mr-tron/base58/base58/index.js.map +1 -1
  39. package/dist/gs/golang.org/x/crypto/scrypt/index.d.ts +2 -0
  40. package/dist/gs/golang.org/x/crypto/scrypt/index.js +39 -0
  41. package/dist/gs/golang.org/x/crypto/scrypt/index.js.map +1 -0
  42. package/dist/gs/hash/fnv/index.js +13 -5
  43. package/dist/gs/hash/fnv/index.js.map +1 -1
  44. package/dist/gs/io/fs/glob.d.ts +3 -3
  45. package/dist/gs/io/fs/glob.js +8 -8
  46. package/dist/gs/io/fs/glob.js.map +1 -1
  47. package/dist/gs/io/fs/readdir.d.ts +2 -2
  48. package/dist/gs/io/fs/readdir.js +13 -74
  49. package/dist/gs/io/fs/readdir.js.map +1 -1
  50. package/dist/gs/io/fs/sub.js +4 -4
  51. package/dist/gs/io/fs/sub.js.map +1 -1
  52. package/dist/gs/io/fs/walk.js +1 -1
  53. package/dist/gs/io/fs/walk.js.map +1 -1
  54. package/dist/gs/maps/iter.js.map +1 -1
  55. package/dist/gs/maps/maps.js.map +1 -1
  56. package/dist/gs/mime/index.js +5 -2
  57. package/dist/gs/mime/index.js.map +1 -1
  58. package/dist/gs/net/http/httptest/index.js +6 -3
  59. package/dist/gs/net/http/httptest/index.js.map +1 -1
  60. package/dist/gs/net/http/index.d.ts +16 -4
  61. package/dist/gs/net/http/index.js +236 -40
  62. package/dist/gs/net/http/index.js.map +1 -1
  63. package/dist/gs/net/http/pprof/index.js.map +1 -1
  64. package/dist/gs/reflect/iter.js +1 -1
  65. package/dist/gs/reflect/iter.js.map +1 -1
  66. package/dist/gs/reflect/type.d.ts +2 -0
  67. package/dist/gs/reflect/type.js +53 -21
  68. package/dist/gs/reflect/type.js.map +1 -1
  69. package/dist/gs/runtime/pprof/index.js.map +1 -1
  70. package/dist/gs/runtime/runtime.js +2 -2
  71. package/dist/gs/runtime/runtime.js.map +1 -1
  72. package/dist/gs/runtime/trace/index.js.map +1 -1
  73. package/dist/gs/slices/slices.d.ts +1 -1
  74. package/dist/gs/slices/slices.js +37 -4
  75. package/dist/gs/slices/slices.js.map +1 -1
  76. package/gs/builtin/builtin.ts +11 -14
  77. package/gs/builtin/defer.ts +2 -2
  78. package/gs/builtin/hostio.ts +5 -5
  79. package/gs/builtin/map.ts +4 -1
  80. package/gs/builtin/slice.test.ts +14 -0
  81. package/gs/builtin/slice.ts +64 -0
  82. package/gs/builtin/type.ts +72 -0
  83. package/gs/bytes/bytes.test.ts +14 -13
  84. package/gs/compress/zlib/index.test.ts +19 -5
  85. package/gs/compress/zlib/index.ts +16 -7
  86. package/gs/context/context.test.ts +3 -1
  87. package/gs/crypto/ecdh/index.test.ts +6 -2
  88. package/gs/crypto/ecdh/index.ts +49 -12
  89. package/gs/crypto/ed25519/index.ts +20 -7
  90. package/gs/crypto/rand/index.ts +6 -3
  91. package/gs/embed/index.test.ts +3 -3
  92. package/gs/embed/index.ts +9 -3
  93. package/gs/fmt/fmt.test.ts +29 -4
  94. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.test.ts +126 -0
  95. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.ts +46 -0
  96. package/gs/github.com/mr-tron/base58/base58/index.ts +9 -3
  97. package/gs/github.com/zeebo/blake3/internal/consts/index.test.ts +2 -8
  98. package/gs/golang.org/x/crypto/scrypt/index.test.ts +81 -0
  99. package/gs/golang.org/x/crypto/scrypt/index.ts +54 -0
  100. package/gs/golang.org/x/crypto/scrypt/meta.json +5 -0
  101. package/gs/hash/fnv/index.test.ts +1 -8
  102. package/gs/hash/fnv/index.ts +27 -10
  103. package/gs/io/fs/glob.ts +13 -10
  104. package/gs/io/fs/meta.json +2 -0
  105. package/gs/io/fs/readdir.test.ts +63 -2
  106. package/gs/io/fs/readdir.ts +33 -30
  107. package/gs/io/fs/sub.ts +4 -4
  108. package/gs/io/fs/walk.ts +1 -1
  109. package/gs/maps/iter.ts +9 -9
  110. package/gs/maps/maps.ts +4 -4
  111. package/gs/math/bits/index.test.ts +10 -1
  112. package/gs/mime/index.test.ts +33 -15
  113. package/gs/mime/index.ts +9 -2
  114. package/gs/net/http/httptest/index.test.ts +17 -3
  115. package/gs/net/http/httptest/index.ts +8 -3
  116. package/gs/net/http/index.test.ts +645 -123
  117. package/gs/net/http/index.ts +548 -113
  118. package/gs/net/http/pprof/index.ts +24 -6
  119. package/gs/os/file_unix_js.test.ts +22 -0
  120. package/gs/reflect/iter.ts +4 -2
  121. package/gs/reflect/map.test.ts +56 -1
  122. package/gs/reflect/type.ts +76 -37
  123. package/gs/runtime/pprof/index.test.ts +7 -1
  124. package/gs/runtime/pprof/index.ts +5 -1
  125. package/gs/runtime/runtime.test.ts +7 -0
  126. package/gs/runtime/runtime.ts +2 -4
  127. package/gs/runtime/trace/index.test.ts +9 -1
  128. package/gs/runtime/trace/index.ts +5 -1
  129. package/gs/slices/meta.json +3 -0
  130. package/gs/slices/slices.test.ts +59 -21
  131. package/gs/slices/slices.ts +61 -20
  132. package/gs/strconv/complex.test.ts +17 -3
  133. package/gs/sync/atomic/doc_64.test.ts +2 -9
  134. package/gs/sync/sync.test.ts +18 -8
  135. package/gs/syscall/js/index.test.ts +9 -4
  136. package/package.json +5 -4
@@ -324,7 +324,10 @@ function parseRequestURL(rawURL) {
324
324
  }
325
325
  const parsed = new URL(rawURL, 'http://goscript.invalid');
326
326
  const hasHost = /^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//.test(rawURL);
327
- return [new RequestURL(parsed.pathname, parsed.search.startsWith('?') ? parsed.search.slice(1) : parsed.search, hasHost ? parsed.protocol.replace(/:$/, '') : '', hasHost ? parsed.host : ''), null];
327
+ return [
328
+ new RequestURL(parsed.pathname, parsed.search.startsWith('?') ? parsed.search.slice(1) : parsed.search, hasHost ? parsed.protocol.replace(/:$/, '') : '', hasHost ? parsed.host : ''),
329
+ null,
330
+ ];
328
331
  }
329
332
  catch {
330
333
  return [null, errors.New(`parse "${rawURL}": invalid URL`)];
@@ -342,6 +345,46 @@ class responseBody {
342
345
  return null;
343
346
  }
344
347
  }
348
+ class fetchResponseBody {
349
+ fetched;
350
+ requestContext;
351
+ abortFetch;
352
+ stopContextWatch;
353
+ reader = null;
354
+ closed = false;
355
+ constructor(fetched, requestContext, abortFetch, stopContextWatch) {
356
+ this.fetched = fetched;
357
+ this.requestContext = requestContext;
358
+ this.abortFetch = abortFetch;
359
+ this.stopContextWatch = stopContextWatch;
360
+ }
361
+ async Read(p) {
362
+ if (this.closed) {
363
+ return [0, ErrBodyReadAfterClose];
364
+ }
365
+ if (this.reader == null) {
366
+ const [data, err] = await readFetchBody(this.fetched, this.requestContext, this.abortFetch);
367
+ if (err != null) {
368
+ this.stopContextWatch();
369
+ return [0, err];
370
+ }
371
+ this.stopContextWatch();
372
+ this.reader = bytes.NewReader(data);
373
+ }
374
+ return this.reader.Read(p);
375
+ }
376
+ Close() {
377
+ if (this.closed) {
378
+ return null;
379
+ }
380
+ this.closed = true;
381
+ this.stopContextWatch();
382
+ if (this.reader == null) {
383
+ this.abortFetch();
384
+ }
385
+ return null;
386
+ }
387
+ }
345
388
  class noBody {
346
389
  Read(_p) {
347
390
  return [0, io.EOF];
@@ -386,7 +429,9 @@ export class Cookie {
386
429
  this.Unparsed = init?.Unparsed ?? null;
387
430
  }
388
431
  String() {
389
- const parts = [`${this.Name}=${this.Quoted ? quoteCookieValue(this.Value) : this.Value}`];
432
+ const parts = [
433
+ `${this.Name}=${this.Quoted ? quoteCookieValue(this.Value) : this.Value}`,
434
+ ];
390
435
  if (this.Path !== '') {
391
436
  parts.push(`Path=${this.Path}`);
392
437
  }
@@ -429,12 +474,19 @@ function isToken(value) {
429
474
  return /^[!#$%&'*+\-.^_`{}|~0-9A-Za-z]+$/.test(value);
430
475
  }
431
476
  function validCookieValueByte(code) {
432
- return code >= 0x20 && code < 0x7f && code !== 0x22 && code !== 0x3b && code !== 0x5c;
477
+ return (code >= 0x20 &&
478
+ code < 0x7f &&
479
+ code !== 0x22 &&
480
+ code !== 0x3b &&
481
+ code !== 0x5c);
433
482
  }
434
483
  function parseCookieValue(raw, allowDoubleQuote) {
435
484
  let value = raw;
436
485
  let quoted = false;
437
- if (allowDoubleQuote && value.length > 1 && value[0] === '"' && value[value.length - 1] === '"') {
486
+ if (allowDoubleQuote &&
487
+ value.length > 1 &&
488
+ value[0] === '"' &&
489
+ value[value.length - 1] === '"') {
438
490
  value = value.slice(1, -1);
439
491
  quoted = true;
440
492
  }
@@ -507,7 +559,7 @@ function inProcessServerRequest(request) {
507
559
  const rawQuery = request.URL?.RawQuery ?? '';
508
560
  const query = rawQuery === '' ? '' : `?${rawQuery}`;
509
561
  req.RequestURI = `${request.URL?.Path ?? '/'}${query}`;
510
- req.Host = request.Host === '' ? request.URL?.Host ?? '' : request.Host;
562
+ req.Host = request.Host === '' ? (request.URL?.Host ?? '') : request.Host;
511
563
  if (req.URL?.clone != null) {
512
564
  req.URL = req.URL.clone();
513
565
  req.URL.Scheme = '';
@@ -560,7 +612,9 @@ export class Request {
560
612
  this.Cancel = init?.Cancel ?? null;
561
613
  this.Response = init?.Response ?? null;
562
614
  this.Pattern = init?.Pattern ?? '';
563
- this.ctx = init?.ctx ?? context.Background();
615
+ this.ctx =
616
+ init?.ctx ??
617
+ context.Background();
564
618
  }
565
619
  Context() {
566
620
  return this.ctx;
@@ -571,7 +625,9 @@ export class Request {
571
625
  Clone(ctx) {
572
626
  return new Request({
573
627
  Method: this.Method,
574
- URL: this.URL?.clone != null ? this.URL.clone() : this.URL == null ? null : { ...this.URL },
628
+ URL: this.URL?.clone != null ? this.URL.clone()
629
+ : this.URL == null ? null
630
+ : { ...this.URL },
575
631
  Proto: this.Proto,
576
632
  ProtoMajor: this.ProtoMajor,
577
633
  ProtoMinor: this.ProtoMinor,
@@ -601,7 +657,8 @@ export class Request {
601
657
  return Header_Get(this.Header, 'Referer');
602
658
  }
603
659
  ProtoAtLeast(major, minor) {
604
- return this.ProtoMajor > major || (this.ProtoMajor === major && this.ProtoMinor >= minor);
660
+ return (this.ProtoMajor > major ||
661
+ (this.ProtoMajor === major && this.ProtoMinor >= minor));
605
662
  }
606
663
  Cookie(name) {
607
664
  for (const cookie of Array.from(this.Cookies() ?? [])) {
@@ -678,7 +735,8 @@ export class Response {
678
735
  this.TLS = init?.TLS ?? null;
679
736
  if (this.Status === '' && this.StatusCode !== 0) {
680
737
  const text = StatusText(this.StatusCode);
681
- this.Status = text === '' ? String(this.StatusCode) : `${this.StatusCode} ${text}`;
738
+ this.Status =
739
+ text === '' ? String(this.StatusCode) : `${this.StatusCode} ${text}`;
682
740
  }
683
741
  }
684
742
  clone() {
@@ -726,7 +784,8 @@ export class Response {
726
784
  }
727
785
  }
728
786
  ProtoAtLeast(major, minor) {
729
- return this.ProtoMajor > major || (this.ProtoMajor === major && this.ProtoMinor >= minor);
787
+ return (this.ProtoMajor > major ||
788
+ (this.ProtoMajor === major && this.ProtoMinor >= minor));
730
789
  }
731
790
  Write(w) {
732
791
  const write = (data) => {
@@ -820,10 +879,8 @@ function encodeFormData(data) {
820
879
  if (data instanceof URLSearchParams) {
821
880
  return data.toString();
822
881
  }
823
- const entries = data instanceof Map ?
824
- Array.from(data.entries())
825
- : typeof data === 'object' ?
826
- Object.entries(data)
882
+ const entries = data instanceof Map ? Array.from(data.entries())
883
+ : typeof data === 'object' ? Object.entries(data)
827
884
  : [];
828
885
  entries.sort(([a], [b]) => String(a).localeCompare(String(b)));
829
886
  const params = new URLSearchParams();
@@ -1015,7 +1072,10 @@ async function fetchRoundTrip(request) {
1015
1072
  };
1016
1073
  if (typeof globalThis.fetch !== 'function') {
1017
1074
  closeRequestBody();
1018
- return [null, errors.New('net/http: Client.Do is not implemented in GoScript')];
1075
+ return [
1076
+ null,
1077
+ errors.New('net/http: Client.Do is not implemented in GoScript'),
1078
+ ];
1019
1079
  }
1020
1080
  const ctxErr = request.Context()?.Err?.();
1021
1081
  if (ctxErr != null) {
@@ -1029,7 +1089,9 @@ async function fetchRoundTrip(request) {
1029
1089
  }
1030
1090
  }
1031
1091
  let body;
1032
- if (requestBody != null && request.Method !== MethodGet && request.Method !== MethodHead) {
1092
+ if (requestBody != null &&
1093
+ request.Method !== MethodGet &&
1094
+ request.Method !== MethodHead) {
1033
1095
  const [data, err] = await io.ReadAll(requestBody);
1034
1096
  const closeErr = closeRequestBody();
1035
1097
  if (err != null) {
@@ -1046,21 +1108,32 @@ async function fetchRoundTrip(request) {
1046
1108
  return [null, closeErr];
1047
1109
  }
1048
1110
  }
1111
+ const fetchContext = newFetchContext(request.Context());
1049
1112
  try {
1050
1113
  const bodyInit = body == null ? undefined : Uint8Array.from(body).buffer;
1051
- const fetched = await globalThis.fetch(request.URL?.String?.() ?? '', {
1114
+ const [fetched, fetchErr] = await fetchContext.wait(globalThis.fetch(request.URL?.String?.() ?? '', {
1052
1115
  method: request.Method || MethodGet,
1053
1116
  headers,
1054
1117
  body: bodyInit,
1055
- });
1056
- const data = new Uint8Array(await fetched.arrayBuffer());
1118
+ signal: fetchContext.signal,
1119
+ }));
1120
+ if (fetchErr != null || fetched == null) {
1121
+ fetchContext.stop();
1122
+ return [null, fetchErr];
1123
+ }
1057
1124
  const respHeader = new Header();
1058
1125
  fetched.headers.forEach((value, key) => Header_Add(respHeader, key, value));
1126
+ const responseBody = request.Method === MethodHead ?
1127
+ NoBody
1128
+ : new fetchResponseBody(fetched, request.Context(), fetchContext.abort, fetchContext.stop);
1129
+ if (request.Method === MethodHead) {
1130
+ fetchContext.stop();
1131
+ }
1059
1132
  return [
1060
1133
  new Response({
1061
1134
  Status: `${fetched.status} ${fetched.statusText}`,
1062
1135
  StatusCode: fetched.status,
1063
- Body: new responseBody(data),
1136
+ Body: responseBody,
1064
1137
  Header: respHeader,
1065
1138
  ContentLength: Number(fetched.headers.get('content-length') ?? -1),
1066
1139
  Request: request,
@@ -1069,12 +1142,79 @@ async function fetchRoundTrip(request) {
1069
1142
  ];
1070
1143
  }
1071
1144
  catch (err) {
1072
- const message = typeof err === 'object' && err != null && 'message' in err
1073
- ? String(err.message)
1074
- : String(err);
1075
- return [null, errors.New(message)];
1145
+ fetchContext.stop();
1146
+ return [null, errorFromUnknown(err)];
1076
1147
  }
1077
1148
  }
1149
+ function newFetchContext(requestContext) {
1150
+ let stopped = false;
1151
+ const watchController = typeof AbortController === 'undefined' ? null : new AbortController();
1152
+ const controller = typeof AbortController === 'undefined' ? null : new AbortController();
1153
+ const abort = () => {
1154
+ if (controller != null && !controller.signal.aborted) {
1155
+ controller.abort(requestContext?.Err?.() ?? context.Canceled);
1156
+ }
1157
+ };
1158
+ const donePromise = requestContext == null ? null : ((async () => {
1159
+ try {
1160
+ await requestContext.Done().selectReceive(0, watchController?.signal);
1161
+ }
1162
+ catch {
1163
+ // Closed channels and receive wakeups both mean the context is done.
1164
+ }
1165
+ const err = requestContext.Err() ?? context.Canceled;
1166
+ if (!stopped) {
1167
+ abort();
1168
+ }
1169
+ return err;
1170
+ })());
1171
+ return {
1172
+ signal: controller?.signal,
1173
+ abort,
1174
+ stop: () => {
1175
+ stopped = true;
1176
+ watchController?.abort();
1177
+ },
1178
+ wait: async (promise) => {
1179
+ const settle = promise.then((value) => ({ value }), (thrown) => ({ thrown }));
1180
+ if (donePromise == null) {
1181
+ const result = await settle;
1182
+ if ('thrown' in result) {
1183
+ return [null, errorFromUnknown(result.thrown)];
1184
+ }
1185
+ return [result.value, null];
1186
+ }
1187
+ const result = await Promise.race([settle, donePromise.then((err) => ({ err }))]);
1188
+ if ('err' in result) {
1189
+ abort();
1190
+ return [null, result.err];
1191
+ }
1192
+ if ('thrown' in result) {
1193
+ return [
1194
+ null,
1195
+ requestContext?.Err?.() ?? errorFromUnknown(result.thrown),
1196
+ ];
1197
+ }
1198
+ return [result.value, null];
1199
+ },
1200
+ };
1201
+ }
1202
+ function errorFromUnknown(err) {
1203
+ const message = typeof err === 'object' && err != null && 'message' in err ?
1204
+ String(err.message)
1205
+ : String(err);
1206
+ return errors.New(message);
1207
+ }
1208
+ async function readFetchBody(fetched, requestContext, abortFetch) {
1209
+ const fetchContext = newFetchContext(requestContext);
1210
+ const [buffer, err] = await fetchContext.wait(fetched.arrayBuffer());
1211
+ fetchContext.stop();
1212
+ if (err != null) {
1213
+ abortFetch();
1214
+ return [new Uint8Array(), err];
1215
+ }
1216
+ return [new Uint8Array(buffer ?? new ArrayBuffer(0)), null];
1217
+ }
1078
1218
  export function FS(fsys) {
1079
1219
  return {
1080
1220
  Open(name) {
@@ -1094,7 +1234,9 @@ function httpFileFromFSFile(file) {
1094
1234
  Read: (p) => file.Read(p instanceof Uint8Array ? p : Uint8Array.from(p ?? [])),
1095
1235
  Close: () => file.Close(),
1096
1236
  Stat: () => file.Stat(),
1097
- Seek: seek == null ? () => [0, errors.New('net/http: file does not support seek')] : seek.bind(file),
1237
+ Seek: seek == null ?
1238
+ () => [0, errors.New('net/http: file does not support seek')]
1239
+ : seek.bind(file),
1098
1240
  Readdir: readdir == null ? () => [null, io.EOF] : readdir.bind(file),
1099
1241
  };
1100
1242
  }
@@ -1109,13 +1251,13 @@ export function FileServer(root) {
1109
1251
  Error(w, 'method not allowed', StatusMethodNotAllowed);
1110
1252
  return;
1111
1253
  }
1112
- const [file, err] = root?.Open(cleanFileServerPath(req.URL?.Path ?? '')) ?? [null, fs.ErrInvalid];
1254
+ const [file, err] = (await root?.Open(cleanFileServerPath(req.URL?.Path ?? ''))) ?? [null, fs.ErrInvalid];
1113
1255
  if (err != null || file == null) {
1114
1256
  NotFound(w, req);
1115
1257
  return;
1116
1258
  }
1117
1259
  try {
1118
- const [info, statErr] = file.Stat();
1260
+ const [info, statErr] = await file.Stat();
1119
1261
  if (statErr != null) {
1120
1262
  Error(w, statErr.Error(), StatusInternalServerError);
1121
1263
  return;
@@ -1138,7 +1280,7 @@ export function FileServer(root) {
1138
1280
  }
1139
1281
  }
1140
1282
  finally {
1141
- file.Close();
1283
+ await file.Close();
1142
1284
  }
1143
1285
  },
1144
1286
  };
@@ -1174,7 +1316,23 @@ function cleanFileServerPath(name) {
1174
1316
  }
1175
1317
  return parts.length === 0 ? '.' : parts.join('/');
1176
1318
  }
1319
+ $.registerInterfaceType('http.Handler', null, [
1320
+ {
1321
+ name: 'ServeHTTP',
1322
+ args: [
1323
+ { name: 'w', type: 'http.ResponseWriter' },
1324
+ {
1325
+ name: 'r',
1326
+ type: { kind: $.TypeKind.Pointer, elemType: 'http.Request' },
1327
+ },
1328
+ ],
1329
+ returns: [],
1330
+ },
1331
+ ]);
1177
1332
  export function HandlerFunc_ServeHTTP(h, w, r) {
1333
+ if (!h) {
1334
+ throw new globalThis.Error('http: nil HandlerFunc');
1335
+ }
1178
1336
  return h(w, r);
1179
1337
  }
1180
1338
  export class CrossOriginProtection {
@@ -1334,7 +1492,8 @@ export class Server {
1334
1492
  this.BaseContext = init?.BaseContext ?? null;
1335
1493
  this.ConnContext = init?.ConnContext ?? null;
1336
1494
  this.Handler = init?.Handler ?? null;
1337
- this.DisableGeneralOptionsHandler = init?.DisableGeneralOptionsHandler ?? false;
1495
+ this.DisableGeneralOptionsHandler =
1496
+ init?.DisableGeneralOptionsHandler ?? false;
1338
1497
  this.TLSConfig = init?.TLSConfig ?? null;
1339
1498
  this.ReadTimeout = init?.ReadTimeout ?? 0;
1340
1499
  this.ReadTimeoutHandler = init?.ReadTimeoutHandler ?? null;
@@ -1492,7 +1651,9 @@ export function StripPrefix(prefix, handler) {
1492
1651
  return {
1493
1652
  ServeHTTP(w, r) {
1494
1653
  const req = $.pointerValue(r);
1495
- if (req?.URL != null && typeof req.URL.Path === 'string' && req.URL.Path.startsWith(prefix)) {
1654
+ if (req?.URL != null &&
1655
+ typeof req.URL.Path === 'string' &&
1656
+ req.URL.Path.startsWith(prefix)) {
1496
1657
  req.URL = { ...req.URL, Path: req.URL.Path.slice(prefix.length) || '/' };
1497
1658
  }
1498
1659
  return handler?.ServeHTTP(w, req);
@@ -1554,7 +1715,10 @@ export function Redirect(w, _r, url, code) {
1554
1715
  export function ParseTime(text) {
1555
1716
  const date = new globalThis.Date(text);
1556
1717
  if (isNaN(date.getTime())) {
1557
- return [new time.Time(), $.newError(`parsing time "${text}" as HTTP-date: cannot parse`)];
1718
+ return [
1719
+ new time.Time(),
1720
+ $.newError(`parsing time "${text}" as HTTP-date: cannot parse`),
1721
+ ];
1558
1722
  }
1559
1723
  return [time.UnixMilli(date.getTime()), null];
1560
1724
  }
@@ -1599,7 +1763,8 @@ export function DetectContentType(data) {
1599
1763
  if (startsWithBytes(bytes, new Uint8Array([0xef, 0xbb, 0xbf]))) {
1600
1764
  return 'text/plain; charset=utf-8';
1601
1765
  }
1602
- if (startsWithBytes(bytes, new Uint8Array([0x00, 0x00, 0x01, 0x00])) || startsWithBytes(bytes, new Uint8Array([0x00, 0x00, 0x02, 0x00]))) {
1766
+ if (startsWithBytes(bytes, new Uint8Array([0x00, 0x00, 0x01, 0x00])) ||
1767
+ startsWithBytes(bytes, new Uint8Array([0x00, 0x00, 0x02, 0x00]))) {
1603
1768
  return 'image/x-icon';
1604
1769
  }
1605
1770
  if (startsWithASCII(bytes, 'BM')) {
@@ -1675,7 +1840,10 @@ export function DetectContentType(data) {
1675
1840
  return 'application/wasm';
1676
1841
  }
1677
1842
  for (const byte of afterWS) {
1678
- if (byte <= 0x08 || byte === 0x0b || (byte >= 0x0e && byte <= 0x1a) || (byte >= 0x1c && byte <= 0x1f)) {
1843
+ if (byte <= 0x08 ||
1844
+ byte === 0x0b ||
1845
+ (byte >= 0x0e && byte <= 0x1a) ||
1846
+ (byte >= 0x1c && byte <= 0x1f)) {
1679
1847
  return 'application/octet-stream';
1680
1848
  }
1681
1849
  }
@@ -1684,7 +1852,11 @@ export function DetectContentType(data) {
1684
1852
  function firstNonWhitespace(data) {
1685
1853
  for (let i = 0; i < data.length; i++) {
1686
1854
  const byte = data[i];
1687
- if (byte !== 0x09 && byte !== 0x0a && byte !== 0x0c && byte !== 0x0d && byte !== 0x20) {
1855
+ if (byte !== 0x09 &&
1856
+ byte !== 0x0a &&
1857
+ byte !== 0x0c &&
1858
+ byte !== 0x0d &&
1859
+ byte !== 0x20) {
1688
1860
  return i;
1689
1861
  }
1690
1862
  }
@@ -1807,7 +1979,12 @@ export function ParseSetCookie(line) {
1807
1979
  if (!ok) {
1808
1980
  return [null, errInvalidCookieValue];
1809
1981
  }
1810
- const cookie = new Cookie({ Name: name, Value: value, Quoted: quoted, Raw: line });
1982
+ const cookie = new Cookie({
1983
+ Name: name,
1984
+ Value: value,
1985
+ Quoted: quoted,
1986
+ Raw: line,
1987
+ });
1811
1988
  const unparsed = [];
1812
1989
  for (const raw of parts.slice(1)) {
1813
1990
  const part = raw.trim();
@@ -1863,7 +2040,8 @@ export function ParseSetCookie(line) {
1863
2040
  break;
1864
2041
  }
1865
2042
  let secs = Number.parseInt(attrValue, 10);
1866
- if ((secs !== 0 && attrValue[0] === '0') || !Number.isSafeInteger(secs)) {
2043
+ if ((secs !== 0 && attrValue[0] === '0') ||
2044
+ !Number.isSafeInteger(secs)) {
1867
2045
  break;
1868
2046
  }
1869
2047
  if (secs <= 0) {
@@ -1901,7 +2079,10 @@ export function NewRequestWithContext(ctx, method, url, body) {
1901
2079
  method = MethodGet;
1902
2080
  }
1903
2081
  if (!isToken(method)) {
1904
- return [null, errors.New(`net/http: invalid method ${JSON.stringify(method)}`)];
2082
+ return [
2083
+ null,
2084
+ errors.New(`net/http: invalid method ${JSON.stringify(method)}`),
2085
+ ];
1905
2086
  }
1906
2087
  if (ctx == null) {
1907
2088
  return [null, errors.New('net/http: nil Context')];
@@ -1911,7 +2092,17 @@ export function NewRequestWithContext(ctx, method, url, body) {
1911
2092
  return [null, err];
1912
2093
  }
1913
2094
  const bodyInfo = requestBodyInfo(body, 0);
1914
- return [new Request({ Method: method, URL: parsedURL, Body: bodyInfo.Body, ContentLength: bodyInfo.ContentLength, Host: parsedURL.Host, ctx }), null];
2095
+ return [
2096
+ new Request({
2097
+ Method: method,
2098
+ URL: parsedURL,
2099
+ Body: bodyInfo.Body,
2100
+ ContentLength: bodyInfo.ContentLength,
2101
+ Host: parsedURL.Host,
2102
+ ctx,
2103
+ }),
2104
+ null,
2105
+ ];
1915
2106
  }
1916
2107
  export async function Get(_url) {
1917
2108
  const [req, err] = NewRequest(MethodGet, _url, null);
@@ -1984,9 +2175,14 @@ function requestBodyInfo(body, unknownLength) {
1984
2175
  if (value === NoBody) {
1985
2176
  return { Body: NoBody, ContentLength: 0 };
1986
2177
  }
1987
- if (value instanceof bytes.Buffer || value instanceof bytes.Reader || value instanceof strings.Reader) {
2178
+ if (value instanceof bytes.Buffer ||
2179
+ value instanceof bytes.Reader ||
2180
+ value instanceof strings.Reader) {
1988
2181
  const length = value.Len();
1989
- return { Body: length === 0 ? NoBody : readCloserForBody(body), ContentLength: length };
2182
+ return {
2183
+ Body: length === 0 ? NoBody : readCloserForBody(body),
2184
+ ContentLength: length,
2185
+ };
1990
2186
  }
1991
2187
  return { Body: readCloserForBody(body), ContentLength: unknownLength };
1992
2188
  }