@pikku/core 0.12.31 → 0.12.32
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/CHANGELOG.md +82 -0
- package/dist/middleware-runner.js +4 -1
- package/dist/pikku-state.js +1 -0
- package/dist/services/gopass-secrets.d.ts +1 -1
- package/dist/services/local-secrets.d.ts +1 -1
- package/dist/services/local-variables.d.ts +1 -0
- package/dist/services/local-variables.js +9 -0
- package/dist/services/scoped-secret-service.d.ts +1 -1
- package/dist/services/scoped-secret-service.js +2 -2
- package/dist/services/secret-service.d.ts +6 -2
- package/dist/services/typed-secret-service.d.ts +1 -1
- package/dist/services/typed-variables-service.d.ts +1 -0
- package/dist/services/typed-variables-service.js +3 -0
- package/dist/services/variables-service.d.ts +9 -0
- package/dist/types/state.types.d.ts +3 -0
- package/dist/wirings/http/http-runner.js +4 -1
- package/dist/wirings/http/pikku-fetch-http-request.js +34 -20
- package/dist/wirings/http/web-request.js +6 -1
- package/package.json +1 -1
- package/src/middleware-runner.test.ts +16 -1
- package/src/middleware-runner.ts +4 -1
- package/src/pikku-state.ts +1 -0
- package/src/services/gopass-secrets.ts +4 -2
- package/src/services/local-secrets.ts +4 -2
- package/src/services/local-variables.ts +11 -0
- package/src/services/scoped-secret-service.test.ts +20 -0
- package/src/services/scoped-secret-service.ts +5 -3
- package/src/services/secret-service.ts +8 -2
- package/src/services/typed-secret-service.ts +4 -2
- package/src/services/typed-variables-service.ts +6 -0
- package/src/services/variables-service.ts +11 -0
- package/src/types/state.types.ts +5 -0
- package/src/wirings/http/http-runner.test.ts +13 -0
- package/src/wirings/http/http-runner.ts +4 -1
- package/src/wirings/http/pikku-fetch-http-request.ts +37 -20
- package/src/wirings/http/web-request.test.ts +2 -2
- package/src/wirings/http/web-request.ts +6 -1
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -16,7 +16,7 @@ export class PikkuFetchHTTPRequest<
|
|
|
16
16
|
#url: URL
|
|
17
17
|
#rawBodyText: string | undefined
|
|
18
18
|
#rawBodyBuffer: ArrayBuffer | undefined
|
|
19
|
-
#
|
|
19
|
+
#rawBufferPromise: Promise<ArrayBuffer> | undefined
|
|
20
20
|
|
|
21
21
|
constructor(private request: Request) {
|
|
22
22
|
this.#url = new URL(request.url)
|
|
@@ -44,36 +44,53 @@ export class PikkuFetchHTTPRequest<
|
|
|
44
44
|
* @returns A promise that resolves to the raw request body.
|
|
45
45
|
*/
|
|
46
46
|
public async arrayBuffer(): Promise<ArrayBuffer> {
|
|
47
|
+
return this.#readRawBuffer()
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Reads the underlying single-use request body exactly once and memoises both
|
|
52
|
+
* the in-flight promise and the result. `json()`, `arrayBuffer()`, `body()`
|
|
53
|
+
* and `toWebRequest()` all funnel through here, so a request whose body is
|
|
54
|
+
* consumed in more than one place can no longer race on the underlying stream
|
|
55
|
+
* and fail with "Body has already been used".
|
|
56
|
+
*
|
|
57
|
+
* If a second consumer asks for the body while the first read is still in
|
|
58
|
+
* flight, that is the concurrent double-read that used to crash — now safe,
|
|
59
|
+
* but warned about so the redundant consumer is found and removed at the
|
|
60
|
+
* source rather than silently leaning on this cache.
|
|
61
|
+
*/
|
|
62
|
+
async #readRawBuffer(): Promise<ArrayBuffer> {
|
|
47
63
|
if (this.#rawBodyBuffer !== undefined) {
|
|
48
64
|
return this.#rawBodyBuffer
|
|
49
65
|
}
|
|
50
|
-
if (this.#
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
66
|
+
if (this.#rawBodyText !== undefined) {
|
|
67
|
+
const buf = new TextEncoder().encode(this.#rawBodyText)
|
|
68
|
+
.buffer as ArrayBuffer
|
|
69
|
+
this.#rawBodyBuffer = buf
|
|
70
|
+
return buf
|
|
71
|
+
}
|
|
72
|
+
if (this.#rawBufferPromise !== undefined) {
|
|
73
|
+
console.warn(
|
|
74
|
+
`[pikku] request body for ${this.method().toUpperCase()} ${this.path()} ` +
|
|
75
|
+
`was requested again before the first read resolved — the read is now ` +
|
|
76
|
+
`shared, but a duplicate body consumer (e.g. middleware calling ` +
|
|
77
|
+
`toWebRequest just for headers) should be removed.`
|
|
78
|
+
)
|
|
79
|
+
return this.#rawBufferPromise
|
|
58
80
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
81
|
+
this.#rawBufferPromise = this.request.arrayBuffer().then((buf) => {
|
|
82
|
+
this.#rawBodyBuffer = buf
|
|
83
|
+
return buf
|
|
84
|
+
})
|
|
85
|
+
return this.#rawBufferPromise
|
|
63
86
|
}
|
|
64
87
|
|
|
65
88
|
async #readRawText(): Promise<string> {
|
|
66
89
|
if (this.#rawBodyText !== undefined) {
|
|
67
90
|
return this.#rawBodyText
|
|
68
91
|
}
|
|
69
|
-
|
|
70
|
-
const text = new TextDecoder().decode(this.#rawBodyBuffer)
|
|
71
|
-
this.#rawBodyText = text
|
|
72
|
-
return text
|
|
73
|
-
}
|
|
74
|
-
const text = await this.request.text()
|
|
92
|
+
const text = new TextDecoder().decode(await this.#readRawBuffer())
|
|
75
93
|
this.#rawBodyText = text
|
|
76
|
-
this.#bodyRead = true
|
|
77
94
|
return text
|
|
78
95
|
}
|
|
79
96
|
|
|
@@ -274,8 +274,8 @@ describe('applyWebResponse', () => {
|
|
|
274
274
|
const { res, state } = createMockResponse()
|
|
275
275
|
const webRes = new Response('{"csrfToken":"abc"}', { status: 200 })
|
|
276
276
|
const cookies = [
|
|
277
|
-
'
|
|
278
|
-
'
|
|
277
|
+
'better-auth.session_token=abc; Path=/; HttpOnly',
|
|
278
|
+
'better-auth.callback-url=http%3A%2F%2Flocalhost; Path=/; HttpOnly',
|
|
279
279
|
]
|
|
280
280
|
;(webRes.headers as any).getSetCookie = () => cookies
|
|
281
281
|
|
|
@@ -30,8 +30,13 @@ export function toWebRequest(req: PikkuHTTPRequest, baseUrl?: string): Request {
|
|
|
30
30
|
return new Request(url, {
|
|
31
31
|
method,
|
|
32
32
|
headers,
|
|
33
|
+
// `pull` (lazy) rather than `start` (eager): the body is only read from the
|
|
34
|
+
// underlying request when this stream is actually consumed. A consumer that
|
|
35
|
+
// builds a web Request just to read its headers (e.g. a session middleware
|
|
36
|
+
// calling getSession({ headers })) never touches the body, so it does zero
|
|
37
|
+
// body I/O and cannot race the route handler's read of the same request.
|
|
33
38
|
body: new ReadableStream({
|
|
34
|
-
async
|
|
39
|
+
async pull(controller) {
|
|
35
40
|
try {
|
|
36
41
|
const buffer = await req.arrayBuffer()
|
|
37
42
|
if (buffer.byteLength > 0) {
|