@nifrajs/core 5.5.0 → 5.6.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 (138) hide show
  1. package/CHANGELOG.md +159 -0
  2. package/dist/assurance.d.ts.map +1 -1
  3. package/dist/assurance.js.map +1 -1
  4. package/dist/evidence.d.ts +2 -0
  5. package/dist/evidence.d.ts.map +1 -1
  6. package/dist/evidence.js +2 -0
  7. package/dist/evidence.js.map +1 -1
  8. package/dist/file-type.d.ts +30 -0
  9. package/dist/file-type.d.ts.map +1 -0
  10. package/dist/file-type.js +118 -0
  11. package/dist/file-type.js.map +1 -0
  12. package/dist/index.d.ts +2 -1
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +2 -1
  15. package/dist/index.js.map +1 -1
  16. package/dist/internal/route-program.d.ts +11 -0
  17. package/dist/internal/route-program.d.ts.map +1 -1
  18. package/dist/internal/route-program.js +133 -85
  19. package/dist/internal/route-program.js.map +1 -1
  20. package/dist/reflection.d.ts +14 -1
  21. package/dist/reflection.d.ts.map +1 -1
  22. package/dist/reflection.js +34 -7
  23. package/dist/reflection.js.map +1 -1
  24. package/dist/response-observer.d.ts +1 -0
  25. package/dist/response-observer.d.ts.map +1 -1
  26. package/dist/response-observer.js +1 -0
  27. package/dist/response-observer.js.map +1 -1
  28. package/dist/server/bare-error-lane.d.ts +4 -1
  29. package/dist/server/bare-error-lane.d.ts.map +1 -1
  30. package/dist/server/bare-error-lane.js +9 -3
  31. package/dist/server/bare-error-lane.js.map +1 -1
  32. package/dist/server/before-handler.d.ts +10 -0
  33. package/dist/server/before-handler.d.ts.map +1 -0
  34. package/dist/server/before-handler.js +12 -0
  35. package/dist/server/before-handler.js.map +1 -0
  36. package/dist/server/body-lane.d.ts.map +1 -1
  37. package/dist/server/body-lane.js +8 -2
  38. package/dist/server/body-lane.js.map +1 -1
  39. package/dist/server/body-parser.d.ts.map +1 -1
  40. package/dist/server/body-parser.js +2 -5
  41. package/dist/server/body-parser.js.map +1 -1
  42. package/dist/server/body.d.ts +24 -8
  43. package/dist/server/body.d.ts.map +1 -1
  44. package/dist/server/body.js +86 -33
  45. package/dist/server/body.js.map +1 -1
  46. package/dist/server/core-copies.js +1 -1
  47. package/dist/server/http.d.ts.map +1 -1
  48. package/dist/server/http.js +6 -17
  49. package/dist/server/http.js.map +1 -1
  50. package/dist/server/multipart.d.ts +3 -0
  51. package/dist/server/multipart.d.ts.map +1 -1
  52. package/dist/server/multipart.js +226 -97
  53. package/dist/server/multipart.js.map +1 -1
  54. package/dist/server/proto-guard.d.ts.map +1 -1
  55. package/dist/server/proto-guard.js +39 -4
  56. package/dist/server/proto-guard.js.map +1 -1
  57. package/dist/server/query.d.ts.map +1 -1
  58. package/dist/server/query.js +8 -14
  59. package/dist/server/query.js.map +1 -1
  60. package/dist/server/repeated-prefix.d.ts +17 -0
  61. package/dist/server/repeated-prefix.d.ts.map +1 -0
  62. package/dist/server/repeated-prefix.js +17 -0
  63. package/dist/server/repeated-prefix.js.map +1 -0
  64. package/dist/server/request-context.d.ts.map +1 -1
  65. package/dist/server/request-context.js +1 -3
  66. package/dist/server/request-context.js.map +1 -1
  67. package/dist/server/respond.d.ts +1 -3
  68. package/dist/server/respond.d.ts.map +1 -1
  69. package/dist/server/respond.js +21 -16
  70. package/dist/server/respond.js.map +1 -1
  71. package/dist/server/response-contract-lane.d.ts +12 -2
  72. package/dist/server/response-contract-lane.d.ts.map +1 -1
  73. package/dist/server/response-contract-lane.js +135 -8
  74. package/dist/server/response-contract-lane.js.map +1 -1
  75. package/dist/server/runtime-core.d.ts +7 -0
  76. package/dist/server/runtime-core.d.ts.map +1 -1
  77. package/dist/server/runtime-core.js +8 -1
  78. package/dist/server/runtime-core.js.map +1 -1
  79. package/dist/server/server-types.d.ts +6 -3
  80. package/dist/server/server-types.d.ts.map +1 -1
  81. package/dist/server/server.d.ts +6 -2
  82. package/dist/server/server.d.ts.map +1 -1
  83. package/dist/server/server.js +239 -78
  84. package/dist/server/server.js.map +1 -1
  85. package/dist/server/sse.d.ts +1 -1
  86. package/dist/server/sse.d.ts.map +1 -1
  87. package/dist/server/sse.js +5 -4
  88. package/dist/server/sse.js.map +1 -1
  89. package/dist/server/webhook.d.ts +1 -1
  90. package/dist/server/webhook.d.ts.map +1 -1
  91. package/dist/server/webhook.js +24 -19
  92. package/dist/server/webhook.js.map +1 -1
  93. package/dist/server/websocket.d.ts +18 -3
  94. package/dist/server/websocket.d.ts.map +1 -1
  95. package/dist/server/websocket.js +45 -5
  96. package/dist/server/websocket.js.map +1 -1
  97. package/dist/server/ws-bun.d.ts.map +1 -1
  98. package/dist/server/ws-bun.js +12 -3
  99. package/dist/server/ws-bun.js.map +1 -1
  100. package/dist/server.d.ts +1 -0
  101. package/dist/server.d.ts.map +1 -1
  102. package/dist/server.js +1 -0
  103. package/dist/server.js.map +1 -1
  104. package/dist/tool-cli.d.ts +64 -0
  105. package/dist/tool-cli.d.ts.map +1 -0
  106. package/dist/tool-cli.js +495 -0
  107. package/dist/tool-cli.js.map +1 -0
  108. package/package.json +11 -1
  109. package/src/assurance.ts +1 -0
  110. package/src/evidence.ts +4 -0
  111. package/src/file-type.ts +130 -0
  112. package/src/index.ts +2 -1
  113. package/src/internal/route-program.ts +261 -93
  114. package/src/reflection.ts +53 -7
  115. package/src/response-observer.ts +6 -0
  116. package/src/server/bare-error-lane.ts +9 -4
  117. package/src/server/before-handler.ts +14 -0
  118. package/src/server/body-lane.ts +19 -9
  119. package/src/server/body-parser.ts +1 -5
  120. package/src/server/body.ts +96 -36
  121. package/src/server/core-copies.ts +1 -1
  122. package/src/server/http.ts +6 -15
  123. package/src/server/multipart.ts +232 -100
  124. package/src/server/proto-guard.ts +39 -4
  125. package/src/server/query.ts +7 -13
  126. package/src/server/repeated-prefix.ts +25 -0
  127. package/src/server/request-context.ts +1 -3
  128. package/src/server/respond.ts +23 -15
  129. package/src/server/response-contract-lane.ts +130 -8
  130. package/src/server/runtime-core.ts +10 -1
  131. package/src/server/server-types.ts +6 -3
  132. package/src/server/server.ts +265 -76
  133. package/src/server/sse.ts +6 -5
  134. package/src/server/webhook.ts +29 -24
  135. package/src/server/websocket.ts +57 -8
  136. package/src/server/ws-bun.ts +17 -2
  137. package/src/server.ts +1 -0
  138. package/src/tool-cli.ts +584 -0
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Magic-byte file-type detection - trust the bytes, not the `Content-Type` header (which a client
3
+ * sets freely). Reads only the leading bytes; imports nothing, so it is edge-safe. Covers the common
4
+ * upload types; returns `null` for anything unrecognized (incl. text formats like SVG/CSV that have no
5
+ * magic number - handle those explicitly if you accept them).
6
+ *
7
+ * The shared owner for every type-by-bytes check: `@nifrajs/schema/form`'s `t.file({ accept })` and
8
+ * `@nifrajs/uploads`'s `validateUpload` must give one file one verdict, so both read this module.
9
+ */
10
+ /**
11
+ * How many leading bytes {@link detectFileType} looks at. Reading this many from the start of a file
12
+ * (`file.slice(0, FILE_TYPE_PREFIX_BYTES)`) is enough for every type it knows: it reaches the first four
13
+ * compatible brands of an ISO-BMFF `ftyp` box, where an AVIF with the generic `mif1` brand says `avif`.
14
+ */
15
+ export const FILE_TYPE_PREFIX_BYTES = 32;
16
+ /**
17
+ * Every MIME type {@link detectFileType} can return. An allow-list entry outside this set (and
18
+ * outside a `type/*` wildcard that covers one of them) can never match, so check a configured
19
+ * allow-list against it up front instead of rejecting every upload at request time.
20
+ */
21
+ export const DETECTABLE_MIME_TYPES = [
22
+ "image/jpeg",
23
+ "image/png",
24
+ "image/gif",
25
+ "image/webp",
26
+ "audio/wav",
27
+ "video/x-msvideo",
28
+ "image/avif",
29
+ "image/heic",
30
+ "audio/mp4",
31
+ "video/mp4",
32
+ "video/webm",
33
+ "audio/ogg",
34
+ "audio/mpeg",
35
+ "application/pdf",
36
+ "application/zip",
37
+ "application/gzip",
38
+ ];
39
+ /**
40
+ * An MPEG audio frame header: an 11-bit frame sync, then a version, layer, bitrate and sample rate that
41
+ * are not reserved values. An MP3 needs no ID3 tag, so this is how an untagged one starts. AAC's ADTS
42
+ * sync shares the first 12 bits, but its layer is always the reserved `00`.
43
+ */
44
+ function mpegAudioFrame(bytes) {
45
+ const [b0 = 0, b1 = 0, b2 = 0] = bytes;
46
+ if (bytes.length < 4 || b0 !== 0xff || (b1 & 0xe0) !== 0xe0)
47
+ return false;
48
+ const version = (b1 >> 3) & 0b11;
49
+ const layer = (b1 >> 1) & 0b11;
50
+ const bitrate = b2 >> 4;
51
+ const sampleRate = (b2 >> 2) & 0b11;
52
+ return version !== 0b01 && layer !== 0b00 && bitrate !== 0b1111 && sampleRate !== 0b11;
53
+ }
54
+ /** Detect a file's type from its magic bytes, or `null` if unrecognized. */
55
+ export function detectFileType(bytes) {
56
+ const at = (offset, ...sig) => sig.every((byte, i) => bytes[offset + i] === byte);
57
+ // Images
58
+ if (at(0, 0xff, 0xd8, 0xff))
59
+ return { mime: "image/jpeg", ext: "jpg" };
60
+ if (at(0, 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a))
61
+ return { mime: "image/png", ext: "png" };
62
+ if (at(0, 0x47, 0x49, 0x46, 0x38))
63
+ return { mime: "image/gif", ext: "gif" };
64
+ // RIFF container (bytes 0-3 "RIFF", 8-11 the form type)
65
+ if (at(0, 0x52, 0x49, 0x46, 0x46)) {
66
+ if (at(8, 0x57, 0x45, 0x42, 0x50))
67
+ return { mime: "image/webp", ext: "webp" };
68
+ if (at(8, 0x57, 0x41, 0x56, 0x45))
69
+ return { mime: "audio/wav", ext: "wav" };
70
+ if (at(8, 0x41, 0x56, 0x49, 0x20))
71
+ return { mime: "video/x-msvideo", ext: "avi" };
72
+ }
73
+ // ISO-BMFF (`ftyp` box at offset 4) - mp4 / avif / heic / m4a, disambiguated by the major brand.
74
+ if (at(4, 0x66, 0x74, 0x79, 0x70)) {
75
+ const brandAt = (offset) => String.fromCharCode(bytes[offset] ?? 0, bytes[offset + 1] ?? 0, bytes[offset + 2] ?? 0, bytes[offset + 3] ?? 0);
76
+ const brand = brandAt(8);
77
+ // The compatible brands follow the minor version, to the end of the ftyp box. Only those inside the
78
+ // prefix count: the box size is the sender's claim, and a verdict must not depend on bytes a caller
79
+ // that sniffs `FILE_TYPE_PREFIX_BYTES` never reads.
80
+ const boxEnd = Math.min(bytes.length, FILE_TYPE_PREFIX_BYTES, ((bytes[0] ?? 0) << 24) | ((bytes[1] ?? 0) << 16) | ((bytes[2] ?? 0) << 8) | (bytes[3] ?? 0));
81
+ const compatible = [];
82
+ for (let offset = 16; offset + 4 <= boxEnd; offset += 4)
83
+ compatible.push(brandAt(offset));
84
+ // A HEIF-family file whose major brand is the generic `mif1`/`msf1`/`miaf` names its codec among
85
+ // the compatible brands: AVIF says `avif`/`avis`.
86
+ const avif = (name) => name === "avif" || name === "avis";
87
+ const generic = brand === "mif1" || brand === "msf1" || brand === "miaf";
88
+ if (avif(brand) || (generic && compatible.some(avif)))
89
+ return { mime: "image/avif", ext: "avif" };
90
+ if (brand.startsWith("hei") || brand.startsWith("hev") || generic) {
91
+ return { mime: "image/heic", ext: "heic" };
92
+ }
93
+ // Audio brands share the ISO-BMFF container but are NOT video - labeling them `video/mp4` would
94
+ // both reject real audio under an `audio/*` allow-list and admit it under `video/*`. `M4A `/`M4B `
95
+ // are AAC audio / audiobooks.
96
+ if (brand === "M4A " || brand === "M4B ")
97
+ return { mime: "audio/mp4", ext: "m4a" };
98
+ return { mime: "video/mp4", ext: "mp4" };
99
+ }
100
+ // A/V + archives
101
+ if (at(0, 0x1a, 0x45, 0xdf, 0xa3))
102
+ return { mime: "video/webm", ext: "webm" }; // Matroska/WebM
103
+ if (at(0, 0x4f, 0x67, 0x67, 0x53))
104
+ return { mime: "audio/ogg", ext: "ogg" };
105
+ if (at(0, 0x49, 0x44, 0x33))
106
+ return { mime: "audio/mpeg", ext: "mp3" }; // ID3 tag
107
+ if (mpegAudioFrame(bytes))
108
+ return { mime: "audio/mpeg", ext: "mp3" }; // an untagged MP3
109
+ if (at(0, 0x25, 0x50, 0x44, 0x46))
110
+ return { mime: "application/pdf", ext: "pdf" }; // "%PDF"
111
+ if (at(0, 0x50, 0x4b, 0x03, 0x04) || at(0, 0x50, 0x4b, 0x05, 0x06)) {
112
+ return { mime: "application/zip", ext: "zip" }; // also docx/xlsx/odt containers
113
+ }
114
+ if (at(0, 0x1f, 0x8b))
115
+ return { mime: "application/gzip", ext: "gz" };
116
+ return null;
117
+ }
118
+ //# sourceMappingURL=file-type.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-type.js","sourceRoot":"","sources":["../src/file-type.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -15,7 +15,7 @@
15
15
  * read its own package.json at runtime. `scripts/version.ts` rewrites it on every release bump and
