Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/start-middleware-registration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@tanstack/start-client-core': patch
---

Avoid an unused array when registering server-function middleware.
11 changes: 6 additions & 5 deletions packages/start-client-core/src/createServerFn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,13 +102,14 @@ export const createServerFn: CreateServerFn<Register> = (options, __opts) => {
// this is primarily useful for letting users create their own abstractions on top of `createServerFn`

const newMiddleware = [...(resolvedOptions.middleware || [])]
middleware.map((m) => {
if (TSS_SERVER_FUNCTION_FACTORY in m) {
if (m.options.middleware) {
newMiddleware.push(...m.options.middleware)
// forEach skips holes and ignores items appended during iteration
middleware.forEach((item) => {
if (TSS_SERVER_FUNCTION_FACTORY in item) {
if (item.options.middleware) {
newMiddleware.push(...item.options.middleware)
}
} else {
newMiddleware.push(m)
newMiddleware.push(item)
}
})

Expand Down
54 changes: 54 additions & 0 deletions packages/start-client-core/tests/createServerFn.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { expect, test } from 'vitest'
import { createMiddleware } from '../src/createMiddleware'
import { createServerFn } from '../src/createServerFn'

test('appends factory middleware in order without changing source builders', () => {
const first = createMiddleware({ type: 'function' })
const second = createMiddleware({ type: 'function' })
const third = createMiddleware({ type: 'function' })
const factory = createServerFn().middleware([second])
const base = createServerFn({ method: 'POST' }).middleware([first])
const middlewares = Object.freeze([factory, third, second])

const combined = base.middleware(middlewares)

expect(combined.options.middleware).toEqual([first, second, third, second])
expect(combined.options.method).toBe('POST')
expect(base.options.middleware).toEqual([first])
expect(factory.options.middleware).toEqual([second])
expect(middlewares).toEqual([factory, third, second])
expect(combined.middleware([]).options.middleware).toEqual([
first,
second,
third,
second,
])
})

test('ignores empty slots in a middleware array', () => {
const middleware = createMiddleware({ type: 'function' })
const middlewares: Array<typeof middleware> = []
middlewares[1] = middleware

expect(createServerFn().middleware(middlewares).options.middleware).toEqual([
middleware,
])
expect(0 in middlewares).toBe(false)
})

test('does not register middleware appended while reading the input', () => {
const first = createMiddleware({ type: 'function' })
const second = createMiddleware({ type: 'function' })
const middlewares = [first]
Object.defineProperty(middlewares, 0, {
get() {
middlewares.push(second)
return first
},
})

expect(createServerFn().middleware(middlewares).options.middleware).toEqual([
first,
])
expect(middlewares).toHaveLength(2)
})
Loading