mirror of
https://github.com/saltbo/zpan.git
synced 2026-08-30 17:50:07 +08:00
fbec74747e
Group all license application logic into a single usecases/licensing.ts (certificate/token verification, binding-state, cloud refresh, license-gated policy) and collapse small single-purpose usecases that belonged together. - delete license-entitlement.ts: a write-only cache nobody read (loadEntitlement had zero live consumers); remove its invalidate* call-sites - merge licensing-refresh-runner -> license-refresh, then fold license-certificate + license-refresh + license-policy + binding-state into one licensing.ts (internal cert<-state<-refresh<-policy edges become in-file) - merge team-count + signup-mode -> license-policy (then into licensing.ts) - merge trash-retention -> purge (manual purge + scheduled retention sweep) Tests follow the source: the runner tests are rewritten against a fake LicensingCloud port (the old module-spy on performRefresh can't survive a same-module call), and the team-limit test seeds a real pro license instead of mocking the licensing module. Net 486+/861-. typecheck clean; unit+integration green (158 files / 3797 tests). Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
27 lines
1.2 KiB
TypeScript
27 lines
1.2 KiB
TypeScript
import type { ProFeature } from '@shared/types'
|
|
import type { Context } from 'hono'
|
|
import { createMiddleware } from 'hono/factory'
|
|
import { ZPAN_CLOUD_URL_DEFAULT } from '../../shared/constants'
|
|
import { hasFeature } from '../domain/licensing'
|
|
import { loadBindingState, normalizeHost } from '../usecases/licensing'
|
|
import { getSitePublicOrigin } from '../usecases/site-public-origin'
|
|
import type { Env } from './platform'
|
|
|
|
async function configuredPublicHost(c: Context<Env>): Promise<string | null> {
|
|
const origin = await getSitePublicOrigin(c.get('deps'))
|
|
return origin ? new URL(origin).host : null
|
|
}
|
|
|
|
export function requireFeature(name: ProFeature) {
|
|
return createMiddleware<Env>(async (c, next) => {
|
|
const cloudBaseUrl = c.get('platform').getEnv('ZPAN_CLOUD_URL') ?? ZPAN_CLOUD_URL_DEFAULT
|
|
const currentHost =
|
|
(await configuredPublicHost(c)) ?? normalizeHost(c.req.header('host')) ?? new URL(c.req.url).host
|
|
const state = await loadBindingState(c.get('deps'), { currentHost, cloudBaseUrl })
|
|
if (!hasFeature(name, state)) {
|
|
return c.json({ error: 'feature_not_available', feature: name, upgrade_url: '/settings/billing' }, 402)
|
|
}
|
|
await next()
|
|
})
|
|
}
|