Skip to content
Merged
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
4 changes: 4 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ export default antfu({
name: ['*', 'bytes'],
message: 'Request/Blob/Response/... .bytes is not widely supported, use readAsBuffer instead',
},
{
name: ['*', 'throwIfAborted'],
message: 'React Native\'s AbortSignal polyfill has no throwIfAborted, use throwIfAborted from @standard-server/shared instead',
},
],
},
}, {
Expand Down
6 changes: 3 additions & 3 deletions packages/peer/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { StandardBody, StandardLazyResponse, StandardRequest } from '@stand
import type { Queue } from '@standard-server/shared'
import type { ClientPeerSendMessage, PeerEventStreamMessage, PeerOctetStreamMessage, ServerPeerSendMessage } from './types'
import { cancelStandardBody } from '@standard-server/core'
import { AbortError, hasAnyDefinedValue, isAsyncIteratorObject, SequentialIdGenerator } from '@standard-server/shared'
import { AbortError, hasAnyDefinedValue, isAsyncIteratorObject, SequentialIdGenerator, throwIfAborted } from '@standard-server/shared'
import { encodeAtomicStandardBody, toStandardBody } from './body'
import { EventStreamTransmitter } from './event-stream'
import { OctetStreamTransmitter } from './octet-stream'
Expand Down Expand Up @@ -32,7 +32,7 @@ export class ClientPeer {
request(request: StandardRequest): Promise<StandardLazyResponse> {
return new Promise<StandardLazyResponse>((resolve, reject) => {
const signal = request.signal
signal?.throwIfAborted()
throwIfAborted(signal)

const id = this.idGenerator.generate()
const state: ClientPeerRequestStateInternal = { resolve, reject }
Expand Down Expand Up @@ -69,7 +69,7 @@ export class ClientPeer {
const encodedAtomicBody = await encodeAtomicStandardBody(request.body, request.headers)

// signal can be aborted during encode
request.signal?.throwIfAborted()
throwIfAborted(request.signal)

// the peer can be closed during encode
if (this.requests.get(id) !== state) {
Expand Down
1 change: 1 addition & 0 deletions packages/shared/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export * from './object'
export * from './promise'
export * from './proxy'
export * from './queue'
export { throwIfAborted } from './signal'
export * from './time'
export * from './types'
export * from './uri'
17 changes: 16 additions & 1 deletion packages/shared/src/signal.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { describe, expect, it, vi } from 'vitest'
import { anyAbortSignal } from './signal'
import { anyAbortSignal, throwIfAborted } from './signal'

/**
* Helper to temporarily disable AbortSignal.any to force fallback implementation.
Expand Down Expand Up @@ -105,3 +105,18 @@ describe('anyAbortSignal', () => {
})
})
})

describe('throwIfAborted', () => {
it('works on a signal without throwIfAborted (React Native polyfill)', () => {
const controller = new AbortController()
Object.defineProperty(controller.signal, 'throwIfAborted', { value: undefined })

expect(() => throwIfAborted(undefined)).not.toThrow()
expect(() => throwIfAborted(controller.signal)).not.toThrow()

const reason = new Error('aborted')
controller.abort(reason)

expect(() => throwIfAborted(controller.signal)).toThrow(reason)
})
})
10 changes: 10 additions & 0 deletions packages/shared/src/signal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,13 @@ export function anyAbortSignal(...signals: (AbortSignal | undefined)[]): AbortSi

return controller.signal
}

/**
* Throws the signal's abort reason if it is aborted, like `signal.throwIfAborted()`.
* React Native's AbortSignal polyfill has no `throwIfAborted`, so use this instead.
*/
export function throwIfAborted(signal: AbortSignal | undefined | null): void {
if (signal?.aborted) {
throw signal.reason
}
}
7 changes: 3 additions & 4 deletions packages/shared/src/time.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { throwIfAborted } from './signal'

export interface SleepOptions {
signal?: AbortSignal | undefined
}
Expand All @@ -7,10 +9,7 @@ export interface SleepOptions {
*/
export function sleep(ms: number, { signal }: SleepOptions = {}): Promise<void> {
return new Promise((resolve, reject) => {
if (signal?.aborted) {
reject(signal.reason)
return
}
throwIfAborted(signal)

let abortListener: (() => void) | null = null

Expand Down
3 changes: 2 additions & 1 deletion tests/client-server.node-http2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import * as http2 from 'node:http2'
import { Readable } from 'node:stream'
import { toFetchBody, toFetchHeaders, toStandardLazyResponse } from '@standard-server/fetch'
import { sendStandardResponse, toStandardLazyRequest } from '@standard-server/node'
import { throwIfAborted } from '@standard-server/shared'
import { generateTlsCert } from './tls'

export interface NodeHttp2ClientServerTestOptions {
Expand Down Expand Up @@ -57,7 +58,7 @@ export function createNodeHttp2ClientServerTest(options: NodeHttp2ClientServerTe
})

const request: ClientServerTest['request'] = vi.fn(async (standardRequest) => {
standardRequest.signal?.throwIfAborted()
throwIfAborted(standardRequest.signal)

const { session, port } = await serverReady

Expand Down
3 changes: 2 additions & 1 deletion tests/client-server.node-https.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import * as https from 'node:https'
import { Readable } from 'node:stream'
import { toFetchBody, toFetchHeaders, toStandardLazyResponse } from '@standard-server/fetch'
import { sendStandardResponse, toStandardLazyRequest } from '@standard-server/node'
import { throwIfAborted } from '@standard-server/shared'
import { generateTlsCert } from './tls'

export function createNodeHttpsClientServerTest(): ClientServerTest {
Expand Down Expand Up @@ -39,7 +40,7 @@ export function createNodeHttpsClientServerTest(): ClientServerTest {
})

const request: ClientServerTest['request'] = vi.fn(async (standardRequest) => {
standardRequest.signal?.throwIfAborted()
throwIfAborted(standardRequest.signal)

const { agent, port } = await serverReady

Expand Down
Loading