fix: add args as keyParts for unstable_cache
This commit is contained in:
committed by
Pontus Dreij
parent
ea8fdc940d
commit
ed3acce57c
@@ -1,5 +1,4 @@
|
|||||||
import { metrics } from "@opentelemetry/api"
|
import { metrics } from "@opentelemetry/api"
|
||||||
import { unstable_cache } from "next/cache"
|
|
||||||
|
|
||||||
import * as api from "@/lib/api"
|
import * as api from "@/lib/api"
|
||||||
import { GetHotelPage } from "@/lib/graphql/Query/HotelPage/HotelPage.graphql"
|
import { GetHotelPage } from "@/lib/graphql/Query/HotelPage/HotelPage.graphql"
|
||||||
@@ -38,7 +37,6 @@ import {
|
|||||||
getCitiesByCountry,
|
getCitiesByCountry,
|
||||||
getCountries,
|
getCountries,
|
||||||
getLocations,
|
getLocations,
|
||||||
locationsAffix,
|
|
||||||
TWENTYFOUR_HOURS,
|
TWENTYFOUR_HOURS,
|
||||||
} from "./utils"
|
} from "./utils"
|
||||||
|
|
||||||
@@ -657,36 +655,19 @@ export const hotelQueryRouter = router({
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const getCachedCountries = unstable_cache(
|
const countries = await getCountries(options, searchParams, ctx.lang)
|
||||||
getCountries,
|
|
||||||
[`${ctx.lang}:${locationsAffix}:countries`],
|
|
||||||
{ revalidate: TWENTYFOUR_HOURS }
|
|
||||||
)
|
|
||||||
|
|
||||||
const countries = await getCachedCountries(options, searchParams)
|
|
||||||
|
|
||||||
const getCachedCitiesByCountry = unstable_cache(
|
|
||||||
getCitiesByCountry,
|
|
||||||
[`${ctx.lang}:${locationsAffix}:cities-by-country`],
|
|
||||||
{ revalidate: TWENTYFOUR_HOURS }
|
|
||||||
)
|
|
||||||
|
|
||||||
let citiesByCountry = null
|
let citiesByCountry = null
|
||||||
if (countries) {
|
if (countries) {
|
||||||
citiesByCountry = await getCachedCitiesByCountry(
|
citiesByCountry = await getCitiesByCountry(
|
||||||
countries,
|
countries,
|
||||||
options,
|
options,
|
||||||
searchParams
|
searchParams,
|
||||||
|
ctx.lang
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const getCachedLocations = unstable_cache(
|
const locations = await getLocations(
|
||||||
getLocations,
|
|
||||||
[`${ctx.lang}:${locationsAffix}`],
|
|
||||||
{ revalidate: TWENTYFOUR_HOURS }
|
|
||||||
)
|
|
||||||
|
|
||||||
const locations = await getCachedLocations(
|
|
||||||
ctx.lang,
|
ctx.lang,
|
||||||
options,
|
options,
|
||||||
searchParams,
|
searchParams,
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import {
|
|||||||
PointOfInterestCategoryNameEnum,
|
PointOfInterestCategoryNameEnum,
|
||||||
PointOfInterestGroupEnum,
|
PointOfInterestGroupEnum,
|
||||||
} from "@/types/hotel"
|
} from "@/types/hotel"
|
||||||
|
import { HotelLocation } from "@/types/trpc/routers/hotel/locations"
|
||||||
import type { Lang } from "@/constants/languages"
|
import type { Lang } from "@/constants/languages"
|
||||||
import type { Endpoint } from "@/lib/api/endpoints"
|
import type { Endpoint } from "@/lib/api/endpoints"
|
||||||
|
|
||||||
@@ -54,89 +55,119 @@ export const locationsAffix = "locations"
|
|||||||
export const TWENTYFOUR_HOURS = 60 * 60 * 24
|
export const TWENTYFOUR_HOURS = 60 * 60 * 24
|
||||||
export async function getCity(
|
export async function getCity(
|
||||||
cityUrl: string,
|
cityUrl: string,
|
||||||
options: RequestOptionsWithOutBody
|
options: RequestOptionsWithOutBody,
|
||||||
|
lang: Lang,
|
||||||
|
relationshipCity: HotelLocation["relationships"]["city"]
|
||||||
) {
|
) {
|
||||||
const url = new URL(cityUrl)
|
return unstable_cache(
|
||||||
const cityResponse = await api.get(
|
async function (locationCityUrl: string) {
|
||||||
url.pathname as Endpoint,
|
const url = new URL(locationCityUrl)
|
||||||
options,
|
const cityResponse = await api.get(
|
||||||
url.searchParams
|
url.pathname as Endpoint,
|
||||||
)
|
options,
|
||||||
|
url.searchParams
|
||||||
|
)
|
||||||
|
|
||||||
if (!cityResponse.ok) {
|
if (!cityResponse.ok) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
const cityJson = await cityResponse.json()
|
const cityJson = await cityResponse.json()
|
||||||
const city = apiCitySchema.safeParse(cityJson)
|
const city = apiCitySchema.safeParse(cityJson)
|
||||||
if (!city.success) {
|
if (!city.success) {
|
||||||
console.info(`Validation of city failed`)
|
console.info(`Validation of city failed`)
|
||||||
console.info(`cityUrl: ${cityUrl}`)
|
console.info(`cityUrl: ${locationCityUrl}`)
|
||||||
console.error(city.error)
|
console.error(city.error)
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
return city.data
|
return city.data
|
||||||
|
},
|
||||||
|
[cityUrl, `${lang}:${relationshipCity}`],
|
||||||
|
{ revalidate: TWENTYFOUR_HOURS }
|
||||||
|
)(cityUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getCountries(
|
export async function getCountries(
|
||||||
options: RequestOptionsWithOutBody,
|
options: RequestOptionsWithOutBody,
|
||||||
params: URLSearchParams
|
params: URLSearchParams,
|
||||||
|
lang: Lang
|
||||||
) {
|
) {
|
||||||
const countryResponse = await api.get(
|
return unstable_cache(
|
||||||
api.endpoints.v1.countries,
|
async function (searchParams) {
|
||||||
options,
|
|
||||||
params
|
|
||||||
)
|
|
||||||
|
|
||||||
if (!countryResponse.ok) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
const countriesJson = await countryResponse.json()
|
|
||||||
const countries = apiCountriesSchema.safeParse(countriesJson)
|
|
||||||
if (!countries.success) {
|
|
||||||
console.info(`Validation for countries failed`)
|
|
||||||
console.error(countries.error)
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
return countries.data
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getCitiesByCountry(
|
|
||||||
countries: Countries,
|
|
||||||
options: RequestOptionsWithOutBody,
|
|
||||||
params: URLSearchParams
|
|
||||||
) {
|
|
||||||
const citiesGroupedByCountry: CitiesGroupedByCountry = {}
|
|
||||||
|
|
||||||
await Promise.all(
|
|
||||||
countries.data.map(async (country) => {
|
|
||||||
const countryResponse = await api.get(
|
const countryResponse = await api.get(
|
||||||
`${api.endpoints.v1.citiesCountry}/${country.name}`,
|
api.endpoints.v1.countries,
|
||||||
options,
|
options,
|
||||||
params
|
searchParams
|
||||||
)
|
)
|
||||||
|
|
||||||
if (!countryResponse.ok) {
|
if (!countryResponse.ok) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
const countryJson = await countryResponse.json()
|
const countriesJson = await countryResponse.json()
|
||||||
const citiesByCountry = apiCitiesByCountrySchema.safeParse(countryJson)
|
const countries = apiCountriesSchema.safeParse(countriesJson)
|
||||||
if (!citiesByCountry.success) {
|
if (!countries.success) {
|
||||||
console.info(`Failed to validate Cities by Country payload`)
|
console.info(`Validation for countries failed`)
|
||||||
console.error(citiesByCountry.error)
|
console.error(countries.error)
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
citiesGroupedByCountry[country.name] = citiesByCountry.data.data
|
return countries.data
|
||||||
return true
|
},
|
||||||
})
|
[`${lang}:${locationsAffix}:countries`, params.toString()],
|
||||||
)
|
{ revalidate: TWENTYFOUR_HOURS }
|
||||||
|
)(params)
|
||||||
|
}
|
||||||
|
|
||||||
return citiesGroupedByCountry
|
export async function getCitiesByCountry(
|
||||||
|
countries: Countries,
|
||||||
|
options: RequestOptionsWithOutBody,
|
||||||
|
params: URLSearchParams,
|
||||||
|
lang: Lang
|
||||||
|
) {
|
||||||
|
return unstable_cache(
|
||||||
|
async function (
|
||||||
|
searchParams: URLSearchParams,
|
||||||
|
searchedCountries: Countries
|
||||||
|
) {
|
||||||
|
const citiesGroupedByCountry: CitiesGroupedByCountry = {}
|
||||||
|
|
||||||
|
await Promise.all(
|
||||||
|
searchedCountries.data.map(async (country) => {
|
||||||
|
const countryResponse = await api.get(
|
||||||
|
`${api.endpoints.v1.citiesCountry}/${country.name}`,
|
||||||
|
options,
|
||||||
|
searchParams
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!countryResponse.ok) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const countryJson = await countryResponse.json()
|
||||||
|
const citiesByCountry =
|
||||||
|
apiCitiesByCountrySchema.safeParse(countryJson)
|
||||||
|
if (!citiesByCountry.success) {
|
||||||
|
console.info(`Failed to validate Cities by Country payload`)
|
||||||
|
console.error(citiesByCountry.error)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
citiesGroupedByCountry[country.name] = citiesByCountry.data.data
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
return citiesGroupedByCountry
|
||||||
|
},
|
||||||
|
[
|
||||||
|
`${lang}:${locationsAffix}:cities-by-country`,
|
||||||
|
params.toString(),
|
||||||
|
JSON.stringify(countries),
|
||||||
|
],
|
||||||
|
{ revalidate: TWENTYFOUR_HOURS }
|
||||||
|
)(params, countries)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getLocations(
|
export async function getLocations(
|
||||||
@@ -145,72 +176,89 @@ export async function getLocations(
|
|||||||
params: URLSearchParams,
|
params: URLSearchParams,
|
||||||
citiesByCountry: CitiesGroupedByCountry | null
|
citiesByCountry: CitiesGroupedByCountry | null
|
||||||
) {
|
) {
|
||||||
const apiResponse = await api.get(api.endpoints.v1.locations, options, params)
|
return unstable_cache(
|
||||||
|
async function (
|
||||||
|
searchParams: URLSearchParams,
|
||||||
|
groupedCitiesByCountry: CitiesGroupedByCountry | null
|
||||||
|
) {
|
||||||
|
const apiResponse = await api.get(
|
||||||
|
api.endpoints.v1.locations,
|
||||||
|
options,
|
||||||
|
searchParams
|
||||||
|
)
|
||||||
|
|
||||||
if (!apiResponse.ok) {
|
if (!apiResponse.ok) {
|
||||||
if (apiResponse.status === 401) {
|
if (apiResponse.status === 401) {
|
||||||
return { error: true, cause: "unauthorized" } as const
|
return { error: true, cause: "unauthorized" } as const
|
||||||
} else if (apiResponse.status === 403) {
|
} else if (apiResponse.status === 403) {
|
||||||
return { error: true, cause: "forbidden" } as const
|
return { error: true, cause: "forbidden" } as const
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
const apiJson = await apiResponse.json()
|
|
||||||
const verifiedLocations = apiLocationsSchema.safeParse(apiJson)
|
|
||||||
if (!verifiedLocations.success) {
|
|
||||||
console.info(`Locations Verification Failed`)
|
|
||||||
console.error(verifiedLocations.error)
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
return await Promise.all(
|
|
||||||
verifiedLocations.data.data.map(async (location) => {
|
|
||||||
if (location.type === "cities") {
|
|
||||||
if (citiesByCountry) {
|
|
||||||
const country = Object.keys(citiesByCountry).find((country) => {
|
|
||||||
if (
|
|
||||||
citiesByCountry[country].find((loc) => loc.name === location.name)
|
|
||||||
) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
})
|
|
||||||
if (country) {
|
|
||||||
return {
|
|
||||||
...location,
|
|
||||||
country,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
console.info(
|
|
||||||
`Location cannot be found in any of the countries cities`
|
|
||||||
)
|
|
||||||
console.info(location)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (location.type === "hotels") {
|
|
||||||
if (location.relationships.city?.url) {
|
|
||||||
const getCachedCity = unstable_cache(
|
|
||||||
getCity,
|
|
||||||
[`${lang}:${location.relationships.city}`],
|
|
||||||
{ revalidate: TWENTYFOUR_HOURS }
|
|
||||||
)
|
|
||||||
|
|
||||||
const city = await getCachedCity(
|
|
||||||
location.relationships.city.url,
|
|
||||||
options
|
|
||||||
)
|
|
||||||
if (city) {
|
|
||||||
return deepmerge(location, {
|
|
||||||
relationships: {
|
|
||||||
city,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
return location
|
const apiJson = await apiResponse.json()
|
||||||
})
|
const verifiedLocations = apiLocationsSchema.safeParse(apiJson)
|
||||||
)
|
if (!verifiedLocations.success) {
|
||||||
|
console.info(`Locations Verification Failed`)
|
||||||
|
console.error(verifiedLocations.error)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return await Promise.all(
|
||||||
|
verifiedLocations.data.data.map(async (location) => {
|
||||||
|
if (location.type === "cities") {
|
||||||
|
if (groupedCitiesByCountry) {
|
||||||
|
const country = Object.keys(groupedCitiesByCountry).find(
|
||||||
|
(country) => {
|
||||||
|
if (
|
||||||
|
groupedCitiesByCountry[country].find(
|
||||||
|
(loc) => loc.name === location.name
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
)
|
||||||
|
if (country) {
|
||||||
|
return {
|
||||||
|
...location,
|
||||||
|
country,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.info(
|
||||||
|
`Location cannot be found in any of the countries cities`
|
||||||
|
)
|
||||||
|
console.info(location)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (location.type === "hotels") {
|
||||||
|
if (location.relationships.city?.url) {
|
||||||
|
const city = await getCity(
|
||||||
|
location.relationships.city.url,
|
||||||
|
options,
|
||||||
|
lang,
|
||||||
|
location.relationships.city
|
||||||
|
)
|
||||||
|
if (city) {
|
||||||
|
return deepmerge(location, {
|
||||||
|
relationships: {
|
||||||
|
city,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return location
|
||||||
|
})
|
||||||
|
)
|
||||||
|
},
|
||||||
|
[
|
||||||
|
`${lang}:${locationsAffix}`,
|
||||||
|
params.toString(),
|
||||||
|
JSON.stringify(citiesByCountry),
|
||||||
|
],
|
||||||
|
{ revalidate: TWENTYFOUR_HOURS }
|
||||||
|
)(params, citiesByCountry)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,24 +5,22 @@ import { env } from "@/env/server"
|
|||||||
|
|
||||||
import { generateServiceTokenTag } from "@/utils/generateTag"
|
import { generateServiceTokenTag } from "@/utils/generateTag"
|
||||||
|
|
||||||
import { ServiceTokenScopeEnum } from "@/types/enums/serviceToken"
|
|
||||||
import { ServiceTokenResponse } from "@/types/tokens"
|
import { ServiceTokenResponse } from "@/types/tokens"
|
||||||
|
|
||||||
// OpenTelemetry metrics: Service token
|
// OpenTelemetry metrics: Service token
|
||||||
const meter = metrics.getMeter("trpc.context.serviceToken")
|
const meter = metrics.getMeter("trpc.context.serviceToken")
|
||||||
const getServiceTokenCounter = meter.createCounter(
|
const fetchServiceTokenCounter = meter.createCounter(
|
||||||
"trpc.context.serviceToken.get-new-token"
|
"trpc.context.serviceToken.fetch-new-token"
|
||||||
)
|
)
|
||||||
const getTempServiceTokenCounter = meter.createCounter(
|
const fetchTempServiceTokenCounter = meter.createCounter(
|
||||||
"trpc.context.serviceToken.get-temporary"
|
"trpc.context.serviceToken.fetch-temporary"
|
||||||
)
|
)
|
||||||
const getServiceTokenFailCounter = meter.createCounter(
|
const fetchServiceTokenFailCounter = meter.createCounter(
|
||||||
"trpc.context.serviceToken.get-fail"
|
"trpc.context.serviceToken.fetch-fail"
|
||||||
)
|
)
|
||||||
|
|
||||||
async function getServiceToken() {
|
async function fetchServiceToken(scopes: string[]) {
|
||||||
getServiceTokenCounter.add(1)
|
fetchServiceTokenCounter.add(1)
|
||||||
const scopes = Object.keys(ServiceTokenScopeEnum)
|
|
||||||
const response = await fetch(`${env.CURITY_ISSUER_USER}/oauth/v2/token`, {
|
const response = await fetch(`${env.CURITY_ISSUER_USER}/oauth/v2/token`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
@@ -38,7 +36,7 @@ async function getServiceToken() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
getServiceTokenFailCounter.add(1, {
|
fetchServiceTokenFailCounter.add(1, {
|
||||||
error_type: "http_error",
|
error_type: "http_error",
|
||||||
error: JSON.stringify({
|
error: JSON.stringify({
|
||||||
status: response.status,
|
status: response.status,
|
||||||
@@ -51,21 +49,22 @@ async function getServiceToken() {
|
|||||||
return response.json()
|
return response.json()
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function fetchServiceToken(): Promise<ServiceTokenResponse> {
|
export async function getServiceToken(): Promise<ServiceTokenResponse> {
|
||||||
try {
|
try {
|
||||||
const tag = generateServiceTokenTag()
|
const scopes = ["profile", "hotel", "booking"]
|
||||||
|
const tag = generateServiceTokenTag(scopes)
|
||||||
const getCachedJwt = unstable_cache(
|
const getCachedJwt = unstable_cache(
|
||||||
async () => {
|
async (scopes) => {
|
||||||
const jwt = await getServiceToken()
|
const jwt = await fetchServiceToken(scopes)
|
||||||
|
|
||||||
const expiresAt = Date.now() + jwt.expires_in * 1000
|
const expiresAt = Date.now() + jwt.expires_in * 1000
|
||||||
return { expiresAt, jwt }
|
return { expiresAt, jwt }
|
||||||
},
|
},
|
||||||
[],
|
[tag],
|
||||||
{ tags: [tag] }
|
{ tags: [tag] }
|
||||||
)
|
)
|
||||||
|
|
||||||
const cachedJwt = await getCachedJwt()
|
const cachedJwt = await getCachedJwt(scopes)
|
||||||
if (cachedJwt.expiresAt < Date.now()) {
|
if (cachedJwt.expiresAt < Date.now()) {
|
||||||
console.log(
|
console.log(
|
||||||
"trpc.context.serviceToken: Service token expired, revalidating tag"
|
"trpc.context.serviceToken: Service token expired, revalidating tag"
|
||||||
@@ -75,8 +74,8 @@ export async function fetchServiceToken(): Promise<ServiceTokenResponse> {
|
|||||||
console.log(
|
console.log(
|
||||||
"trpc.context.serviceToken: Fetching new temporary service token."
|
"trpc.context.serviceToken: Fetching new temporary service token."
|
||||||
)
|
)
|
||||||
getTempServiceTokenCounter.add(1)
|
fetchTempServiceTokenCounter.add(1)
|
||||||
const newToken = await getServiceToken()
|
const newToken = await fetchServiceToken(scopes)
|
||||||
return newToken
|
return newToken
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,16 +11,12 @@ import {
|
|||||||
unauthorizedError,
|
unauthorizedError,
|
||||||
} from "./errors/trpc"
|
} from "./errors/trpc"
|
||||||
import { type Context, createContext } from "./context"
|
import { type Context, createContext } from "./context"
|
||||||
import { fetchServiceToken } from "./tokenManager"
|
import { getServiceToken } from "./tokenManager"
|
||||||
import { transformer } from "./transformer"
|
import { transformer } from "./transformer"
|
||||||
import { langInput } from "./utils"
|
import { langInput } from "./utils"
|
||||||
|
|
||||||
import type { Session } from "next-auth"
|
import type { Session } from "next-auth"
|
||||||
|
|
||||||
import {
|
|
||||||
ServiceTokenScope,
|
|
||||||
ServiceTokenScopeEnum,
|
|
||||||
} from "@/types/enums/serviceToken"
|
|
||||||
import type { Meta } from "@/types/trpc/meta"
|
import type { Meta } from "@/types/trpc/meta"
|
||||||
|
|
||||||
const t = initTRPC
|
const t = initTRPC
|
||||||
@@ -126,7 +122,7 @@ export const safeProtectedProcedure = t.procedure.use(async function (opts) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
export const serviceProcedure = t.procedure.use(async (opts) => {
|
export const serviceProcedure = t.procedure.use(async (opts) => {
|
||||||
const { access_token } = await fetchServiceToken()
|
const { access_token } = await getServiceToken()
|
||||||
if (!access_token) {
|
if (!access_token) {
|
||||||
throw internalServerError(`Failed to obtain service token`)
|
throw internalServerError(`Failed to obtain service token`)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
export enum ServiceTokenScopeEnum {
|
|
||||||
profile = "profile",
|
|
||||||
hotel = "hotel",
|
|
||||||
booking = "booking",
|
|
||||||
}
|
|
||||||
|
|
||||||
export type ServiceTokenScope = keyof typeof ServiceTokenScopeEnum
|
|
||||||
@@ -6,3 +6,6 @@ export interface LocationSchema extends z.output<typeof apiLocationsSchema> {}
|
|||||||
|
|
||||||
export type Locations = LocationSchema["data"]
|
export type Locations = LocationSchema["data"]
|
||||||
export type Location = Locations[number]
|
export type Location = Locations[number]
|
||||||
|
|
||||||
|
export type CityLocation = Location & { type: "cities" }
|
||||||
|
export type HotelLocation = Location & { type: "hotels" }
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { ServiceTokenScopeEnum } from "@/types/enums/serviceToken"
|
|
||||||
import { System } from "@/types/requests/system"
|
import { System } from "@/types/requests/system"
|
||||||
import type { Edges } from "@/types/requests/utils/edges"
|
import type { Edges } from "@/types/requests/utils/edges"
|
||||||
import type { NodeRefs } from "@/types/requests/utils/refs"
|
import type { NodeRefs } from "@/types/requests/utils/refs"
|
||||||
@@ -107,7 +106,6 @@ export function generateLoyaltyConfigTag(
|
|||||||
* @param serviceTokenScope scope of service token
|
* @param serviceTokenScope scope of service token
|
||||||
* @returns string
|
* @returns string
|
||||||
*/
|
*/
|
||||||
export function generateServiceTokenTag() {
|
export function generateServiceTokenTag(scopes: string[]) {
|
||||||
const scopes = Object.keys(ServiceTokenScopeEnum).join("-")
|
return `service_token:${scopes.join("-")}`
|
||||||
return `service_token:${scopes}`
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user