code: nextjs,frontends,validate (2 files)

This commit is contained in:
Richard Ward
2025-12-30 23:00:51 +00:00
parent 9923aa1b86
commit bc8fe80b20
2 changed files with 54 additions and 7 deletions

View File

@@ -3,10 +3,15 @@
*
* This layout wraps all pages under /{tenant}/{package}/...
* It provides tenant context to all child components.
*
* A page has one PRIMARY package (from the URL) but may use
* components and data from additional packages (dependencies).
*/
import { headers } from 'next/headers'
import { notFound } from 'next/navigation'
import { loadPackageMetadata } from '@/lib/routing/auth/validate-package-route'
import { TenantProvider } from './tenant-context'
interface TenantLayoutProps {
@@ -17,6 +22,25 @@ interface TenantLayoutProps {
}>
}
/**
* Load package dependencies recursively (1 level deep for now)
*/
function getPackageDependencies(packageId: string): { id: string; name?: string }[] {
const metadata = loadPackageMetadata(packageId)
if (!metadata?.dependencies) {
return []
}
return metadata.dependencies.map(depId => {
const depMetadata = loadPackageMetadata(depId)
return {
id: depId,
name: depMetadata?.name,
minLevel: depMetadata?.minLevel,
}
})
}
export default async function TenantLayout({
children,
params,
@@ -24,23 +48,40 @@ export default async function TenantLayout({
const resolvedParams = await params
const { tenant, package: pkg } = resolvedParams
// Validate tenant exists
// TODO: Check against database
// Load primary package metadata
const packageMetadata = loadPackageMetadata(pkg)
if (!packageMetadata) {
// Package doesn't exist
notFound()
}
// Load dependencies that this page can also use
const additionalPackages = getPackageDependencies(pkg)
// TODO: Validate tenant exists against database
// const tenantData = await getTenant(tenant)
// if (!tenantData) {
// notFound()
// }
// Validate package exists and is installed for tenant
// TODO: Check against database
// TODO: Validate package is installed for this tenant
// const packageInstalled = await isPackageInstalled(tenant, pkg)
// if (!packageInstalled) {
// notFound()
// }
return (
<TenantProvider tenant={tenant} packageId={pkg}>
<div className="tenant-layout" data-tenant={tenant} data-package={pkg}>
<TenantProvider
tenant={tenant}
packageId={pkg}
additionalPackages={additionalPackages}
>
<div
className="tenant-layout"
data-tenant={tenant}
data-package={pkg}
data-packages={[pkg, ...additionalPackages.map(p => p.id)].join(',')}
>
{children}
</div>
</TenantProvider>

View File

@@ -26,6 +26,10 @@ export interface PackageMetadata {
version: string
description?: string
minLevel: number
/** Package dependencies that this package can access */
dependencies?: string[]
/** Dev dependencies (not included in runtime) */
devDependencies?: string[]
routes?: PackageRoute[]
schema?: {
entities?: string[]
@@ -42,6 +46,8 @@ export interface RouteClaimResult {
package: PackageMetadata | null
reason?: string
entities?: string[]
/** Packages accessible from this route (primary + dependencies) */
accessiblePackages?: string[]
}
// Cache loaded package metadata