This PR consists of two separate changes. One change cannot pass CI without the other, so both are included in this single PR. ## CI - ensure types are generated Our website template is currently failing to build due to a type error. This error was introduced by a change in our generated types. Our CI did not catch this issue because it wasn't generating types / import map before attempting to build the templates. This PR updates the CI to generate types first. It also updates some CI step names for improved clarity. ## Fix: type error  This fixes the type error by ensuring we consistently use the _same_ generated `TypedUser` object within payload, instead of `BaseUser`. Previously, we sometimes used the generated-types user and sometimes the base user, which was causing type conflicts depending on what the generated user type was. It also deprecates the `User` type (which was essentially just `BaseUser`), as consumers should use `TypedUser` instead. `TypedUser` will automatically fall back to `BaseUser` if no generated types exists, but will accept passing it a generated-types User. Without this change, additional properties added to the user via generated-types may cause the user object to not be accepted by functions that only accept a `User` instead of a `TypedUser`, which is what failed here. ## Templates: re-generate templates to update generated types --- - To see the specific tasks where the Asana app for GitHub is being used, see below: - https://app.asana.com/0/0/1210668927737258
144 lines
4.1 KiB
TypeScript
144 lines
4.1 KiB
TypeScript
import type { Payload, RequestContext, TypedLocale, TypedUser } from '../index.js'
|
|
import type { PayloadRequest } from '../types/index.js'
|
|
|
|
import { getDataLoader } from '../collections/dataloader.js'
|
|
import { getLocalI18n } from '../translations/getLocalI18n.js'
|
|
import { sanitizeFallbackLocale } from '../utilities/sanitizeFallbackLocale.js'
|
|
|
|
function getRequestContext(
|
|
req: Partial<PayloadRequest> = { context: null } as unknown as PayloadRequest,
|
|
context: RequestContext = {},
|
|
): RequestContext {
|
|
if (req.context) {
|
|
if (Object.keys(req.context).length === 0 && req.context.constructor === Object) {
|
|
// if req.context is `{}` avoid unnecessary spread
|
|
return context
|
|
} else {
|
|
return { ...req.context, ...context }
|
|
}
|
|
} else {
|
|
return context
|
|
}
|
|
}
|
|
|
|
const attachFakeURLProperties = (req: Partial<PayloadRequest>, urlSuffix?: string) => {
|
|
/**
|
|
* *NOTE*
|
|
* If no URL is provided, the local API was called outside
|
|
* the context of a request. Therefore we create a fake URL object.
|
|
* `ts-expect-error` is used below for properties that are 'read-only'.
|
|
* Since they do not exist yet we can safely ignore the error.
|
|
*/
|
|
let urlObject: undefined | URL
|
|
|
|
function getURLObject() {
|
|
if (urlObject) {
|
|
return urlObject
|
|
}
|
|
|
|
const fallbackURL = `http://${req.host || 'localhost'}${urlSuffix || ''}`
|
|
|
|
const urlToUse =
|
|
req?.url || req.payload?.config?.serverURL
|
|
? `${req.payload?.config.serverURL}${urlSuffix || ''}`
|
|
: fallbackURL
|
|
|
|
try {
|
|
urlObject = new URL(urlToUse)
|
|
} catch (_err) {
|
|
req.payload?.logger.error(
|
|
`Failed to create URL object from URL: ${urlToUse}, falling back to ${fallbackURL}`,
|
|
)
|
|
|
|
urlObject = new URL(fallbackURL)
|
|
}
|
|
|
|
return urlObject
|
|
}
|
|
|
|
if (!req.host) {
|
|
req.host = getURLObject().host
|
|
}
|
|
|
|
if (!req.protocol) {
|
|
req.protocol = getURLObject().protocol
|
|
}
|
|
|
|
if (!req.pathname) {
|
|
req.pathname = getURLObject().pathname
|
|
}
|
|
|
|
if (!req.searchParams) {
|
|
// @ts-expect-error eslint-disable-next-line no-param-reassign
|
|
req.searchParams = getURLObject().searchParams
|
|
}
|
|
|
|
if (!req.origin) {
|
|
// @ts-expect-error eslint-disable-next-line no-param-reassign
|
|
req.origin = getURLObject().origin
|
|
}
|
|
|
|
if (!req?.url) {
|
|
// @ts-expect-error eslint-disable-next-line no-param-reassign
|
|
req.url = getURLObject().href
|
|
}
|
|
}
|
|
|
|
export type CreateLocalReqOptions = {
|
|
context?: RequestContext
|
|
fallbackLocale?: false | TypedLocale
|
|
locale?: string
|
|
req?: Partial<PayloadRequest>
|
|
urlSuffix?: string
|
|
user?: TypedUser
|
|
}
|
|
|
|
type CreateLocalReq = (options: CreateLocalReqOptions, payload: Payload) => Promise<PayloadRequest>
|
|
|
|
export const createLocalReq: CreateLocalReq = async (
|
|
{ context, fallbackLocale, locale: localeArg, req = {} as PayloadRequest, urlSuffix, user },
|
|
payload,
|
|
): Promise<PayloadRequest> => {
|
|
const localization = payload.config?.localization
|
|
|
|
if (localization) {
|
|
const locale = localeArg === '*' ? 'all' : localeArg
|
|
const defaultLocale = localization.defaultLocale
|
|
const localeCandidate = locale || req?.locale || req?.query?.locale
|
|
|
|
req.locale =
|
|
localeCandidate && typeof localeCandidate === 'string' ? localeCandidate : defaultLocale
|
|
|
|
const sanitizedFallback = sanitizeFallbackLocale({
|
|
fallbackLocale: fallbackLocale!,
|
|
locale: req.locale,
|
|
localization,
|
|
})
|
|
|
|
req.fallbackLocale = sanitizedFallback!
|
|
}
|
|
|
|
const i18n =
|
|
req?.i18n ||
|
|
(await getLocalI18n({ config: payload.config, language: payload.config.i18n.fallbackLanguage }))
|
|
|
|
if (!req.headers) {
|
|
// @ts-expect-error eslint-disable-next-line no-param-reassign
|
|
req.headers = new Headers()
|
|
}
|
|
|
|
req.context = getRequestContext(req, context)
|
|
req.payloadAPI = req?.payloadAPI || 'local'
|
|
req.payload = payload
|
|
req.i18n = i18n
|
|
req.t = i18n.t
|
|
req.user = user || req?.user || null
|
|
req.payloadDataLoader = req?.payloadDataLoader || getDataLoader(req as PayloadRequest)
|
|
req.routeParams = req?.routeParams || {}
|
|
req.query = req?.query || {}
|
|
|
|
attachFakeURLProperties(req, urlSuffix)
|
|
|
|
return req as PayloadRequest
|
|
}
|