From 59bd477e4f9f7fcc8aaead6f37243127e18c96b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rge=20N=C3=A6ss?= Date: Tue, 3 Dec 2024 13:31:50 +0100 Subject: [PATCH] feat(query): add support for release perspectives (#934) * feat(query): add support for release perspectives * feat(query): allow perspective=drafts --- src/config.ts | 26 ++++++++++++++++++++++++-- src/data/dataMethods.ts | 15 ++++++++++----- src/types.ts | 10 +++++++++- test/client.test.ts | 24 ++++++++++++++++++++++++ 4 files changed, 67 insertions(+), 8 deletions(-) diff --git a/src/config.ts b/src/config.ts index 32b2f2b3..dcf6c4a4 100644 --- a/src/config.ts +++ b/src/config.ts @@ -28,9 +28,31 @@ function validateApiVersion(apiVersion: string) { } } -export const validateApiPerspective = function validateApiPerspective(perspective: string) { +export const validateApiPerspective = function validateApiPerspective(perspective: unknown) { + if (Array.isArray(perspective)) { + for (const perspectiveValue of perspective) { + if (perspectiveValue === 'published') { + continue + } + if (perspectiveValue === 'drafts') { + continue + } + if ( + typeof perspectiveValue === 'string' && + perspectiveValue.startsWith('r') && + perspectiveValue !== 'raw' + ) { + continue + } + throw new TypeError( + 'Invalid API perspective value, expected `published`, `drafts` or a valid release identifier string', + ) + } + return + } switch (perspective as ClientPerspective) { case 'previewDrafts': + case 'drafts': case 'published': case 'raw': return @@ -74,7 +96,7 @@ export const initConfig = ( throw new Error('Configuration must contain `projectId`') } - if (typeof newConfig.perspective === 'string') { + if (typeof newConfig.perspective !== 'undefined') { validateApiPerspective(newConfig.perspective) } diff --git a/src/data/dataMethods.ts b/src/data/dataMethods.ts index 8bc25f83..77af8a87 100644 --- a/src/data/dataMethods.ts +++ b/src/data/dataMethods.ts @@ -405,12 +405,17 @@ export function _requestObservable( if (resultSourceMap !== undefined && resultSourceMap !== false) { options.query = {resultSourceMap, ...options.query} } - const perspective = options.perspective || config.perspective - if (typeof perspective === 'string' && perspective !== 'raw') { - validateApiPerspective(perspective) - options.query = {perspective, ...options.query} + const perspectiveOption = options.perspective || config.perspective + if (typeof perspectiveOption !== 'undefined') { + validateApiPerspective(perspectiveOption) + options.query = { + perspective: Array.isArray(perspectiveOption) + ? perspectiveOption.join(',') + : perspectiveOption, + ...options.query, + } // If the perspective is set to `previewDrafts` we can't use the CDN, the API will throw - if (perspective === 'previewDrafts' && useCdn) { + if (perspectiveOption === 'previewDrafts' && useCdn) { useCdn = false printCdnPreviewDraftsWarning() } diff --git a/src/types.ts b/src/types.ts index cc40dd1f..c1af94e6 100644 --- a/src/types.ts +++ b/src/types.ts @@ -32,7 +32,15 @@ export interface RequestOptions { } /** @public */ -export type ClientPerspective = 'previewDrafts' | 'published' | 'raw' +export type ReleaseId = `r${string}` + +/** @public */ +export type ClientPerspective = + | 'previewDrafts' + | 'published' + | 'drafts' + | 'raw' + | ('published' | 'drafts' | ReleaseId)[] /** @public */ export interface ClientConfig { diff --git a/test/client.test.ts b/test/client.test.ts index ff2ddd30..1da99d12 100644 --- a/test/client.test.ts +++ b/test/client.test.ts @@ -171,6 +171,9 @@ describe('client', async () => { expect(() => createClient({projectId: 'abc123', perspective: 'previewDrafts'})).not.toThrow( /Invalid API perspective/, ) + expect(() => createClient({projectId: 'abc123', perspective: 'drafts'})).not.toThrow( + /Invalid API perspective/, + ) expect(() => createClient({projectId: 'abc123', perspective: 'raw'})).not.toThrow( /Invalid API perspective/, ) @@ -178,6 +181,27 @@ describe('client', async () => { expect(() => createClient({projectId: 'abc123', perspective: 'preview drafts'})).toThrow( /Invalid API perspective/, ) + + // valid because it begins with `r` + const validReleaseIdentifier = 'rfoobar' + expect(() => + createClient({ + projectId: 'abc123', + perspective: ['published', 'drafts', validReleaseIdentifier], + }), + ).not.toThrow(/Invalid API perspective/) + + // special case – "raw" would be a valid release id given that it starts with ´r` + // but 'raw' is not possible to use with multiple perspectives and is explicitly + // banned by the backend + expect(() => + createClient({projectId: 'abc123', perspective: ['published', 'drafts', 'raw']}), + ).toThrow(/Invalid API perspective/) + + expect(() => + // @ts-expect-error -- we want to test that it throws an error + createClient({projectId: 'abc123', perspective: ['XyzAbC']}), + ).toThrow(/Invalid API perspective/) }) test('throws on invalid project ids', () => {