Skip to content

Commit

Permalink
feat(live): add experimental includeDrafts option (#890)
Browse files Browse the repository at this point in the history
  • Loading branch information
stipsan authored Sep 23, 2024
1 parent 847ad5b commit e1406b1
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 8 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@sanity/client",
"version": "6.21.3",
"version": "6.21.4-canary.2",
"description": "Client for retrieving, creating and patching data from Sanity.io",
"keywords": [
"sanity",
Expand Down
35 changes: 30 additions & 5 deletions src/data/live.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,44 @@ export class LiveClient {
/**
* Requires `apiVersion` to be `2021-03-26` or later.
*/
events(): Observable<LiveEventMessage | LiveEventRestart> {
const apiVersion = this.#client.config().apiVersion.replace(/^v/, '')
events({
includeDrafts = false,
}: {
/** @alpha this API is experimental and may change or even be removed */
includeDrafts?: boolean
} = {}): Observable<LiveEventMessage | LiveEventRestart> {
const {apiVersion: _apiVersion, token} = this.#client.config()
const apiVersion = _apiVersion.replace(/^v/, '')
if (apiVersion !== 'X' && apiVersion < requiredApiVersion) {
throw new Error(
`The live events API requires API version ${requiredApiVersion} or later. ` +
`The current API version is ${apiVersion}. ` +
`Please update your API version to use this feature.`,
)
}
if (includeDrafts && !token) {
throw new Error(
`The live events API requires a token when 'includeDrafts: true'. Please update your client configuration. The token should have the lowest possible access role.`,
)
}
if (includeDrafts && apiVersion !== 'X') {
throw new Error(
`The live events API requires API version X when 'includeDrafts: true'. This API is experimental and may change or even be removed.`,
)
}
const path = _getDataUrl(this.#client, 'live/events')
const url = new URL(this.#client.getUrl(path, false))
if (includeDrafts) {
url.searchParams.set('includeDrafts', 'true')
}

const listenFor = ['restart', 'message'] as const
const esOptions: EventSourceInit & {headers?: Record<string, string>} = {}
if (includeDrafts && token) {
esOptions.headers = {
Authorization: `Bearer ${token}`,
}
}

return new Observable((observer) => {
let es: InstanceType<typeof EventSource> | undefined
Expand Down Expand Up @@ -83,8 +108,8 @@ export class LiveClient {

async function getEventSource() {
const EventSourceImplementation: typeof EventSource =
typeof EventSource === 'undefined'
? ((await import('@sanity/eventsource')).default as typeof EventSource)
typeof EventSource === 'undefined' || esOptions.headers
? ((await import('@sanity/eventsource')).default as unknown as typeof EventSource)
: EventSource

// If the listener has been unsubscribed from before we managed to load the module,
Expand All @@ -93,7 +118,7 @@ export class LiveClient {
return
}

const evs = new EventSourceImplementation(url.toString())
const evs = new EventSourceImplementation(url.toString(), esOptions)
evs.addEventListener('error', onError)
for (const type of listenFor) {
evs.addEventListener(type, onMessage)
Expand Down
56 changes: 56 additions & 0 deletions test/live.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,19 @@ describe.skipIf(typeof EdgeRuntime === 'string' || typeof document !== 'undefine
`[Error: The live events API requires API version 2021-03-26 or later. The current API version is 2020-01-01. Please update your API version to use this feature.]`,
)
})
test('requires token when includeDrafts is true', () => {
const client = getClient({apiVersion: 'vX', port: 1234})
expect(() => client.live.events({includeDrafts: true})).toThrowErrorMatchingInlineSnapshot(
`[Error: The live events API requires a token when 'includeDrafts: true'. Please update your client configuration. The token should have the lowest possible access role.]`,
)
})
test('requires apiVersion X when includeDrafts is true', () => {
const client = getClient({apiVersion: 'v2021-03-26', token: 'abc123', port: 1234})
expect(() => client.live.events({includeDrafts: true})).toThrowErrorMatchingInlineSnapshot(
`[Error: The live events API requires API version X when 'includeDrafts: true'. This API is experimental and may change or even be removed.]`,
)
})

test('can listen for tags', async () => {
expect.assertions(2)

Expand Down Expand Up @@ -102,6 +115,49 @@ describe.skipIf(typeof EdgeRuntime === 'string' || typeof document !== 'undefine
}
})

test('can listen for tags with includeDrafts', async () => {
expect.assertions(2)

const eventData = {
tags: ['tag1', 'tag2'],
}

const {server, client} = await testSse(
({request, channel}) => {
expect(request.url, 'url should be correct').toEqual(
`/vX/data/live/events/prod?includeDrafts=true`,
)

channel!.send({id: '123', data: eventData})
process.nextTick(() => channel!.close())
},
{token: 'abc123'},
)

try {
await new Promise<void>((resolve, reject) => {
const subscription = client.live.events({includeDrafts: true}).subscribe({
next: (msg) => {
expect(msg, 'event data should be correct').toEqual({
...eventData,
id: '123',
type: 'message',
})

subscription.unsubscribe()
resolve()
},
error: (err) => {
subscription.unsubscribe()
reject(err)
},
})
})
} finally {
server.close()
}
})

test('supports restart events', async () => {
expect.assertions(1)

Expand Down

0 comments on commit e1406b1

Please sign in to comment.