@pikku/core 0.12.30 → 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 +105 -0
- package/dist/data-classification.d.ts +3 -3
- 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/data-classification.ts +10 -3
- 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
package/src/types/state.types.ts
CHANGED
|
@@ -171,6 +171,11 @@ export interface PikkuPackageState {
|
|
|
171
171
|
} | null
|
|
172
172
|
/** Cached singleton services for this package */
|
|
173
173
|
singletonServices: CoreSingletonServices | null
|
|
174
|
+
/** The pikkuBetterAuth factory, self-registered when auth.ts is evaluated.
|
|
175
|
+
* pikkuServices reads it to build and inject the `auth` singleton. */
|
|
176
|
+
authFactory:
|
|
177
|
+
| ((services: CoreSingletonServices) => unknown | Promise<unknown>)
|
|
178
|
+
| null
|
|
174
179
|
/** Credential metadata for this addon package */
|
|
175
180
|
credentialsMeta: Record<
|
|
176
181
|
string,
|
|
@@ -272,6 +272,19 @@ describe('http-runner helpers', () => {
|
|
|
272
272
|
)
|
|
273
273
|
})
|
|
274
274
|
|
|
275
|
+
test('addHTTPMiddleware composes repeated registrations for the same pattern', () => {
|
|
276
|
+
const first: CorePikkuMiddleware = async (_s, _w, next) => next()
|
|
277
|
+
const second: CorePikkuMiddleware = async (_s, _w, next) => next()
|
|
278
|
+
|
|
279
|
+
addHTTPMiddleware('*', [first])
|
|
280
|
+
addHTTPMiddleware('*', [second])
|
|
281
|
+
|
|
282
|
+
assert.deepEqual(pikkuState(null, 'middleware', 'httpGroup')['*'], [
|
|
283
|
+
first,
|
|
284
|
+
second,
|
|
285
|
+
])
|
|
286
|
+
})
|
|
287
|
+
|
|
275
288
|
test('createHTTPWire combines request and response when present', () => {
|
|
276
289
|
const req = new TestRequest('/x', 'get')
|
|
277
290
|
const res = new TestResponse()
|
|
@@ -96,7 +96,10 @@ export const addHTTPMiddleware = <PikkuMiddleware extends CorePikkuMiddleware>(
|
|
|
96
96
|
packageName: string | null = null
|
|
97
97
|
): CorePikkuMiddlewareGroup => {
|
|
98
98
|
const httpGroups = pikkuState(packageName, 'middleware', 'httpGroup')
|
|
99
|
-
httpGroups[pattern]
|
|
99
|
+
const existing = httpGroups[pattern] as CorePikkuMiddleware[] | undefined
|
|
100
|
+
httpGroups[pattern] = existing
|
|
101
|
+
? [...existing, ...(middleware as CorePikkuMiddleware[])]
|
|
102
|
+
: middleware
|
|
100
103
|
return middleware
|
|
101
104
|
}
|
|
102
105
|
|
|
@@ -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) {
|