@avelonjs/next 0.3.5 → 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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/cookies.ts +33 -10
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@avelonjs/next",
3
- "version": "0.3.5",
3
+ "version": "0.3.6",
4
4
  "private": false,
5
5
  "description": "Next.js adapter for Avelon routing, server actions, and pages.",
6
6
  "license": "MIT",
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
- /** Writes queued cookies through `next/headers` when available. */
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
- // Tests and non-Next hosts keep the queue discarded after takePendingCookies.
153
+ } catch (error) {
154
+ reportFailure('cookies', pending.map((cookie) => cookie.name).join(', '), error)
132
155
  }
133
156
  }
134
157