16
16
  * `check:publish` asserts it equals `@nifrajs/core`'s package version.
17
17
  */
18
- export declare const VERSION: "5.5.0";
18
+ export declare const VERSION: "5.6.0";
19
19
  export type Version = typeof VERSION;
20
20
  export { FrameworkError, RouteConfigError, type RouteConfigErrorCode } from "./errors.js";
21
21
  export { FRAMEWORK_NAME, type FrameworkName } from "./internal/brand.js";
@@ -24,6 +24,7 @@ export { ROUTE_PATTERN_OVERLAP_MAX_STATES, RoutePatternOverlapLimitError, routeP
24
24
  export { METHODS, type Method, type RouteMethod, Router, type RouterMatch, } from "./router/router.js";
25
25
  export type { InferInput, InferOutput, StandardIssue, StandardResult, StandardSchemaV1, StandardTypes, ValidationOutcome, } from "./schema/standard.js";
26
26
  export { type AuthenticationFailure, type AuthenticationFailureReason, type AuthenticationInput, type AuthenticationResult, type AuthenticationStage, type AuthenticationSuccess, type AuthHeaders, type AuthMaybePromise, authenticated, isAuthenticatedRequest, markAuthenticatedRequest, rejected, } from "./server/auth.js";
27
+ export { beforeHandler } from "./server/before-handler.js";
27
28
  export type { Context, Params, Platform, Prettify, RequestPath, ResponseControls, RouteSchema, } from "./server/context.js";
28
29
  export { type CookieOptions, type CookieSecret, cookieNamePrefix, hasDuplicateCookie, parseCookies, serializeCookie, signValue, unsignValue, } from "./server/cookies.js";
29
30
  export { type DurableObjectNamespaceLike, type ExecutionContext, type ScheduledController, type ScheduledHandler, toFetchHandler, } from "./server/edge.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -15,13 +15,14 @@
15
15
  * read its own package.json at runtime. `scripts/version.ts` rewrites it on every release bump and
16
16
  * `check:publish` asserts it equals `@nifrajs/core`'s package version.
17
17
  */
18
- export const VERSION = "5.5.0";
18
+ export const VERSION = "5.6.0";
19
19
  export { FrameworkError, RouteConfigError } from "./errors.js";
20
20
  export { FRAMEWORK_NAME } from "./internal/brand.js";
21
21
  export { isSameOriginForm, isSameOriginRequest } from "./internal/same-origin.js";
22
22
  export { ROUTE_PATTERN_OVERLAP_MAX_STATES, RoutePatternOverlapLimitError, routePatternOverlap, } from "./router/overlap.js";
23
23
  export { METHODS, Router, } from "./router/router.js";
24
24
  export { authenticated, isAuthenticatedRequest, markAuthenticatedRequest, rejected, } from "./server/auth.js";
25
+ export { beforeHandler } from "./server/before-handler.js";
25
26
  export { cookieNamePrefix, hasDuplicateCookie, parseCookies, serializeCookie, signValue, unsignValue, } from "./server/cookies.js";
26
27
  export { toFetchHandler, } from "./server/edge.js";
27
28
  export { isSameOriginPath, pathnameOf, urlPartsOf } from "./server/http.js";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH;;;;GAIG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,OAAgB,CAAA;AAIvC,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAA6B,MAAM,aAAa,CAAA;AACzF,OAAO,EAAE,cAAc,EAAsB,MAAM,qBAAqB,CAAA;AACxE,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAA;AACjF,OAAO,EACL,gCAAgC,EAChC,6BAA6B,EAC7B,mBAAmB,GACpB,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EACL,OAAO,EAGP,MAAM,GAEP,MAAM,oBAAoB,CAAA;AAU3B,OAAO,EASL,aAAa,EACb,sBAAsB,EACtB,wBAAwB,EACxB,QAAQ,GACT,MAAM,kBAAkB,CAAA;AAUzB,OAAO,EAGL,gBAAgB,EAChB,kBAAkB,EAClB,YAAY,EACZ,eAAe,EACf,SAAS,EACT,WAAW,GACZ,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EAKL,cAAc,GACf,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAiB,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC1F,OAAO,EACL,oBAAoB,EACpB,UAAU,EAIV,eAAe,EACf,YAAY,GACb,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EAUL,eAAe,EACf,gBAAgB,EAChB,eAAe,GAEhB,MAAM,+BAA+B,CAAA;AAStC,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAA;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AACtD,OAAO,EAIL,MAAM,GACP,MAAM,0BAA0B,CAAA;AACjC,OAAO,EAOL,mBAAmB,EACnB,oBAAoB,EACpB,YAAY,EACZ,kBAAkB,EA8BlB,MAAM,EAEN,MAAM,GAEP,MAAM,oBAAoB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH;;;;GAIG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,OAAgB,CAAA;AAIvC,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAA6B,MAAM,aAAa,CAAA;AACzF,OAAO,EAAE,cAAc,EAAsB,MAAM,qBAAqB,CAAA;AACxE,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAA;AACjF,OAAO,EACL,gCAAgC,EAChC,6BAA6B,EAC7B,mBAAmB,GACpB,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EACL,OAAO,EAGP,MAAM,GAEP,MAAM,oBAAoB,CAAA;AAU3B,OAAO,EASL,aAAa,EACb,sBAAsB,EACtB,wBAAwB,EACxB,QAAQ,GACT,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAA;AAU1D,OAAO,EAGL,gBAAgB,EAChB,kBAAkB,EAClB,YAAY,EACZ,eAAe,EACf,SAAS,EACT,WAAW,GACZ,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EAKL,cAAc,GACf,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAiB,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC1F,OAAO,EACL,oBAAoB,EACpB,UAAU,EAIV,eAAe,EACf,YAAY,GACb,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EAUL,eAAe,EACf,gBAAgB,EAChB,eAAe,GAEhB,MAAM,+BAA+B,CAAA;AAStC,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAA;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AACtD,OAAO,EAIL,MAAM,GACP,MAAM,0BAA0B,CAAA;AACjC,OAAO,EAOL,mBAAmB,EACnB,oBAAoB,EACpB,YAAY,EACZ,kBAAkB,EA8BlB,MAAM,EAEN,MAAM,GAEP,MAAM,oBAAoB,CAAA"}
@@ -7,6 +7,7 @@
7
7
  * of rediscovering which lifecycle features are present.
8
8
  */
9
9
  import type { StandardSchemaV1 } from "../schema/standard.js";
10
+ import type { Logger } from "../server/logger.js";
10
11
  import type { Registry } from "../server/registry.js";
11
12
  import { type ResponseResult } from "../server/runtime-core.js";
12
13
  import type { CtxSet, MaybePromise, RawContext, RequestSource, Server } from "../server/server.js";
@@ -73,6 +74,16 @@ export declare function compileRouteProgram(input: RouteProgramInput): RouteProg
73
74
  * buffered, and with a replay entry and program when the key already holds a response.
74
75
  */
75
76
  export type IdempotencyResume<T> = (entry: RouteEntry, program: RouteProgram) => ProgramResult<T>;
77
+ /**
78
+ * Run the `authenticate()` stages a mount was registered after, in order, against the request the
79
+ * mount would receive: `undefined` once each one authenticated, else the response that refuses it. A
80
+ * stage that throws or decides nothing valid answers 503, and its cause goes to `logger`, as a route
81
+ * error no hook answers does.
82
+ */
83
+ export declare function authenticateMount(stages: readonly RawAuthStage[], request: Request, platform: {
84
+ readonly env?: unknown;
85
+ readonly clientIp?: string | undefined;
86
+ } | undefined, logger: Logger): MaybePromise<Response | undefined>;
76
87
  type ProgramResult<T> = MaybePromise<T>;
77
88
  /** Execute the general program. The first synchronous stage sequence stays synchronous. */
78
89
  export declare function executeRouteProgram<T, R extends Registry, Ctx>(runtime: Server<R, Ctx>, entry: RouteEntry, program: RouteProgram, source: RequestSource, ctx: RawContext, finalize: (result: unknown, set: CtxSet, ctx?: RawContext) => T, wrapResponse: (response: Response | ResponseResult) => T): ProgramResult<T>;
@@ -1 +1 @@
1
- {"version":3,"file":"route-program.d.ts","sourceRoot":"","sources":["../../src/internal/route-program.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAK7D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAA;AACrD,OAAO,EAKL,KAAK,cAAc,EAGpB,MAAM,2BAA2B,CAAA;AAClC,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAClG,OAAO,KAAK,EACV,eAAe,EACf,cAAc,EACd,YAAY,EACZ,eAAe,EACf,SAAS,EACT,eAAe,EACf,UAAU,EACX,MAAM,sBAAsB,CAAA;AAE7B,MAAM,MAAM,qBAAqB,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAA;AAEvF,MAAM,MAAM,iBAAiB,GACzB;IACE,QAAQ,CAAC,IAAI,EAAE,qBAAqB,CAAA;IACpC,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAA;IACjC,kFAAkF;IAClF,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAA;CAC/C,GACD;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,SAAS,CAAA;CAAE,GACpD;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,eAAe,CAAA;CAAE,GAC1D;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,eAAe,CAAA;CAAE,GAC3D;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,cAAc,CAAA;CAAE,CAAA;AAE5D,6EAA6E;AAC7E,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,MAAM,EAAE,SAAS,iBAAiB,EAAE,CAAA;IAC7C,QAAQ,CAAC,eAAe,EAAE,sBAAsB,GAAG,wBAAwB,CAAA;IAC3E,QAAQ,CAAC,oBAAoB,EAAE,OAAO,CAAA;IACtC,QAAQ,CAAC,UAAU,EAAE,SAAS,YAAY,EAAE,CAAA;IAC5C,gGAAgG;IAChG,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAA;IAC9B,QAAQ,CAAC,gBAAgB,EAAE,SAAS,OAAO,CAAC,iBAAiB,EAAE;QAAE,IAAI,EAAE,qBAAqB,CAAA;KAAE,CAAC,EAAE,CAAA;IACjG,QAAQ,CAAC,OAAO,EAAE,SAAS,SAAS,EAAE,CAAA;IACtC,QAAQ,CAAC,YAAY,EAAE,SAAS,eAAe,EAAE,CAAA;IACjD,QAAQ,CAAC,WAAW,EAAE,SAAS,cAAc,EAAE,CAAA;IAC/C,QAAQ,CAAC,OAAO,EAAE,SAAS,eAAe,EAAE,CAAA;IAC5C,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAA;IACjC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAAA;IAClD,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAA;IAChC,QAAQ,CAAC,UAAU,EAAE,gBAAgB,GAAG,SAAS,CAAA;IACjD,QAAQ,CAAC,SAAS,EAAE,UAAU,CAAC,WAAW,CAAC,CAAA;IAC3C,QAAQ,CAAC,gBAAgB,EAAE,UAAU,CAAC,kBAAkB,CAAC,CAAA;CAC1D;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAA;IACrC,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAA;IACjC,QAAQ,CAAC,OAAO,EAAE,SAAS,SAAS,EAAE,CAAA;IACtC,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,YAAY,EAAE,CAAA;IAC7C,QAAQ,CAAC,YAAY,EAAE,SAAS,eAAe,EAAE,CAAA;IACjD,QAAQ,CAAC,WAAW,EAAE,SAAS,cAAc,EAAE,CAAA;IAC/C,QAAQ,CAAC,OAAO,EAAE,SAAS,eAAe,EAAE,CAAA;IAC5C,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAAA;IAClD,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAA;IAChC,QAAQ,CAAC,UAAU,EAAE,gBAAgB,GAAG,SAAS,CAAA;IACjD,QAAQ,CAAC,SAAS,EAAE,UAAU,CAAC,WAAW,CAAC,CAAA;IAC3C,QAAQ,CAAC,gBAAgB,EAAE,UAAU,CAAC,kBAAkB,CAAC,CAAA;CAC1D;AAED,uFAAuF;AACvF,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,iBAAiB,GAAG,YAAY,CA6C1E;AAyCD;;;GAGG;AACH,MAAM,MAAM,iBAAiB,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,YAAY,KAAK,aAAa,CAAC,CAAC,CAAC,CAAA;AAubjG,KAAK,aAAa,CAAC,CAAC,IAAI,YAAY,CAAC,CAAC,CAAC,CAAA;AAmEvC,2FAA2F;AAC3F,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,CAAC,SAAS,QAAQ,EAAE,GAAG,EAC5D,OAAO,EAAE,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,EACvB,KAAK,EAAE,UAAU,EACjB,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,aAAa,EACrB,GAAG,EAAE,UAAU,EACf,QAAQ,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,UAAU,KAAK,CAAC,EAC/D,YAAY,EAAE,CAAC,QAAQ,EAAE,QAAQ,GAAG,cAAc,KAAK,CAAC,GACvD,aAAa,CAAC,CAAC,CAAC,CAgClB"}
1
+ {"version":3,"file":"route-program.d.ts","sourceRoot":"","sources":["../../src/internal/route-program.ts"],"names":[],"mappings":"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"}
@@ -10,6 +10,7 @@ import { markAuthenticatedRequest } from "../server/auth.js";
10
10
  import { declaredHeaderNames } from "../server/headers.js";
11
11
  import { pathnameOf } from "../server/http.js";
12
12
  import { queryObjectOf } from "../server/query.js";
13
+ import { toResponse } from "../server/respond.js";
13
14
  import { CONTEXT_SEARCH, CONTEXT_SET, EMPTY_RESPONSE_CONTROLS, isResponseResult, requestOf, status, } from "../server/runtime-core.js";
14
15
  /** Build the immutable stage sequence once, while the server is still configurable. */
15
16
  export function compileRouteProgram(input) {
@@ -119,6 +120,70 @@ function authenticationInputOf(source, ctx) {
119
120
  signal: ctx.signal,
120
121
  });
121
122
  }
123
+ /**
124
+ * Run the `authenticate()` stages a mount was registered after, in order, against the request the
125
+ * mount would receive: `undefined` once each one authenticated, else the response that refuses it. A
126
+ * stage that throws or decides nothing valid answers 503, and its cause goes to `logger`, as a route
127
+ * error no hook answers does.
128
+ */
129
+ export function authenticateMount(stages, request, platform, logger) {
130
+ let query;
131
+ const search = (() => {
132
+ const at = request.url.indexOf("?");
133
+ return at === -1 ? "" : request.url.slice(at);
134
+ })();
135
+ const input = Object.freeze({
136
+ method: request.method,
137
+ pathname: pathnameOf(request.url),
138
+ headers: authHeadersOf(request),
139
+ params: Object.freeze({}),
140
+ search,
141
+ get query() {
142
+ query ??= frozenQueryOf(search);
143
+ return query;
144
+ },
145
+ request,
146
+ env: platform?.env,
147
+ clientIp: platform?.clientIp,
148
+ signal: request.signal,
149
+ });
150
+ const unavailable = (error) => {
151
+ logger.error("authenticate() stage failed before a mount", {
152
+ method: request.method,
153
+ path: input.pathname,
154
+ error: error instanceof Error ? error.message : String(error),
155
+ });
156
+ return toResponse(defaultAuthenticationResponse("unavailable"), EMPTY_RESPONSE_CONTROLS);
157
+ };
158
+ const decide = (index, result) => {
159
+ if (!isAuthenticationDecision(result)) {
160
+ const id = stages[index]?.id;
161
+ return unavailable(new TypeError(`authenticate() stage "${id}" returned an invalid decision`));
162
+ }
163
+ if (result.kind === "rejected") {
164
+ const refusal = result.response ?? defaultAuthenticationResponse(result.reason);
165
+ return refusal instanceof Response ? refusal : toResponse(refusal, EMPTY_RESPONSE_CONTROLS);
166
+ }
167
+ markAuthenticatedRequest(request);
168
+ return run(index + 1);
169
+ };
170
+ const run = (index) => {
171
+ const stage = stages[index];
172
+ if (stage === undefined)
173
+ return undefined;
174
+ let outcome;
175
+ try {
176
+ outcome = stage.run(input);
177
+ }
178
+ catch (error) {
179
+ return unavailable(error);
180
+ }
181
+ return outcome instanceof Promise
182
+ ? outcome.then((settled) => decide(index, settled), unavailable)
183
+ : decide(index, outcome);
184
+ };
185
+ return run(0);
186
+ }
122
187
  function defaultAuthenticationResponse(reason) {
123
188
  if (reason === "forbidden")
124
189
  return status(403, { ok: false, error: "forbidden" });
@@ -126,6 +191,20 @@ function defaultAuthenticationResponse(reason) {
126
191
  return status(503, { ok: false, error: "auth_unavailable" });
127
192
  return status(401, { ok: false, error: "unauthorized" });
128
193
  }
194
+ /** Whether a stage returned a decision it may: a rejection with a known reason and a response, if
195
+ * any, that answers; or a principal. */
196
+ function isAuthenticationDecision(result) {
197
+ return (result !== null &&
198
+ typeof result === "object" &&
199
+ (result.kind === "rejected"
200
+ ? validAuthenticationFailureReason(result.reason) &&
201
+ (result.response === undefined ||
202
+ result.response instanceof Response ||
203
+ isResponseResult(result.response))
204
+ : result.kind === "authenticated" &&
205
+ result.principal !== null &&
206
+ result.principal !== undefined));
207
+ }
129
208
  function validAuthenticationFailureReason(value) {
130
209
  return (value === undefined ||
131
210
  value === "unauthenticated" ||
@@ -176,16 +255,7 @@ function runAuthenticationStages(host, entry, program, source, ctx, finalize, wr
176
255
  return finishAuthentication(host, entry, program, source, ctx, finalize, wrapResponse, outcome, start + 1, validationComplete);
177
256
  }
178
257
  function finishAuthentication(host, entry, program, source, ctx, finalize, wrapResponse, result, next, validationComplete = false) {
179
- if (result === null ||
180
- typeof result !== "object" ||
181
- (result.kind === "rejected"
182
- ? !validAuthenticationFailureReason(result.reason) ||
183
- (result.response !== undefined &&
184
- !(result.response instanceof Response) &&
185
- !isResponseResult(result.response))
186
- : result.kind !== "authenticated" ||
187
- result.principal === null ||
188
- result.principal === undefined)) {
258
+ if (!isAuthenticationDecision(result)) {
189
259
  const id = program.authStages[next - 1].id;
190
260
  const error = new TypeError(`authenticate() stage "${id}" returned an invalid decision`);
191
261
  return failAuthentication(host, entry, ctx, finalize, wrapResponse, error);
@@ -223,7 +293,8 @@ async function continueFastAuthenticatedProgram(host, entry, program, source, ct
223
293
  const settled = await pending;
224
294
  if (settled !== undefined)
225
295
  return wrapResponse(settled);
226
- return await runFastAuthenticatedProgram(host, entry, program, source, ctx, finalize, wrapResponse, validationIndex);
296
+ const outcome = runFastAuthenticatedProgram(host, entry, program, source, ctx, finalize, wrapResponse, validationIndex);
297
+ return outcome instanceof Promise ? await outcome : outcome;
227
298
  }
228
299
  catch (error) {
229
300
  return await host.handleProgramError(entry, error, ctx, finalize, wrapResponse);
@@ -261,7 +332,8 @@ async function continueValidationBeforeAuthentication(host, entry, program, sour
261
332
  const settled = await pending;
262
333
  if (settled !== undefined)
263
334
  return wrapResponse(settled);
264
- return await runValidationBeforeAuthentication(host, entry, program, source, ctx, finalize, wrapResponse, validationIndex);
335
+ const outcome = runValidationBeforeAuthentication(host, entry, program, source, ctx, finalize, wrapResponse, validationIndex);
336
+ return outcome instanceof Promise ? await outcome : outcome;
265
337
  }
266
338
  catch (error) {
267
339
  return await host.handleProgramError(entry, error, ctx, finalize, wrapResponse);
@@ -273,23 +345,27 @@ function runValidatedProgram(host, entry, program, source, ctx, finalize, wrapRe
273
345
  return runSync(host, entry, program, source, ctx, finalize, wrapResponse, 0, undefined);
274
346
  }
275
347
  /** Opt-in sensitive-route lane: run authentication/policy hooks before parsing untrusted input. */
276
- async function runAuthBeforeValidation(host, entry, program, source, ctx, finalize, wrapResponse, gated = false) {
348
+ function runAuthBeforeValidation(host, entry, program, source, ctx, finalize, wrapResponse, gated = false, deriveStart = 0, beforeStart = 0, validationStart = 0) {
277
349
  try {
278
350
  if (!gated) {
279
- if (program.hasDecorations)
351
+ if (deriveStart === 0 && beforeStart === 0 && program.hasDecorations)
280
352
  Object.assign(ctx, program.decorations);
281
- for (const derive of program.derives) {
282
- const result = derive(ctx);
283
- const settled = result instanceof Promise ? await result : result;
284
- if (isEarly(settled))
285
- return finishEarly(host, entry, ctx, settled, finalize, wrapResponse);
286
- Object.assign(ctx, settled);
353
+ for (let i = deriveStart; i < program.derives.length; i++) {
354
+ const result = program.derives[i](ctx);
355
+ if (result instanceof Promise) {
356
+ return continueProgram(host, entry, program, source, ctx, finalize, wrapResponse, { kind: "derive", next: i + 1, policy: true }, result, undefined);
357
+ }
358
+ if (isEarly(result))
359
+ return finishEarly(host, entry, ctx, result, finalize, wrapResponse);
360
+ Object.assign(ctx, result);
287
361
  }
288
- for (const before of program.beforeHandle) {
289
- const result = before(ctx);
290
- const settled = result instanceof Promise ? await result : result;
291
- if (settled !== undefined)
292
- return finishEarly(host, entry, ctx, settled, finalize, wrapResponse);
362
+ for (let i = beforeStart; i < program.beforeHandle.length; i++) {
363
+ const result = program.beforeHandle[i](ctx);
364
+ if (result instanceof Promise) {
365
+ return continueProgram(host, entry, program, source, ctx, finalize, wrapResponse, { kind: "before", next: i + 1, policy: true }, result, undefined);
366
+ }
367
+ if (result !== undefined)
368
+ return finishEarly(host, entry, ctx, result, finalize, wrapResponse);
293
369
  }
294
370
  // The policy hooks have passed, so the idempotency gate may buffer the body now. Not awaited:
295
371
  // the gate reports its own failures, and one the resumed program let escape must skip this catch.
@@ -297,23 +373,23 @@ async function runAuthBeforeValidation(host, entry, program, source, ctx, finali
297
373
  return runIdempotencyGate(host, entry, ctx, finalize, wrapResponse, (e, p) => runAuthBeforeValidation(host, e, p, source, ctx, finalize, wrapResponse, true));
298
374
  }
299
375
  }
300
- for (const stage of program.validationStages) {
376
+ for (let i = validationStart; i < program.validationStages.length; i++) {
377
+ const stage = program.validationStages[i];
301
378
  const result = stage.kind === "body"
302
- ? await host.readProgramBody(entry, source, ctx)
379
+ ? host.readProgramBody(entry, source, ctx)
303
380
  : host.validateProgramStage(entry, stage, source, ctx);
304
- const settled = result instanceof Promise ? await result : result;
305
- if (settled !== undefined)
306
- return wrapResponse(settled);
307
- }
308
- let result = await program.handler(ctx);
309
- for (const after of program.afterHandle) {
310
- const transformed = after(result, ctx);
311
- result = transformed instanceof Promise ? await transformed : transformed;
381
+ if (result instanceof Promise) {
382
+ return continueProgram(host, entry, program, source, ctx, finalize, wrapResponse, { kind: "validation", next: i + 1, policy: true }, result, undefined);
383
+ }
384
+ if (result !== undefined)
385
+ return wrapResponse(result);
312
386
  }
313
- return await host.finishProgramResult(entry, ctx, result, finalize, wrapResponse);
387
+ // A pending outcome here already met the error boundary (continueProgram or the response
388
+ // contract), so wrapping it in another catch would only add a promise.
389
+ return runHooksSync(host, entry, program, source, ctx, finalize, wrapResponse, program.derives.length, program.beforeHandle.length, undefined);
314
390
  }
315
391
  catch (error) {
316
- return await host.handleProgramError(entry, error, ctx, finalize, wrapResponse);
392
+ return host.handleProgramError(entry, error, ctx, finalize, wrapResponse);
317
393
  }
318
394
  }
319
395
  /** Execute the general program. The first synchronous stage sequence stays synchronous. */
@@ -356,9 +432,9 @@ function runSync(host, entry, program, source, ctx, finalize, wrapResponse, vali
356
432
  if (outcome !== undefined)
357
433
  return wrapResponse(outcome);
358
434
  }
359
- return runHooksSync(host, entry, program, source, ctx, finalize, wrapResponse, 0, 0, 0, initial);
435
+ return runHooksSync(host, entry, program, source, ctx, finalize, wrapResponse, 0, 0, initial);
360
436
  }
361
- function runHooksSync(host, entry, program, source, ctx, finalize, wrapResponse, deriveIndex, beforeIndex, afterIndex, initial) {
437
+ function runHooksSync(host, entry, program, source, ctx, finalize, wrapResponse, deriveIndex, beforeIndex, initial) {
362
438
  for (let i = deriveIndex; i < program.derives.length; i++) {
363
439
  const outcome = program.derives[i](ctx);
364
440
  if (outcome instanceof Promise) {
@@ -380,7 +456,9 @@ function runHooksSync(host, entry, program, source, ctx, finalize, wrapResponse,
380
456
  if (output instanceof Promise) {
381
457
  return continueProgram(host, entry, program, source, ctx, finalize, wrapResponse, { kind: "handler" }, output, initial);
382
458
  }
383
- let result = output;
459
+ return runAfterSync(host, entry, program, source, ctx, finalize, wrapResponse, 0, output);
460
+ }
461
+ function runAfterSync(host, entry, program, source, ctx, finalize, wrapResponse, afterIndex, result) {
384
462
  for (let i = afterIndex; i < program.afterHandle.length; i++) {
385
463
  const outcome = program.afterHandle[i](result, ctx);
386
464
  if (outcome instanceof Promise) {
@@ -413,58 +491,28 @@ async function continueProgram(host, entry, program, source, ctx, finalize, wrap
413
491
  else {
414
492
  result = settled;
415
493
  }
416
- return await runAsyncStages(host, entry, program, source, ctx, finalize, wrapResponse, pendingPhase, result);
494
+ const outcome = runAsyncStages(host, entry, program, source, ctx, finalize, wrapResponse, pendingPhase, result);
495
+ return outcome instanceof Promise ? await outcome : outcome;
417
496
  }
418
497
  catch (error) {
419
498
  return await host.handleProgramError(entry, error, ctx, finalize, wrapResponse);
420
499
  }
421
500
  }
422
- async function runAsyncStages(host, entry, program, source, ctx, finalize, wrapResponse, pendingPhase, result) {
423
- try {
424
- if (pendingPhase.kind === "validation") {
425
- const validations = program.validationStages;
426
- for (let i = pendingPhase.next; i < validations.length; i++) {
427
- const stage = validations[i];
428
- const outcome = stage.kind === "body"
429
- ? await host.readProgramBody(entry, source, ctx)
430
- : host.validateProgramStage(entry, stage, source, ctx);
431
- const settled = outcome instanceof Promise ? await outcome : outcome;
432
- if (settled !== undefined)
433
- return wrapResponse(settled);
434
- }
501
+ function runAsyncStages(host, entry, program, source, ctx, finalize, wrapResponse, pendingPhase, result) {
502
+ // After an actual async boundary, resume the same sync runner until the next pending stage.
503
+ // Sync hooks and finalization need no async function wrapper or additional microtask turn.
504
+ if (pendingPhase.kind === "validation") {
505
+ if (pendingPhase.policy) {
506
+ return runAuthBeforeValidation(host, entry, program, source, ctx, finalize, wrapResponse, true, 0, 0, pendingPhase.next);
435
507
  }
436
- const deriveStart = pendingPhase.kind === "derive" ? pendingPhase.next : 0;
437
- if (pendingPhase.kind === "validation" || pendingPhase.kind === "derive") {
438
- for (let i = deriveStart; i < program.derives.length; i++) {
439
- const outcome = program.derives[i](ctx);
440
- const settled = outcome instanceof Promise ? await outcome : outcome;
441
- if (isEarly(settled))
442
- return finishEarly(host, entry, ctx, settled, finalize, wrapResponse);
443
- Object.assign(ctx, settled);
444
- }
445
- }
446
- const beforeStart = pendingPhase.kind === "before" ? pendingPhase.next : 0;
447
- if (pendingPhase.kind === "validation" ||
448
- pendingPhase.kind === "derive" ||
449
- pendingPhase.kind === "before") {
450
- for (let i = beforeStart; i < program.beforeHandle.length; i++) {
451
- const outcome = program.beforeHandle[i](ctx);
452
- const settled = outcome instanceof Promise ? await outcome : outcome;
453
- if (settled !== undefined)
454
- return finishEarly(host, entry, ctx, settled, finalize, wrapResponse);
455
- }
456
- const output = program.handler(ctx);
457
- result = output instanceof Promise ? await output : output;
458
- }
459
- const afterStart = pendingPhase.kind === "after" ? pendingPhase.next : 0;
460
- for (let i = afterStart; i < program.afterHandle.length; i++) {
461
- const outcome = program.afterHandle[i](result, ctx);
462
- result = outcome instanceof Promise ? await outcome : outcome;
463
- }
464
- return await host.finishProgramResult(entry, ctx, result, finalize, wrapResponse);
508
+ return runSync(host, entry, program, source, ctx, finalize, wrapResponse, pendingPhase.next, result);
465
509
  }
466
- catch (error) {
467
- return await host.handleProgramError(entry, error, ctx, finalize, wrapResponse);
510
+ if (pendingPhase.kind === "derive" || pendingPhase.kind === "before") {
511
+ if (pendingPhase.policy) {
512
+ return runAuthBeforeValidation(host, entry, program, source, ctx, finalize, wrapResponse, false, pendingPhase.kind === "derive" ? pendingPhase.next : program.derives.length, pendingPhase.kind === "before" ? pendingPhase.next : 0);
513
+ }
514
+ return runHooksSync(host, entry, program, source, ctx, finalize, wrapResponse, pendingPhase.kind === "derive" ? pendingPhase.next : program.derives.length, pendingPhase.kind === "before" ? pendingPhase.next : 0, result);
468
515
  }
516
+ return runAfterSync(host, entry, program, source, ctx, finalize, wrapResponse, pendingPhase.kind === "after" ? pendingPhase.next : 0, result);
469
517
  }
470
518
  //# sourceMappingURL=route-program.js.map