From 11e19ff29fefca69944cbeb0be86792f47c20117 Mon Sep 17 00:00:00 2001 From: Charis <26616127+charislam@users.noreply.github.com> Date: Fri, 13 Sep 2024 09:45:55 -0400 Subject: [PATCH] refactor(docs): convert self-hosting to app router (#29268) * chore(docs,refs): prebuild self-hosted ref data Pregenerate self-hosted ref data files, in the style of the client lib, Management API, and CLI references. Preparatory step for migrating the self-hosted references to App Router. * refactor(docs): convert self-hosting to app router Convert self-hosting reference pages to App Router. * fix(docs,sitemap) --- apps/docs/app/reference/[...slug]/page.tsx | 9 +- apps/docs/components/ApiSchema.tsx | 30 +++-- apps/docs/content/navigation.references.ts | 39 +++++++ .../docs/features/docs/Reference.api.utils.ts | 6 +- .../docs/Reference.generated.script.ts | 110 +++++++++++++++++- .../docs/Reference.generated.singleton.ts | 14 +++ .../docs/features/docs/Reference.sections.tsx | 75 ++++++++---- .../docs/Reference.selfHostingPage.tsx | 79 +++++++++++++ apps/docs/features/docs/Reference.ui.tsx | 38 +++--- apps/docs/features/docs/Reference.utils.ts | 22 +++- apps/docs/internals/files/api.ts | 17 --- apps/docs/internals/files/reference-lib.ts | 10 ++ apps/docs/internals/generate-sitemap.ts | 5 +- apps/docs/middleware.ts | 5 + apps/docs/package.json | 6 +- .../self-hosting-analytics/[...slug].tsx | 35 ------ .../reference/self-hosting-auth/[...slug].tsx | 35 ------ .../self-hosting-functions/[...slug].tsx | 29 ----- .../self-hosting-realtime/[...slug].tsx | 29 ----- .../self-hosting-storage/[...slug].tsx | 35 ------ ...ommon-self-hosting-analytics-sections.json | 31 ++--- .../common-self-hosting-auth-sections.json | 41 +++---- .../common-self-hosting-storage-sections.json | 43 +++---- package-lock.json | 10 ++ 24 files changed, 456 insertions(+), 297 deletions(-) create mode 100644 apps/docs/features/docs/Reference.selfHostingPage.tsx delete mode 100644 apps/docs/internals/files/api.ts delete mode 100644 apps/docs/pages/reference/self-hosting-analytics/[...slug].tsx delete mode 100644 apps/docs/pages/reference/self-hosting-auth/[...slug].tsx delete mode 100644 apps/docs/pages/reference/self-hosting-functions/[...slug].tsx delete mode 100644 apps/docs/pages/reference/self-hosting-realtime/[...slug].tsx delete mode 100644 apps/docs/pages/reference/self-hosting-storage/[...slug].tsx diff --git a/apps/docs/app/reference/[...slug]/page.tsx b/apps/docs/app/reference/[...slug]/page.tsx index 58dcdb621e3..8d483ffcbf2 100644 --- a/apps/docs/app/reference/[...slug]/page.tsx +++ b/apps/docs/app/reference/[...slug]/page.tsx @@ -4,6 +4,7 @@ import { REFERENCES } from '~/content/navigation.references' import { ApiReferencePage } from '~/features/docs/Reference.apiPage' import { CliReferencePage } from '~/features/docs/Reference.cliPage' import { ClientSdkReferencePage } from '~/features/docs/Reference.sdkPage' +import { SelfHostingReferencePage } from '~/features/docs/Reference.selfHostingPage' import { generateReferenceMetadata, generateReferenceStaticParams, @@ -17,7 +18,7 @@ export default async function ReferencePage({ }: { params: { slug: Array } }) { - if (!Object.keys(REFERENCES).includes(slug[0])) { + if (!Object.keys(REFERENCES).includes(slug[0].replaceAll('-', '_'))) { redirect(notFoundLink(slug.join('/'))) } @@ -25,6 +26,7 @@ export default async function ReferencePage({ const isClientSdkReference = parsedPath.__type === 'clientSdk' const isCliReference = parsedPath.__type === 'cli' const isApiReference = parsedPath.__type === 'api' + const isSelfHostingReference = parsedPath.__type === 'self-hosting' if (isClientSdkReference) { const { sdkId, maybeVersion, path } = parsedPath @@ -40,8 +42,11 @@ export default async function ReferencePage({ return } else if (isApiReference) { return + } else if (isSelfHostingReference) { + return ( + + ) } else { - // Unimplemented -- eventually API redirect(notFoundLink(slug.join('/'))) } } diff --git a/apps/docs/components/ApiSchema.tsx b/apps/docs/components/ApiSchema.tsx index d7a32797e71..6a5ee1c11cf 100644 --- a/apps/docs/components/ApiSchema.tsx +++ b/apps/docs/components/ApiSchema.tsx @@ -5,16 +5,28 @@ import { Tabs, TabPanel } from '~/features/ui/Tabs' type IParamProps = any const ApiSchema = ({ schema, id }: IParamProps) => { - const example = sample(schema, { skipReadOnly: true, quiet: true }) + let example: string + try { + example = sample(schema, { skipReadOnly: true, quiet: true }) + } catch { + // ignore + } return ( - - -
- - {JSON.stringify(example, null, 2)} - -
-
+ + {example && ( + +
+ + {JSON.stringify(example, null, 2)} + +
+
+ )}
diff --git a/apps/docs/content/navigation.references.ts b/apps/docs/content/navigation.references.ts index 782255eab1c..49d144b20f2 100644 --- a/apps/docs/content/navigation.references.ts +++ b/apps/docs/content/navigation.references.ts @@ -118,8 +118,47 @@ export const REFERENCES = { versions: [], icon: 'reference-api', }, + self_hosting_analytics: { + type: 'self-hosting', + name: 'Self-Hosting Analytics', + libPath: 'self-hosting-analytics', + versions: [], + icon: 'reference-analytics', + }, + self_hosting_auth: { + type: 'self-hosting', + name: 'Self-Hosting Auth', + libPath: 'self-hosting-auth', + versions: [], + icon: 'self-hosting', + }, + self_hosting_functions: { + type: 'self-hosting', + name: 'Self-Hosting Functions', + libPath: 'self-hosting-functions', + versions: [], + icon: 'reference-functions', + }, + self_hosting_realtime: { + type: 'self-hosting', + name: 'Self-Hosting Realtime', + libPath: 'self-hosting-realtime', + versions: [], + icon: 'self-hosting', + }, + self_hosting_storage: { + type: 'self-hosting', + name: 'Self-Hosting Storage', + libPath: 'self-hosting-storage', + versions: [], + icon: 'self-hosting', + }, } as const export const clientSdkIds = Object.keys(REFERENCES).filter( (reference) => REFERENCES[reference].type === 'sdk' ) + +export const selfHostingServices = Object.keys(REFERENCES).filter( + (reference) => REFERENCES[reference].type === 'self-hosting' +) diff --git a/apps/docs/features/docs/Reference.api.utils.ts b/apps/docs/features/docs/Reference.api.utils.ts index 1aeaeee85a7..4d425c467cf 100644 --- a/apps/docs/features/docs/Reference.api.utils.ts +++ b/apps/docs/features/docs/Reference.api.utils.ts @@ -12,7 +12,7 @@ export interface IApiEndPoint { schema: ISchema }> requestBody?: { - required: boolean + required?: boolean content: IApiRequestBody } responses: { @@ -99,13 +99,13 @@ interface ISchemaOneOf extends ISchemaBase { interface IApiRequestBody extends IApiJsonDTO, IApiFormUrlEncodedDTO {} interface IApiJsonDTO { - 'application/json': { + 'application/json'?: { schema: ISchema } } interface IApiFormUrlEncodedDTO { - 'application/x-www-form-urlencoded': { + 'application/x-www-form-urlencoded'?: { schema: ISchema } } diff --git a/apps/docs/features/docs/Reference.generated.script.ts b/apps/docs/features/docs/Reference.generated.script.ts index 3345bd6bd2e..4eb584ae6a9 100644 --- a/apps/docs/features/docs/Reference.generated.script.ts +++ b/apps/docs/features/docs/Reference.generated.script.ts @@ -2,6 +2,7 @@ import { keyBy, isPlainObject } from 'lodash' import { mkdir, readFile, writeFile } from 'node:fs/promises' import { dirname, join } from 'node:path' import { fileURLToPath } from 'node:url' +import slugify from 'slugify' import { parse } from 'yaml' import { REFERENCES, clientSdkIds } from '~/content/navigation.references' @@ -9,9 +10,17 @@ import { parseTypeSpec } from '~/features/docs/Reference.typeSpec' import type { AbbrevApiReferenceSection } from '~/features/docs/Reference.utils' import { deepFilterRec } from '~/features/helpers.fn' import type { Json } from '~/features/helpers.types' +import authSpec from '~/spec/auth_v1_openapi.json' assert { type: 'json' } import apiCommonSections from '~/spec/common-api-sections.json' assert { type: 'json' } import cliCommonSections from '~/spec/common-cli-sections.json' assert { type: 'json' } import commonClientLibSections from '~/spec/common-client-libs-sections.json' assert { type: 'json' } +import selfHostingAnalyticsCommonSections from '~/spec/common-self-hosting-analytics-sections.json' assert { type: 'json' } +import selfHostingAuthCommonSections from '~/spec/common-self-hosting-auth-sections.json' +import selfHostingFunctionsCommonSections from '~/spec/common-self-hosting-functions-sections.json' assert { type: 'json' } +import selfHostingRealtimeCommonSections from '~/spec/common-self-hosting-realtime-sections.json' assert { type: 'json' } +import selfHostingStorageCommonSections from '~/spec/common-self-hosting-storage-sections.json' assert { type: 'json' } +import storageSpec from '~/spec/storage_v0_openapi.json' assert { type: 'json' } +import analyticsSpec from '~/spec/transforms/analytics_v0_openapi_deparsed.json' assert { type: 'json' } import openApiSpec from '~/spec/transforms/api_v1_openapi_deparsed.json' assert { type: 'json' } import { IApiEndPoint } from './Reference.api.utils' @@ -19,6 +28,32 @@ const DOCS_DIRECTORY = join(dirname(fileURLToPath(import.meta.url)), '../..') const SPEC_DIRECTORY = join(DOCS_DIRECTORY, 'spec') const GENERATED_DIRECTORY = join(dirname(fileURLToPath(import.meta.url)), 'generated') +const selfHostingSpecs = [ + { + id: 'self-hosting-analytics', + sections: selfHostingAnalyticsCommonSections, + spec: analyticsSpec, + }, + { + id: 'self-hosting-auth', + sections: selfHostingAuthCommonSections, + spec: authSpec, + }, + { + id: 'self-hosting-functions', + sections: selfHostingFunctionsCommonSections, + }, + { + id: 'self-hosting-realtime', + sections: selfHostingRealtimeCommonSections, + }, + { + id: 'self-hosting-storage', + sections: selfHostingStorageCommonSections, + spec: storageSpec, + }, +] + async function getSpec(specFile: string, { ext = 'yml' }: { ext?: string } = {}) { const specFullPath = join(SPEC_DIRECTORY, `${specFile}.${ext}`) const rawSpec = await readFile(specFullPath, 'utf-8') @@ -36,14 +71,17 @@ async function parseFnsList(rawSpec: Json): Promise> { return [] } -function mapEndpointsById(spec: typeof openApiSpec): Map { +function mapEndpointsById( + spec: any, + getId = (details: any) => details.operationId +): Map { const endpoints = spec.paths const endpointsById = new Map() Object.entries(endpoints).forEach(([path, methods]) => { Object.entries(methods).forEach(([method, details]) => { - endpointsById.set(details.operationId, { - id: details.operationId, + endpointsById.set(getId(details), { + id: getId(details), path, method, ...details, @@ -89,6 +127,16 @@ function genApiSectionTree(endpointsById: Map) { return validSections } +function genSelfHostedSectionTree( + spec: Array, + endpointsById: Map +) { + const validSections = deepFilterRec(spec, 'items', (section) => + section.type === 'self-hosted-operation' ? endpointsById.has(section.id) : true + ) + return validSections +} + export function flattenCommonClientLibSections(tree: Array) { return tree.reduce((acc, elem) => { if ('items' in elem) { @@ -234,6 +282,61 @@ async function writeApiReferenceSections() { ]) } +async function writeSelfHostingReferenceSections() { + let id = 0 + + return Promise.all( + selfHostingSpecs.flatMap((service) => { + let tasks: Promise[] = [] + + let endpointsById: Map + if (service.spec) { + endpointsById = mapEndpointsById(service.spec, (details) => + slugify(details.summary || `dummy-id-${String(id++)}`, { + lower: true, + remove: /[^\w\s-]/g, + }) + ) + tasks.push( + writeFile( + join(GENERATED_DIRECTORY, `${service.id}.latest.endpointsById.json`), + JSON.stringify(Array.from(endpointsById.entries())) + ) + ) + } + + const selfHostedSectionTree = genSelfHostedSectionTree(service.sections, endpointsById) + tasks.push( + writeFile( + join(GENERATED_DIRECTORY, `${service.id}.latest.sections.json`), + JSON.stringify(selfHostedSectionTree) + ) + ) + + const flattenedSelfHostedSections = flattenCommonClientLibSections(selfHostedSectionTree) + tasks.push( + writeFile( + join(GENERATED_DIRECTORY, `${service.id}.latest.flat.json`), + JSON.stringify(flattenedSelfHostedSections) + ) + ) + + const selfHostedSectionsBySlug = keyBy( + flattenedSelfHostedSections.filter(({ slug }) => !!slug), + (section) => section.slug + ) + tasks.push( + writeFile( + join(GENERATED_DIRECTORY, `${service.id}.latest.bySlug.json`), + JSON.stringify(selfHostedSectionsBySlug) + ) + ) + + return tasks + }) + ) +} + async function run() { try { await mkdir(GENERATED_DIRECTORY, { recursive: true }) @@ -243,6 +346,7 @@ async function run() { writeSdkReferenceSections(), writeCliReferenceSections(), writeApiReferenceSections(), + writeSelfHostingReferenceSections(), ]) } catch (err) { console.error(err) diff --git a/apps/docs/features/docs/Reference.generated.singleton.ts b/apps/docs/features/docs/Reference.generated.singleton.ts index 99a20756b5d..88e49412b52 100644 --- a/apps/docs/features/docs/Reference.generated.singleton.ts +++ b/apps/docs/features/docs/Reference.generated.singleton.ts @@ -62,6 +62,20 @@ export async function getApiEndpointById(id: string) { return apiEndpointsById.get(id) } +let selfHostedEndpointsById = new Map>() + +export async function getSelfHostedApiEndpointById(servicePath: string, id: string) { + if (!selfHostedEndpointsById.has(servicePath)) { + const rawJson = await readFile( + join(process.cwd(), 'features/docs', `./generated/${servicePath}.latest.endpointsById.json`), + 'utf-8' + ) + selfHostedEndpointsById.set(servicePath, new Map(JSON.parse(rawJson))) + } + + return selfHostedEndpointsById.get(servicePath)?.get(id) +} + const functionsList = new Map>() export async function getFunctionsList(sdkId: string, version: string) { diff --git a/apps/docs/features/docs/Reference.sections.tsx b/apps/docs/features/docs/Reference.sections.tsx index 3581e0f1f06..6bab6c1acc3 100644 --- a/apps/docs/features/docs/Reference.sections.tsx +++ b/apps/docs/features/docs/Reference.sections.tsx @@ -9,6 +9,7 @@ import { CodeBlock, } from 'ui' +import ApiSchema from '~/components/ApiSchema' import { REFERENCES } from '~/content/navigation.references' import { MDXRemoteRefs, getRefMarkdown } from '~/features/docs/Reference.mdx' import { MDXProviderReference } from '~/features/docs/Reference.mdx.client' @@ -18,12 +19,13 @@ import { getCliSpec, getFlattenedSections, getFunctionsList, + getSelfHostedApiEndpointById, getTypeSpec, } from '~/features/docs/Reference.generated.singleton' +import { type IApiEndPoint } from './Reference.api.utils' import { ApiOperationRequestBodyDetails, ApiSchemaParamDetails, - ApiSchemaParamSubdetails, CollapsibleDetails, FnParameterDetails, RefSubLayout, @@ -34,9 +36,7 @@ import { import type { AbbrevApiReferenceSection } from '~/features/docs/Reference.utils' import { normalizeMarkdown } from '~/features/docs/Reference.utils' import { RefInternalLink } from './Reference.navigation.client' -import { getTypeDisplayFromSchema } from './Reference.api.utils' import { ApiOperationBodySchemeSelector } from './Reference.ui.client' -import ApiSchema from '~/components/ApiSchema' type RefSectionsProps = { libraryId: string @@ -82,8 +82,8 @@ type SectionSwitchProps = { } export function SectionSwitch({ libraryId, version, section }: SectionSwitchProps) { - const libPath = REFERENCES[libraryId].libPath - const allAvailableVersions = REFERENCES[libraryId].versions + const libPath = REFERENCES[libraryId.replaceAll('-', '_')].libPath + const allAvailableVersions = REFERENCES[libraryId.replaceAll('-', '_')].versions const isLatestVersion = allAvailableVersions.length === 0 || version === allAvailableVersions[0] const sectionLink = `/docs/reference/${libPath}/${isLatestVersion ? '' : `${version}/`}${section.slug}` @@ -113,6 +113,8 @@ export function SectionSwitch({ libraryId, version, section }: SectionSwitchProp return case 'operation': return + case 'self-hosted-operation': + return default: console.error(`Unhandled type in reference sections: ${section.type}`) return null @@ -261,14 +263,35 @@ async function CliCommandSection({ link, section }: CliCommandSectionProps) { interface ApiEndpointSectionProps { link: string section: AbbrevApiReferenceSection + servicePath?: string } -async function ApiEndpointSection({ link, section }: ApiEndpointSectionProps) { - const endpointDetails = await getApiEndpointById(section.id) +async function ApiEndpointSection({ link, section, servicePath }: ApiEndpointSectionProps) { + const endpointDetails = servicePath + ? await getSelfHostedApiEndpointById(servicePath, section.id) + : await getApiEndpointById(section.id) if (!endpointDetails) return null - const pathParameters = endpointDetails.parameters.filter((param) => param.in === 'path') - const queryParameters = endpointDetails.parameters.filter((param) => param.in === 'query') + const pathParameters = (endpointDetails.parameters ?? []).filter((param) => param.in === 'path') + const queryParameters = (endpointDetails.parameters ?? []).filter((param) => param.in === 'query') + const bodyParameters = + endpointDetails.requestBody ?? + (endpointDetails.parameters ?? []) + .filter((param) => param.in === 'body') + .map( + (bodyParam) => + ({ + content: { + 'application/json': { + schema: bodyParam.schema, + }, + }, + }) satisfies IApiEndPoint['requestBody'] + )[0] + + const first2xxCode = Object.keys(endpointDetails.responses ?? {}) + .filter((code) => code.startsWith('2')) + .sort()[0] return ( @@ -305,27 +328,35 @@ async function ApiEndpointSection({ link, section }: ApiEndpointSectionProps) { )} - {endpointDetails.requestBody && ( + {bodyParameters && (
- - + + +
+ )} + {endpointDetails.responses && ( +
+

Response codes

+
    + {Object.keys(endpointDetails.responses).map((code) => ( +
  • + {code} +
  • + ))} +
)}
- {Object.keys(endpointDetails.responses).filter((code) => code.startsWith('2')).length > 0 && ( + {endpointDetails.responses && first2xxCode && (
-

Response

+

{`Response (${first2xxCode})`}

code.startsWith('2')) - .sort()[0] - ].content?.['application/json']?.schema ?? {} + endpointDetails.responses[first2xxCode].content?.['application/json']?.schema ?? + // @ts-ignore - schema is here in older versions + endpointDetails.responses[first2xxCode].schema ?? + {} } />
diff --git a/apps/docs/features/docs/Reference.selfHostingPage.tsx b/apps/docs/features/docs/Reference.selfHostingPage.tsx new file mode 100644 index 00000000000..53773af3514 --- /dev/null +++ b/apps/docs/features/docs/Reference.selfHostingPage.tsx @@ -0,0 +1,79 @@ +import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu' +import { + reference_self_hosting_analytics, + reference_self_hosting_auth, + reference_self_hosting_functions, + reference_self_hosting_realtime, + reference_self_hosting_storage, +} from '~/components/Navigation/NavigationMenu/NavigationMenu.constants' +import { REFERENCES } from '~/content/navigation.references' +import { ClientLibIntroduction } from '~/features/docs/Reference.introduction' +import { ReferenceNavigation } from '~/features/docs/Reference.navigation' +import { ReferenceContentScrollHandler } from '~/features/docs/Reference.navigation.client' +import { RefSections } from '~/features/docs/Reference.sections' +import { LayoutMainContent } from '~/layouts/DefaultLayout' +import { SidebarSkeleton } from '~/layouts/MainSkeleton' + +export async function SelfHostingReferencePage({ + service, + servicePath, +}: { + service: string + servicePath: string +}) { + const menuId = + service === 'analytics' + ? MenuId.SelfHostingAnalytics + : service === 'auth' + ? MenuId.SelfHostingAuth + : service === 'functions' + ? MenuId.SelfHostingFunctions + : service === 'realtime' + ? MenuId.SelfHostingRealtime + : service === 'storage' + ? MenuId.SelfHostingStorage + : MenuId.SelfHosting + + const menuData = + service === 'analytics' + ? reference_self_hosting_analytics + : service === 'auth' + ? reference_self_hosting_auth + : service === 'functions' + ? reference_self_hosting_functions + : service === 'realtime' + ? reference_self_hosting_realtime + : reference_self_hosting_storage + + const name = REFERENCES[servicePath.replaceAll('-', '_')].name + + return ( + + + } + > + +
+ + +
+
+
+
+ ) +} diff --git a/apps/docs/features/docs/Reference.ui.tsx b/apps/docs/features/docs/Reference.ui.tsx index 3eea44d315b..0a6eae3427a 100644 --- a/apps/docs/features/docs/Reference.ui.tsx +++ b/apps/docs/features/docs/Reference.ui.tsx @@ -344,15 +344,17 @@ export function ApiSchemaParamDetails({ param }: { param: IApiEndPoint['paramete {param.name} - {param.schema.deprecated && Deprecated} - - {getTypeDisplayFromSchema(param.schema).displayName} - + {param.schema?.deprecated && Deprecated} + {param.schema && ( + + {getTypeDisplayFromSchema(param.schema)?.displayName ?? ''} + + )} {param.description && ( {param.description} )} - + {param.schema && } ) } @@ -481,14 +483,20 @@ export function ApiSchemaParamSubdetails({ const subContent = 'enum' in schema ? schema.enum - : 'type' in schema && schema.type === 'string' - ? ['minLength', 'maxLength', 'pattern'] - .filter((key) => key in schema) - .map((key) => ({ - constraint: key, - value: schema[key], - })) - : [] + : 'anyOf' in schema + ? schema.anyOf + : 'oneOf' in schema + ? schema.oneOf + : 'allOf' in schema + ? schema.allOf + : 'type' in schema && schema.type === 'string' + ? ['minLength', 'maxLength', 'pattern'] + .filter((key) => key in schema) + .map((key) => ({ + constraint: key, + value: schema[key], + })) + : [] return ( @@ -552,6 +560,10 @@ export function ApiSchemaParamSubdetails({ {detail.value} + ) : 'anyOf' in schema || 'allOf' in schema || 'oneOf' in schema ? ( + ) : null} ))} diff --git a/apps/docs/features/docs/Reference.utils.ts b/apps/docs/features/docs/Reference.utils.ts index 1fd053dc805..a48a4620777 100644 --- a/apps/docs/features/docs/Reference.utils.ts +++ b/apps/docs/features/docs/Reference.utils.ts @@ -6,7 +6,7 @@ import type { Metadata, ResolvingMetadata } from 'next' import { redirect } from 'next/navigation' import { visit } from 'unist-util-visit' -import { REFERENCES, clientSdkIds } from '~/content/navigation.references' +import { REFERENCES, clientSdkIds, selfHostingServices } from '~/content/navigation.references' import { getFlattenedSections } from '~/features/docs/Reference.generated.singleton' import { generateOpenGraphImageMeta } from '~/features/seo/openGraph' import { BASE_PATH } from '~/lib/constants' @@ -27,6 +27,7 @@ export function parseReferencePath(slug: Array) { const isClientSdkReference = clientSdkIds.includes(slug[0]) const isCliReference = slug[0] === 'cli' const isApiReference = slug[0] === 'api' + const isSelfHostingReference = slug[0].startsWith('self-hosting-') if (isClientSdkReference) { let [sdkId, maybeVersion, maybeCrawlers, ...path] = slug @@ -57,6 +58,13 @@ export function parseReferencePath(slug: Array) { __type: 'api' as const, path: slug.slice(1), } + } else if (isSelfHostingReference) { + return { + __type: 'self-hosting' as const, + service: slug[0].replace('self-hosting-', ''), + servicePath: slug[0], + path: slug.slice(1), + } } else { return { __type: 'UNIMPLEMENTED' as const, @@ -103,7 +111,11 @@ export async function generateReferenceStaticParams() { }, ] - return [...sdkPages, ...cliPages, ...apiPages] + const selfHostingPages = selfHostingServices.map((service) => ({ + slug: [REFERENCES[service].libPath], + })) + + return [...sdkPages, ...cliPages, ...apiPages, ...selfHostingPages] } export async function generateReferenceMetadata( @@ -116,7 +128,7 @@ export async function generateReferenceMetadata( const isClientSdkReference = parsedPath.__type === 'clientSdk' const isCliReference = parsedPath.__type === 'cli' const isApiReference = parsedPath.__type === 'api' - + const isSelfHostingReference = parsedPath.__type === 'self-hosting' if (isClientSdkReference) { const { sdkId, maybeVersion } = parsedPath const version = maybeVersion ?? REFERENCES[sdkId].versions[0] @@ -162,6 +174,10 @@ export async function generateReferenceMetadata( title: 'Management API Reference | Supabase Docs', description: 'Management API reference for the Supabase API', } + } else if (isSelfHostingReference) { + return { + title: 'Self-Hosting | Supabase Docs', + } } else { return {} } diff --git a/apps/docs/internals/files/api.ts b/apps/docs/internals/files/api.ts deleted file mode 100644 index 86ba4de49ef..00000000000 --- a/apps/docs/internals/files/api.ts +++ /dev/null @@ -1,17 +0,0 @@ -import sections from '../../spec/common-api-sections.json' -import { flattenSections } from '../helpers' - -const flatSections = flattenSections(sections) - -/** - * Generates the API page links for the management API reference. - * @returns {Array<{link: string}>} - An array of API page links. - */ -export function generateAPIPages() { - let apiPages = [] - - flatSections.map((section) => { - apiPages.push({ link: `reference/api/${section.slug}` }) - }) - return apiPages -} diff --git a/apps/docs/internals/files/reference-lib.ts b/apps/docs/internals/files/reference-lib.ts index c9722ed3ec7..4a77415406c 100644 --- a/apps/docs/internals/files/reference-lib.ts +++ b/apps/docs/internals/files/reference-lib.ts @@ -6,6 +6,16 @@ export async function generateReferencePages() { await Promise.all( Object.keys(REFERENCES) .flatMap((key) => { + if (REFERENCES[key].versions.length === 0) { + return [ + { + sdkId: REFERENCES[key].libPath, + version: 'latest', + isLatestVersion: true, + libPath: REFERENCES[key].libPath, + }, + ] + } return REFERENCES[key].versions.map((version) => { return { sdkId: key, diff --git a/apps/docs/internals/generate-sitemap.ts b/apps/docs/internals/generate-sitemap.ts index 1e50baf5ae8..876507a4719 100644 --- a/apps/docs/internals/generate-sitemap.ts +++ b/apps/docs/internals/generate-sitemap.ts @@ -8,12 +8,10 @@ import { globby } from 'globby' import matter from 'gray-matter' import prettier from 'prettier' -import { generateAPIPages } from './files/api' import { generateCLIPages } from './files/cli' import { generateReferencePages } from './files/reference-lib' async function generate() { - const apiPages = generateAPIPages() const cliPages = generateCLIPages() const referencePages = await generateReferencePages() @@ -34,8 +32,7 @@ async function generate() { const allPages = (contentPages as Array<{ link: string; priority?: number }>).concat( referencePages, - cliPages, - apiPages + cliPages ) const sitemap = ` diff --git a/apps/docs/middleware.ts b/apps/docs/middleware.ts index 7eb4d79e7a6..ff2318fcbc5 100644 --- a/apps/docs/middleware.ts +++ b/apps/docs/middleware.ts @@ -43,6 +43,11 @@ export function middleware(request: NextRequest) { return NextResponse.rewrite(new URL(rewritePath, request.url)) } + if (lib.startsWith('self-hosting-')) { + const rewritePath = [REFERENCE_PATH, lib].join('/') + return NextResponse.rewrite(new URL(rewritePath, request.url)) + } + if (clientSdkIds.includes(lib)) { const version = /v\d+/.test(maybeVersion) ? maybeVersion : null const rewritePath = [REFERENCE_PATH, lib, version].filter(Boolean).join('/') diff --git a/apps/docs/package.json b/apps/docs/package.json index cdadd2ec720..e99d0f75bc4 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -9,19 +9,20 @@ "prebuild": "npm run codegen:references", "build": "next build", "build:analyze": "ANALYZE=true next build", + "build:sitemap": "tsx ./internals/generate-sitemap.ts", + "postbuild": "npm run build:sitemap", "start": "next start", "lint": "next lint", "typecheck": "tsc --noEmit", "test": "vitest --exclude \"**/*.smoke.test.ts\"", "test:smoke": "npm run codegen:references && vitest -t \"prod smoke test\"", - "build:sitemap": "tsx ./internals/generate-sitemap.ts", "embeddings": "tsx scripts/search/generate-embeddings.ts", "embeddings:refresh": "npm run embeddings -- --refresh", "last-changed": "tsx scripts/last-changed.ts", "last-changed:reset": "npm run last-changed -- --reset", "codegen:references": "tsx features/docs/Reference.generated.script.ts", "codemod:frontmatter": "node ./scripts/codemod/mdx-meta.mjs && prettier --write \"content/**/*.mdx\"", - "postbuild": "npm run build:sitemap" + "clean": "rm -rf ./docs/features/docs/generated" }, "dependencies": { "@code-hike/mdx": "^0.9.0", @@ -107,6 +108,7 @@ "npm-run-all": "^4.1.5", "openapi-types": "^12.1.3", "simple-git": "^3.24.0", + "slugify": "^1.6.6", "tsconfig": "*", "tsx": "^4.6.2", "typescript": "^5.5.0", diff --git a/apps/docs/pages/reference/self-hosting-analytics/[...slug].tsx b/apps/docs/pages/reference/self-hosting-analytics/[...slug].tsx deleted file mode 100644 index 54dedb13bca..00000000000 --- a/apps/docs/pages/reference/self-hosting-analytics/[...slug].tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu' -import RefSectionHandler from '~/components/reference/RefSectionHandler' -import { flattenSections } from '~/lib/helpers' -import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths' -import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps' -import { gen_v3 } from '~/lib/refGenerator/helpers' - -import selfHostingAnalyticsCommonSections from '~/spec/common-self-hosting-analytics-sections.json' assert { type: 'json' } -import analyticsSpec from '~/spec/transforms/analytics_v0_openapi_deparsed.json' assert { type: 'json' } - -const sections = flattenSections(selfHostingAnalyticsCommonSections) -const libraryPath = '/self-hosting-analytics' - -// @ts-ignore -const spec = gen_v3(analyticsSpec, 'wat', { apiUrl: 'apiv0' }) - -export default function SelfHostAnalyticsReference(props) { - return ( - - ) -} - -export async function getStaticProps() { - return handleRefStaticProps(sections, libraryPath) -} - -export async function getStaticPaths() { - return handleRefGetStaticPaths(sections) -} diff --git a/apps/docs/pages/reference/self-hosting-auth/[...slug].tsx b/apps/docs/pages/reference/self-hosting-auth/[...slug].tsx deleted file mode 100644 index fbd09b75644..00000000000 --- a/apps/docs/pages/reference/self-hosting-auth/[...slug].tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu' -import RefSectionHandler from '~/components/reference/RefSectionHandler' -import { flattenSections } from '~/lib/helpers' -import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths' -import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps' -import { gen_v3 } from '~/lib/refGenerator/helpers' - -import authSpec from '~/spec/auth_v1_openapi.json' assert { type: 'json' } -import selfHostingAuthCommonSections from '~/spec/common-self-hosting-auth-sections.json' - -const sections = flattenSections(selfHostingAuthCommonSections) -const libraryPath = '/self-hosting-auth' - -// @ts-ignore -const spec = gen_v3(authSpec, 'wat', { apiUrl: 'apiv0' }) - -export default function SelfHostAuthReference(props) { - return ( - - ) -} - -export async function getStaticProps() { - return handleRefStaticProps(sections, libraryPath) -} - -export async function getStaticPaths() { - return handleRefGetStaticPaths(sections) -} diff --git a/apps/docs/pages/reference/self-hosting-functions/[...slug].tsx b/apps/docs/pages/reference/self-hosting-functions/[...slug].tsx deleted file mode 100644 index 432e1a6cec0..00000000000 --- a/apps/docs/pages/reference/self-hosting-functions/[...slug].tsx +++ /dev/null @@ -1,29 +0,0 @@ -import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu' -import RefSectionHandler from '~/components/reference/RefSectionHandler' -import { flattenSections } from '~/lib/helpers' -import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths' -import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps' - -import selfHostingFunctionsCommonSections from '~/spec/common-self-hosting-functions-sections.json' assert { type: 'json' } - -const sections = flattenSections(selfHostingFunctionsCommonSections) -const libraryPath = '/self-hosting-functions' - -export default function SelfHostFunctionsReference(props) { - return ( - - ) -} - -export async function getStaticProps() { - return handleRefStaticProps(sections, libraryPath) -} - -export async function getStaticPaths() { - return handleRefGetStaticPaths(sections) -} diff --git a/apps/docs/pages/reference/self-hosting-realtime/[...slug].tsx b/apps/docs/pages/reference/self-hosting-realtime/[...slug].tsx deleted file mode 100644 index 3b894c15f8b..00000000000 --- a/apps/docs/pages/reference/self-hosting-realtime/[...slug].tsx +++ /dev/null @@ -1,29 +0,0 @@ -import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu' -import RefSectionHandler from '~/components/reference/RefSectionHandler' -import { flattenSections } from '~/lib/helpers' -import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths' -import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps' - -import selfHostingRealtimeCommonSections from '~/spec/common-self-hosting-realtime-sections.json' assert { type: 'json' } - -const sections = flattenSections(selfHostingRealtimeCommonSections) -const libraryPath = '/self-hosting-realtime' - -export default function SelfHostRealtimeReference(props) { - return ( - - ) -} - -export async function getStaticProps() { - return handleRefStaticProps(sections, libraryPath) -} - -export async function getStaticPaths() { - return handleRefGetStaticPaths(sections) -} diff --git a/apps/docs/pages/reference/self-hosting-storage/[...slug].tsx b/apps/docs/pages/reference/self-hosting-storage/[...slug].tsx deleted file mode 100644 index 13559bdc7dc..00000000000 --- a/apps/docs/pages/reference/self-hosting-storage/[...slug].tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu' -import RefSectionHandler from '~/components/reference/RefSectionHandler' -import { flattenSections } from '~/lib/helpers' -import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths' -import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps' -import { gen_v3 } from '~/lib/refGenerator/helpers' - -import storageSpec from '~/spec/storage_v0_openapi.json' assert { type: 'json' } -import selfHostingStorageCommonSections from '~/spec/common-self-hosting-storage-sections.json' assert { type: 'json' } - -const sections = flattenSections(selfHostingStorageCommonSections) -const libraryPath = '/self-hosting-storage' - -// @ts-ignore -const spec = gen_v3(storageSpec, 'wat', { apiUrl: 'apiv0' }) - -export default function SelfHostStorageReference(props) { - return ( - - ) -} - -export async function getStaticProps() { - return handleRefStaticProps(sections, libraryPath) -} - -export async function getStaticPaths() { - return handleRefGetStaticPaths(sections) -} diff --git a/apps/docs/spec/common-self-hosting-analytics-sections.json b/apps/docs/spec/common-self-hosting-analytics-sections.json index 4579dd3a298..fe5d622bc93 100644 --- a/apps/docs/spec/common-self-hosting-analytics-sections.json +++ b/apps/docs/spec/common-self-hosting-analytics-sections.json @@ -7,6 +7,7 @@ "type": "markdown" }, { + "id": "management-api", "type": "category", "title": "Management API", "items": [ @@ -14,91 +15,91 @@ "id": "list-endpoints", "slug": "list-endpoints", "title": "List endpoints", - "type": "operation" + "type": "self-hosted-operation" }, { "id": "create-endpoint", "slug": "create-endpoint", "title": "Create endpoint", - "type": "operation" + "type": "self-hosted-operation" }, { "id": "delete-endpoint", "slug": "delete-endpoint", "title": "Delete endpoint", - "type": "operation" + "type": "self-hosted-operation" }, { "id": "fetch-endpoint", "slug": "fetch-endpoint", "title": "Fetch endpoint", - "type": "operation" + "type": "self-hosted-operation" }, { "id": "update-endpoint", "slug": "update-endpoint", "title": "Update endpoint", - "type": "operation" + "type": "self-hosted-operation" }, { "id": "list-sources", "slug": "list-sources", "title": "List sources", - "type": "operation" + "type": "self-hosted-operation" }, { "id": "create-source", "slug": "create-source", "title": "Create source", - "type": "operation" + "type": "self-hosted-operation" }, { "id": "delete-source", "slug": "delete-source", "title": "Delete source", - "type": "operation" + "type": "self-hosted-operation" }, { "id": "fetch-source", "slug": "fetch-source", "title": "Fetch source", - "type": "operation" + "type": "self-hosted-operation" }, { "id": "update-source", "slug": "update-source", "title": "Update source", - "type": "operation" + "type": "self-hosted-operation" }, { "id": "list-teams", "slug": "list-teams", "title": "List teams", - "type": "operation" + "type": "self-hosted-operation" }, { "id": "create-team", "slug": "create-team", "title": "Create team", - "type": "operation" + "type": "self-hosted-operation" }, { "id": "delete-team", "slug": "delete-team", "title": "Delete team", - "type": "operation" + "type": "self-hosted-operation" }, { "id": "fetch-team", "slug": "fetch-team", "title": "Fetch team", - "type": "operation" + "type": "self-hosted-operation" }, { "id": "update-team", "slug": "update-team", "title": "Update team", - "type": "operation" + "type": "self-hosted-operation" } ] } diff --git a/apps/docs/spec/common-self-hosting-auth-sections.json b/apps/docs/spec/common-self-hosting-auth-sections.json index 2814fb67584..224eb0b71e7 100644 --- a/apps/docs/spec/common-self-hosting-auth-sections.json +++ b/apps/docs/spec/common-self-hosting-auth-sections.json @@ -7,6 +7,7 @@ "type": "markdown" }, { + "id": "usage", "type": "category", "title": "Usage", "items": [ @@ -14,121 +15,121 @@ "id": "generates-an-email-action-link", "slug": "generates-an-email-action-link", "title": "Generates an email action link", - "type": "operation" + "type": "self-hosted-operation" }, { "id": "get-a-user", "slug": "get-a-user", "title": "Get a user", - "type": "operation" + "type": "self-hosted-operation" }, { "id": "update-a-user", "slug": "update-a-user", "title": "Update a user", - "type": "operation" + "type": "self-hosted-operation" }, { "id": "deletes-a-user", "slug": "deletes-a-user", "title": "Deletes a user", - "type": "operation" + "type": "self-hosted-operation" }, { "id": "list-all-users", "slug": "list-all-users", "title": "List all users", - "type": "operation" + "type": "self-hosted-operation" }, { "id": "returns-the-created-user", "slug": "returns-the-created-user", "title": "Returns the created user", - "type": "operation" + "type": "self-hosted-operation" }, { "id": "redirects-the-user-to-the-3rd-party-oauth-provider-to-start-the-oauth1-0-or-oauth2-0-authentication-process", "slug": "redirects-the-user-to-the-3rd-party-oauth-provider-to-start-the-oauth1-0-or-oauth2-0-authentication-process", "title": "Redirects the user to the 3rd party oauth provider to start the oauth1 0 or oauth2 0 authentication process", - "type": "operation" + "type": "self-hosted-operation" }, { "id": "receives-the-redirect-from-an-external-provider-during-the-oauth-authentication-process-starts-the-process-of-creating-an-access-and-refresh-token", "slug": "receives-the-redirect-from-an-external-provider-during-the-oauth-authentication-process-starts-the-process-of-creating-an-access-and-refresh-token", "title": "Receives the redirect from an external provider during the oauth authentication process starts the process of creating an access and refresh token", - "type": "operation" + "type": "self-hosted-operation" }, { "id": "the-healthcheck-endpoint-for-gotrue-returns-the-current-gotrue-version", "slug": "the-healthcheck-endpoint-for-gotrue-returns-the-current-gotrue-version", "title": "The healthcheck endpoint for gotrue returns the current gotrue version", - "type": "operation" + "type": "self-hosted-operation" }, { "id": "sends-an-invite-link-to-the-user", "slug": "sends-an-invite-link-to-the-user", "title": "Sends an invite link to the user", - "type": "operation" + "type": "self-hosted-operation" }, { "id": "logs-out-the-user", "slug": "logs-out-the-user", "title": "Logs out the user", - "type": "operation" + "type": "self-hosted-operation" }, { "id": "passwordless-sign-in-method-for-email-or-phone", "slug": "passwordless-sign-in-method-for-email-or-phone", "title": "Passwordless sign in method for email or phone", - "type": "operation" + "type": "self-hosted-operation" }, { "id": "sends-a-password-recovery-email-link-to-the-users-email", "slug": "sends-a-password-recovery-email-link-to-the-users-email", "title": "Sends a password recovery email link to the users email", - "type": "operation" + "type": "self-hosted-operation" }, { "id": "returns-the-configuration-settings-for-the-gotrue-server", "slug": "returns-the-configuration-settings-for-the-gotrue-server", "title": "Returns the configuration settings for the gotrue server", - "type": "operation" + "type": "self-hosted-operation" }, { "id": "password-based-signup-with-either-email-or-phone", "slug": "password-based-signup-with-either-email-or-phone", "title": "Password based signup with either email or phone", - "type": "operation" + "type": "self-hosted-operation" }, { "id": "signs-in-a-user-with-a-password", "slug": "signs-in-a-user-with-a-password", "title": "Signs in a user with a password", - "type": "operation" + "type": "self-hosted-operation" }, { "id": "refreshes-a-users-refresh-token", "slug": "refreshes-a-users-refresh-token", "title": "Refreshes a users refresh token", - "type": "operation" + "type": "self-hosted-operation" }, { "id": "get-information-for-the-logged-in-user", "slug": "get-information-for-the-logged-in-user", "title": "Get information for the logged in user", - "type": "operation" + "type": "self-hosted-operation" }, { "id": "returns-the-updated-user", "slug": "returns-the-updated-user", "title": "Returns the updated user", - "type": "operation" + "type": "self-hosted-operation" }, { "id": "verifies-a-sign-up", "slug": "verifies-a-sign-up", "title": "Verifies a sign up", - "type": "operation" + "type": "self-hosted-operation" } ] } diff --git a/apps/docs/spec/common-self-hosting-storage-sections.json b/apps/docs/spec/common-self-hosting-storage-sections.json index 0e90c80c252..0970ad38ea6 100644 --- a/apps/docs/spec/common-self-hosting-storage-sections.json +++ b/apps/docs/spec/common-self-hosting-storage-sections.json @@ -7,6 +7,7 @@ "type": "markdown" }, { + "id": "usage", "type": "category", "title": "Usage", "items": [ @@ -15,147 +16,147 @@ "title": "Create a bucket", "slug": "create-a-bucket", "summary": "Create a bucket", - "type": "operation" + "type": "self-hosted-operation" }, { "id": "gets-all-buckets", "title": "Gets all buckets", "slug": "gets-all-buckets", "summary": "Gets all buckets", - "type": "operation" + "type": "self-hosted-operation" }, { "id": "empty-a-bucket", "title": "Empty a bucket", "slug": "empty-a-bucket", "summary": "Empty a bucket", - "type": "operation" + "type": "self-hosted-operation" }, { "id": "get-details-of-a-bucket", "title": "Get details of a bucket", "slug": "get-details-of-a-bucket", "summary": "Get details of a bucket", - "type": "operation" + "type": "self-hosted-operation" }, { "id": "update-properties-of-a-bucket", "title": "Update properties of a bucket", "slug": "update-properties-of-a-bucket", "summary": "Update properties of a bucket", - "type": "operation" + "type": "self-hosted-operation" }, { "id": "delete-a-bucket", "title": "Delete a bucket", "slug": "delete-a-bucket", "summary": "Delete a bucket", - "type": "operation" + "type": "self-hosted-operation" }, { "id": "delete-an-object", "title": "Delete an object", "slug": "delete-an-object", "summary": "Delete an object", - "type": "operation" + "type": "self-hosted-operation" }, { "id": "get-object", "title": "Get object", "slug": "get-object", "summary": "Get object", - "type": "operation" + "type": "self-hosted-operation" }, { "id": "update-the-object-at-an-existing-key", "title": "Update the object at an existing key", "slug": "update-the-object-at-an-existing-key", "summary": "Update the object at an existing key", - "type": "operation" + "type": "self-hosted-operation" }, { "id": "upload-a-new-object", "title": "Upload a new object", "slug": "upload-a-new-object", "summary": "Upload a new object", - "type": "operation" + "type": "self-hosted-operation" }, { "id": "delete-multiple-objects", "title": "Delete multiple objects", "slug": "delete-multiple-objects", "summary": "Delete multiple objects", - "type": "operation" + "type": "self-hosted-operation" }, { "id": "retrieve-an-object", "title": "Retrieve an object", "slug": "retrieve-an-object", "summary": "Retrieve an object", - "type": "operation" + "type": "self-hosted-operation" }, { "id": "generate-a-presigned-url-to-retrieve-an-object", "title": "Generate a presigned url to retrieve an object", "slug": "generate-a-presigned-url-to-retrieve-an-object", "summary": "Generate a presigned url to retrieve an object", - "type": "operation" + "type": "self-hosted-operation" }, { "id": "retrieve-an-object-via-a-presigned-url", "title": "Retrieve an object via a presigned URL", "slug": "retrieve-an-object-via-a-presigned-url", "summary": "Retrieve an object via a presigned URL", - "type": "operation" + "type": "self-hosted-operation" }, { "id": "generate-presigned-urls-to-retrieve-objects", "title": "Generate presigned urls to retrieve objects", "slug": "generate-presigned-urls-to-retrieve-objects", "summary": "Generate presigned urls to retrieve objects", - "type": "operation" + "type": "self-hosted-operation" }, { "id": "moves-an-object", "title": "Moves an object", "slug": "moves-an-object", "summary": "Moves an object", - "type": "operation" + "type": "self-hosted-operation" }, { "id": "search-for-objects-under-a-prefix", "title": "Search for objects under a prefix", "slug": "search-for-objects-under-a-prefix", "summary": "Search for objects under a prefix", - "type": "operation" + "type": "self-hosted-operation" }, { "id": "retrieve-object-info", "title": "Retrieve object info", "slug": "retrieve-object-info", "summary": "Retrieve object info", - "type": "operation" + "type": "self-hosted-operation" }, { "id": "copies-an-object", "title": "Copies an object", "slug": "copies-an-object", "summary": "Copies an object", - "type": "operation" + "type": "self-hosted-operation" }, { "id": "retrieve-an-object-from-a-public-bucket", "title": "Retrieve an object from a public bucket", "slug": "retrieve-an-object-from-a-public-bucket", "summary": "Retrieve an object from a public bucket", - "type": "operation" + "type": "self-hosted-operation" }, { "id": "get-object-info", "title": "Get object info", "slug": "get-object-info", "summary": "Get object info", - "type": "operation" + "type": "self-hosted-operation" } ] } diff --git a/package-lock.json b/package-lock.json index b8bcff1b7bf..433587e9625 100644 --- a/package-lock.json +++ b/package-lock.json @@ -932,6 +932,7 @@ "npm-run-all": "^4.1.5", "openapi-types": "^12.1.3", "simple-git": "^3.24.0", + "slugify": "^1.6.6", "tsconfig": "*", "tsx": "^4.6.2", "typescript": "^5.5.0", @@ -1376,6 +1377,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "apps/docs/node_modules/slugify": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.6.6.tgz", + "integrity": "sha512-h+z7HKHYXj6wJU+AnS/+IH8Uh9fdcX1Lrhg1/VMdf9PwoBQXFcXiAdsy2tSK0P6gKwJLXp02r90ahUCqHk9rrw==", + "dev": true, + "engines": { + "node": ">=8.0.0" + } + }, "apps/docs/node_modules/strip-final-newline": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz",