@avelonjs/next 0.3.4 → 0.3.6
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/cookies.ts +33 -10
package/package.json
CHANGED
package/src/cookies.ts
CHANGED
|
@@ -2,6 +2,8 @@ import { AsyncLocalStorage } from 'node:async_hooks'
|
|
|
2
2
|
import type { CookieOptions } from '@avelonjs/core'
|
|
3
3
|
import type { ReactNode } from 'react'
|
|
4
4
|
|
|
5
|
+
import { reportFailure } from './failures'
|
|
6
|
+
|
|
5
7
|
/** One cookie write queued during kernel dispatch. */
|
|
6
8
|
export interface PendingCookie {
|
|
7
9
|
/** Cookie name. */
|
|
@@ -111,24 +113,45 @@ function toNextCookieOptions(options?: CookieOptions): Record<string, unknown> {
|
|
|
111
113
|
}
|
|
112
114
|
}
|
|
113
115
|
|
|
114
|
-
|
|
116
|
+
interface NextCookieJar {
|
|
117
|
+
set: (name: string, value: string, options?: Record<string, unknown>) => void
|
|
118
|
+
delete: (name: string) => void
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** The request's cookie jar, or undefined outside a Next runtime. */
|
|
122
|
+
async function nextCookieJar(): Promise<NextCookieJar | undefined> {
|
|
123
|
+
try {
|
|
124
|
+
const headers = (await import('next/headers')) as {
|
|
125
|
+
cookies: () => Promise<NextCookieJar>
|
|
126
|
+
}
|
|
127
|
+
return await headers.cookies()
|
|
128
|
+
} catch {
|
|
129
|
+
// Tests and non-Next hosts have no jar; the queue is already discarded.
|
|
130
|
+
return undefined
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Writes queued cookies through `next/headers` when available.
|
|
136
|
+
*
|
|
137
|
+
* A rejected write is reported rather than swallowed. Next allows a cookie write only from a
|
|
138
|
+
* server action or a route handler, so a controller reached by a page that signs an actor in
|
|
139
|
+
* throws here — and swallowing it produced the worst shape of failure: the driver had already
|
|
140
|
+
* spent the actor's one-time token, the request redirected as though it had worked, and the
|
|
141
|
+
* reader arrived signed out with nothing written anywhere saying why.
|
|
142
|
+
*/
|
|
115
143
|
export async function flushOutgoingCookies(): Promise<void> {
|
|
116
144
|
const pending = takePendingCookies()
|
|
117
145
|
if (pending.length === 0) return
|
|
146
|
+
const jar = await nextCookieJar()
|
|
147
|
+
if (jar === undefined) return
|
|
118
148
|
try {
|
|
119
|
-
const headers = (await import('next/headers')) as {
|
|
120
|
-
cookies: () => Promise<{
|
|
121
|
-
set: (name: string, value: string, options?: Record<string, unknown>) => void
|
|
122
|
-
delete: (name: string) => void
|
|
123
|
-
}>
|
|
124
|
-
}
|
|
125
|
-
const jar = await headers.cookies()
|
|
126
149
|
for (const cookie of pending) {
|
|
127
150
|
if (cookie.value === null) jar.delete(cookie.name)
|
|
128
151
|
else jar.set(cookie.name, cookie.value, toNextCookieOptions(cookie.options))
|
|
129
152
|
}
|
|
130
|
-
} catch {
|
|
131
|
-
|
|
153
|
+
} catch (error) {
|
|
154
|
+
reportFailure('cookies', pending.map((cookie) => cookie.name).join(', '), error)
|
|
132
155
|
}
|
|
133
156
|
}
|
|
134
157
|
|