Skip to content

Commit cd31858

Browse files
refactor: simplify the client constructor (#420)
* refactor: simplify the client constructor * fix: warnings and bindings * test: adjust expected fetch error * refactor: use destructured `documentAPIEndpoint`
1 parent 31d5815 commit cd31858

File tree

2 files changed

+75
-71
lines changed

2 files changed

+75
-71
lines changed

src/Client.ts

Lines changed: 74 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ export class Client<TDocuments extends PrismicDocument = PrismicDocument> {
267267
*/
268268
fetchFn: FetchLike
269269

270-
fetchOptions?: RequestInitLike
270+
fetchOptions: RequestInitLike
271271

272272
#repositoryName: string | undefined
273273

@@ -378,92 +378,96 @@ export class Client<TDocuments extends PrismicDocument = PrismicDocument> {
378378
* @returns A client that can query content from the repository.
379379
*/
380380
constructor(repositoryNameOrEndpoint: string, options: ClientConfig = {}) {
381-
this.fetchOptions = options.fetchOptions
382-
383-
if (typeof options.fetch === "function") {
384-
this.fetchFn = options.fetch
385-
} else if (typeof globalThis.fetch === "function") {
386-
this.fetchFn = globalThis.fetch as FetchLike
387-
} else {
388-
throw new PrismicError(
389-
"A valid fetch implementation was not provided. In environments where fetch is not available (including Node.js), a fetch implementation must be provided via a polyfill or the `fetch` option.",
390-
undefined,
391-
undefined,
392-
)
393-
}
394-
395-
// If the global fetch function is used, we must bind it to the global scope.
396-
if (this.fetchFn === globalThis.fetch) {
397-
this.fetchFn = this.fetchFn.bind(globalThis)
398-
}
399-
400-
if (
401-
(options.documentAPIEndpoint ||
402-
isRepositoryEndpoint(repositoryNameOrEndpoint)) &&
403-
process.env.NODE_ENV === "development"
404-
) {
405-
const documentAPIEndpoint =
406-
options.documentAPIEndpoint || repositoryNameOrEndpoint
407-
408-
// Matches non-API v2 `.prismic.io` endpoints, see: https://regex101.com/r/xRsavu/1
409-
if (/\.prismic\.io\/(?!api\/v2\/?)/i.test(documentAPIEndpoint)) {
410-
throw new PrismicError(
411-
"@prismicio/client only supports Prismic Rest API V2. Please provide only the repository name to the first createClient() parameter or use the getRepositoryEndpoint() helper to generate a valid Rest API V2 endpoint URL.",
412-
undefined,
413-
undefined,
414-
)
415-
}
416-
417-
const hostname = new URL(documentAPIEndpoint).hostname.toLowerCase()
418-
419-
// Matches non-.cdn `.prismic.io` endpoints
420-
if (
421-
hostname.endsWith(".prismic.io") &&
422-
!hostname.endsWith(".cdn.prismic.io")
423-
) {
424-
console.warn(
425-
`[@prismicio/client] The client was created with a non-CDN endpoint. Convert it to the CDN endpoint for better performance. For more details, see ${devMsg("endpoint-must-use-cdn")}`,
426-
)
427-
}
428-
429-
// Warn if the user provided both a repository endpoint and an `documentAPIEndpoint` and they are different
430-
if (
431-
options.documentAPIEndpoint &&
432-
isRepositoryEndpoint(repositoryNameOrEndpoint) &&
433-
repositoryNameOrEndpoint !== options.documentAPIEndpoint
434-
) {
435-
console.warn(
436-
`[@prismicio/client] Multiple incompatible endpoints were provided. Create the client using a repository name to prevent this error. For more details, see ${devMsg("prefer-repository-name")}`,
437-
)
438-
}
439-
}
381+
const {
382+
documentAPIEndpoint,
383+
accessToken,
384+
ref,
385+
routes,
386+
brokenRoute,
387+
defaultParams,
388+
fetchOptions = {},
389+
fetch = globalThis.fetch?.bind(globalThis),
390+
} = options
440391

441392
if (isRepositoryEndpoint(repositoryNameOrEndpoint)) {
442-
this.documentAPIEndpoint = repositoryNameOrEndpoint
443393
try {
444394
this.repositoryName = getRepositoryName(repositoryNameOrEndpoint)
445395
} catch {
446396
console.warn(
447397
`[@prismicio/client] A repository name could not be inferred from the provided endpoint (\`${repositoryNameOrEndpoint}\`). Some methods will be disabled. Create the client using a repository name to prevent this warning. For more details, see ${devMsg("prefer-repository-name")}`,
448398
)
449399
}
400+
this.documentAPIEndpoint = documentAPIEndpoint || repositoryNameOrEndpoint
450401
} else {
451-
this.documentAPIEndpoint =
452-
options.documentAPIEndpoint ||
453-
getRepositoryEndpoint(repositoryNameOrEndpoint)
454402
this.repositoryName = repositoryNameOrEndpoint
403+
this.documentAPIEndpoint =
404+
documentAPIEndpoint || getRepositoryEndpoint(repositoryNameOrEndpoint)
455405
}
456406

457-
this.accessToken = options.accessToken
458-
this.routes = options.routes
459-
this.brokenRoute = options.brokenRoute
460-
this.defaultParams = options.defaultParams
407+
if (!fetch) {
408+
throw new PrismicError(
409+
"A valid fetch implementation was not provided. In environments where fetch is not available, a fetch implementation must be provided via a polyfill or the `fetch` option.",
410+
undefined,
411+
undefined,
412+
)
413+
}
414+
if (typeof fetch !== "function") {
415+
throw new PrismicError(
416+
`fetch must be a function, but received: ${typeof fetch}`,
417+
undefined,
418+
undefined,
419+
)
420+
}
461421

462-
if (options.ref) {
463-
this.queryContentFromRef(options.ref)
422+
if (!isRepositoryEndpoint(this.documentAPIEndpoint)) {
423+
throw new PrismicError(
424+
`documentAPIEndpoint is not a valid URL: ${documentAPIEndpoint}`,
425+
undefined,
426+
undefined,
427+
)
428+
}
429+
if (
430+
isRepositoryEndpoint(repositoryNameOrEndpoint) &&
431+
documentAPIEndpoint &&
432+
repositoryNameOrEndpoint !== documentAPIEndpoint
433+
) {
434+
console.warn(
435+
`[@prismicio/client] Multiple incompatible endpoints were provided. Create the client using a repository name to prevent this error. For more details, see ${devMsg("prefer-repository-name")}`,
436+
)
437+
}
438+
if (
439+
/\.prismic\.io\/(?!api\/v2\/?)/i.test(this.documentAPIEndpoint) &&
440+
process.env.NODE_ENV === "development"
441+
) {
442+
throw new PrismicError(
443+
"@prismicio/client only supports Prismic Rest API V2. Please provide only the repository name to the first createClient() parameter or use the getRepositoryEndpoint() helper to generate a valid Rest API V2 endpoint URL.",
444+
undefined,
445+
undefined,
446+
)
447+
}
448+
if (
449+
/(?<!\.cdn)\.prismic\.io$/i.test(
450+
new URL(this.documentAPIEndpoint).hostname,
451+
) &&
452+
process.env.NODE_ENV === "development"
453+
) {
454+
console.warn(
455+
`[@prismicio/client] The client was created with a non-CDN endpoint. Convert it to the CDN endpoint for better performance. For more details, see ${devMsg("endpoint-must-use-cdn")}`,
456+
)
464457
}
465458

459+
this.accessToken = accessToken
460+
this.routes = routes
461+
this.brokenRoute = brokenRoute
462+
this.defaultParams = defaultParams
463+
this.fetchOptions = fetchOptions
464+
this.fetchFn = fetch
465+
466466
this.graphQLFetch = this.graphQLFetch.bind(this)
467+
468+
if (ref) {
469+
this.queryContentFromRef(ref)
470+
}
467471
}
468472

469473
/**

test/createClient.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ it("throws if given fetch is not a function", ({ expect }) => {
118118
// @ts-expect-error - Intentional wrong type
119119
createClient("example", { fetch: "invalid" })
120120
expect(invalid).toThrow(PrismicError)
121-
expect(invalid).toThrow(/fetch implementation was not provided/i)
121+
expect(invalid).toThrow(/fetch must be a function/i)
122122
vi.unstubAllGlobals()
123123
})
124124

0 commit comments

Comments
 (0)