effect-start 0.15.0 → 0.16.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.
- package/package.json +1 -1
- package/src/ContentNegotiation.test.ts +103 -0
- package/src/ContentNegotiation.ts +10 -3
- package/src/Entity.test.ts +592 -0
- package/src/Entity.ts +362 -0
- package/src/Http.test.ts +315 -20
- package/src/Http.ts +153 -11
- package/src/PathPattern.ts +3 -1
- package/src/Route.ts +22 -10
- package/src/RouteBody.test.ts +81 -29
- package/src/RouteBody.ts +122 -35
- package/src/RouteHook.ts +15 -14
- package/src/RouteHttp.test.ts +2546 -83
- package/src/RouteHttp.ts +321 -113
- package/src/RouteHttpTracer.ts +92 -0
- package/src/RouteMount.test.ts +23 -10
- package/src/RouteMount.ts +161 -4
- package/src/RouteSchema.test.ts +346 -0
- package/src/RouteSchema.ts +386 -7
- package/src/RouteTree.test.ts +233 -85
- package/src/RouteTree.ts +98 -44
- package/src/StreamExtra.ts +21 -1
- package/src/Values.test.ts +263 -0
- package/src/Values.ts +60 -0
- package/src/bun/BunHttpServer.ts +23 -7
- package/src/bun/BunRoute.test.ts +162 -0
- package/src/bun/BunRoute.ts +146 -105
- package/src/index.ts +1 -0
- package/src/testing/TestLogger.test.ts +0 -3
- package/src/testing/TestLogger.ts +15 -9
package/package.json
CHANGED
|
@@ -148,6 +148,109 @@ test.describe("ContentNegotiation.media", () => {
|
|
|
148
148
|
.expect(result)
|
|
149
149
|
.toEqual(["text/html", "application/json"])
|
|
150
150
|
})
|
|
151
|
+
|
|
152
|
+
test.describe("wildcard in available types", () => {
|
|
153
|
+
test.it("text/* matches text/event-stream", () => {
|
|
154
|
+
const result = ContentNegotiation.media(
|
|
155
|
+
"text/event-stream",
|
|
156
|
+
["text/*", "application/json"],
|
|
157
|
+
)
|
|
158
|
+
test
|
|
159
|
+
.expect(result)
|
|
160
|
+
.toEqual(["text/*"])
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
test.it("text/* matches text/markdown", () => {
|
|
164
|
+
const result = ContentNegotiation.media(
|
|
165
|
+
"text/markdown",
|
|
166
|
+
["text/*"],
|
|
167
|
+
)
|
|
168
|
+
test
|
|
169
|
+
.expect(result)
|
|
170
|
+
.toEqual(["text/*"])
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
test.it("text/* matches text/plain", () => {
|
|
174
|
+
const result = ContentNegotiation.media(
|
|
175
|
+
"text/plain",
|
|
176
|
+
["text/*"],
|
|
177
|
+
)
|
|
178
|
+
test
|
|
179
|
+
.expect(result)
|
|
180
|
+
.toEqual(["text/*"])
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
test.it("text/* does not match application/json", () => {
|
|
184
|
+
const result = ContentNegotiation.media(
|
|
185
|
+
"application/json",
|
|
186
|
+
["text/*"],
|
|
187
|
+
)
|
|
188
|
+
test
|
|
189
|
+
.expect(result)
|
|
190
|
+
.toEqual([])
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
test.it("prefers exact match over wildcard available type", () => {
|
|
194
|
+
const result = ContentNegotiation.media(
|
|
195
|
+
"text/html",
|
|
196
|
+
["text/*", "text/html"],
|
|
197
|
+
)
|
|
198
|
+
test
|
|
199
|
+
.expect(result)
|
|
200
|
+
.toEqual(["text/html", "text/*"])
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
test.it("text/* matches multiple text types in Accept", () => {
|
|
204
|
+
const result = ContentNegotiation.media(
|
|
205
|
+
"text/html, text/plain",
|
|
206
|
+
["text/*"],
|
|
207
|
+
)
|
|
208
|
+
test
|
|
209
|
+
.expect(result)
|
|
210
|
+
.toEqual(["text/*"])
|
|
211
|
+
})
|
|
212
|
+
|
|
213
|
+
test.it("application/* matches application/xml", () => {
|
|
214
|
+
const result = ContentNegotiation.media(
|
|
215
|
+
"application/xml",
|
|
216
|
+
["application/*", "text/html"],
|
|
217
|
+
)
|
|
218
|
+
test
|
|
219
|
+
.expect(result)
|
|
220
|
+
.toEqual(["application/*"])
|
|
221
|
+
})
|
|
222
|
+
|
|
223
|
+
test.it("*/* in available matches any type", () => {
|
|
224
|
+
const result = ContentNegotiation.media(
|
|
225
|
+
"image/png",
|
|
226
|
+
["*/*"],
|
|
227
|
+
)
|
|
228
|
+
test
|
|
229
|
+
.expect(result)
|
|
230
|
+
.toEqual(["*/*"])
|
|
231
|
+
})
|
|
232
|
+
|
|
233
|
+
test.it("combines client and server wildcards", () => {
|
|
234
|
+
// Client wants text/*, server offers text/*
|
|
235
|
+
const result = ContentNegotiation.media(
|
|
236
|
+
"text/*",
|
|
237
|
+
["text/*"],
|
|
238
|
+
)
|
|
239
|
+
test
|
|
240
|
+
.expect(result)
|
|
241
|
+
.toEqual(["text/*"])
|
|
242
|
+
})
|
|
243
|
+
|
|
244
|
+
test.it("quality values still apply with wildcard available", () => {
|
|
245
|
+
const result = ContentNegotiation.media(
|
|
246
|
+
"text/html;q=0.5, text/event-stream;q=0.9",
|
|
247
|
+
["text/*"],
|
|
248
|
+
)
|
|
249
|
+
test
|
|
250
|
+
.expect(result)
|
|
251
|
+
.toEqual(["text/*"])
|
|
252
|
+
})
|
|
253
|
+
})
|
|
151
254
|
})
|
|
152
255
|
|
|
153
256
|
test.describe("ContentNegotiation.language", () => {
|
|
@@ -113,17 +113,24 @@ function specifyMediaType(
|
|
|
113
113
|
let s = 0
|
|
114
114
|
|
|
115
115
|
if (spec.type === type) {
|
|
116
|
-
s |= 4
|
|
116
|
+
s |= 4 // exact match: highest specificity
|
|
117
|
+
} else if (type === "*") {
|
|
118
|
+
s |= 0 // server offers wildcard (e.g. */*): matches any client type
|
|
117
119
|
} else if (spec.type !== "*") {
|
|
120
|
+
// client is NOT requesting wildcard: no match
|
|
118
121
|
return null
|
|
119
122
|
}
|
|
120
123
|
|
|
124
|
+
// client requests wildcard (e.g. Accept: */*)
|
|
121
125
|
if (spec.subtype === subtype) {
|
|
122
|
-
s |= 2
|
|
126
|
+
s |= 2 // // exact match: highest specificity
|
|
127
|
+
} else if (subtype === "*") {
|
|
128
|
+
s |= 1 // server offers wildcard (e.g. text/*)
|
|
123
129
|
} else if (spec.subtype !== "*") {
|
|
124
|
-
return null
|
|
130
|
+
return null // client is NOT requesting wildcard
|
|
125
131
|
}
|
|
126
132
|
|
|
133
|
+
// client requests wildcard (e.g. Accept: text/*): matches any server subtype
|
|
127
134
|
const specParams = Object.keys(spec.params)
|
|
128
135
|
if (specParams.length > 0) {
|
|
129
136
|
if (
|