@usebetterdev/tenant-core 0.5.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- import type { ConsoleProductEndpoint } from "@usebetterdev/console-contract";
1
+ import type { ConsoleProductEndpoint } from "@usebetterdev/contract";
2
2
  import type { TenantApi } from "./better-tenant.js";
3
3
  export declare function createTenantConsoleEndpoints(api: TenantApi): ConsoleProductEndpoint[];
4
4
  //# sourceMappingURL=console-endpoints.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"console-endpoints.d.ts","sourceRoot":"","sources":["../src/console-endpoints.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,sBAAsB,EAKvB,MAAM,gCAAgC,CAAC;AAKxC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAepD,wBAAgB,4BAA4B,CAC1C,GAAG,EAAE,SAAS,GACb,sBAAsB,EAAE,CA0I1B"}
1
+ {"version":3,"file":"console-endpoints.d.ts","sourceRoot":"","sources":["../src/console-endpoints.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,sBAAsB,EAKvB,MAAM,wBAAwB,CAAC;AAKhC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAepD,wBAAgB,4BAA4B,CAC1C,GAAG,EAAE,SAAS,GACb,sBAAsB,EAAE,CA0I1B"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/telemetry.ts","../src/context.ts","../src/adapter.ts","../src/errors.ts","../src/handle-request.ts","../src/api.ts","../src/resolver.ts","../../../shared/console-utils/src/index.ts","../src/console-endpoints.ts","../src/better-tenant.ts","../src/request.ts"],"sourcesContent":["export { betterTenant } from \"./better-tenant.js\";\nexport type { BetterTenantInstance, TenantApi } from \"./better-tenant.js\";\nexport { getContext, runWithTenant } from \"./context.js\";\nexport { resolveTenant, describeStrategies } from \"./resolver.js\";\nexport { handleRequest } from \"./handle-request.js\";\nexport { toResolvableRequest } from \"./request.js\";\nexport { TenantNotResolvedError, TenantMiddlewareError } from \"./errors.js\";\nexport { runAs, runAsSystem, createTenantApi } from \"./api.js\";\nexport type {\n CreateTenantData,\n UpdateTenantData,\n ListTenantsOptions,\n} from \"./api.js\";\nexport type { HandleRequestOptions } from \"./handle-request.js\";\nexport type { NodeLikeRequest } from \"./request.js\";\nexport type {\n Tenant,\n TenantContext,\n TenantScopedDatabase,\n SystemDatabase,\n TenantAdapter,\n TenantRepository,\n DatabaseProvider,\n TenantResolverConfig,\n ResolvableRequest,\n BetterTenantPlugin,\n BetterTenantConfig,\n TelemetryConfig,\n PathResolverConfig,\n SubdomainResolverConfig,\n JwtResolverConfig,\n ConsoleRegistration,\n} from \"./types.js\";\nexport { sendCliTelemetry } from \"./telemetry.js\";\nexport type { TelemetryCliConfig, CliConfigForTelemetry } from \"./telemetry.js\";\n","/**\n * Anonymous telemetry for Better Tenant.\n * On by default, opt-out via BETTER_TENANT_TELEMETRY=0 or telemetry: { enabled: false }.\n * See docs/TELEMETRY.md.\n */\n\nimport { createHash } from \"node:crypto\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { platform, release, arch, cpus, totalmem } from \"node:os\";\nimport type { BetterTenantConfig } from \"./types.js\";\n\n/** Subset of BetterTenantConfig used by telemetry (avoids contravariance issues with generic DB types). */\ntype TelemetryConfigInput = Pick<\n BetterTenantConfig,\n \"tenantResolver\" | \"basePath\" | \"plugins\" | \"loadTenant\" | \"telemetry\"\n>;\n\nconst TELEMETRY_ENDPOINT = \"https://telemetry.usebetter.dev/v1/events\";\nconst LIBRARY_ID = \"better-tenant\";\n\n// --- Redacted config types ---\n\nexport interface TelemetryTenantConfig {\n resolver: {\n header: boolean;\n path: boolean;\n subdomain: boolean;\n jwt: boolean;\n custom: boolean;\n };\n tenantTablesCount: number;\n loadTenant: boolean | undefined;\n basePathSet: boolean;\n plugins: string[];\n}\n\nexport interface TelemetryCliConfig {\n tenantTablesCount: number;\n hasSchemaDir: boolean;\n hasMigrationsDir: boolean;\n}\n\nexport interface TelemetryPayload {\n library: string;\n type: string;\n timestamp: string;\n anonymousId?: string;\n runtime?: { name: string; version: string };\n environment?: string;\n framework?: { name: string; version?: string };\n database?: { name: string; version?: string };\n system?: {\n platform: string;\n release: string;\n arch: string;\n cpus: number;\n totalMemoryMb: number;\n isDocker?: boolean;\n isWSL?: boolean;\n };\n packageManager?: { name: string; version?: string };\n config?: TelemetryTenantConfig | TelemetryCliConfig;\n outcome?: string;\n}\n\n// --- Telemetry options ---\n\nexport interface TelemetryOptions {\n /** Override enabled (default: true). Set false to opt out. */\n enabled?: boolean;\n /** Debug mode: log to console only, do not send. */\n debug?: boolean;\n /** When true, return Promise that resolves when send completes. Use before process.exit. */\n wait?: boolean;\n}\n\n// --- Redaction ---\n\nexport function getTelemetryTenantConfig(\n config: TelemetryConfigInput,\n): TelemetryTenantConfig {\n const r = config.tenantResolver ?? {};\n return {\n resolver: {\n header: !!r.header,\n path: !!r.path,\n subdomain: !!r.subdomain,\n jwt: !!r.jwt,\n custom: !!r.custom,\n },\n tenantTablesCount: 0,\n loadTenant: config.loadTenant,\n basePathSet: !!config.basePath,\n plugins: (config.plugins ?? []).map((p) => String(p.id)),\n };\n}\n\nexport function getTelemetryCliConfig(config: {\n tenantTables: string[];\n schemaDir?: string;\n migrationsDir?: string;\n}): TelemetryCliConfig {\n return {\n tenantTablesCount: config.tenantTables?.length ?? 0,\n hasSchemaDir: !!config.schemaDir,\n hasMigrationsDir: !!config.migrationsDir,\n };\n}\n\n// --- Detection ---\n\nfunction getAnonymousId(cwd: string): string | undefined {\n try {\n const pkgPath = join(cwd, \"package.json\");\n if (!existsSync(pkgPath)) {\n return undefined;\n }\n\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\")) as {\n name?: string;\n betterTenant?: { basePath?: string };\n };\n const name = typeof pkg?.name === \"string\" ? pkg.name : \"\";\n const basePath =\n typeof pkg?.betterTenant?.basePath === \"string\"\n ? pkg.betterTenant.basePath\n : \"\";\n const input = `${name}:${basePath}`.trim() || \"unknown\";\n return createHash(\"sha256\").update(input).digest(\"hex\").slice(0, 16);\n } catch {\n return undefined;\n }\n}\n\nfunction detectRuntime(): { name: string; version: string } {\n const g = globalThis as Record<string, unknown>;\n if (typeof g.Bun !== \"undefined\") {\n const bun = g.Bun as { version?: string };\n return {\n name: \"bun\",\n version: typeof bun?.version === \"string\" ? bun.version : \"unknown\",\n };\n }\n if (typeof g.Deno !== \"undefined\") {\n const deno = g.Deno as { version?: { deno?: string } };\n const v = deno?.version?.deno;\n return { name: \"deno\", version: typeof v === \"string\" ? v : \"unknown\" };\n }\n const v = (typeof process !== \"undefined\" && process.versions?.node) || \"\";\n return { name: \"node\", version: v || \"unknown\" };\n}\n\nfunction detectEnvironment(): string {\n const env = process.env.NODE_ENV || \"development\";\n if (env === \"test\") {\n return \"test\";\n }\n\n // CI check before NODE_ENV so CI is detected even when NODE_ENV=production\n if (\n process.env.CI === \"true\" ||\n process.env.GITHUB_ACTIONS === \"true\" ||\n process.env.GITLAB_CI === \"true\" ||\n process.env.CIRCLECI === \"true\"\n ) {\n return \"ci\";\n }\n if (env === \"production\") {\n return \"production\";\n }\n\n return \"development\";\n}\n\nfunction detectFramework(\n cwd: string,\n): { name: string; version?: string } | undefined {\n try {\n const pkgPath = join(cwd, \"package.json\");\n if (!existsSync(pkgPath)) {\n return undefined;\n }\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\")) as {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n };\n const deps = { ...pkg?.dependencies, ...pkg?.devDependencies };\n if (deps[\"next\"]) {\n return { name: \"next\", version: deps[\"next\"] };\n }\n if (deps[\"hono\"]) {\n return { name: \"hono\", version: deps[\"hono\"] };\n }\n if (deps[\"express\"]) {\n return { name: \"express\", version: deps[\"express\"] };\n }\n return undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction detectDatabase(\n cwd: string,\n): { name: string; version?: string } | undefined {\n try {\n const pkgPath = join(cwd, \"package.json\");\n if (!existsSync(pkgPath)) {\n return undefined;\n }\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\")) as {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n };\n const deps = { ...pkg?.dependencies, ...pkg?.devDependencies };\n if (deps[\"drizzle-orm\"]) {\n return { name: \"drizzle\", version: deps[\"drizzle-orm\"] };\n }\n if (deps[\"prisma\"]) {\n return { name: \"prisma\", version: deps[\"prisma\"] };\n }\n return undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction detectSystem(): NonNullable<TelemetryPayload[\"system\"]> {\n const isDocker = existsSync(\"/.dockerenv\");\n const isWSL =\n typeof process.env.WSL_DISTRO_NAME === \"string\" ||\n (typeof process.env.WSL_INTEROP === \"string\" &&\n process.env.WSL_INTEROP.length > 0);\n return {\n platform: platform(),\n release: release(),\n arch: arch(),\n cpus: cpus().length,\n totalMemoryMb: Math.round(totalmem() / 1024 / 1024),\n isDocker,\n isWSL,\n };\n}\n\nfunction detectPackageManager():\n | { name: string; version?: string }\n | undefined {\n const ua = process.env.npm_config_user_agent;\n if (!ua || typeof ua !== \"string\") {\n return undefined;\n }\n const match = ua.match(/^(.+?)\\/(\\d+\\.\\d+\\.\\d+.*?)(?:\\s|$)/);\n if (match) {\n const name = (match[1] ?? \"unknown\").toLowerCase();\n const version = match[2];\n return version ? { name, version } : { name };\n }\n if (ua.includes(\"pnpm\")) {\n return { name: \"pnpm\" };\n }\n if (ua.includes(\"yarn\")) {\n return { name: \"yarn\" };\n }\n return { name: \"npm\" };\n}\n\n// --- Send ---\n\nfunction isTelemetryEnabled(options?: TelemetryOptions): boolean {\n if (process.env.NODE_ENV === \"test\") {\n return false;\n }\n const env = process.env.BETTER_TENANT_TELEMETRY;\n if (env === \"0\" || env?.toLowerCase() === \"false\") {\n return false;\n }\n if (env === \"1\" || env?.toLowerCase() === \"true\") {\n return true;\n }\n return options?.enabled !== false;\n}\n\nfunction isDebugMode(options?: TelemetryOptions): boolean {\n if (process.env.BETTER_TENANT_TELEMETRY_DEBUG === \"1\") {\n return true;\n }\n return options?.debug === true;\n}\n\n/**\n * Send telemetry event. Fire-and-forget by default; use options.wait for process-exit paths.\n * Skips when NODE_ENV=test, when disabled via env/config, or when debug mode logs only.\n */\nexport function sendTelemetry(\n type: string,\n payload: Omit<TelemetryPayload, \"library\" | \"type\" | \"timestamp\">,\n options?: TelemetryOptions,\n): void | Promise<void> {\n if (!isTelemetryEnabled(options)) {\n return options?.wait ? Promise.resolve() : undefined;\n }\n const fullPayload: TelemetryPayload = {\n library: LIBRARY_ID,\n type,\n timestamp: new Date().toISOString(),\n ...payload,\n };\n if (isDebugMode(options)) {\n console.log(\n \"[better-tenant telemetry]\",\n JSON.stringify(fullPayload, null, 2),\n );\n return options?.wait ? Promise.resolve() : undefined;\n }\n const doSend = () =>\n fetch(TELEMETRY_ENDPOINT, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(fullPayload),\n }).catch(() => {\n // Silently ignore send failures\n });\n\n if (options?.wait) {\n return new Promise<void>((resolve) => {\n setImmediate(async () => {\n await doSend();\n resolve();\n });\n });\n }\n\n setImmediate(() => doSend());\n}\n\n/**\n * Build and send init telemetry (call from betterTenant()).\n */\nexport function sendInitTelemetry(\n config: TelemetryConfigInput,\n options?: TelemetryOptions,\n): void {\n const cwd = process.cwd();\n const payload: Omit<TelemetryPayload, \"library\" | \"type\" | \"timestamp\"> = {\n runtime: detectRuntime(),\n environment: detectEnvironment(),\n config: getTelemetryTenantConfig(config),\n };\n const anonymousId = getAnonymousId(cwd);\n if (anonymousId) payload.anonymousId = anonymousId;\n const framework = detectFramework(cwd);\n if (framework) payload.framework = framework;\n const database = detectDatabase(cwd);\n if (database) payload.database = database;\n payload.system = detectSystem();\n const pkgMgr = detectPackageManager();\n if (pkgMgr) payload.packageManager = pkgMgr;\n sendTelemetry(\"init\", payload, options ?? config.telemetry);\n}\n\n/** Raw CLI config shape (subset needed for telemetry). */\nexport interface CliConfigForTelemetry {\n tenantTables: string[];\n schemaDir?: string;\n migrationsDir?: string;\n}\n\n/**\n * Build and send CLI telemetry. Use from CLI commands.\n * Accepts raw config; redaction happens internally.\n * Use options.wait: true before process.exit so the send completes.\n */\nexport function sendCliTelemetry(\n type: \"cli_generate\" | \"cli_migrate\" | \"cli_check\" | \"cli_seed\" | \"cli_init\",\n outcome: string,\n config?: CliConfigForTelemetry,\n options?: { wait?: boolean },\n): void | Promise<void> {\n const cwd = process.cwd();\n const redactedConfig = config ? getTelemetryCliConfig(config) : undefined;\n const payload: Omit<TelemetryPayload, \"library\" | \"type\" | \"timestamp\"> = {\n runtime: detectRuntime(),\n environment: detectEnvironment(),\n outcome,\n };\n if (redactedConfig) payload.config = redactedConfig;\n payload.system = detectSystem();\n const anonymousId = getAnonymousId(cwd);\n if (anonymousId) payload.anonymousId = anonymousId;\n const framework = detectFramework(cwd);\n if (framework) payload.framework = framework;\n const database = detectDatabase(cwd);\n if (database) payload.database = database;\n const pkgMgr = detectPackageManager();\n if (pkgMgr) payload.packageManager = pkgMgr;\n return sendTelemetry(type, payload, options);\n}\n","import type { TenantContext } from \"./types.js\";\nimport { AsyncLocalStorage } from \"node:async_hooks\";\n\nconst storage = new AsyncLocalStorage<TenantContext>();\n\n/**\n * Returns the current tenant context, or undefined when not inside runWithTenant / runWithTenantAndDatabase.\n */\nexport function getContext(): TenantContext | undefined {\n return storage.getStore();\n}\n\n/**\n * Runs fn inside a scope where getContext() returns { tenantId }.\n * No adapter/DB involved; use for tests or when adapter is not configured.\n * If tenantId is empty string, it is treated as undefined (no tenant).\n */\nexport function runWithTenant<T>(\n tenantId: string,\n fn: () => T | Promise<T>,\n): Promise<T> {\n const normalized = tenantId.trim() || undefined;\n if (normalized === undefined) {\n return Promise.reject(\n new Error(\"better-tenant: tenantId must be a non-empty string\"),\n );\n }\n return Promise.resolve(\n storage.run({ tenantId: normalized }, () => fn()),\n );\n}\n\n/**\n * Internal: set context with optional database handle. Used by runWithTenantAndDatabase.\n */\nexport function runWithContext<T>(\n context: TenantContext,\n fn: () => T | Promise<T>,\n): Promise<T> {\n return Promise.resolve(storage.run(context, () => fn()));\n}\n\n","import type {\n TenantAdapter,\n TenantContext,\n RunWithTenantAndDatabaseOptions,\n} from \"./types.js\";\nimport { getContext, runWithContext } from \"./context.js\";\n\n/**\n * Returns the tenant-scoped database handle when inside a runWithTenantAndDatabase (or runAs) scope.\n *\n * Use only the handle from getDatabase() for tenant-scoped tables. Outside scope, returns undefined.\n * Config requires an adapter when tenant-scoped DB is used; getDatabase() is then available inside\n * request handlers that ran via runWithTenantAndDatabase(tenantId, adapter, next).\n */\nexport function getDatabase(): unknown {\n const context = getContext();\n return context?.database;\n}\n\n/**\n * Sets AsyncLocalStorage context and runs fn with the adapter's tenant-scoped DB.\n *\n * (1) Sets AsyncLocalStorage context with tenantId and database.\n * (2) Calls adapter.runWithTenant(tenantId, (database) => fn(database)).\n * (3) Stores the database handle in context so getDatabase() returns it.\n *\n * Middleware should resolve tenantId from the request, then call\n * runWithTenantAndDatabase(tenantId, adapter, next) so both context and DB handle are available.\n *\n * When options.loadTenant is true and options.getTenantRepository and adapter.runAsSystem are set,\n * loads the full Tenant row into context so getContext().tenant is available (or undefined if not found).\n */\nexport async function runWithTenantAndDatabase<TDb, SDb, T>(\n tenantId: string,\n adapter: TenantAdapter<TDb, SDb>,\n fn: (database: TDb) => Promise<T>,\n options?: RunWithTenantAndDatabaseOptions<SDb>,\n): Promise<T> {\n const result = await adapter.runWithTenant(tenantId, async (database) => {\n let context: TenantContext = { tenantId, database };\n const getTenantRepository = options?.getTenantRepository;\n if (\n options?.loadTenant &&\n getTenantRepository &&\n adapter.runAsSystem\n ) {\n const tenant = await adapter.runAsSystem((systemDb) =>\n getTenantRepository(systemDb).getById(tenantId),\n );\n context = tenant != null ? { ...context, tenant } : context;\n }\n return runWithContext(context, () => fn(database));\n });\n return result;\n}\n","export class TenantNotResolvedError extends Error {\n constructor(message = \"better-tenant: tenant could not be resolved from request\") {\n super(message);\n this.name = \"TenantNotResolvedError\";\n }\n}\n\nexport class TenantMiddlewareError extends Error {\n constructor(\n message = \"better-tenant: failed to run tenant middleware\",\n options?: { cause?: unknown },\n ) {\n super(message, options);\n this.name = \"TenantMiddlewareError\";\n }\n}\n","import { runWithTenantAndDatabase } from \"./adapter.js\";\nimport { TenantMiddlewareError, TenantNotResolvedError } from \"./errors.js\";\nimport type { TenantAdapter } from \"./types.js\";\n\ntype MaybePromise<T> = T | Promise<T>;\n\nexport interface HandleRequestOptions<Req, Result> {\n resolveTenant: (request: Req) => MaybePromise<string | undefined>;\n adapter: TenantAdapter;\n onMissingTenant?: (request: Req) => MaybePromise<Result>;\n onError?: (error: unknown, request: Req) => MaybePromise<Result>;\n}\n\n/**\n * Generic request helper for framework adapters.\n *\n * It resolves a tenant id from the framework request, then runs the request handler\n * inside runWithTenantAndDatabase so both getContext() and getDatabase() are available.\n */\nexport async function handleRequest<Req, Result>(\n request: Req,\n next: () => Promise<Result>,\n options: HandleRequestOptions<Req, Result>,\n): Promise<Result> {\n const tenantId = await options.resolveTenant(request);\n const normalizedTenantId = tenantId?.trim();\n if (!normalizedTenantId) {\n if (options.onMissingTenant) {\n return options.onMissingTenant(request);\n }\n\n const error = new TenantNotResolvedError();\n if (options.onError) {\n return options.onError(error, request);\n }\n throw error;\n }\n\n try {\n return await runWithTenantAndDatabase(\n normalizedTenantId,\n options.adapter,\n async () => next(),\n );\n } catch (error) {\n if (options.onError) {\n return options.onError(error, request);\n }\n\n if (\n error instanceof TenantNotResolvedError ||\n error instanceof TenantMiddlewareError\n ) {\n throw error;\n }\n\n throw new TenantMiddlewareError(undefined, { cause: error });\n }\n}\n","import type { TenantAdapter, Tenant, TenantRepository } from \"./types.js\";\nimport { runWithContext } from \"./context.js\";\nimport { runWithTenantAndDatabase } from \"./adapter.js\";\n\nconst DEFAULT_LIST_LIMIT = 50;\n\nexport interface CreateTenantData {\n name: string;\n slug: string;\n}\n\nexport interface UpdateTenantData {\n name?: string;\n slug?: string;\n}\n\nexport interface ListTenantsOptions {\n limit?: number;\n offset?: number;\n}\n\nfunction requireRunAsSystem<TDb, SDb>(\n adapter: TenantAdapter<TDb, SDb>,\n): <T>(fn: (database: SDb) => Promise<T>) => Promise<T> {\n if (!adapter.runAsSystem) {\n throw new Error(\n \"better-tenant: tenant.api and runAsSystem require adapter.runAsSystem; this adapter does not implement it\",\n );\n }\n return adapter.runAsSystem;\n}\n\n/**\n * Tenant CRUD API. All methods run via adapter.runAsSystem and getTenantRepository.\n * The runAsSystem check is deferred to call time so that betterTenant() can be\n * constructed with adapters that don't implement runAsSystem (e.g. test mocks).\n */\nexport function createTenantApi<TDb, SDb>(\n adapter: TenantAdapter<TDb, SDb>,\n getTenantRepository: (database: SDb) => TenantRepository,\n) {\n return {\n async createTenant(data: CreateTenantData): Promise<Tenant> {\n if (!data.name?.trim()) {\n throw new Error(\"better-tenant: createTenant requires name\");\n }\n if (!data.slug?.trim()) {\n throw new Error(\"better-tenant: createTenant requires slug\");\n }\n const runAsSystem = requireRunAsSystem(adapter);\n return runAsSystem((database) =>\n getTenantRepository(database).create({\n name: data.name.trim(),\n slug: data.slug.trim(),\n }),\n );\n },\n\n async updateTenant(\n tenantId: string,\n data: UpdateTenantData,\n ): Promise<Tenant> {\n if (!tenantId?.trim()) {\n throw new Error(\"better-tenant: updateTenant requires tenantId\");\n }\n const runAsSystem = requireRunAsSystem(adapter);\n return runAsSystem((database) =>\n getTenantRepository(database).update(tenantId, {\n ...(data.name !== undefined && { name: data.name }),\n ...(data.slug !== undefined && { slug: data.slug }),\n }),\n );\n },\n\n async listTenants(options: ListTenantsOptions = {}): Promise<Tenant[]> {\n const limit = options.limit ?? DEFAULT_LIST_LIMIT;\n const offset = Math.max(0, options.offset ?? 0);\n const runAsSystem = requireRunAsSystem(adapter);\n return runAsSystem((database) =>\n getTenantRepository(database).list({ limit, offset }),\n );\n },\n\n async deleteTenant(tenantId: string): Promise<void> {\n if (!tenantId?.trim()) {\n throw new Error(\"better-tenant: deleteTenant requires tenantId\");\n }\n const runAsSystem = requireRunAsSystem(adapter);\n return runAsSystem((database) =>\n getTenantRepository(database).delete(tenantId),\n );\n },\n\n async getTenant(tenantId: string): Promise<Tenant | null> {\n if (!tenantId?.trim()) {\n throw new Error(\"better-tenant: getTenant requires tenantId\");\n }\n const runAsSystem = requireRunAsSystem(adapter);\n return runAsSystem((database) =>\n getTenantRepository(database).getById(tenantId),\n );\n },\n\n async countTenants(): Promise<number> {\n const runAsSystem = requireRunAsSystem(adapter);\n return runAsSystem((database) =>\n getTenantRepository(database).count(),\n );\n },\n };\n}\n\n/**\n * runAs(tenantId, fn): same as request flow — set context + run inside adapter.runWithTenant\n * so code can use getDatabase() and run tenant-scoped queries. Use for cron, per-tenant migrations.\n */\nexport async function runAs<TDb, T>(\n tenantId: string,\n adapter: TenantAdapter<TDb>,\n fn: (database: TDb) => Promise<T>,\n): Promise<T> {\n return runWithTenantAndDatabase(tenantId, adapter, fn);\n}\n\n/**\n * runAsSystem(fn): run fn with a DB handle that has RLS bypass.\n * Optionally set context so getContext() reflects system mode.\n */\nexport async function runAsSystem<SDb, T>(\n adapter: TenantAdapter<unknown, SDb>,\n fn: (database: SDb) => Promise<T>,\n): Promise<T> {\n const run = requireRunAsSystem(adapter);\n return runWithContext({ isSystem: true }, () => run(fn));\n}\n","import type {\n ResolvableRequest,\n TenantResolverConfig,\n JwtResolverConfig,\n PathResolverConfig,\n SubdomainResolverConfig,\n} from \"./types.js\";\n\nfunction getHeader(\n headers: ResolvableRequest[\"headers\"],\n name: string,\n): string | undefined {\n const key = name.toLowerCase();\n if (headers instanceof Headers) {\n const value = headers.get(key);\n return value?.trim() || undefined;\n }\n const raw = headers[key] ?? headers[name];\n if (raw === undefined) {\n return undefined;\n }\n const value = Array.isArray(raw) ? raw[0] : raw;\n return (typeof value === \"string\" ? value : \"\").trim() || undefined;\n}\n\nfunction resolveFromHeader(\n request: ResolvableRequest,\n headerName: string,\n): string | undefined {\n if (!headerName) {\n return undefined;\n }\n return getHeader(request.headers, headerName);\n}\n\nfunction resolveFromPath(\n request: ResolvableRequest,\n pathConfig: string | PathResolverConfig,\n): string | undefined {\n const pathOrUrl = request.path ?? request.url;\n if (!pathOrUrl) {\n return undefined;\n }\n\n let path: string;\n try {\n path = pathOrUrl.startsWith(\"http\")\n ? new URL(pathOrUrl).pathname\n : pathOrUrl;\n } catch {\n path = pathOrUrl;\n }\n\n const pattern =\n typeof pathConfig === \"string\" ? pathConfig : pathConfig.pattern;\n const segmentIndex =\n typeof pathConfig === \"object\" && pathConfig.segmentIndex !== undefined\n ? pathConfig.segmentIndex\n : parseTenantSegmentIndex(pattern);\n\n const segments = path.split(\"/\").filter(Boolean);\n const value = segments[segmentIndex];\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n\n/** e.g. \"/t/:tenantId/*\" -> segment 1 (0-based). */\nfunction parseTenantSegmentIndex(pattern: string): number {\n const segments = pattern.split(\"/\").filter(Boolean);\n const idx = segments.indexOf(\":tenantId\");\n return idx >= 0 ? idx : 0;\n}\n\nfunction resolveFromSubdomain(\n request: ResolvableRequest,\n config: SubdomainResolverConfig,\n): string | undefined {\n const host = request.host ?? (request.url ? new URL(request.url).host : \"\");\n if (!host) {\n return undefined;\n }\n const hostname = host.split(\":\")[0];\n if (!hostname) {\n return undefined;\n }\n const parts = hostname.split(\".\");\n // Only one segment (e.g. \"localhost\") or domain.tld (e.g. \"example.com\") = no subdomain\n if (parts.length <= 2) {\n return undefined;\n }\n const index =\n config === true\n ? 0\n : typeof config === \"object\" && config.segmentIndex !== undefined\n ? config.segmentIndex\n : 0;\n const value = parts[index];\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n\nfunction decodeJwtPayload(token: string): Record<string, unknown> | null {\n try {\n const parts = token.split(\".\");\n if (parts.length < 2) {\n return null;\n }\n const payload = parts[1];\n if (!payload) {\n return null;\n }\n const decoded = atob(payload.replace(/-/g, \"+\").replace(/_/g, \"/\"));\n const parsed: unknown = JSON.parse(decoded);\n if (typeof parsed !== \"object\" || parsed === null) {\n return null;\n }\n return parsed as Record<string, unknown>;\n } catch {\n return null;\n }\n}\n\nasync function resolveFromJwt(\n request: ResolvableRequest,\n config: string | JwtResolverConfig,\n): Promise<string | undefined> {\n const getToken = request.getToken;\n if (!getToken) {\n return undefined;\n }\n const token = typeof getToken === \"function\" ? getToken() : getToken;\n const value = token instanceof Promise ? await token : token;\n const resolved = value ?? undefined;\n if (!resolved) {\n return undefined;\n }\n\n const claim = typeof config === \"string\" ? config : config.claim;\n if (!claim) {\n return undefined;\n }\n\n const verifyToken =\n typeof config === \"object\" ? config.verifyToken : undefined;\n\n let payload: Record<string, unknown> | null;\n if (verifyToken) {\n payload = await verifyToken(resolved);\n } else {\n payload = decodeJwtPayload(resolved);\n }\n\n if (!payload) {\n return undefined;\n }\n\n const claimValue = payload[claim];\n return typeof claimValue === \"string\" && claimValue.length > 0\n ? claimValue\n : undefined;\n}\n\n/**\n * Returns human-readable descriptions of the configured resolution strategies.\n * Useful for error messages when tenant resolution fails.\n */\nexport function describeStrategies(config: TenantResolverConfig): string[] {\n const strategies: string[] = [];\n if (config.header !== undefined) {\n strategies.push(`header '${config.header}'`);\n }\n if (config.path !== undefined) {\n const pattern =\n typeof config.path === \"string\" ? config.path : config.path.pattern;\n strategies.push(`path '${pattern}'`);\n }\n if (config.subdomain !== undefined && config.subdomain !== false) {\n strategies.push(\"subdomain\");\n }\n if (config.jwt !== undefined) {\n const claim =\n typeof config.jwt === \"string\" ? config.jwt : config.jwt.claim;\n strategies.push(`jwt claim '${claim}'`);\n }\n if (config.custom !== undefined) {\n strategies.push(\"custom resolver\");\n }\n return strategies;\n}\n\n/**\n * Resolution order: header → path → subdomain → jwt → custom.\n * Returns the first defined tenant id.\n */\nexport async function resolveTenant(\n request: ResolvableRequest,\n config: TenantResolverConfig,\n): Promise<string | undefined> {\n if (config.header !== undefined) {\n const v = resolveFromHeader(request, config.header);\n if (v !== undefined) {\n return v;\n }\n }\n if (config.path !== undefined) {\n const v = resolveFromPath(request, config.path);\n if (v !== undefined) {\n return v;\n }\n }\n if (config.subdomain !== undefined && config.subdomain !== false) {\n const v = resolveFromSubdomain(request, config.subdomain);\n if (v !== undefined) {\n return v;\n }\n }\n if (config.jwt !== undefined) {\n const v = await resolveFromJwt(request, config.jwt);\n if (v !== undefined) {\n return v;\n }\n }\n if (config.custom !== undefined) {\n const v = await Promise.resolve(config.custom(request));\n if (typeof v === \"string\" && v.length > 0) {\n return v;\n }\n }\n return undefined;\n}\n","/**\n * Shared parse and validation utilities for console endpoint handlers.\n *\n * These are small, pure, zero-dep helpers used by product endpoint handlers\n * (audit, tenant) to validate and parse incoming request data.\n */\n\n/** Type guard that narrows `unknown` to a plain object (not array, not null). */\nexport function isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/**\n * Parse a string to an integer within [min, max].\n * Returns `undefined` when `value` is `undefined` (param absent),\n * not a finite number, or below `min`.\n */\nexport function parseBoundedInt(\n value: string | undefined,\n min: number,\n max: number,\n): number | undefined {\n if (value === undefined) {\n return undefined;\n }\n const parsed = Number(value);\n if (!Number.isFinite(parsed) || parsed < min) {\n return undefined;\n }\n return Math.min(Math.floor(parsed), max);\n}\n\n/**\n * Parse an ISO-8601 date string.\n * Returns `undefined` when `value` is `undefined` or not a valid date.\n */\nexport function parseIsoDate(value: string | undefined): Date | undefined {\n if (value === undefined) {\n return undefined;\n }\n const date = new Date(value);\n if (Number.isNaN(date.getTime())) {\n return undefined;\n }\n return date;\n}\n","import type {\n ConsoleProductEndpoint,\n ConsoleProductRequest,\n ConsoleErrorResponse,\n TenantWire,\n TenantStatsResponse,\n} from \"@usebetterdev/console-contract\";\nimport {\n isPlainObject,\n parseBoundedInt,\n} from \"@usebetterdev/console-utils\";\nimport type { TenantApi } from \"./better-tenant.js\";\nimport type { Tenant } from \"./types.js\";\n\nconst MAX_FIELD_LENGTH = 255;\n\nfunction serializeTenant(tenant: Tenant): TenantWire {\n return {\n ...tenant,\n createdAt:\n tenant.createdAt instanceof Date\n ? tenant.createdAt.toISOString()\n : tenant.createdAt,\n };\n}\n\nexport function createTenantConsoleEndpoints(\n api: TenantApi,\n): ConsoleProductEndpoint[] {\n return [\n {\n method: \"GET\",\n path: \"/tenants\",\n requiredPermission: \"read\",\n async handler(request: ConsoleProductRequest) {\n try {\n const options: { limit?: number; offset?: number } = {};\n if (request.query.limit !== undefined) {\n const limit = parseBoundedInt(request.query.limit, 1, 1000);\n if (limit === undefined) {\n return { status: 400, body: { error: \"Invalid 'limit': must be a positive integer (max 1000)\" } satisfies ConsoleErrorResponse };\n }\n options.limit = limit;\n }\n if (request.query.offset !== undefined) {\n const offset = parseBoundedInt(request.query.offset, 0, Number.MAX_SAFE_INTEGER);\n if (offset === undefined) {\n return { status: 400, body: { error: \"Invalid 'offset': must be a non-negative integer\" } satisfies ConsoleErrorResponse };\n }\n options.offset = offset;\n }\n const tenants = await api.listTenants(options);\n return { status: 200, body: tenants.map(serializeTenant) satisfies TenantWire[] };\n } catch {\n return { status: 500, body: { error: \"Internal server error\" } satisfies ConsoleErrorResponse };\n }\n },\n },\n {\n method: \"GET\",\n path: \"/tenants/:id\",\n requiredPermission: \"read\",\n async handler(request: ConsoleProductRequest) {\n try {\n const id = request.params.id?.trim();\n if (!id) {\n return { status: 400, body: { error: \"Missing tenant id\" } satisfies ConsoleErrorResponse };\n }\n const tenant = await api.getTenant(id);\n if (!tenant) {\n return { status: 404, body: { error: \"Tenant not found\" } satisfies ConsoleErrorResponse };\n }\n return { status: 200, body: serializeTenant(tenant) satisfies TenantWire };\n } catch {\n return { status: 500, body: { error: \"Internal server error\" } satisfies ConsoleErrorResponse };\n }\n },\n },\n {\n method: \"POST\",\n path: \"/tenants\",\n requiredPermission: \"write\",\n async handler(request: ConsoleProductRequest) {\n try {\n if (!isPlainObject(request.body)) {\n return { status: 400, body: { error: \"Request body is required\" } satisfies ConsoleErrorResponse };\n }\n const name = typeof request.body.name === \"string\" ? request.body.name : \"\";\n const slug = typeof request.body.slug === \"string\" ? request.body.slug : \"\";\n if (!name.trim() || !slug.trim()) {\n return { status: 400, body: { error: \"name and slug are required\" } satisfies ConsoleErrorResponse };\n }\n if (name.length > MAX_FIELD_LENGTH || slug.length > MAX_FIELD_LENGTH) {\n return { status: 400, body: { error: \"name and slug must not exceed 255 characters\" } satisfies ConsoleErrorResponse };\n }\n const tenant = await api.createTenant({ name, slug });\n return { status: 201, body: serializeTenant(tenant) satisfies TenantWire };\n } catch {\n return { status: 500, body: { error: \"Internal server error\" } satisfies ConsoleErrorResponse };\n }\n },\n },\n {\n method: \"PATCH\",\n path: \"/tenants/:id\",\n requiredPermission: \"write\",\n async handler(request: ConsoleProductRequest) {\n try {\n const id = request.params.id?.trim();\n if (!id) {\n return { status: 400, body: { error: \"Missing tenant id\" } satisfies ConsoleErrorResponse };\n }\n if (!isPlainObject(request.body)) {\n return { status: 400, body: { error: \"Request body is required\" } satisfies ConsoleErrorResponse };\n }\n const data: { name?: string; slug?: string } = {};\n if (typeof request.body.name === \"string\") {\n if (request.body.name.length > MAX_FIELD_LENGTH) {\n return { status: 400, body: { error: \"name must not exceed 255 characters\" } satisfies ConsoleErrorResponse };\n }\n data.name = request.body.name;\n }\n if (typeof request.body.slug === \"string\") {\n if (request.body.slug.length > MAX_FIELD_LENGTH) {\n return { status: 400, body: { error: \"slug must not exceed 255 characters\" } satisfies ConsoleErrorResponse };\n }\n data.slug = request.body.slug;\n }\n const tenant = await api.updateTenant(id, data);\n return { status: 200, body: serializeTenant(tenant) satisfies TenantWire };\n } catch {\n return { status: 500, body: { error: \"Internal server error\" } satisfies ConsoleErrorResponse };\n }\n },\n },\n {\n method: \"DELETE\",\n path: \"/tenants/:id\",\n requiredPermission: \"admin\",\n async handler(request: ConsoleProductRequest) {\n try {\n const id = request.params.id?.trim();\n if (!id) {\n return { status: 400, body: { error: \"Missing tenant id\" } satisfies ConsoleErrorResponse };\n }\n await api.deleteTenant(id);\n return { status: 204, body: null };\n } catch {\n return { status: 500, body: { error: \"Internal server error\" } satisfies ConsoleErrorResponse };\n }\n },\n },\n {\n method: \"GET\",\n path: \"/stats\",\n requiredPermission: \"read\",\n async handler() {\n try {\n const tenantCount = await api.countTenants();\n return { status: 200, body: { tenantCount } satisfies TenantStatsResponse };\n } catch {\n return { status: 500, body: { error: \"Internal server error\" } satisfies ConsoleErrorResponse };\n }\n },\n },\n ];\n}\n","import type {\n BetterTenantConfig,\n Tenant,\n TenantAdapter,\n TenantRepository,\n TenantResolverConfig,\n ResolvableRequest,\n TenantContext,\n RunWithTenantAndDatabaseOptions,\n} from \"./types.js\";\nimport { sendInitTelemetry } from \"./telemetry.js\";\nimport { getContext, runWithTenant } from \"./context.js\";\nimport { getDatabase, runWithTenantAndDatabase } from \"./adapter.js\";\nimport {\n handleRequest as handleTenantRequest,\n type HandleRequestOptions,\n} from \"./handle-request.js\";\nimport {\n createTenantApi,\n runAsSystem as runAsSystemWithAdapter,\n} from \"./api.js\";\nimport { resolveTenant, describeStrategies } from \"./resolver.js\";\nimport { createTenantConsoleEndpoints } from \"./console-endpoints.js\";\n\n/** UUID v4 pattern for detecting whether an identifier is already a UUID. */\nconst UUID_RE =\n /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\n/**\n * Normalize a resolved identifier to a tenant UUID.\n *\n * - If resolveToId is configured, call it (takes full precedence).\n * - If the identifier is already a UUID, pass through.\n * - If adapter.runAsSystem is available, look up by slug via getTenantRepository.\n * - Otherwise, return as-is (will likely fail at DB level).\n */\nasync function resolveIdentifierToId(\n identifier: string,\n resolverConfig: TenantResolverConfig,\n adapter: TenantAdapter,\n getTenantRepository: (db: unknown) => TenantRepository,\n): Promise<string | undefined> {\n if (resolverConfig.resolveToId) {\n return resolverConfig.resolveToId(identifier);\n }\n if (UUID_RE.test(identifier)) {\n return identifier;\n }\n if (adapter.runAsSystem) {\n const tenant = await adapter.runAsSystem((systemDb: unknown) =>\n getTenantRepository(systemDb).getBySlug(identifier),\n );\n return tenant?.id;\n }\n return identifier;\n}\n\nexport interface TenantApi {\n createTenant(data: { name: string; slug: string }): Promise<Tenant>;\n updateTenant(\n tenantId: string,\n data: { name?: string; slug?: string },\n ): Promise<Tenant>;\n listTenants(options?: { limit?: number; offset?: number }): Promise<Tenant[]>;\n deleteTenant(tenantId: string): Promise<void>;\n getTenant(tenantId: string): Promise<Tenant | null>;\n countTenants(): Promise<number>;\n}\n\nexport interface BetterTenantInstance<TDb = unknown, SDb = unknown> {\n getContext: () => TenantContext | undefined;\n getDatabase: () => TDb | undefined;\n runWithTenant: typeof runWithTenant;\n runAs: <T>(tenantId: string, fn: (database: TDb) => Promise<T>) => Promise<T>;\n runAsSystem: <T>(fn: (database: SDb) => Promise<T>) => Promise<T>;\n resolveTenant: (request: ResolvableRequest) => Promise<string | undefined>;\n /** Human-readable descriptions of the configured resolution strategies. */\n resolverStrategies: string[];\n handleRequest: <Req extends ResolvableRequest, Result>(\n request: Req,\n next: () => Promise<Result>,\n options?: Omit<\n HandleRequestOptions<Req, Result>,\n \"resolveTenant\" | \"adapter\"\n >,\n ) => Promise<Result>;\n api: TenantApi;\n}\n\n/**\n * Creates the Better Tenant instance. Config must include adapter, tenantResolver, and getTenantRepository.\n */\nexport function betterTenant<TDb, SDb>(\n config: BetterTenantConfig<TDb, SDb>,\n): BetterTenantInstance<TDb, SDb> {\n const { database, tenantResolver, loadTenant } = config;\n const { adapter, getTenantRepository } = database;\n\n sendInitTelemetry(config, config.telemetry);\n\n const api = createTenantApi(adapter, getTenantRepository);\n\n const runWithTenantAndDatabaseOptions:\n | RunWithTenantAndDatabaseOptions<SDb>\n | undefined =\n loadTenant !== false\n ? { loadTenant: true as const, getTenantRepository }\n : undefined;\n\n const resolverStrategies = describeStrategies(tenantResolver);\n\n /** Resolve raw identifier from request, then normalize to UUID. */\n async function resolveAndNormalize(\n request: ResolvableRequest,\n ): Promise<string | undefined> {\n const raw = await resolveTenant(request, tenantResolver);\n if (!raw) return undefined;\n return resolveIdentifierToId(\n raw,\n tenantResolver,\n adapter,\n getTenantRepository as (db: unknown) => TenantRepository,\n );\n }\n\n if (config.console) {\n const endpoints = createTenantConsoleEndpoints(api);\n config.console.registerProduct({\n id: \"tenant\",\n name: \"Better Tenant\",\n endpoints,\n });\n }\n\n return {\n getContext,\n getDatabase: () => getDatabase() as TDb | undefined,\n runWithTenant,\n runAs: (tenantId, fn) =>\n runWithTenantAndDatabase(\n tenantId,\n adapter,\n fn,\n runWithTenantAndDatabaseOptions,\n ),\n runAsSystem: <T>(fn: (database: SDb) => Promise<T>) =>\n runAsSystemWithAdapter(adapter, fn),\n resolveTenant: resolveAndNormalize,\n resolverStrategies,\n handleRequest: (request, next, options) =>\n handleTenantRequest(request, next, {\n ...options,\n resolveTenant: resolveAndNormalize,\n adapter,\n }),\n api,\n };\n}\n","import type { ResolvableRequest } from \"./types.js\";\n\ntype NodeHeaders = Record<string, string | string[] | undefined>;\n\nexport interface NodeLikeRequest {\n headers?: Record<string, string | string[] | number | undefined>;\n url?: string;\n originalUrl?: string;\n path?: string;\n hostname?: string;\n host?: string;\n method?: string;\n}\n\nfunction isFetchRequest(input: unknown): input is Request {\n return typeof Request !== \"undefined\" && input instanceof Request;\n}\n\nfunction normalizeHost(raw: string | undefined): string | undefined {\n if (!raw) {\n return undefined;\n }\n const value = raw.split(\":\")[0]?.trim();\n return value || undefined;\n}\n\nfunction normalizeHeaders(\n headers: Record<string, string | string[] | number | undefined> | undefined,\n): NodeHeaders {\n if (!headers) {\n return {};\n }\n const normalized: NodeHeaders = {};\n for (const [key, value] of Object.entries(headers)) {\n const normalizedKey = key.toLowerCase();\n if (Array.isArray(value)) {\n normalized[normalizedKey] = value.map((part) => String(part));\n continue;\n }\n if (value === undefined) {\n normalized[normalizedKey] = undefined;\n continue;\n }\n normalized[normalizedKey] = String(value);\n }\n return normalized;\n}\n\nfunction pathWithoutQuery(value: string | undefined): string | undefined {\n if (!value) {\n return undefined;\n }\n const [pathname] = value.split(\"?\");\n return pathname || undefined;\n}\n\nexport function toResolvableRequest(\n request: Request | NodeLikeRequest,\n): ResolvableRequest {\n if (isFetchRequest(request)) {\n const url = request.url;\n let host: string | undefined;\n let path: string | undefined;\n try {\n const parsedUrl = new URL(url);\n host = normalizeHost(parsedUrl.host);\n path = parsedUrl.pathname || undefined;\n } catch {\n host = undefined;\n path = undefined;\n }\n const resolved: ResolvableRequest = {\n headers: request.headers,\n url,\n method: request.method,\n };\n if (path !== undefined) {\n resolved.path = path;\n }\n if (host !== undefined) {\n resolved.host = host;\n }\n return resolved;\n }\n\n const headers = normalizeHeaders(request.headers);\n const hostFromHeaders = headers.host;\n const hostValue = Array.isArray(hostFromHeaders)\n ? hostFromHeaders[0]\n : hostFromHeaders;\n const host = normalizeHost(request.hostname ?? request.host ?? hostValue);\n const path = pathWithoutQuery(\n request.path ?? request.originalUrl ?? request.url,\n );\n\n const resolved: ResolvableRequest = {\n headers,\n };\n if (path !== undefined) {\n resolved.path = path;\n }\n if (host !== undefined) {\n resolved.host = host;\n }\n if (request.method !== undefined) {\n resolved.method = request.method;\n }\n return resolved;\n}\n"],"mappings":"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","names":["v","runAsSystem","value","host","path","resolved"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/telemetry.ts","../src/context.ts","../src/adapter.ts","../src/errors.ts","../src/handle-request.ts","../src/api.ts","../src/resolver.ts","../../../shared/console-utils/src/index.ts","../src/console-endpoints.ts","../src/better-tenant.ts","../src/request.ts"],"sourcesContent":["export { betterTenant } from \"./better-tenant.js\";\nexport type { BetterTenantInstance, TenantApi } from \"./better-tenant.js\";\nexport { getContext, runWithTenant } from \"./context.js\";\nexport { resolveTenant, describeStrategies } from \"./resolver.js\";\nexport { handleRequest } from \"./handle-request.js\";\nexport { toResolvableRequest } from \"./request.js\";\nexport { TenantNotResolvedError, TenantMiddlewareError } from \"./errors.js\";\nexport { runAs, runAsSystem, createTenantApi } from \"./api.js\";\nexport type {\n CreateTenantData,\n UpdateTenantData,\n ListTenantsOptions,\n} from \"./api.js\";\nexport type { HandleRequestOptions } from \"./handle-request.js\";\nexport type { NodeLikeRequest } from \"./request.js\";\nexport type {\n Tenant,\n TenantContext,\n TenantScopedDatabase,\n SystemDatabase,\n TenantAdapter,\n TenantRepository,\n DatabaseProvider,\n TenantResolverConfig,\n ResolvableRequest,\n BetterTenantPlugin,\n BetterTenantConfig,\n TelemetryConfig,\n PathResolverConfig,\n SubdomainResolverConfig,\n JwtResolverConfig,\n ConsoleRegistration,\n} from \"./types.js\";\nexport { sendCliTelemetry } from \"./telemetry.js\";\nexport type { TelemetryCliConfig, CliConfigForTelemetry } from \"./telemetry.js\";\n","/**\n * Anonymous telemetry for Better Tenant.\n * On by default, opt-out via BETTER_TENANT_TELEMETRY=0 or telemetry: { enabled: false }.\n * See docs/TELEMETRY.md.\n */\n\nimport { createHash } from \"node:crypto\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { platform, release, arch, cpus, totalmem } from \"node:os\";\nimport type { BetterTenantConfig } from \"./types.js\";\n\n/** Subset of BetterTenantConfig used by telemetry (avoids contravariance issues with generic DB types). */\ntype TelemetryConfigInput = Pick<\n BetterTenantConfig,\n \"tenantResolver\" | \"basePath\" | \"plugins\" | \"loadTenant\" | \"telemetry\"\n>;\n\nconst TELEMETRY_ENDPOINT = \"https://telemetry.usebetter.dev/v1/events\";\nconst LIBRARY_ID = \"better-tenant\";\n\n// --- Redacted config types ---\n\nexport interface TelemetryTenantConfig {\n resolver: {\n header: boolean;\n path: boolean;\n subdomain: boolean;\n jwt: boolean;\n custom: boolean;\n };\n tenantTablesCount: number;\n loadTenant: boolean | undefined;\n basePathSet: boolean;\n plugins: string[];\n}\n\nexport interface TelemetryCliConfig {\n tenantTablesCount: number;\n hasSchemaDir: boolean;\n hasMigrationsDir: boolean;\n}\n\nexport interface TelemetryPayload {\n library: string;\n type: string;\n timestamp: string;\n anonymousId?: string;\n runtime?: { name: string; version: string };\n environment?: string;\n framework?: { name: string; version?: string };\n database?: { name: string; version?: string };\n system?: {\n platform: string;\n release: string;\n arch: string;\n cpus: number;\n totalMemoryMb: number;\n isDocker?: boolean;\n isWSL?: boolean;\n };\n packageManager?: { name: string; version?: string };\n config?: TelemetryTenantConfig | TelemetryCliConfig;\n outcome?: string;\n}\n\n// --- Telemetry options ---\n\nexport interface TelemetryOptions {\n /** Override enabled (default: true). Set false to opt out. */\n enabled?: boolean;\n /** Debug mode: log to console only, do not send. */\n debug?: boolean;\n /** When true, return Promise that resolves when send completes. Use before process.exit. */\n wait?: boolean;\n}\n\n// --- Redaction ---\n\nexport function getTelemetryTenantConfig(\n config: TelemetryConfigInput,\n): TelemetryTenantConfig {\n const r = config.tenantResolver ?? {};\n return {\n resolver: {\n header: !!r.header,\n path: !!r.path,\n subdomain: !!r.subdomain,\n jwt: !!r.jwt,\n custom: !!r.custom,\n },\n tenantTablesCount: 0,\n loadTenant: config.loadTenant,\n basePathSet: !!config.basePath,\n plugins: (config.plugins ?? []).map((p) => String(p.id)),\n };\n}\n\nexport function getTelemetryCliConfig(config: {\n tenantTables: string[];\n schemaDir?: string;\n migrationsDir?: string;\n}): TelemetryCliConfig {\n return {\n tenantTablesCount: config.tenantTables?.length ?? 0,\n hasSchemaDir: !!config.schemaDir,\n hasMigrationsDir: !!config.migrationsDir,\n };\n}\n\n// --- Detection ---\n\nfunction getAnonymousId(cwd: string): string | undefined {\n try {\n const pkgPath = join(cwd, \"package.json\");\n if (!existsSync(pkgPath)) {\n return undefined;\n }\n\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\")) as {\n name?: string;\n betterTenant?: { basePath?: string };\n };\n const name = typeof pkg?.name === \"string\" ? pkg.name : \"\";\n const basePath =\n typeof pkg?.betterTenant?.basePath === \"string\"\n ? pkg.betterTenant.basePath\n : \"\";\n const input = `${name}:${basePath}`.trim() || \"unknown\";\n return createHash(\"sha256\").update(input).digest(\"hex\").slice(0, 16);\n } catch {\n return undefined;\n }\n}\n\nfunction detectRuntime(): { name: string; version: string } {\n const g = globalThis as Record<string, unknown>;\n if (typeof g.Bun !== \"undefined\") {\n const bun = g.Bun as { version?: string };\n return {\n name: \"bun\",\n version: typeof bun?.version === \"string\" ? bun.version : \"unknown\",\n };\n }\n if (typeof g.Deno !== \"undefined\") {\n const deno = g.Deno as { version?: { deno?: string } };\n const v = deno?.version?.deno;\n return { name: \"deno\", version: typeof v === \"string\" ? v : \"unknown\" };\n }\n const v = (typeof process !== \"undefined\" && process.versions?.node) || \"\";\n return { name: \"node\", version: v || \"unknown\" };\n}\n\nfunction detectEnvironment(): string {\n const env = process.env.NODE_ENV || \"development\";\n if (env === \"test\") {\n return \"test\";\n }\n\n // CI check before NODE_ENV so CI is detected even when NODE_ENV=production\n if (\n process.env.CI === \"true\" ||\n process.env.GITHUB_ACTIONS === \"true\" ||\n process.env.GITLAB_CI === \"true\" ||\n process.env.CIRCLECI === \"true\"\n ) {\n return \"ci\";\n }\n if (env === \"production\") {\n return \"production\";\n }\n\n return \"development\";\n}\n\nfunction detectFramework(\n cwd: string,\n): { name: string; version?: string } | undefined {\n try {\n const pkgPath = join(cwd, \"package.json\");\n if (!existsSync(pkgPath)) {\n return undefined;\n }\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\")) as {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n };\n const deps = { ...pkg?.dependencies, ...pkg?.devDependencies };\n if (deps[\"next\"]) {\n return { name: \"next\", version: deps[\"next\"] };\n }\n if (deps[\"hono\"]) {\n return { name: \"hono\", version: deps[\"hono\"] };\n }\n if (deps[\"express\"]) {\n return { name: \"express\", version: deps[\"express\"] };\n }\n return undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction detectDatabase(\n cwd: string,\n): { name: string; version?: string } | undefined {\n try {\n const pkgPath = join(cwd, \"package.json\");\n if (!existsSync(pkgPath)) {\n return undefined;\n }\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\")) as {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n };\n const deps = { ...pkg?.dependencies, ...pkg?.devDependencies };\n if (deps[\"drizzle-orm\"]) {\n return { name: \"drizzle\", version: deps[\"drizzle-orm\"] };\n }\n if (deps[\"prisma\"]) {\n return { name: \"prisma\", version: deps[\"prisma\"] };\n }\n return undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction detectSystem(): NonNullable<TelemetryPayload[\"system\"]> {\n const isDocker = existsSync(\"/.dockerenv\");\n const isWSL =\n typeof process.env.WSL_DISTRO_NAME === \"string\" ||\n (typeof process.env.WSL_INTEROP === \"string\" &&\n process.env.WSL_INTEROP.length > 0);\n return {\n platform: platform(),\n release: release(),\n arch: arch(),\n cpus: cpus().length,\n totalMemoryMb: Math.round(totalmem() / 1024 / 1024),\n isDocker,\n isWSL,\n };\n}\n\nfunction detectPackageManager():\n | { name: string; version?: string }\n | undefined {\n const ua = process.env.npm_config_user_agent;\n if (!ua || typeof ua !== \"string\") {\n return undefined;\n }\n const match = ua.match(/^(.+?)\\/(\\d+\\.\\d+\\.\\d+.*?)(?:\\s|$)/);\n if (match) {\n const name = (match[1] ?? \"unknown\").toLowerCase();\n const version = match[2];\n return version ? { name, version } : { name };\n }\n if (ua.includes(\"pnpm\")) {\n return { name: \"pnpm\" };\n }\n if (ua.includes(\"yarn\")) {\n return { name: \"yarn\" };\n }\n return { name: \"npm\" };\n}\n\n// --- Send ---\n\nfunction isTelemetryEnabled(options?: TelemetryOptions): boolean {\n if (process.env.NODE_ENV === \"test\") {\n return false;\n }\n const env = process.env.BETTER_TENANT_TELEMETRY;\n if (env === \"0\" || env?.toLowerCase() === \"false\") {\n return false;\n }\n if (env === \"1\" || env?.toLowerCase() === \"true\") {\n return true;\n }\n return options?.enabled !== false;\n}\n\nfunction isDebugMode(options?: TelemetryOptions): boolean {\n if (process.env.BETTER_TENANT_TELEMETRY_DEBUG === \"1\") {\n return true;\n }\n return options?.debug === true;\n}\n\n/**\n * Send telemetry event. Fire-and-forget by default; use options.wait for process-exit paths.\n * Skips when NODE_ENV=test, when disabled via env/config, or when debug mode logs only.\n */\nexport function sendTelemetry(\n type: string,\n payload: Omit<TelemetryPayload, \"library\" | \"type\" | \"timestamp\">,\n options?: TelemetryOptions,\n): void | Promise<void> {\n if (!isTelemetryEnabled(options)) {\n return options?.wait ? Promise.resolve() : undefined;\n }\n const fullPayload: TelemetryPayload = {\n library: LIBRARY_ID,\n type,\n timestamp: new Date().toISOString(),\n ...payload,\n };\n if (isDebugMode(options)) {\n console.log(\n \"[better-tenant telemetry]\",\n JSON.stringify(fullPayload, null, 2),\n );\n return options?.wait ? Promise.resolve() : undefined;\n }\n const doSend = () =>\n fetch(TELEMETRY_ENDPOINT, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(fullPayload),\n }).catch(() => {\n // Silently ignore send failures\n });\n\n if (options?.wait) {\n return new Promise<void>((resolve) => {\n setImmediate(async () => {\n await doSend();\n resolve();\n });\n });\n }\n\n setImmediate(() => doSend());\n}\n\n/**\n * Build and send init telemetry (call from betterTenant()).\n */\nexport function sendInitTelemetry(\n config: TelemetryConfigInput,\n options?: TelemetryOptions,\n): void {\n const cwd = process.cwd();\n const payload: Omit<TelemetryPayload, \"library\" | \"type\" | \"timestamp\"> = {\n runtime: detectRuntime(),\n environment: detectEnvironment(),\n config: getTelemetryTenantConfig(config),\n };\n const anonymousId = getAnonymousId(cwd);\n if (anonymousId) payload.anonymousId = anonymousId;\n const framework = detectFramework(cwd);\n if (framework) payload.framework = framework;\n const database = detectDatabase(cwd);\n if (database) payload.database = database;\n payload.system = detectSystem();\n const pkgMgr = detectPackageManager();\n if (pkgMgr) payload.packageManager = pkgMgr;\n sendTelemetry(\"init\", payload, options ?? config.telemetry);\n}\n\n/** Raw CLI config shape (subset needed for telemetry). */\nexport interface CliConfigForTelemetry {\n tenantTables: string[];\n schemaDir?: string;\n migrationsDir?: string;\n}\n\n/**\n * Build and send CLI telemetry. Use from CLI commands.\n * Accepts raw config; redaction happens internally.\n * Use options.wait: true before process.exit so the send completes.\n */\nexport function sendCliTelemetry(\n type: \"cli_generate\" | \"cli_migrate\" | \"cli_check\" | \"cli_seed\" | \"cli_init\",\n outcome: string,\n config?: CliConfigForTelemetry,\n options?: { wait?: boolean },\n): void | Promise<void> {\n const cwd = process.cwd();\n const redactedConfig = config ? getTelemetryCliConfig(config) : undefined;\n const payload: Omit<TelemetryPayload, \"library\" | \"type\" | \"timestamp\"> = {\n runtime: detectRuntime(),\n environment: detectEnvironment(),\n outcome,\n };\n if (redactedConfig) payload.config = redactedConfig;\n payload.system = detectSystem();\n const anonymousId = getAnonymousId(cwd);\n if (anonymousId) payload.anonymousId = anonymousId;\n const framework = detectFramework(cwd);\n if (framework) payload.framework = framework;\n const database = detectDatabase(cwd);\n if (database) payload.database = database;\n const pkgMgr = detectPackageManager();\n if (pkgMgr) payload.packageManager = pkgMgr;\n return sendTelemetry(type, payload, options);\n}\n","import type { TenantContext } from \"./types.js\";\nimport { AsyncLocalStorage } from \"node:async_hooks\";\n\nconst storage = new AsyncLocalStorage<TenantContext>();\n\n/**\n * Returns the current tenant context, or undefined when not inside runWithTenant / runWithTenantAndDatabase.\n */\nexport function getContext(): TenantContext | undefined {\n return storage.getStore();\n}\n\n/**\n * Runs fn inside a scope where getContext() returns { tenantId }.\n * No adapter/DB involved; use for tests or when adapter is not configured.\n * If tenantId is empty string, it is treated as undefined (no tenant).\n */\nexport function runWithTenant<T>(\n tenantId: string,\n fn: () => T | Promise<T>,\n): Promise<T> {\n const normalized = tenantId.trim() || undefined;\n if (normalized === undefined) {\n return Promise.reject(\n new Error(\"better-tenant: tenantId must be a non-empty string\"),\n );\n }\n return Promise.resolve(\n storage.run({ tenantId: normalized }, () => fn()),\n );\n}\n\n/**\n * Internal: set context with optional database handle. Used by runWithTenantAndDatabase.\n */\nexport function runWithContext<T>(\n context: TenantContext,\n fn: () => T | Promise<T>,\n): Promise<T> {\n return Promise.resolve(storage.run(context, () => fn()));\n}\n\n","import type {\n TenantAdapter,\n TenantContext,\n RunWithTenantAndDatabaseOptions,\n} from \"./types.js\";\nimport { getContext, runWithContext } from \"./context.js\";\n\n/**\n * Returns the tenant-scoped database handle when inside a runWithTenantAndDatabase (or runAs) scope.\n *\n * Use only the handle from getDatabase() for tenant-scoped tables. Outside scope, returns undefined.\n * Config requires an adapter when tenant-scoped DB is used; getDatabase() is then available inside\n * request handlers that ran via runWithTenantAndDatabase(tenantId, adapter, next).\n */\nexport function getDatabase(): unknown {\n const context = getContext();\n return context?.database;\n}\n\n/**\n * Sets AsyncLocalStorage context and runs fn with the adapter's tenant-scoped DB.\n *\n * (1) Sets AsyncLocalStorage context with tenantId and database.\n * (2) Calls adapter.runWithTenant(tenantId, (database) => fn(database)).\n * (3) Stores the database handle in context so getDatabase() returns it.\n *\n * Middleware should resolve tenantId from the request, then call\n * runWithTenantAndDatabase(tenantId, adapter, next) so both context and DB handle are available.\n *\n * When options.loadTenant is true and options.getTenantRepository and adapter.runAsSystem are set,\n * loads the full Tenant row into context so getContext().tenant is available (or undefined if not found).\n */\nexport async function runWithTenantAndDatabase<TDb, SDb, T>(\n tenantId: string,\n adapter: TenantAdapter<TDb, SDb>,\n fn: (database: TDb) => Promise<T>,\n options?: RunWithTenantAndDatabaseOptions<SDb>,\n): Promise<T> {\n const result = await adapter.runWithTenant(tenantId, async (database) => {\n let context: TenantContext = { tenantId, database };\n const getTenantRepository = options?.getTenantRepository;\n if (\n options?.loadTenant &&\n getTenantRepository &&\n adapter.runAsSystem\n ) {\n const tenant = await adapter.runAsSystem((systemDb) =>\n getTenantRepository(systemDb).getById(tenantId),\n );\n context = tenant != null ? { ...context, tenant } : context;\n }\n return runWithContext(context, () => fn(database));\n });\n return result;\n}\n","export class TenantNotResolvedError extends Error {\n constructor(message = \"better-tenant: tenant could not be resolved from request\") {\n super(message);\n this.name = \"TenantNotResolvedError\";\n }\n}\n\nexport class TenantMiddlewareError extends Error {\n constructor(\n message = \"better-tenant: failed to run tenant middleware\",\n options?: { cause?: unknown },\n ) {\n super(message, options);\n this.name = \"TenantMiddlewareError\";\n }\n}\n","import { runWithTenantAndDatabase } from \"./adapter.js\";\nimport { TenantMiddlewareError, TenantNotResolvedError } from \"./errors.js\";\nimport type { TenantAdapter } from \"./types.js\";\n\ntype MaybePromise<T> = T | Promise<T>;\n\nexport interface HandleRequestOptions<Req, Result> {\n resolveTenant: (request: Req) => MaybePromise<string | undefined>;\n adapter: TenantAdapter;\n onMissingTenant?: (request: Req) => MaybePromise<Result>;\n onError?: (error: unknown, request: Req) => MaybePromise<Result>;\n}\n\n/**\n * Generic request helper for framework adapters.\n *\n * It resolves a tenant id from the framework request, then runs the request handler\n * inside runWithTenantAndDatabase so both getContext() and getDatabase() are available.\n */\nexport async function handleRequest<Req, Result>(\n request: Req,\n next: () => Promise<Result>,\n options: HandleRequestOptions<Req, Result>,\n): Promise<Result> {\n const tenantId = await options.resolveTenant(request);\n const normalizedTenantId = tenantId?.trim();\n if (!normalizedTenantId) {\n if (options.onMissingTenant) {\n return options.onMissingTenant(request);\n }\n\n const error = new TenantNotResolvedError();\n if (options.onError) {\n return options.onError(error, request);\n }\n throw error;\n }\n\n try {\n return await runWithTenantAndDatabase(\n normalizedTenantId,\n options.adapter,\n async () => next(),\n );\n } catch (error) {\n if (options.onError) {\n return options.onError(error, request);\n }\n\n if (\n error instanceof TenantNotResolvedError ||\n error instanceof TenantMiddlewareError\n ) {\n throw error;\n }\n\n throw new TenantMiddlewareError(undefined, { cause: error });\n }\n}\n","import type { TenantAdapter, Tenant, TenantRepository } from \"./types.js\";\nimport { runWithContext } from \"./context.js\";\nimport { runWithTenantAndDatabase } from \"./adapter.js\";\n\nconst DEFAULT_LIST_LIMIT = 50;\n\nexport interface CreateTenantData {\n name: string;\n slug: string;\n}\n\nexport interface UpdateTenantData {\n name?: string;\n slug?: string;\n}\n\nexport interface ListTenantsOptions {\n limit?: number;\n offset?: number;\n}\n\nfunction requireRunAsSystem<TDb, SDb>(\n adapter: TenantAdapter<TDb, SDb>,\n): <T>(fn: (database: SDb) => Promise<T>) => Promise<T> {\n if (!adapter.runAsSystem) {\n throw new Error(\n \"better-tenant: tenant.api and runAsSystem require adapter.runAsSystem; this adapter does not implement it\",\n );\n }\n return adapter.runAsSystem;\n}\n\n/**\n * Tenant CRUD API. All methods run via adapter.runAsSystem and getTenantRepository.\n * The runAsSystem check is deferred to call time so that betterTenant() can be\n * constructed with adapters that don't implement runAsSystem (e.g. test mocks).\n */\nexport function createTenantApi<TDb, SDb>(\n adapter: TenantAdapter<TDb, SDb>,\n getTenantRepository: (database: SDb) => TenantRepository,\n) {\n return {\n async createTenant(data: CreateTenantData): Promise<Tenant> {\n if (!data.name?.trim()) {\n throw new Error(\"better-tenant: createTenant requires name\");\n }\n if (!data.slug?.trim()) {\n throw new Error(\"better-tenant: createTenant requires slug\");\n }\n const runAsSystem = requireRunAsSystem(adapter);\n return runAsSystem((database) =>\n getTenantRepository(database).create({\n name: data.name.trim(),\n slug: data.slug.trim(),\n }),\n );\n },\n\n async updateTenant(\n tenantId: string,\n data: UpdateTenantData,\n ): Promise<Tenant> {\n if (!tenantId?.trim()) {\n throw new Error(\"better-tenant: updateTenant requires tenantId\");\n }\n const runAsSystem = requireRunAsSystem(adapter);\n return runAsSystem((database) =>\n getTenantRepository(database).update(tenantId, {\n ...(data.name !== undefined && { name: data.name }),\n ...(data.slug !== undefined && { slug: data.slug }),\n }),\n );\n },\n\n async listTenants(options: ListTenantsOptions = {}): Promise<Tenant[]> {\n const limit = options.limit ?? DEFAULT_LIST_LIMIT;\n const offset = Math.max(0, options.offset ?? 0);\n const runAsSystem = requireRunAsSystem(adapter);\n return runAsSystem((database) =>\n getTenantRepository(database).list({ limit, offset }),\n );\n },\n\n async deleteTenant(tenantId: string): Promise<void> {\n if (!tenantId?.trim()) {\n throw new Error(\"better-tenant: deleteTenant requires tenantId\");\n }\n const runAsSystem = requireRunAsSystem(adapter);\n return runAsSystem((database) =>\n getTenantRepository(database).delete(tenantId),\n );\n },\n\n async getTenant(tenantId: string): Promise<Tenant | null> {\n if (!tenantId?.trim()) {\n throw new Error(\"better-tenant: getTenant requires tenantId\");\n }\n const runAsSystem = requireRunAsSystem(adapter);\n return runAsSystem((database) =>\n getTenantRepository(database).getById(tenantId),\n );\n },\n\n async countTenants(): Promise<number> {\n const runAsSystem = requireRunAsSystem(adapter);\n return runAsSystem((database) =>\n getTenantRepository(database).count(),\n );\n },\n };\n}\n\n/**\n * runAs(tenantId, fn): same as request flow — set context + run inside adapter.runWithTenant\n * so code can use getDatabase() and run tenant-scoped queries. Use for cron, per-tenant migrations.\n */\nexport async function runAs<TDb, T>(\n tenantId: string,\n adapter: TenantAdapter<TDb>,\n fn: (database: TDb) => Promise<T>,\n): Promise<T> {\n return runWithTenantAndDatabase(tenantId, adapter, fn);\n}\n\n/**\n * runAsSystem(fn): run fn with a DB handle that has RLS bypass.\n * Optionally set context so getContext() reflects system mode.\n */\nexport async function runAsSystem<SDb, T>(\n adapter: TenantAdapter<unknown, SDb>,\n fn: (database: SDb) => Promise<T>,\n): Promise<T> {\n const run = requireRunAsSystem(adapter);\n return runWithContext({ isSystem: true }, () => run(fn));\n}\n","import type {\n ResolvableRequest,\n TenantResolverConfig,\n JwtResolverConfig,\n PathResolverConfig,\n SubdomainResolverConfig,\n} from \"./types.js\";\n\nfunction getHeader(\n headers: ResolvableRequest[\"headers\"],\n name: string,\n): string | undefined {\n const key = name.toLowerCase();\n if (headers instanceof Headers) {\n const value = headers.get(key);\n return value?.trim() || undefined;\n }\n const raw = headers[key] ?? headers[name];\n if (raw === undefined) {\n return undefined;\n }\n const value = Array.isArray(raw) ? raw[0] : raw;\n return (typeof value === \"string\" ? value : \"\").trim() || undefined;\n}\n\nfunction resolveFromHeader(\n request: ResolvableRequest,\n headerName: string,\n): string | undefined {\n if (!headerName) {\n return undefined;\n }\n return getHeader(request.headers, headerName);\n}\n\nfunction resolveFromPath(\n request: ResolvableRequest,\n pathConfig: string | PathResolverConfig,\n): string | undefined {\n const pathOrUrl = request.path ?? request.url;\n if (!pathOrUrl) {\n return undefined;\n }\n\n let path: string;\n try {\n path = pathOrUrl.startsWith(\"http\")\n ? new URL(pathOrUrl).pathname\n : pathOrUrl;\n } catch {\n path = pathOrUrl;\n }\n\n const pattern =\n typeof pathConfig === \"string\" ? pathConfig : pathConfig.pattern;\n const segmentIndex =\n typeof pathConfig === \"object\" && pathConfig.segmentIndex !== undefined\n ? pathConfig.segmentIndex\n : parseTenantSegmentIndex(pattern);\n\n const segments = path.split(\"/\").filter(Boolean);\n const value = segments[segmentIndex];\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n\n/** e.g. \"/t/:tenantId/*\" -> segment 1 (0-based). */\nfunction parseTenantSegmentIndex(pattern: string): number {\n const segments = pattern.split(\"/\").filter(Boolean);\n const idx = segments.indexOf(\":tenantId\");\n return idx >= 0 ? idx : 0;\n}\n\nfunction resolveFromSubdomain(\n request: ResolvableRequest,\n config: SubdomainResolverConfig,\n): string | undefined {\n const host = request.host ?? (request.url ? new URL(request.url).host : \"\");\n if (!host) {\n return undefined;\n }\n const hostname = host.split(\":\")[0];\n if (!hostname) {\n return undefined;\n }\n const parts = hostname.split(\".\");\n // Only one segment (e.g. \"localhost\") or domain.tld (e.g. \"example.com\") = no subdomain\n if (parts.length <= 2) {\n return undefined;\n }\n const index =\n config === true\n ? 0\n : typeof config === \"object\" && config.segmentIndex !== undefined\n ? config.segmentIndex\n : 0;\n const value = parts[index];\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n\nfunction decodeJwtPayload(token: string): Record<string, unknown> | null {\n try {\n const parts = token.split(\".\");\n if (parts.length < 2) {\n return null;\n }\n const payload = parts[1];\n if (!payload) {\n return null;\n }\n const decoded = atob(payload.replace(/-/g, \"+\").replace(/_/g, \"/\"));\n const parsed: unknown = JSON.parse(decoded);\n if (typeof parsed !== \"object\" || parsed === null) {\n return null;\n }\n return parsed as Record<string, unknown>;\n } catch {\n return null;\n }\n}\n\nasync function resolveFromJwt(\n request: ResolvableRequest,\n config: string | JwtResolverConfig,\n): Promise<string | undefined> {\n const getToken = request.getToken;\n if (!getToken) {\n return undefined;\n }\n const token = typeof getToken === \"function\" ? getToken() : getToken;\n const value = token instanceof Promise ? await token : token;\n const resolved = value ?? undefined;\n if (!resolved) {\n return undefined;\n }\n\n const claim = typeof config === \"string\" ? config : config.claim;\n if (!claim) {\n return undefined;\n }\n\n const verifyToken =\n typeof config === \"object\" ? config.verifyToken : undefined;\n\n let payload: Record<string, unknown> | null;\n if (verifyToken) {\n payload = await verifyToken(resolved);\n } else {\n payload = decodeJwtPayload(resolved);\n }\n\n if (!payload) {\n return undefined;\n }\n\n const claimValue = payload[claim];\n return typeof claimValue === \"string\" && claimValue.length > 0\n ? claimValue\n : undefined;\n}\n\n/**\n * Returns human-readable descriptions of the configured resolution strategies.\n * Useful for error messages when tenant resolution fails.\n */\nexport function describeStrategies(config: TenantResolverConfig): string[] {\n const strategies: string[] = [];\n if (config.header !== undefined) {\n strategies.push(`header '${config.header}'`);\n }\n if (config.path !== undefined) {\n const pattern =\n typeof config.path === \"string\" ? config.path : config.path.pattern;\n strategies.push(`path '${pattern}'`);\n }\n if (config.subdomain !== undefined && config.subdomain !== false) {\n strategies.push(\"subdomain\");\n }\n if (config.jwt !== undefined) {\n const claim =\n typeof config.jwt === \"string\" ? config.jwt : config.jwt.claim;\n strategies.push(`jwt claim '${claim}'`);\n }\n if (config.custom !== undefined) {\n strategies.push(\"custom resolver\");\n }\n return strategies;\n}\n\n/**\n * Resolution order: header → path → subdomain → jwt → custom.\n * Returns the first defined tenant id.\n */\nexport async function resolveTenant(\n request: ResolvableRequest,\n config: TenantResolverConfig,\n): Promise<string | undefined> {\n if (config.header !== undefined) {\n const v = resolveFromHeader(request, config.header);\n if (v !== undefined) {\n return v;\n }\n }\n if (config.path !== undefined) {\n const v = resolveFromPath(request, config.path);\n if (v !== undefined) {\n return v;\n }\n }\n if (config.subdomain !== undefined && config.subdomain !== false) {\n const v = resolveFromSubdomain(request, config.subdomain);\n if (v !== undefined) {\n return v;\n }\n }\n if (config.jwt !== undefined) {\n const v = await resolveFromJwt(request, config.jwt);\n if (v !== undefined) {\n return v;\n }\n }\n if (config.custom !== undefined) {\n const v = await Promise.resolve(config.custom(request));\n if (typeof v === \"string\" && v.length > 0) {\n return v;\n }\n }\n return undefined;\n}\n","/**\n * Shared parse and validation utilities for console endpoint handlers.\n *\n * These are small, pure, zero-dep helpers used by product endpoint handlers\n * (audit, tenant) to validate and parse incoming request data.\n */\n\n/** Type guard that narrows `unknown` to a plain object (not array, not null). */\nexport function isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/**\n * Parse a string to an integer within [min, max].\n * Returns `undefined` when `value` is `undefined` (param absent),\n * not a finite number, or below `min`.\n */\nexport function parseBoundedInt(\n value: string | undefined,\n min: number,\n max: number,\n): number | undefined {\n if (value === undefined) {\n return undefined;\n }\n const parsed = Number(value);\n if (!Number.isFinite(parsed) || parsed < min) {\n return undefined;\n }\n return Math.min(Math.floor(parsed), max);\n}\n\n/**\n * Parse an ISO-8601 date string.\n * Returns `undefined` when `value` is `undefined` or not a valid date.\n */\nexport function parseIsoDate(value: string | undefined): Date | undefined {\n if (value === undefined) {\n return undefined;\n }\n const date = new Date(value);\n if (Number.isNaN(date.getTime())) {\n return undefined;\n }\n return date;\n}\n","import type {\n ConsoleProductEndpoint,\n ConsoleProductRequest,\n ConsoleErrorResponse,\n TenantWire,\n TenantStatsResponse,\n} from \"@usebetterdev/contract\";\nimport {\n isPlainObject,\n parseBoundedInt,\n} from \"@usebetterdev/console-utils\";\nimport type { TenantApi } from \"./better-tenant.js\";\nimport type { Tenant } from \"./types.js\";\n\nconst MAX_FIELD_LENGTH = 255;\n\nfunction serializeTenant(tenant: Tenant): TenantWire {\n return {\n ...tenant,\n createdAt:\n tenant.createdAt instanceof Date\n ? tenant.createdAt.toISOString()\n : tenant.createdAt,\n };\n}\n\nexport function createTenantConsoleEndpoints(\n api: TenantApi,\n): ConsoleProductEndpoint[] {\n return [\n {\n method: \"GET\",\n path: \"/tenants\",\n requiredPermission: \"read\",\n async handler(request: ConsoleProductRequest) {\n try {\n const options: { limit?: number; offset?: number } = {};\n if (request.query.limit !== undefined) {\n const limit = parseBoundedInt(request.query.limit, 1, 1000);\n if (limit === undefined) {\n return { status: 400, body: { error: \"Invalid 'limit': must be a positive integer (max 1000)\" } satisfies ConsoleErrorResponse };\n }\n options.limit = limit;\n }\n if (request.query.offset !== undefined) {\n const offset = parseBoundedInt(request.query.offset, 0, Number.MAX_SAFE_INTEGER);\n if (offset === undefined) {\n return { status: 400, body: { error: \"Invalid 'offset': must be a non-negative integer\" } satisfies ConsoleErrorResponse };\n }\n options.offset = offset;\n }\n const tenants = await api.listTenants(options);\n return { status: 200, body: tenants.map(serializeTenant) satisfies TenantWire[] };\n } catch {\n return { status: 500, body: { error: \"Internal server error\" } satisfies ConsoleErrorResponse };\n }\n },\n },\n {\n method: \"GET\",\n path: \"/tenants/:id\",\n requiredPermission: \"read\",\n async handler(request: ConsoleProductRequest) {\n try {\n const id = request.params.id?.trim();\n if (!id) {\n return { status: 400, body: { error: \"Missing tenant id\" } satisfies ConsoleErrorResponse };\n }\n const tenant = await api.getTenant(id);\n if (!tenant) {\n return { status: 404, body: { error: \"Tenant not found\" } satisfies ConsoleErrorResponse };\n }\n return { status: 200, body: serializeTenant(tenant) satisfies TenantWire };\n } catch {\n return { status: 500, body: { error: \"Internal server error\" } satisfies ConsoleErrorResponse };\n }\n },\n },\n {\n method: \"POST\",\n path: \"/tenants\",\n requiredPermission: \"write\",\n async handler(request: ConsoleProductRequest) {\n try {\n if (!isPlainObject(request.body)) {\n return { status: 400, body: { error: \"Request body is required\" } satisfies ConsoleErrorResponse };\n }\n const name = typeof request.body.name === \"string\" ? request.body.name : \"\";\n const slug = typeof request.body.slug === \"string\" ? request.body.slug : \"\";\n if (!name.trim() || !slug.trim()) {\n return { status: 400, body: { error: \"name and slug are required\" } satisfies ConsoleErrorResponse };\n }\n if (name.length > MAX_FIELD_LENGTH || slug.length > MAX_FIELD_LENGTH) {\n return { status: 400, body: { error: \"name and slug must not exceed 255 characters\" } satisfies ConsoleErrorResponse };\n }\n const tenant = await api.createTenant({ name, slug });\n return { status: 201, body: serializeTenant(tenant) satisfies TenantWire };\n } catch {\n return { status: 500, body: { error: \"Internal server error\" } satisfies ConsoleErrorResponse };\n }\n },\n },\n {\n method: \"PATCH\",\n path: \"/tenants/:id\",\n requiredPermission: \"write\",\n async handler(request: ConsoleProductRequest) {\n try {\n const id = request.params.id?.trim();\n if (!id) {\n return { status: 400, body: { error: \"Missing tenant id\" } satisfies ConsoleErrorResponse };\n }\n if (!isPlainObject(request.body)) {\n return { status: 400, body: { error: \"Request body is required\" } satisfies ConsoleErrorResponse };\n }\n const data: { name?: string; slug?: string } = {};\n if (typeof request.body.name === \"string\") {\n if (request.body.name.length > MAX_FIELD_LENGTH) {\n return { status: 400, body: { error: \"name must not exceed 255 characters\" } satisfies ConsoleErrorResponse };\n }\n data.name = request.body.name;\n }\n if (typeof request.body.slug === \"string\") {\n if (request.body.slug.length > MAX_FIELD_LENGTH) {\n return { status: 400, body: { error: \"slug must not exceed 255 characters\" } satisfies ConsoleErrorResponse };\n }\n data.slug = request.body.slug;\n }\n const tenant = await api.updateTenant(id, data);\n return { status: 200, body: serializeTenant(tenant) satisfies TenantWire };\n } catch {\n return { status: 500, body: { error: \"Internal server error\" } satisfies ConsoleErrorResponse };\n }\n },\n },\n {\n method: \"DELETE\",\n path: \"/tenants/:id\",\n requiredPermission: \"admin\",\n async handler(request: ConsoleProductRequest) {\n try {\n const id = request.params.id?.trim();\n if (!id) {\n return { status: 400, body: { error: \"Missing tenant id\" } satisfies ConsoleErrorResponse };\n }\n await api.deleteTenant(id);\n return { status: 204, body: null };\n } catch {\n return { status: 500, body: { error: \"Internal server error\" } satisfies ConsoleErrorResponse };\n }\n },\n },\n {\n method: \"GET\",\n path: \"/stats\",\n requiredPermission: \"read\",\n async handler() {\n try {\n const tenantCount = await api.countTenants();\n return { status: 200, body: { tenantCount } satisfies TenantStatsResponse };\n } catch {\n return { status: 500, body: { error: \"Internal server error\" } satisfies ConsoleErrorResponse };\n }\n },\n },\n ];\n}\n","import type {\n BetterTenantConfig,\n Tenant,\n TenantAdapter,\n TenantRepository,\n TenantResolverConfig,\n ResolvableRequest,\n TenantContext,\n RunWithTenantAndDatabaseOptions,\n} from \"./types.js\";\nimport { sendInitTelemetry } from \"./telemetry.js\";\nimport { getContext, runWithTenant } from \"./context.js\";\nimport { getDatabase, runWithTenantAndDatabase } from \"./adapter.js\";\nimport {\n handleRequest as handleTenantRequest,\n type HandleRequestOptions,\n} from \"./handle-request.js\";\nimport {\n createTenantApi,\n runAsSystem as runAsSystemWithAdapter,\n} from \"./api.js\";\nimport { resolveTenant, describeStrategies } from \"./resolver.js\";\nimport { createTenantConsoleEndpoints } from \"./console-endpoints.js\";\n\n/** UUID v4 pattern for detecting whether an identifier is already a UUID. */\nconst UUID_RE =\n /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\n/**\n * Normalize a resolved identifier to a tenant UUID.\n *\n * - If resolveToId is configured, call it (takes full precedence).\n * - If the identifier is already a UUID, pass through.\n * - If adapter.runAsSystem is available, look up by slug via getTenantRepository.\n * - Otherwise, return as-is (will likely fail at DB level).\n */\nasync function resolveIdentifierToId(\n identifier: string,\n resolverConfig: TenantResolverConfig,\n adapter: TenantAdapter,\n getTenantRepository: (db: unknown) => TenantRepository,\n): Promise<string | undefined> {\n if (resolverConfig.resolveToId) {\n return resolverConfig.resolveToId(identifier);\n }\n if (UUID_RE.test(identifier)) {\n return identifier;\n }\n if (adapter.runAsSystem) {\n const tenant = await adapter.runAsSystem((systemDb: unknown) =>\n getTenantRepository(systemDb).getBySlug(identifier),\n );\n return tenant?.id;\n }\n return identifier;\n}\n\nexport interface TenantApi {\n createTenant(data: { name: string; slug: string }): Promise<Tenant>;\n updateTenant(\n tenantId: string,\n data: { name?: string; slug?: string },\n ): Promise<Tenant>;\n listTenants(options?: { limit?: number; offset?: number }): Promise<Tenant[]>;\n deleteTenant(tenantId: string): Promise<void>;\n getTenant(tenantId: string): Promise<Tenant | null>;\n countTenants(): Promise<number>;\n}\n\nexport interface BetterTenantInstance<TDb = unknown, SDb = unknown> {\n getContext: () => TenantContext | undefined;\n getDatabase: () => TDb | undefined;\n runWithTenant: typeof runWithTenant;\n runAs: <T>(tenantId: string, fn: (database: TDb) => Promise<T>) => Promise<T>;\n runAsSystem: <T>(fn: (database: SDb) => Promise<T>) => Promise<T>;\n resolveTenant: (request: ResolvableRequest) => Promise<string | undefined>;\n /** Human-readable descriptions of the configured resolution strategies. */\n resolverStrategies: string[];\n handleRequest: <Req extends ResolvableRequest, Result>(\n request: Req,\n next: () => Promise<Result>,\n options?: Omit<\n HandleRequestOptions<Req, Result>,\n \"resolveTenant\" | \"adapter\"\n >,\n ) => Promise<Result>;\n api: TenantApi;\n}\n\n/**\n * Creates the Better Tenant instance. Config must include adapter, tenantResolver, and getTenantRepository.\n */\nexport function betterTenant<TDb, SDb>(\n config: BetterTenantConfig<TDb, SDb>,\n): BetterTenantInstance<TDb, SDb> {\n const { database, tenantResolver, loadTenant } = config;\n const { adapter, getTenantRepository } = database;\n\n sendInitTelemetry(config, config.telemetry);\n\n const api = createTenantApi(adapter, getTenantRepository);\n\n const runWithTenantAndDatabaseOptions:\n | RunWithTenantAndDatabaseOptions<SDb>\n | undefined =\n loadTenant !== false\n ? { loadTenant: true as const, getTenantRepository }\n : undefined;\n\n const resolverStrategies = describeStrategies(tenantResolver);\n\n /** Resolve raw identifier from request, then normalize to UUID. */\n async function resolveAndNormalize(\n request: ResolvableRequest,\n ): Promise<string | undefined> {\n const raw = await resolveTenant(request, tenantResolver);\n if (!raw) return undefined;\n return resolveIdentifierToId(\n raw,\n tenantResolver,\n adapter,\n getTenantRepository as (db: unknown) => TenantRepository,\n );\n }\n\n if (config.console) {\n const endpoints = createTenantConsoleEndpoints(api);\n config.console.registerProduct({\n id: \"tenant\",\n name: \"Better Tenant\",\n endpoints,\n });\n }\n\n return {\n getContext,\n getDatabase: () => getDatabase() as TDb | undefined,\n runWithTenant,\n runAs: (tenantId, fn) =>\n runWithTenantAndDatabase(\n tenantId,\n adapter,\n fn,\n runWithTenantAndDatabaseOptions,\n ),\n runAsSystem: <T>(fn: (database: SDb) => Promise<T>) =>\n runAsSystemWithAdapter(adapter, fn),\n resolveTenant: resolveAndNormalize,\n resolverStrategies,\n handleRequest: (request, next, options) =>\n handleTenantRequest(request, next, {\n ...options,\n resolveTenant: resolveAndNormalize,\n adapter,\n }),\n api,\n };\n}\n","import type { ResolvableRequest } from \"./types.js\";\n\ntype NodeHeaders = Record<string, string | string[] | undefined>;\n\nexport interface NodeLikeRequest {\n headers?: Record<string, string | string[] | number | undefined>;\n url?: string;\n originalUrl?: string;\n path?: string;\n hostname?: string;\n host?: string;\n method?: string;\n}\n\nfunction isFetchRequest(input: unknown): input is Request {\n return typeof Request !== \"undefined\" && input instanceof Request;\n}\n\nfunction normalizeHost(raw: string | undefined): string | undefined {\n if (!raw) {\n return undefined;\n }\n const value = raw.split(\":\")[0]?.trim();\n return value || undefined;\n}\n\nfunction normalizeHeaders(\n headers: Record<string, string | string[] | number | undefined> | undefined,\n): NodeHeaders {\n if (!headers) {\n return {};\n }\n const normalized: NodeHeaders = {};\n for (const [key, value] of Object.entries(headers)) {\n const normalizedKey = key.toLowerCase();\n if (Array.isArray(value)) {\n normalized[normalizedKey] = value.map((part) => String(part));\n continue;\n }\n if (value === undefined) {\n normalized[normalizedKey] = undefined;\n continue;\n }\n normalized[normalizedKey] = String(value);\n }\n return normalized;\n}\n\nfunction pathWithoutQuery(value: string | undefined): string | undefined {\n if (!value) {\n return undefined;\n }\n const [pathname] = value.split(\"?\");\n return pathname || undefined;\n}\n\nexport function toResolvableRequest(\n request: Request | NodeLikeRequest,\n): ResolvableRequest {\n if (isFetchRequest(request)) {\n const url = request.url;\n let host: string | undefined;\n let path: string | undefined;\n try {\n const parsedUrl = new URL(url);\n host = normalizeHost(parsedUrl.host);\n path = parsedUrl.pathname || undefined;\n } catch {\n host = undefined;\n path = undefined;\n }\n const resolved: ResolvableRequest = {\n headers: request.headers,\n url,\n method: request.method,\n };\n if (path !== undefined) {\n resolved.path = path;\n }\n if (host !== undefined) {\n resolved.host = host;\n }\n return resolved;\n }\n\n const headers = normalizeHeaders(request.headers);\n const hostFromHeaders = headers.host;\n const hostValue = Array.isArray(hostFromHeaders)\n ? hostFromHeaders[0]\n : hostFromHeaders;\n const host = normalizeHost(request.hostname ?? request.host ?? hostValue);\n const path = pathWithoutQuery(\n request.path ?? request.originalUrl ?? request.url,\n );\n\n const resolved: ResolvableRequest = {\n headers,\n };\n if (path !== undefined) {\n resolved.path = path;\n }\n if (host !== undefined) {\n resolved.host = host;\n }\n if (request.method !== undefined) {\n resolved.method = request.method;\n }\n return resolved;\n}\n"],"mappings":"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","names":["v","runAsSystem","value","host","path","resolved"]}
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/telemetry.ts","../src/context.ts","../src/adapter.ts","../src/errors.ts","../src/handle-request.ts","../src/api.ts","../src/resolver.ts","../../../shared/console-utils/src/index.ts","../src/console-endpoints.ts","../src/better-tenant.ts","../src/request.ts"],"sourcesContent":["/**\n * Anonymous telemetry for Better Tenant.\n * On by default, opt-out via BETTER_TENANT_TELEMETRY=0 or telemetry: { enabled: false }.\n * See docs/TELEMETRY.md.\n */\n\nimport { createHash } from \"node:crypto\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { platform, release, arch, cpus, totalmem } from \"node:os\";\nimport type { BetterTenantConfig } from \"./types.js\";\n\n/** Subset of BetterTenantConfig used by telemetry (avoids contravariance issues with generic DB types). */\ntype TelemetryConfigInput = Pick<\n BetterTenantConfig,\n \"tenantResolver\" | \"basePath\" | \"plugins\" | \"loadTenant\" | \"telemetry\"\n>;\n\nconst TELEMETRY_ENDPOINT = \"https://telemetry.usebetter.dev/v1/events\";\nconst LIBRARY_ID = \"better-tenant\";\n\n// --- Redacted config types ---\n\nexport interface TelemetryTenantConfig {\n resolver: {\n header: boolean;\n path: boolean;\n subdomain: boolean;\n jwt: boolean;\n custom: boolean;\n };\n tenantTablesCount: number;\n loadTenant: boolean | undefined;\n basePathSet: boolean;\n plugins: string[];\n}\n\nexport interface TelemetryCliConfig {\n tenantTablesCount: number;\n hasSchemaDir: boolean;\n hasMigrationsDir: boolean;\n}\n\nexport interface TelemetryPayload {\n library: string;\n type: string;\n timestamp: string;\n anonymousId?: string;\n runtime?: { name: string; version: string };\n environment?: string;\n framework?: { name: string; version?: string };\n database?: { name: string; version?: string };\n system?: {\n platform: string;\n release: string;\n arch: string;\n cpus: number;\n totalMemoryMb: number;\n isDocker?: boolean;\n isWSL?: boolean;\n };\n packageManager?: { name: string; version?: string };\n config?: TelemetryTenantConfig | TelemetryCliConfig;\n outcome?: string;\n}\n\n// --- Telemetry options ---\n\nexport interface TelemetryOptions {\n /** Override enabled (default: true). Set false to opt out. */\n enabled?: boolean;\n /** Debug mode: log to console only, do not send. */\n debug?: boolean;\n /** When true, return Promise that resolves when send completes. Use before process.exit. */\n wait?: boolean;\n}\n\n// --- Redaction ---\n\nexport function getTelemetryTenantConfig(\n config: TelemetryConfigInput,\n): TelemetryTenantConfig {\n const r = config.tenantResolver ?? {};\n return {\n resolver: {\n header: !!r.header,\n path: !!r.path,\n subdomain: !!r.subdomain,\n jwt: !!r.jwt,\n custom: !!r.custom,\n },\n tenantTablesCount: 0,\n loadTenant: config.loadTenant,\n basePathSet: !!config.basePath,\n plugins: (config.plugins ?? []).map((p) => String(p.id)),\n };\n}\n\nexport function getTelemetryCliConfig(config: {\n tenantTables: string[];\n schemaDir?: string;\n migrationsDir?: string;\n}): TelemetryCliConfig {\n return {\n tenantTablesCount: config.tenantTables?.length ?? 0,\n hasSchemaDir: !!config.schemaDir,\n hasMigrationsDir: !!config.migrationsDir,\n };\n}\n\n// --- Detection ---\n\nfunction getAnonymousId(cwd: string): string | undefined {\n try {\n const pkgPath = join(cwd, \"package.json\");\n if (!existsSync(pkgPath)) {\n return undefined;\n }\n\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\")) as {\n name?: string;\n betterTenant?: { basePath?: string };\n };\n const name = typeof pkg?.name === \"string\" ? pkg.name : \"\";\n const basePath =\n typeof pkg?.betterTenant?.basePath === \"string\"\n ? pkg.betterTenant.basePath\n : \"\";\n const input = `${name}:${basePath}`.trim() || \"unknown\";\n return createHash(\"sha256\").update(input).digest(\"hex\").slice(0, 16);\n } catch {\n return undefined;\n }\n}\n\nfunction detectRuntime(): { name: string; version: string } {\n const g = globalThis as Record<string, unknown>;\n if (typeof g.Bun !== \"undefined\") {\n const bun = g.Bun as { version?: string };\n return {\n name: \"bun\",\n version: typeof bun?.version === \"string\" ? bun.version : \"unknown\",\n };\n }\n if (typeof g.Deno !== \"undefined\") {\n const deno = g.Deno as { version?: { deno?: string } };\n const v = deno?.version?.deno;\n return { name: \"deno\", version: typeof v === \"string\" ? v : \"unknown\" };\n }\n const v = (typeof process !== \"undefined\" && process.versions?.node) || \"\";\n return { name: \"node\", version: v || \"unknown\" };\n}\n\nfunction detectEnvironment(): string {\n const env = process.env.NODE_ENV || \"development\";\n if (env === \"test\") {\n return \"test\";\n }\n\n // CI check before NODE_ENV so CI is detected even when NODE_ENV=production\n if (\n process.env.CI === \"true\" ||\n process.env.GITHUB_ACTIONS === \"true\" ||\n process.env.GITLAB_CI === \"true\" ||\n process.env.CIRCLECI === \"true\"\n ) {\n return \"ci\";\n }\n if (env === \"production\") {\n return \"production\";\n }\n\n return \"development\";\n}\n\nfunction detectFramework(\n cwd: string,\n): { name: string; version?: string } | undefined {\n try {\n const pkgPath = join(cwd, \"package.json\");\n if (!existsSync(pkgPath)) {\n return undefined;\n }\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\")) as {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n };\n const deps = { ...pkg?.dependencies, ...pkg?.devDependencies };\n if (deps[\"next\"]) {\n return { name: \"next\", version: deps[\"next\"] };\n }\n if (deps[\"hono\"]) {\n return { name: \"hono\", version: deps[\"hono\"] };\n }\n if (deps[\"express\"]) {\n return { name: \"express\", version: deps[\"express\"] };\n }\n return undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction detectDatabase(\n cwd: string,\n): { name: string; version?: string } | undefined {\n try {\n const pkgPath = join(cwd, \"package.json\");\n if (!existsSync(pkgPath)) {\n return undefined;\n }\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\")) as {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n };\n const deps = { ...pkg?.dependencies, ...pkg?.devDependencies };\n if (deps[\"drizzle-orm\"]) {\n return { name: \"drizzle\", version: deps[\"drizzle-orm\"] };\n }\n if (deps[\"prisma\"]) {\n return { name: \"prisma\", version: deps[\"prisma\"] };\n }\n return undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction detectSystem(): NonNullable<TelemetryPayload[\"system\"]> {\n const isDocker = existsSync(\"/.dockerenv\");\n const isWSL =\n typeof process.env.WSL_DISTRO_NAME === \"string\" ||\n (typeof process.env.WSL_INTEROP === \"string\" &&\n process.env.WSL_INTEROP.length > 0);\n return {\n platform: platform(),\n release: release(),\n arch: arch(),\n cpus: cpus().length,\n totalMemoryMb: Math.round(totalmem() / 1024 / 1024),\n isDocker,\n isWSL,\n };\n}\n\nfunction detectPackageManager():\n | { name: string; version?: string }\n | undefined {\n const ua = process.env.npm_config_user_agent;\n if (!ua || typeof ua !== \"string\") {\n return undefined;\n }\n const match = ua.match(/^(.+?)\\/(\\d+\\.\\d+\\.\\d+.*?)(?:\\s|$)/);\n if (match) {\n const name = (match[1] ?? \"unknown\").toLowerCase();\n const version = match[2];\n return version ? { name, version } : { name };\n }\n if (ua.includes(\"pnpm\")) {\n return { name: \"pnpm\" };\n }\n if (ua.includes(\"yarn\")) {\n return { name: \"yarn\" };\n }\n return { name: \"npm\" };\n}\n\n// --- Send ---\n\nfunction isTelemetryEnabled(options?: TelemetryOptions): boolean {\n if (process.env.NODE_ENV === \"test\") {\n return false;\n }\n const env = process.env.BETTER_TENANT_TELEMETRY;\n if (env === \"0\" || env?.toLowerCase() === \"false\") {\n return false;\n }\n if (env === \"1\" || env?.toLowerCase() === \"true\") {\n return true;\n }\n return options?.enabled !== false;\n}\n\nfunction isDebugMode(options?: TelemetryOptions): boolean {\n if (process.env.BETTER_TENANT_TELEMETRY_DEBUG === \"1\") {\n return true;\n }\n return options?.debug === true;\n}\n\n/**\n * Send telemetry event. Fire-and-forget by default; use options.wait for process-exit paths.\n * Skips when NODE_ENV=test, when disabled via env/config, or when debug mode logs only.\n */\nexport function sendTelemetry(\n type: string,\n payload: Omit<TelemetryPayload, \"library\" | \"type\" | \"timestamp\">,\n options?: TelemetryOptions,\n): void | Promise<void> {\n if (!isTelemetryEnabled(options)) {\n return options?.wait ? Promise.resolve() : undefined;\n }\n const fullPayload: TelemetryPayload = {\n library: LIBRARY_ID,\n type,\n timestamp: new Date().toISOString(),\n ...payload,\n };\n if (isDebugMode(options)) {\n console.log(\n \"[better-tenant telemetry]\",\n JSON.stringify(fullPayload, null, 2),\n );\n return options?.wait ? Promise.resolve() : undefined;\n }\n const doSend = () =>\n fetch(TELEMETRY_ENDPOINT, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(fullPayload),\n }).catch(() => {\n // Silently ignore send failures\n });\n\n if (options?.wait) {\n return new Promise<void>((resolve) => {\n setImmediate(async () => {\n await doSend();\n resolve();\n });\n });\n }\n\n setImmediate(() => doSend());\n}\n\n/**\n * Build and send init telemetry (call from betterTenant()).\n */\nexport function sendInitTelemetry(\n config: TelemetryConfigInput,\n options?: TelemetryOptions,\n): void {\n const cwd = process.cwd();\n const payload: Omit<TelemetryPayload, \"library\" | \"type\" | \"timestamp\"> = {\n runtime: detectRuntime(),\n environment: detectEnvironment(),\n config: getTelemetryTenantConfig(config),\n };\n const anonymousId = getAnonymousId(cwd);\n if (anonymousId) payload.anonymousId = anonymousId;\n const framework = detectFramework(cwd);\n if (framework) payload.framework = framework;\n const database = detectDatabase(cwd);\n if (database) payload.database = database;\n payload.system = detectSystem();\n const pkgMgr = detectPackageManager();\n if (pkgMgr) payload.packageManager = pkgMgr;\n sendTelemetry(\"init\", payload, options ?? config.telemetry);\n}\n\n/** Raw CLI config shape (subset needed for telemetry). */\nexport interface CliConfigForTelemetry {\n tenantTables: string[];\n schemaDir?: string;\n migrationsDir?: string;\n}\n\n/**\n * Build and send CLI telemetry. Use from CLI commands.\n * Accepts raw config; redaction happens internally.\n * Use options.wait: true before process.exit so the send completes.\n */\nexport function sendCliTelemetry(\n type: \"cli_generate\" | \"cli_migrate\" | \"cli_check\" | \"cli_seed\" | \"cli_init\",\n outcome: string,\n config?: CliConfigForTelemetry,\n options?: { wait?: boolean },\n): void | Promise<void> {\n const cwd = process.cwd();\n const redactedConfig = config ? getTelemetryCliConfig(config) : undefined;\n const payload: Omit<TelemetryPayload, \"library\" | \"type\" | \"timestamp\"> = {\n runtime: detectRuntime(),\n environment: detectEnvironment(),\n outcome,\n };\n if (redactedConfig) payload.config = redactedConfig;\n payload.system = detectSystem();\n const anonymousId = getAnonymousId(cwd);\n if (anonymousId) payload.anonymousId = anonymousId;\n const framework = detectFramework(cwd);\n if (framework) payload.framework = framework;\n const database = detectDatabase(cwd);\n if (database) payload.database = database;\n const pkgMgr = detectPackageManager();\n if (pkgMgr) payload.packageManager = pkgMgr;\n return sendTelemetry(type, payload, options);\n}\n","import type { TenantContext } from \"./types.js\";\nimport { AsyncLocalStorage } from \"node:async_hooks\";\n\nconst storage = new AsyncLocalStorage<TenantContext>();\n\n/**\n * Returns the current tenant context, or undefined when not inside runWithTenant / runWithTenantAndDatabase.\n */\nexport function getContext(): TenantContext | undefined {\n return storage.getStore();\n}\n\n/**\n * Runs fn inside a scope where getContext() returns { tenantId }.\n * No adapter/DB involved; use for tests or when adapter is not configured.\n * If tenantId is empty string, it is treated as undefined (no tenant).\n */\nexport function runWithTenant<T>(\n tenantId: string,\n fn: () => T | Promise<T>,\n): Promise<T> {\n const normalized = tenantId.trim() || undefined;\n if (normalized === undefined) {\n return Promise.reject(\n new Error(\"better-tenant: tenantId must be a non-empty string\"),\n );\n }\n return Promise.resolve(\n storage.run({ tenantId: normalized }, () => fn()),\n );\n}\n\n/**\n * Internal: set context with optional database handle. Used by runWithTenantAndDatabase.\n */\nexport function runWithContext<T>(\n context: TenantContext,\n fn: () => T | Promise<T>,\n): Promise<T> {\n return Promise.resolve(storage.run(context, () => fn()));\n}\n\n","import type {\n TenantAdapter,\n TenantContext,\n RunWithTenantAndDatabaseOptions,\n} from \"./types.js\";\nimport { getContext, runWithContext } from \"./context.js\";\n\n/**\n * Returns the tenant-scoped database handle when inside a runWithTenantAndDatabase (or runAs) scope.\n *\n * Use only the handle from getDatabase() for tenant-scoped tables. Outside scope, returns undefined.\n * Config requires an adapter when tenant-scoped DB is used; getDatabase() is then available inside\n * request handlers that ran via runWithTenantAndDatabase(tenantId, adapter, next).\n */\nexport function getDatabase(): unknown {\n const context = getContext();\n return context?.database;\n}\n\n/**\n * Sets AsyncLocalStorage context and runs fn with the adapter's tenant-scoped DB.\n *\n * (1) Sets AsyncLocalStorage context with tenantId and database.\n * (2) Calls adapter.runWithTenant(tenantId, (database) => fn(database)).\n * (3) Stores the database handle in context so getDatabase() returns it.\n *\n * Middleware should resolve tenantId from the request, then call\n * runWithTenantAndDatabase(tenantId, adapter, next) so both context and DB handle are available.\n *\n * When options.loadTenant is true and options.getTenantRepository and adapter.runAsSystem are set,\n * loads the full Tenant row into context so getContext().tenant is available (or undefined if not found).\n */\nexport async function runWithTenantAndDatabase<TDb, SDb, T>(\n tenantId: string,\n adapter: TenantAdapter<TDb, SDb>,\n fn: (database: TDb) => Promise<T>,\n options?: RunWithTenantAndDatabaseOptions<SDb>,\n): Promise<T> {\n const result = await adapter.runWithTenant(tenantId, async (database) => {\n let context: TenantContext = { tenantId, database };\n const getTenantRepository = options?.getTenantRepository;\n if (\n options?.loadTenant &&\n getTenantRepository &&\n adapter.runAsSystem\n ) {\n const tenant = await adapter.runAsSystem((systemDb) =>\n getTenantRepository(systemDb).getById(tenantId),\n );\n context = tenant != null ? { ...context, tenant } : context;\n }\n return runWithContext(context, () => fn(database));\n });\n return result;\n}\n","export class TenantNotResolvedError extends Error {\n constructor(message = \"better-tenant: tenant could not be resolved from request\") {\n super(message);\n this.name = \"TenantNotResolvedError\";\n }\n}\n\nexport class TenantMiddlewareError extends Error {\n constructor(\n message = \"better-tenant: failed to run tenant middleware\",\n options?: { cause?: unknown },\n ) {\n super(message, options);\n this.name = \"TenantMiddlewareError\";\n }\n}\n","import { runWithTenantAndDatabase } from \"./adapter.js\";\nimport { TenantMiddlewareError, TenantNotResolvedError } from \"./errors.js\";\nimport type { TenantAdapter } from \"./types.js\";\n\ntype MaybePromise<T> = T | Promise<T>;\n\nexport interface HandleRequestOptions<Req, Result> {\n resolveTenant: (request: Req) => MaybePromise<string | undefined>;\n adapter: TenantAdapter;\n onMissingTenant?: (request: Req) => MaybePromise<Result>;\n onError?: (error: unknown, request: Req) => MaybePromise<Result>;\n}\n\n/**\n * Generic request helper for framework adapters.\n *\n * It resolves a tenant id from the framework request, then runs the request handler\n * inside runWithTenantAndDatabase so both getContext() and getDatabase() are available.\n */\nexport async function handleRequest<Req, Result>(\n request: Req,\n next: () => Promise<Result>,\n options: HandleRequestOptions<Req, Result>,\n): Promise<Result> {\n const tenantId = await options.resolveTenant(request);\n const normalizedTenantId = tenantId?.trim();\n if (!normalizedTenantId) {\n if (options.onMissingTenant) {\n return options.onMissingTenant(request);\n }\n\n const error = new TenantNotResolvedError();\n if (options.onError) {\n return options.onError(error, request);\n }\n throw error;\n }\n\n try {\n return await runWithTenantAndDatabase(\n normalizedTenantId,\n options.adapter,\n async () => next(),\n );\n } catch (error) {\n if (options.onError) {\n return options.onError(error, request);\n }\n\n if (\n error instanceof TenantNotResolvedError ||\n error instanceof TenantMiddlewareError\n ) {\n throw error;\n }\n\n throw new TenantMiddlewareError(undefined, { cause: error });\n }\n}\n","import type { TenantAdapter, Tenant, TenantRepository } from \"./types.js\";\nimport { runWithContext } from \"./context.js\";\nimport { runWithTenantAndDatabase } from \"./adapter.js\";\n\nconst DEFAULT_LIST_LIMIT = 50;\n\nexport interface CreateTenantData {\n name: string;\n slug: string;\n}\n\nexport interface UpdateTenantData {\n name?: string;\n slug?: string;\n}\n\nexport interface ListTenantsOptions {\n limit?: number;\n offset?: number;\n}\n\nfunction requireRunAsSystem<TDb, SDb>(\n adapter: TenantAdapter<TDb, SDb>,\n): <T>(fn: (database: SDb) => Promise<T>) => Promise<T> {\n if (!adapter.runAsSystem) {\n throw new Error(\n \"better-tenant: tenant.api and runAsSystem require adapter.runAsSystem; this adapter does not implement it\",\n );\n }\n return adapter.runAsSystem;\n}\n\n/**\n * Tenant CRUD API. All methods run via adapter.runAsSystem and getTenantRepository.\n * The runAsSystem check is deferred to call time so that betterTenant() can be\n * constructed with adapters that don't implement runAsSystem (e.g. test mocks).\n */\nexport function createTenantApi<TDb, SDb>(\n adapter: TenantAdapter<TDb, SDb>,\n getTenantRepository: (database: SDb) => TenantRepository,\n) {\n return {\n async createTenant(data: CreateTenantData): Promise<Tenant> {\n if (!data.name?.trim()) {\n throw new Error(\"better-tenant: createTenant requires name\");\n }\n if (!data.slug?.trim()) {\n throw new Error(\"better-tenant: createTenant requires slug\");\n }\n const runAsSystem = requireRunAsSystem(adapter);\n return runAsSystem((database) =>\n getTenantRepository(database).create({\n name: data.name.trim(),\n slug: data.slug.trim(),\n }),\n );\n },\n\n async updateTenant(\n tenantId: string,\n data: UpdateTenantData,\n ): Promise<Tenant> {\n if (!tenantId?.trim()) {\n throw new Error(\"better-tenant: updateTenant requires tenantId\");\n }\n const runAsSystem = requireRunAsSystem(adapter);\n return runAsSystem((database) =>\n getTenantRepository(database).update(tenantId, {\n ...(data.name !== undefined && { name: data.name }),\n ...(data.slug !== undefined && { slug: data.slug }),\n }),\n );\n },\n\n async listTenants(options: ListTenantsOptions = {}): Promise<Tenant[]> {\n const limit = options.limit ?? DEFAULT_LIST_LIMIT;\n const offset = Math.max(0, options.offset ?? 0);\n const runAsSystem = requireRunAsSystem(adapter);\n return runAsSystem((database) =>\n getTenantRepository(database).list({ limit, offset }),\n );\n },\n\n async deleteTenant(tenantId: string): Promise<void> {\n if (!tenantId?.trim()) {\n throw new Error(\"better-tenant: deleteTenant requires tenantId\");\n }\n const runAsSystem = requireRunAsSystem(adapter);\n return runAsSystem((database) =>\n getTenantRepository(database).delete(tenantId),\n );\n },\n\n async getTenant(tenantId: string): Promise<Tenant | null> {\n if (!tenantId?.trim()) {\n throw new Error(\"better-tenant: getTenant requires tenantId\");\n }\n const runAsSystem = requireRunAsSystem(adapter);\n return runAsSystem((database) =>\n getTenantRepository(database).getById(tenantId),\n );\n },\n\n async countTenants(): Promise<number> {\n const runAsSystem = requireRunAsSystem(adapter);\n return runAsSystem((database) =>\n getTenantRepository(database).count(),\n );\n },\n };\n}\n\n/**\n * runAs(tenantId, fn): same as request flow — set context + run inside adapter.runWithTenant\n * so code can use getDatabase() and run tenant-scoped queries. Use for cron, per-tenant migrations.\n */\nexport async function runAs<TDb, T>(\n tenantId: string,\n adapter: TenantAdapter<TDb>,\n fn: (database: TDb) => Promise<T>,\n): Promise<T> {\n return runWithTenantAndDatabase(tenantId, adapter, fn);\n}\n\n/**\n * runAsSystem(fn): run fn with a DB handle that has RLS bypass.\n * Optionally set context so getContext() reflects system mode.\n */\nexport async function runAsSystem<SDb, T>(\n adapter: TenantAdapter<unknown, SDb>,\n fn: (database: SDb) => Promise<T>,\n): Promise<T> {\n const run = requireRunAsSystem(adapter);\n return runWithContext({ isSystem: true }, () => run(fn));\n}\n","import type {\n ResolvableRequest,\n TenantResolverConfig,\n JwtResolverConfig,\n PathResolverConfig,\n SubdomainResolverConfig,\n} from \"./types.js\";\n\nfunction getHeader(\n headers: ResolvableRequest[\"headers\"],\n name: string,\n): string | undefined {\n const key = name.toLowerCase();\n if (headers instanceof Headers) {\n const value = headers.get(key);\n return value?.trim() || undefined;\n }\n const raw = headers[key] ?? headers[name];\n if (raw === undefined) {\n return undefined;\n }\n const value = Array.isArray(raw) ? raw[0] : raw;\n return (typeof value === \"string\" ? value : \"\").trim() || undefined;\n}\n\nfunction resolveFromHeader(\n request: ResolvableRequest,\n headerName: string,\n): string | undefined {\n if (!headerName) {\n return undefined;\n }\n return getHeader(request.headers, headerName);\n}\n\nfunction resolveFromPath(\n request: ResolvableRequest,\n pathConfig: string | PathResolverConfig,\n): string | undefined {\n const pathOrUrl = request.path ?? request.url;\n if (!pathOrUrl) {\n return undefined;\n }\n\n let path: string;\n try {\n path = pathOrUrl.startsWith(\"http\")\n ? new URL(pathOrUrl).pathname\n : pathOrUrl;\n } catch {\n path = pathOrUrl;\n }\n\n const pattern =\n typeof pathConfig === \"string\" ? pathConfig : pathConfig.pattern;\n const segmentIndex =\n typeof pathConfig === \"object\" && pathConfig.segmentIndex !== undefined\n ? pathConfig.segmentIndex\n : parseTenantSegmentIndex(pattern);\n\n const segments = path.split(\"/\").filter(Boolean);\n const value = segments[segmentIndex];\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n\n/** e.g. \"/t/:tenantId/*\" -> segment 1 (0-based). */\nfunction parseTenantSegmentIndex(pattern: string): number {\n const segments = pattern.split(\"/\").filter(Boolean);\n const idx = segments.indexOf(\":tenantId\");\n return idx >= 0 ? idx : 0;\n}\n\nfunction resolveFromSubdomain(\n request: ResolvableRequest,\n config: SubdomainResolverConfig,\n): string | undefined {\n const host = request.host ?? (request.url ? new URL(request.url).host : \"\");\n if (!host) {\n return undefined;\n }\n const hostname = host.split(\":\")[0];\n if (!hostname) {\n return undefined;\n }\n const parts = hostname.split(\".\");\n // Only one segment (e.g. \"localhost\") or domain.tld (e.g. \"example.com\") = no subdomain\n if (parts.length <= 2) {\n return undefined;\n }\n const index =\n config === true\n ? 0\n : typeof config === \"object\" && config.segmentIndex !== undefined\n ? config.segmentIndex\n : 0;\n const value = parts[index];\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n\nfunction decodeJwtPayload(token: string): Record<string, unknown> | null {\n try {\n const parts = token.split(\".\");\n if (parts.length < 2) {\n return null;\n }\n const payload = parts[1];\n if (!payload) {\n return null;\n }\n const decoded = atob(payload.replace(/-/g, \"+\").replace(/_/g, \"/\"));\n const parsed: unknown = JSON.parse(decoded);\n if (typeof parsed !== \"object\" || parsed === null) {\n return null;\n }\n return parsed as Record<string, unknown>;\n } catch {\n return null;\n }\n}\n\nasync function resolveFromJwt(\n request: ResolvableRequest,\n config: string | JwtResolverConfig,\n): Promise<string | undefined> {\n const getToken = request.getToken;\n if (!getToken) {\n return undefined;\n }\n const token = typeof getToken === \"function\" ? getToken() : getToken;\n const value = token instanceof Promise ? await token : token;\n const resolved = value ?? undefined;\n if (!resolved) {\n return undefined;\n }\n\n const claim = typeof config === \"string\" ? config : config.claim;\n if (!claim) {\n return undefined;\n }\n\n const verifyToken =\n typeof config === \"object\" ? config.verifyToken : undefined;\n\n let payload: Record<string, unknown> | null;\n if (verifyToken) {\n payload = await verifyToken(resolved);\n } else {\n payload = decodeJwtPayload(resolved);\n }\n\n if (!payload) {\n return undefined;\n }\n\n const claimValue = payload[claim];\n return typeof claimValue === \"string\" && claimValue.length > 0\n ? claimValue\n : undefined;\n}\n\n/**\n * Returns human-readable descriptions of the configured resolution strategies.\n * Useful for error messages when tenant resolution fails.\n */\nexport function describeStrategies(config: TenantResolverConfig): string[] {\n const strategies: string[] = [];\n if (config.header !== undefined) {\n strategies.push(`header '${config.header}'`);\n }\n if (config.path !== undefined) {\n const pattern =\n typeof config.path === \"string\" ? config.path : config.path.pattern;\n strategies.push(`path '${pattern}'`);\n }\n if (config.subdomain !== undefined && config.subdomain !== false) {\n strategies.push(\"subdomain\");\n }\n if (config.jwt !== undefined) {\n const claim =\n typeof config.jwt === \"string\" ? config.jwt : config.jwt.claim;\n strategies.push(`jwt claim '${claim}'`);\n }\n if (config.custom !== undefined) {\n strategies.push(\"custom resolver\");\n }\n return strategies;\n}\n\n/**\n * Resolution order: header → path → subdomain → jwt → custom.\n * Returns the first defined tenant id.\n */\nexport async function resolveTenant(\n request: ResolvableRequest,\n config: TenantResolverConfig,\n): Promise<string | undefined> {\n if (config.header !== undefined) {\n const v = resolveFromHeader(request, config.header);\n if (v !== undefined) {\n return v;\n }\n }\n if (config.path !== undefined) {\n const v = resolveFromPath(request, config.path);\n if (v !== undefined) {\n return v;\n }\n }\n if (config.subdomain !== undefined && config.subdomain !== false) {\n const v = resolveFromSubdomain(request, config.subdomain);\n if (v !== undefined) {\n return v;\n }\n }\n if (config.jwt !== undefined) {\n const v = await resolveFromJwt(request, config.jwt);\n if (v !== undefined) {\n return v;\n }\n }\n if (config.custom !== undefined) {\n const v = await Promise.resolve(config.custom(request));\n if (typeof v === \"string\" && v.length > 0) {\n return v;\n }\n }\n return undefined;\n}\n","/**\n * Shared parse and validation utilities for console endpoint handlers.\n *\n * These are small, pure, zero-dep helpers used by product endpoint handlers\n * (audit, tenant) to validate and parse incoming request data.\n */\n\n/** Type guard that narrows `unknown` to a plain object (not array, not null). */\nexport function isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/**\n * Parse a string to an integer within [min, max].\n * Returns `undefined` when `value` is `undefined` (param absent),\n * not a finite number, or below `min`.\n */\nexport function parseBoundedInt(\n value: string | undefined,\n min: number,\n max: number,\n): number | undefined {\n if (value === undefined) {\n return undefined;\n }\n const parsed = Number(value);\n if (!Number.isFinite(parsed) || parsed < min) {\n return undefined;\n }\n return Math.min(Math.floor(parsed), max);\n}\n\n/**\n * Parse an ISO-8601 date string.\n * Returns `undefined` when `value` is `undefined` or not a valid date.\n */\nexport function parseIsoDate(value: string | undefined): Date | undefined {\n if (value === undefined) {\n return undefined;\n }\n const date = new Date(value);\n if (Number.isNaN(date.getTime())) {\n return undefined;\n }\n return date;\n}\n","import type {\n ConsoleProductEndpoint,\n ConsoleProductRequest,\n ConsoleErrorResponse,\n TenantWire,\n TenantStatsResponse,\n} from \"@usebetterdev/console-contract\";\nimport {\n isPlainObject,\n parseBoundedInt,\n} from \"@usebetterdev/console-utils\";\nimport type { TenantApi } from \"./better-tenant.js\";\nimport type { Tenant } from \"./types.js\";\n\nconst MAX_FIELD_LENGTH = 255;\n\nfunction serializeTenant(tenant: Tenant): TenantWire {\n return {\n ...tenant,\n createdAt:\n tenant.createdAt instanceof Date\n ? tenant.createdAt.toISOString()\n : tenant.createdAt,\n };\n}\n\nexport function createTenantConsoleEndpoints(\n api: TenantApi,\n): ConsoleProductEndpoint[] {\n return [\n {\n method: \"GET\",\n path: \"/tenants\",\n requiredPermission: \"read\",\n async handler(request: ConsoleProductRequest) {\n try {\n const options: { limit?: number; offset?: number } = {};\n if (request.query.limit !== undefined) {\n const limit = parseBoundedInt(request.query.limit, 1, 1000);\n if (limit === undefined) {\n return { status: 400, body: { error: \"Invalid 'limit': must be a positive integer (max 1000)\" } satisfies ConsoleErrorResponse };\n }\n options.limit = limit;\n }\n if (request.query.offset !== undefined) {\n const offset = parseBoundedInt(request.query.offset, 0, Number.MAX_SAFE_INTEGER);\n if (offset === undefined) {\n return { status: 400, body: { error: \"Invalid 'offset': must be a non-negative integer\" } satisfies ConsoleErrorResponse };\n }\n options.offset = offset;\n }\n const tenants = await api.listTenants(options);\n return { status: 200, body: tenants.map(serializeTenant) satisfies TenantWire[] };\n } catch {\n return { status: 500, body: { error: \"Internal server error\" } satisfies ConsoleErrorResponse };\n }\n },\n },\n {\n method: \"GET\",\n path: \"/tenants/:id\",\n requiredPermission: \"read\",\n async handler(request: ConsoleProductRequest) {\n try {\n const id = request.params.id?.trim();\n if (!id) {\n return { status: 400, body: { error: \"Missing tenant id\" } satisfies ConsoleErrorResponse };\n }\n const tenant = await api.getTenant(id);\n if (!tenant) {\n return { status: 404, body: { error: \"Tenant not found\" } satisfies ConsoleErrorResponse };\n }\n return { status: 200, body: serializeTenant(tenant) satisfies TenantWire };\n } catch {\n return { status: 500, body: { error: \"Internal server error\" } satisfies ConsoleErrorResponse };\n }\n },\n },\n {\n method: \"POST\",\n path: \"/tenants\",\n requiredPermission: \"write\",\n async handler(request: ConsoleProductRequest) {\n try {\n if (!isPlainObject(request.body)) {\n return { status: 400, body: { error: \"Request body is required\" } satisfies ConsoleErrorResponse };\n }\n const name = typeof request.body.name === \"string\" ? request.body.name : \"\";\n const slug = typeof request.body.slug === \"string\" ? request.body.slug : \"\";\n if (!name.trim() || !slug.trim()) {\n return { status: 400, body: { error: \"name and slug are required\" } satisfies ConsoleErrorResponse };\n }\n if (name.length > MAX_FIELD_LENGTH || slug.length > MAX_FIELD_LENGTH) {\n return { status: 400, body: { error: \"name and slug must not exceed 255 characters\" } satisfies ConsoleErrorResponse };\n }\n const tenant = await api.createTenant({ name, slug });\n return { status: 201, body: serializeTenant(tenant) satisfies TenantWire };\n } catch {\n return { status: 500, body: { error: \"Internal server error\" } satisfies ConsoleErrorResponse };\n }\n },\n },\n {\n method: \"PATCH\",\n path: \"/tenants/:id\",\n requiredPermission: \"write\",\n async handler(request: ConsoleProductRequest) {\n try {\n const id = request.params.id?.trim();\n if (!id) {\n return { status: 400, body: { error: \"Missing tenant id\" } satisfies ConsoleErrorResponse };\n }\n if (!isPlainObject(request.body)) {\n return { status: 400, body: { error: \"Request body is required\" } satisfies ConsoleErrorResponse };\n }\n const data: { name?: string; slug?: string } = {};\n if (typeof request.body.name === \"string\") {\n if (request.body.name.length > MAX_FIELD_LENGTH) {\n return { status: 400, body: { error: \"name must not exceed 255 characters\" } satisfies ConsoleErrorResponse };\n }\n data.name = request.body.name;\n }\n if (typeof request.body.slug === \"string\") {\n if (request.body.slug.length > MAX_FIELD_LENGTH) {\n return { status: 400, body: { error: \"slug must not exceed 255 characters\" } satisfies ConsoleErrorResponse };\n }\n data.slug = request.body.slug;\n }\n const tenant = await api.updateTenant(id, data);\n return { status: 200, body: serializeTenant(tenant) satisfies TenantWire };\n } catch {\n return { status: 500, body: { error: \"Internal server error\" } satisfies ConsoleErrorResponse };\n }\n },\n },\n {\n method: \"DELETE\",\n path: \"/tenants/:id\",\n requiredPermission: \"admin\",\n async handler(request: ConsoleProductRequest) {\n try {\n const id = request.params.id?.trim();\n if (!id) {\n return { status: 400, body: { error: \"Missing tenant id\" } satisfies ConsoleErrorResponse };\n }\n await api.deleteTenant(id);\n return { status: 204, body: null };\n } catch {\n return { status: 500, body: { error: \"Internal server error\" } satisfies ConsoleErrorResponse };\n }\n },\n },\n {\n method: \"GET\",\n path: \"/stats\",\n requiredPermission: \"read\",\n async handler() {\n try {\n const tenantCount = await api.countTenants();\n return { status: 200, body: { tenantCount } satisfies TenantStatsResponse };\n } catch {\n return { status: 500, body: { error: \"Internal server error\" } satisfies ConsoleErrorResponse };\n }\n },\n },\n ];\n}\n","import type {\n BetterTenantConfig,\n Tenant,\n TenantAdapter,\n TenantRepository,\n TenantResolverConfig,\n ResolvableRequest,\n TenantContext,\n RunWithTenantAndDatabaseOptions,\n} from \"./types.js\";\nimport { sendInitTelemetry } from \"./telemetry.js\";\nimport { getContext, runWithTenant } from \"./context.js\";\nimport { getDatabase, runWithTenantAndDatabase } from \"./adapter.js\";\nimport {\n handleRequest as handleTenantRequest,\n type HandleRequestOptions,\n} from \"./handle-request.js\";\nimport {\n createTenantApi,\n runAsSystem as runAsSystemWithAdapter,\n} from \"./api.js\";\nimport { resolveTenant, describeStrategies } from \"./resolver.js\";\nimport { createTenantConsoleEndpoints } from \"./console-endpoints.js\";\n\n/** UUID v4 pattern for detecting whether an identifier is already a UUID. */\nconst UUID_RE =\n /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\n/**\n * Normalize a resolved identifier to a tenant UUID.\n *\n * - If resolveToId is configured, call it (takes full precedence).\n * - If the identifier is already a UUID, pass through.\n * - If adapter.runAsSystem is available, look up by slug via getTenantRepository.\n * - Otherwise, return as-is (will likely fail at DB level).\n */\nasync function resolveIdentifierToId(\n identifier: string,\n resolverConfig: TenantResolverConfig,\n adapter: TenantAdapter,\n getTenantRepository: (db: unknown) => TenantRepository,\n): Promise<string | undefined> {\n if (resolverConfig.resolveToId) {\n return resolverConfig.resolveToId(identifier);\n }\n if (UUID_RE.test(identifier)) {\n return identifier;\n }\n if (adapter.runAsSystem) {\n const tenant = await adapter.runAsSystem((systemDb: unknown) =>\n getTenantRepository(systemDb).getBySlug(identifier),\n );\n return tenant?.id;\n }\n return identifier;\n}\n\nexport interface TenantApi {\n createTenant(data: { name: string; slug: string }): Promise<Tenant>;\n updateTenant(\n tenantId: string,\n data: { name?: string; slug?: string },\n ): Promise<Tenant>;\n listTenants(options?: { limit?: number; offset?: number }): Promise<Tenant[]>;\n deleteTenant(tenantId: string): Promise<void>;\n getTenant(tenantId: string): Promise<Tenant | null>;\n countTenants(): Promise<number>;\n}\n\nexport interface BetterTenantInstance<TDb = unknown, SDb = unknown> {\n getContext: () => TenantContext | undefined;\n getDatabase: () => TDb | undefined;\n runWithTenant: typeof runWithTenant;\n runAs: <T>(tenantId: string, fn: (database: TDb) => Promise<T>) => Promise<T>;\n runAsSystem: <T>(fn: (database: SDb) => Promise<T>) => Promise<T>;\n resolveTenant: (request: ResolvableRequest) => Promise<string | undefined>;\n /** Human-readable descriptions of the configured resolution strategies. */\n resolverStrategies: string[];\n handleRequest: <Req extends ResolvableRequest, Result>(\n request: Req,\n next: () => Promise<Result>,\n options?: Omit<\n HandleRequestOptions<Req, Result>,\n \"resolveTenant\" | \"adapter\"\n >,\n ) => Promise<Result>;\n api: TenantApi;\n}\n\n/**\n * Creates the Better Tenant instance. Config must include adapter, tenantResolver, and getTenantRepository.\n */\nexport function betterTenant<TDb, SDb>(\n config: BetterTenantConfig<TDb, SDb>,\n): BetterTenantInstance<TDb, SDb> {\n const { database, tenantResolver, loadTenant } = config;\n const { adapter, getTenantRepository } = database;\n\n sendInitTelemetry(config, config.telemetry);\n\n const api = createTenantApi(adapter, getTenantRepository);\n\n const runWithTenantAndDatabaseOptions:\n | RunWithTenantAndDatabaseOptions<SDb>\n | undefined =\n loadTenant !== false\n ? { loadTenant: true as const, getTenantRepository }\n : undefined;\n\n const resolverStrategies = describeStrategies(tenantResolver);\n\n /** Resolve raw identifier from request, then normalize to UUID. */\n async function resolveAndNormalize(\n request: ResolvableRequest,\n ): Promise<string | undefined> {\n const raw = await resolveTenant(request, tenantResolver);\n if (!raw) return undefined;\n return resolveIdentifierToId(\n raw,\n tenantResolver,\n adapter,\n getTenantRepository as (db: unknown) => TenantRepository,\n );\n }\n\n if (config.console) {\n const endpoints = createTenantConsoleEndpoints(api);\n config.console.registerProduct({\n id: \"tenant\",\n name: \"Better Tenant\",\n endpoints,\n });\n }\n\n return {\n getContext,\n getDatabase: () => getDatabase() as TDb | undefined,\n runWithTenant,\n runAs: (tenantId, fn) =>\n runWithTenantAndDatabase(\n tenantId,\n adapter,\n fn,\n runWithTenantAndDatabaseOptions,\n ),\n runAsSystem: <T>(fn: (database: SDb) => Promise<T>) =>\n runAsSystemWithAdapter(adapter, fn),\n resolveTenant: resolveAndNormalize,\n resolverStrategies,\n handleRequest: (request, next, options) =>\n handleTenantRequest(request, next, {\n ...options,\n resolveTenant: resolveAndNormalize,\n adapter,\n }),\n api,\n };\n}\n","import type { ResolvableRequest } from \"./types.js\";\n\ntype NodeHeaders = Record<string, string | string[] | undefined>;\n\nexport interface NodeLikeRequest {\n headers?: Record<string, string | string[] | number | undefined>;\n url?: string;\n originalUrl?: string;\n path?: string;\n hostname?: string;\n host?: string;\n method?: string;\n}\n\nfunction isFetchRequest(input: unknown): input is Request {\n return typeof Request !== \"undefined\" && input instanceof Request;\n}\n\nfunction normalizeHost(raw: string | undefined): string | undefined {\n if (!raw) {\n return undefined;\n }\n const value = raw.split(\":\")[0]?.trim();\n return value || undefined;\n}\n\nfunction normalizeHeaders(\n headers: Record<string, string | string[] | number | undefined> | undefined,\n): NodeHeaders {\n if (!headers) {\n return {};\n }\n const normalized: NodeHeaders = {};\n for (const [key, value] of Object.entries(headers)) {\n const normalizedKey = key.toLowerCase();\n if (Array.isArray(value)) {\n normalized[normalizedKey] = value.map((part) => String(part));\n continue;\n }\n if (value === undefined) {\n normalized[normalizedKey] = undefined;\n continue;\n }\n normalized[normalizedKey] = String(value);\n }\n return normalized;\n}\n\nfunction pathWithoutQuery(value: string | undefined): string | undefined {\n if (!value) {\n return undefined;\n }\n const [pathname] = value.split(\"?\");\n return pathname || undefined;\n}\n\nexport function toResolvableRequest(\n request: Request | NodeLikeRequest,\n): ResolvableRequest {\n if (isFetchRequest(request)) {\n const url = request.url;\n let host: string | undefined;\n let path: string | undefined;\n try {\n const parsedUrl = new URL(url);\n host = normalizeHost(parsedUrl.host);\n path = parsedUrl.pathname || undefined;\n } catch {\n host = undefined;\n path = undefined;\n }\n const resolved: ResolvableRequest = {\n headers: request.headers,\n url,\n method: request.method,\n };\n if (path !== undefined) {\n resolved.path = path;\n }\n if (host !== undefined) {\n resolved.host = host;\n }\n return resolved;\n }\n\n const headers = normalizeHeaders(request.headers);\n const hostFromHeaders = headers.host;\n const hostValue = Array.isArray(hostFromHeaders)\n ? hostFromHeaders[0]\n : hostFromHeaders;\n const host = normalizeHost(request.hostname ?? request.host ?? hostValue);\n const path = pathWithoutQuery(\n request.path ?? request.originalUrl ?? request.url,\n );\n\n const resolved: ResolvableRequest = {\n headers,\n };\n if (path !== undefined) {\n resolved.path = path;\n }\n if (host !== undefined) {\n resolved.host = host;\n }\n if (request.method !== undefined) {\n resolved.method = request.method;\n }\n return resolved;\n}\n"],"mappings":";AAMA,SAAS,kBAAkB;AAC3B,SAAS,YAAY,oBAAoB;AACzC,SAAS,YAAY;AACrB,SAAS,UAAU,SAAS,MAAM,MAAM,gBAAgB;AASxD,IAAM,qBAAqB;AAC3B,IAAM,aAAa;AA4DZ,SAAS,yBACd,QACuB;AACvB,QAAM,IAAI,OAAO,kBAAkB,CAAC;AACpC,SAAO;AAAA,IACL,UAAU;AAAA,MACR,QAAQ,CAAC,CAAC,EAAE;AAAA,MACZ,MAAM,CAAC,CAAC,EAAE;AAAA,MACV,WAAW,CAAC,CAAC,EAAE;AAAA,MACf,KAAK,CAAC,CAAC,EAAE;AAAA,MACT,QAAQ,CAAC,CAAC,EAAE;AAAA,IACd;AAAA,IACA,mBAAmB;AAAA,IACnB,YAAY,OAAO;AAAA,IACnB,aAAa,CAAC,CAAC,OAAO;AAAA,IACtB,UAAU,OAAO,WAAW,CAAC,GAAG,IAAI,CAAC,MAAM,OAAO,EAAE,EAAE,CAAC;AAAA,EACzD;AACF;AAEO,SAAS,sBAAsB,QAIf;AACrB,SAAO;AAAA,IACL,mBAAmB,OAAO,cAAc,UAAU;AAAA,IAClD,cAAc,CAAC,CAAC,OAAO;AAAA,IACvB,kBAAkB,CAAC,CAAC,OAAO;AAAA,EAC7B;AACF;AAIA,SAAS,eAAe,KAAiC;AACvD,MAAI;AACF,UAAM,UAAU,KAAK,KAAK,cAAc;AACxC,QAAI,CAAC,WAAW,OAAO,GAAG;AACxB,aAAO;AAAA,IACT;AAEA,UAAM,MAAM,KAAK,MAAM,aAAa,SAAS,OAAO,CAAC;AAIrD,UAAM,OAAO,OAAO,KAAK,SAAS,WAAW,IAAI,OAAO;AACxD,UAAM,WACJ,OAAO,KAAK,cAAc,aAAa,WACnC,IAAI,aAAa,WACjB;AACN,UAAM,QAAQ,GAAG,IAAI,IAAI,QAAQ,GAAG,KAAK,KAAK;AAC9C,WAAO,WAAW,QAAQ,EAAE,OAAO,KAAK,EAAE,OAAO,KAAK,EAAE,MAAM,GAAG,EAAE;AAAA,EACrE,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,gBAAmD;AAC1D,QAAM,IAAI;AACV,MAAI,OAAO,EAAE,QAAQ,aAAa;AAChC,UAAM,MAAM,EAAE;AACd,WAAO;AAAA,MACL,MAAM;AAAA,MACN,SAAS,OAAO,KAAK,YAAY,WAAW,IAAI,UAAU;AAAA,IAC5D;AAAA,EACF;AACA,MAAI,OAAO,EAAE,SAAS,aAAa;AACjC,UAAM,OAAO,EAAE;AACf,UAAMA,KAAI,MAAM,SAAS;AACzB,WAAO,EAAE,MAAM,QAAQ,SAAS,OAAOA,OAAM,WAAWA,KAAI,UAAU;AAAA,EACxE;AACA,QAAM,IAAK,OAAO,YAAY,eAAe,QAAQ,UAAU,QAAS;AACxE,SAAO,EAAE,MAAM,QAAQ,SAAS,KAAK,UAAU;AACjD;AAEA,SAAS,oBAA4B;AACnC,QAAM,MAAM,QAAQ,IAAI,YAAY;AACpC,MAAI,QAAQ,QAAQ;AAClB,WAAO;AAAA,EACT;AAGA,MACE,QAAQ,IAAI,OAAO,UACnB,QAAQ,IAAI,mBAAmB,UAC/B,QAAQ,IAAI,cAAc,UAC1B,QAAQ,IAAI,aAAa,QACzB;AACA,WAAO;AAAA,EACT;AACA,MAAI,QAAQ,cAAc;AACxB,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEA,SAAS,gBACP,KACgD;AAChD,MAAI;AACF,UAAM,UAAU,KAAK,KAAK,cAAc;AACxC,QAAI,CAAC,WAAW,OAAO,GAAG;AACxB,aAAO;AAAA,IACT;AACA,UAAM,MAAM,KAAK,MAAM,aAAa,SAAS,OAAO,CAAC;AAIrD,UAAM,OAAO,EAAE,GAAG,KAAK,cAAc,GAAG,KAAK,gBAAgB;AAC7D,QAAI,KAAK,MAAM,GAAG;AAChB,aAAO,EAAE,MAAM,QAAQ,SAAS,KAAK,MAAM,EAAE;AAAA,IAC/C;AACA,QAAI,KAAK,MAAM,GAAG;AAChB,aAAO,EAAE,MAAM,QAAQ,SAAS,KAAK,MAAM,EAAE;AAAA,IAC/C;AACA,QAAI,KAAK,SAAS,GAAG;AACnB,aAAO,EAAE,MAAM,WAAW,SAAS,KAAK,SAAS,EAAE;AAAA,IACrD;AACA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,eACP,KACgD;AAChD,MAAI;AACF,UAAM,UAAU,KAAK,KAAK,cAAc;AACxC,QAAI,CAAC,WAAW,OAAO,GAAG;AACxB,aAAO;AAAA,IACT;AACA,UAAM,MAAM,KAAK,MAAM,aAAa,SAAS,OAAO,CAAC;AAIrD,UAAM,OAAO,EAAE,GAAG,KAAK,cAAc,GAAG,KAAK,gBAAgB;AAC7D,QAAI,KAAK,aAAa,GAAG;AACvB,aAAO,EAAE,MAAM,WAAW,SAAS,KAAK,aAAa,EAAE;AAAA,IACzD;AACA,QAAI,KAAK,QAAQ,GAAG;AAClB,aAAO,EAAE,MAAM,UAAU,SAAS,KAAK,QAAQ,EAAE;AAAA,IACnD;AACA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,eAAwD;AAC/D,QAAM,WAAW,WAAW,aAAa;AACzC,QAAM,QACJ,OAAO,QAAQ,IAAI,oBAAoB,YACtC,OAAO,QAAQ,IAAI,gBAAgB,YAClC,QAAQ,IAAI,YAAY,SAAS;AACrC,SAAO;AAAA,IACL,UAAU,SAAS;AAAA,IACnB,SAAS,QAAQ;AAAA,IACjB,MAAM,KAAK;AAAA,IACX,MAAM,KAAK,EAAE;AAAA,IACb,eAAe,KAAK,MAAM,SAAS,IAAI,OAAO,IAAI;AAAA,IAClD;AAAA,IACA;AAAA,EACF;AACF;AAEA,SAAS,uBAEK;AACZ,QAAM,KAAK,QAAQ,IAAI;AACvB,MAAI,CAAC,MAAM,OAAO,OAAO,UAAU;AACjC,WAAO;AAAA,EACT;AACA,QAAM,QAAQ,GAAG,MAAM,oCAAoC;AAC3D,MAAI,OAAO;AACT,UAAM,QAAQ,MAAM,CAAC,KAAK,WAAW,YAAY;AACjD,UAAM,UAAU,MAAM,CAAC;AACvB,WAAO,UAAU,EAAE,MAAM,QAAQ,IAAI,EAAE,KAAK;AAAA,EAC9C;AACA,MAAI,GAAG,SAAS,MAAM,GAAG;AACvB,WAAO,EAAE,MAAM,OAAO;AAAA,EACxB;AACA,MAAI,GAAG,SAAS,MAAM,GAAG;AACvB,WAAO,EAAE,MAAM,OAAO;AAAA,EACxB;AACA,SAAO,EAAE,MAAM,MAAM;AACvB;AAIA,SAAS,mBAAmB,SAAqC;AAC/D,MAAI,QAAQ,IAAI,aAAa,QAAQ;AACnC,WAAO;AAAA,EACT;AACA,QAAM,MAAM,QAAQ,IAAI;AACxB,MAAI,QAAQ,OAAO,KAAK,YAAY,MAAM,SAAS;AACjD,WAAO;AAAA,EACT;AACA,MAAI,QAAQ,OAAO,KAAK,YAAY,MAAM,QAAQ;AAChD,WAAO;AAAA,EACT;AACA,SAAO,SAAS,YAAY;AAC9B;AAEA,SAAS,YAAY,SAAqC;AACxD,MAAI,QAAQ,IAAI,kCAAkC,KAAK;AACrD,WAAO;AAAA,EACT;AACA,SAAO,SAAS,UAAU;AAC5B;AAMO,SAAS,cACd,MACA,SACA,SACsB;AACtB,MAAI,CAAC,mBAAmB,OAAO,GAAG;AAChC,WAAO,SAAS,OAAO,QAAQ,QAAQ,IAAI;AAAA,EAC7C;AACA,QAAM,cAAgC;AAAA,IACpC,SAAS;AAAA,IACT;AAAA,IACA,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IAClC,GAAG;AAAA,EACL;AACA,MAAI,YAAY,OAAO,GAAG;AACxB,YAAQ;AAAA,MACN;AAAA,MACA,KAAK,UAAU,aAAa,MAAM,CAAC;AAAA,IACrC;AACA,WAAO,SAAS,OAAO,QAAQ,QAAQ,IAAI;AAAA,EAC7C;AACA,QAAM,SAAS,MACb,MAAM,oBAAoB;AAAA,IACxB,QAAQ;AAAA,IACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,IAC9C,MAAM,KAAK,UAAU,WAAW;AAAA,EAClC,CAAC,EAAE,MAAM,MAAM;AAAA,EAEf,CAAC;AAEH,MAAI,SAAS,MAAM;AACjB,WAAO,IAAI,QAAc,CAAC,YAAY;AACpC,mBAAa,YAAY;AACvB,cAAM,OAAO;AACb,gBAAQ;AAAA,MACV,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAEA,eAAa,MAAM,OAAO,CAAC;AAC7B;AAKO,SAAS,kBACd,QACA,SACM;AACN,QAAM,MAAM,QAAQ,IAAI;AACxB,QAAM,UAAoE;AAAA,IACxE,SAAS,cAAc;AAAA,IACvB,aAAa,kBAAkB;AAAA,IAC/B,QAAQ,yBAAyB,MAAM;AAAA,EACzC;AACA,QAAM,cAAc,eAAe,GAAG;AACtC,MAAI,YAAa,SAAQ,cAAc;AACvC,QAAM,YAAY,gBAAgB,GAAG;AACrC,MAAI,UAAW,SAAQ,YAAY;AACnC,QAAM,WAAW,eAAe,GAAG;AACnC,MAAI,SAAU,SAAQ,WAAW;AACjC,UAAQ,SAAS,aAAa;AAC9B,QAAM,SAAS,qBAAqB;AACpC,MAAI,OAAQ,SAAQ,iBAAiB;AACrC,gBAAc,QAAQ,SAAS,WAAW,OAAO,SAAS;AAC5D;AAcO,SAAS,iBACd,MACA,SACA,QACA,SACsB;AACtB,QAAM,MAAM,QAAQ,IAAI;AACxB,QAAM,iBAAiB,SAAS,sBAAsB,MAAM,IAAI;AAChE,QAAM,UAAoE;AAAA,IACxE,SAAS,cAAc;AAAA,IACvB,aAAa,kBAAkB;AAAA,IAC/B;AAAA,EACF;AACA,MAAI,eAAgB,SAAQ,SAAS;AACrC,UAAQ,SAAS,aAAa;AAC9B,QAAM,cAAc,eAAe,GAAG;AACtC,MAAI,YAAa,SAAQ,cAAc;AACvC,QAAM,YAAY,gBAAgB,GAAG;AACrC,MAAI,UAAW,SAAQ,YAAY;AACnC,QAAM,WAAW,eAAe,GAAG;AACnC,MAAI,SAAU,SAAQ,WAAW;AACjC,QAAM,SAAS,qBAAqB;AACpC,MAAI,OAAQ,SAAQ,iBAAiB;AACrC,SAAO,cAAc,MAAM,SAAS,OAAO;AAC7C;;;AC5YA,SAAS,yBAAyB;AAElC,IAAM,UAAU,IAAI,kBAAiC;AAK9C,SAAS,aAAwC;AACtD,SAAO,QAAQ,SAAS;AAC1B;AAOO,SAAS,cACd,UACA,IACY;AACZ,QAAM,aAAa,SAAS,KAAK,KAAK;AACtC,MAAI,eAAe,QAAW;AAC5B,WAAO,QAAQ;AAAA,MACb,IAAI,MAAM,oDAAoD;AAAA,IAChE;AAAA,EACF;AACA,SAAO,QAAQ;AAAA,IACb,QAAQ,IAAI,EAAE,UAAU,WAAW,GAAG,MAAM,GAAG,CAAC;AAAA,EAClD;AACF;AAKO,SAAS,eACd,SACA,IACY;AACZ,SAAO,QAAQ,QAAQ,QAAQ,IAAI,SAAS,MAAM,GAAG,CAAC,CAAC;AACzD;;;AC1BO,SAAS,cAAuB;AACrC,QAAM,UAAU,WAAW;AAC3B,SAAO,SAAS;AAClB;AAeA,eAAsB,yBACpB,UACA,SACA,IACA,SACY;AACZ,QAAM,SAAS,MAAM,QAAQ,cAAc,UAAU,OAAO,aAAa;AACvE,QAAI,UAAyB,EAAE,UAAU,SAAS;AAClD,UAAM,sBAAsB,SAAS;AACrC,QACE,SAAS,cACT,uBACA,QAAQ,aACR;AACA,YAAM,SAAS,MAAM,QAAQ;AAAA,QAAY,CAAC,aACxC,oBAAoB,QAAQ,EAAE,QAAQ,QAAQ;AAAA,MAChD;AACA,gBAAU,UAAU,OAAO,EAAE,GAAG,SAAS,OAAO,IAAI;AAAA,IACtD;AACA,WAAO,eAAe,SAAS,MAAM,GAAG,QAAQ,CAAC;AAAA,EACnD,CAAC;AACD,SAAO;AACT;;;ACtDO,IAAM,yBAAN,cAAqC,MAAM;AAAA,EAChD,YAAY,UAAU,4DAA4D;AAChF,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,wBAAN,cAAoC,MAAM;AAAA,EAC/C,YACE,UAAU,kDACV,SACA;AACA,UAAM,SAAS,OAAO;AACtB,SAAK,OAAO;AAAA,EACd;AACF;;;ACIA,eAAsB,cACpB,SACA,MACA,SACiB;AACjB,QAAM,WAAW,MAAM,QAAQ,cAAc,OAAO;AACpD,QAAM,qBAAqB,UAAU,KAAK;AAC1C,MAAI,CAAC,oBAAoB;AACvB,QAAI,QAAQ,iBAAiB;AAC3B,aAAO,QAAQ,gBAAgB,OAAO;AAAA,IACxC;AAEA,UAAM,QAAQ,IAAI,uBAAuB;AACzC,QAAI,QAAQ,SAAS;AACnB,aAAO,QAAQ,QAAQ,OAAO,OAAO;AAAA,IACvC;AACA,UAAM;AAAA,EACR;AAEA,MAAI;AACF,WAAO,MAAM;AAAA,MACX;AAAA,MACA,QAAQ;AAAA,MACR,YAAY,KAAK;AAAA,IACnB;AAAA,EACF,SAAS,OAAO;AACd,QAAI,QAAQ,SAAS;AACnB,aAAO,QAAQ,QAAQ,OAAO,OAAO;AAAA,IACvC;AAEA,QACE,iBAAiB,0BACjB,iBAAiB,uBACjB;AACA,YAAM;AAAA,IACR;AAEA,UAAM,IAAI,sBAAsB,QAAW,EAAE,OAAO,MAAM,CAAC;AAAA,EAC7D;AACF;;;ACtDA,IAAM,qBAAqB;AAiB3B,SAAS,mBACP,SACsD;AACtD,MAAI,CAAC,QAAQ,aAAa;AACxB,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,SAAO,QAAQ;AACjB;AAOO,SAAS,gBACd,SACA,qBACA;AACA,SAAO;AAAA,IACL,MAAM,aAAa,MAAyC;AAC1D,UAAI,CAAC,KAAK,MAAM,KAAK,GAAG;AACtB,cAAM,IAAI,MAAM,2CAA2C;AAAA,MAC7D;AACA,UAAI,CAAC,KAAK,MAAM,KAAK,GAAG;AACtB,cAAM,IAAI,MAAM,2CAA2C;AAAA,MAC7D;AACA,YAAMC,eAAc,mBAAmB,OAAO;AAC9C,aAAOA;AAAA,QAAY,CAAC,aAClB,oBAAoB,QAAQ,EAAE,OAAO;AAAA,UACnC,MAAM,KAAK,KAAK,KAAK;AAAA,UACrB,MAAM,KAAK,KAAK,KAAK;AAAA,QACvB,CAAC;AAAA,MACH;AAAA,IACF;AAAA,IAEA,MAAM,aACJ,UACA,MACiB;AACjB,UAAI,CAAC,UAAU,KAAK,GAAG;AACrB,cAAM,IAAI,MAAM,+CAA+C;AAAA,MACjE;AACA,YAAMA,eAAc,mBAAmB,OAAO;AAC9C,aAAOA;AAAA,QAAY,CAAC,aAClB,oBAAoB,QAAQ,EAAE,OAAO,UAAU;AAAA,UAC7C,GAAI,KAAK,SAAS,UAAa,EAAE,MAAM,KAAK,KAAK;AAAA,UACjD,GAAI,KAAK,SAAS,UAAa,EAAE,MAAM,KAAK,KAAK;AAAA,QACnD,CAAC;AAAA,MACH;AAAA,IACF;AAAA,IAEA,MAAM,YAAY,UAA8B,CAAC,GAAsB;AACrE,YAAM,QAAQ,QAAQ,SAAS;AAC/B,YAAM,SAAS,KAAK,IAAI,GAAG,QAAQ,UAAU,CAAC;AAC9C,YAAMA,eAAc,mBAAmB,OAAO;AAC9C,aAAOA;AAAA,QAAY,CAAC,aAClB,oBAAoB,QAAQ,EAAE,KAAK,EAAE,OAAO,OAAO,CAAC;AAAA,MACtD;AAAA,IACF;AAAA,IAEA,MAAM,aAAa,UAAiC;AAClD,UAAI,CAAC,UAAU,KAAK,GAAG;AACrB,cAAM,IAAI,MAAM,+CAA+C;AAAA,MACjE;AACA,YAAMA,eAAc,mBAAmB,OAAO;AAC9C,aAAOA;AAAA,QAAY,CAAC,aAClB,oBAAoB,QAAQ,EAAE,OAAO,QAAQ;AAAA,MAC/C;AAAA,IACF;AAAA,IAEA,MAAM,UAAU,UAA0C;AACxD,UAAI,CAAC,UAAU,KAAK,GAAG;AACrB,cAAM,IAAI,MAAM,4CAA4C;AAAA,MAC9D;AACA,YAAMA,eAAc,mBAAmB,OAAO;AAC9C,aAAOA;AAAA,QAAY,CAAC,aAClB,oBAAoB,QAAQ,EAAE,QAAQ,QAAQ;AAAA,MAChD;AAAA,IACF;AAAA,IAEA,MAAM,eAAgC;AACpC,YAAMA,eAAc,mBAAmB,OAAO;AAC9C,aAAOA;AAAA,QAAY,CAAC,aAClB,oBAAoB,QAAQ,EAAE,MAAM;AAAA,MACtC;AAAA,IACF;AAAA,EACF;AACF;AAMA,eAAsB,MACpB,UACA,SACA,IACY;AACZ,SAAO,yBAAyB,UAAU,SAAS,EAAE;AACvD;AAMA,eAAsB,YACpB,SACA,IACY;AACZ,QAAM,MAAM,mBAAmB,OAAO;AACtC,SAAO,eAAe,EAAE,UAAU,KAAK,GAAG,MAAM,IAAI,EAAE,CAAC;AACzD;;;AC9HA,SAAS,UACP,SACA,MACoB;AACpB,QAAM,MAAM,KAAK,YAAY;AAC7B,MAAI,mBAAmB,SAAS;AAC9B,UAAMC,SAAQ,QAAQ,IAAI,GAAG;AAC7B,WAAOA,QAAO,KAAK,KAAK;AAAA,EAC1B;AACA,QAAM,MAAM,QAAQ,GAAG,KAAK,QAAQ,IAAI;AACxC,MAAI,QAAQ,QAAW;AACrB,WAAO;AAAA,EACT;AACA,QAAM,QAAQ,MAAM,QAAQ,GAAG,IAAI,IAAI,CAAC,IAAI;AAC5C,UAAQ,OAAO,UAAU,WAAW,QAAQ,IAAI,KAAK,KAAK;AAC5D;AAEA,SAAS,kBACP,SACA,YACoB;AACpB,MAAI,CAAC,YAAY;AACf,WAAO;AAAA,EACT;AACA,SAAO,UAAU,QAAQ,SAAS,UAAU;AAC9C;AAEA,SAAS,gBACP,SACA,YACoB;AACpB,QAAM,YAAY,QAAQ,QAAQ,QAAQ;AAC1C,MAAI,CAAC,WAAW;AACd,WAAO;AAAA,EACT;AAEA,MAAI;AACJ,MAAI;AACF,WAAO,UAAU,WAAW,MAAM,IAC9B,IAAI,IAAI,SAAS,EAAE,WACnB;AAAA,EACN,QAAQ;AACN,WAAO;AAAA,EACT;AAEA,QAAM,UACJ,OAAO,eAAe,WAAW,aAAa,WAAW;AAC3D,QAAM,eACJ,OAAO,eAAe,YAAY,WAAW,iBAAiB,SAC1D,WAAW,eACX,wBAAwB,OAAO;AAErC,QAAM,WAAW,KAAK,MAAM,GAAG,EAAE,OAAO,OAAO;AAC/C,QAAM,QAAQ,SAAS,YAAY;AACnC,SAAO,OAAO,UAAU,YAAY,MAAM,SAAS,IAAI,QAAQ;AACjE;AAGA,SAAS,wBAAwB,SAAyB;AACxD,QAAM,WAAW,QAAQ,MAAM,GAAG,EAAE,OAAO,OAAO;AAClD,QAAM,MAAM,SAAS,QAAQ,WAAW;AACxC,SAAO,OAAO,IAAI,MAAM;AAC1B;AAEA,SAAS,qBACP,SACA,QACoB;AACpB,QAAM,OAAO,QAAQ,SAAS,QAAQ,MAAM,IAAI,IAAI,QAAQ,GAAG,EAAE,OAAO;AACxE,MAAI,CAAC,MAAM;AACT,WAAO;AAAA,EACT;AACA,QAAM,WAAW,KAAK,MAAM,GAAG,EAAE,CAAC;AAClC,MAAI,CAAC,UAAU;AACb,WAAO;AAAA,EACT;AACA,QAAM,QAAQ,SAAS,MAAM,GAAG;AAEhC,MAAI,MAAM,UAAU,GAAG;AACrB,WAAO;AAAA,EACT;AACA,QAAM,QACJ,WAAW,OACP,IACA,OAAO,WAAW,YAAY,OAAO,iBAAiB,SACpD,OAAO,eACP;AACR,QAAM,QAAQ,MAAM,KAAK;AACzB,SAAO,OAAO,UAAU,YAAY,MAAM,SAAS,IAAI,QAAQ;AACjE;AAEA,SAAS,iBAAiB,OAA+C;AACvE,MAAI;AACF,UAAM,QAAQ,MAAM,MAAM,GAAG;AAC7B,QAAI,MAAM,SAAS,GAAG;AACpB,aAAO;AAAA,IACT;AACA,UAAM,UAAU,MAAM,CAAC;AACvB,QAAI,CAAC,SAAS;AACZ,aAAO;AAAA,IACT;AACA,UAAM,UAAU,KAAK,QAAQ,QAAQ,MAAM,GAAG,EAAE,QAAQ,MAAM,GAAG,CAAC;AAClE,UAAM,SAAkB,KAAK,MAAM,OAAO;AAC1C,QAAI,OAAO,WAAW,YAAY,WAAW,MAAM;AACjD,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAe,eACb,SACA,QAC6B;AAC7B,QAAM,WAAW,QAAQ;AACzB,MAAI,CAAC,UAAU;AACb,WAAO;AAAA,EACT;AACA,QAAM,QAAQ,OAAO,aAAa,aAAa,SAAS,IAAI;AAC5D,QAAM,QAAQ,iBAAiB,UAAU,MAAM,QAAQ;AACvD,QAAM,WAAW,SAAS;AAC1B,MAAI,CAAC,UAAU;AACb,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ,OAAO,WAAW,WAAW,SAAS,OAAO;AAC3D,MAAI,CAAC,OAAO;AACV,WAAO;AAAA,EACT;AAEA,QAAM,cACJ,OAAO,WAAW,WAAW,OAAO,cAAc;AAEpD,MAAI;AACJ,MAAI,aAAa;AACf,cAAU,MAAM,YAAY,QAAQ;AAAA,EACtC,OAAO;AACL,cAAU,iBAAiB,QAAQ;AAAA,EACrC;AAEA,MAAI,CAAC,SAAS;AACZ,WAAO;AAAA,EACT;AAEA,QAAM,aAAa,QAAQ,KAAK;AAChC,SAAO,OAAO,eAAe,YAAY,WAAW,SAAS,IACzD,aACA;AACN;AAMO,SAAS,mBAAmB,QAAwC;AACzE,QAAM,aAAuB,CAAC;AAC9B,MAAI,OAAO,WAAW,QAAW;AAC/B,eAAW,KAAK,WAAW,OAAO,MAAM,GAAG;AAAA,EAC7C;AACA,MAAI,OAAO,SAAS,QAAW;AAC7B,UAAM,UACJ,OAAO,OAAO,SAAS,WAAW,OAAO,OAAO,OAAO,KAAK;AAC9D,eAAW,KAAK,SAAS,OAAO,GAAG;AAAA,EACrC;AACA,MAAI,OAAO,cAAc,UAAa,OAAO,cAAc,OAAO;AAChE,eAAW,KAAK,WAAW;AAAA,EAC7B;AACA,MAAI,OAAO,QAAQ,QAAW;AAC5B,UAAM,QACJ,OAAO,OAAO,QAAQ,WAAW,OAAO,MAAM,OAAO,IAAI;AAC3D,eAAW,KAAK,cAAc,KAAK,GAAG;AAAA,EACxC;AACA,MAAI,OAAO,WAAW,QAAW;AAC/B,eAAW,KAAK,iBAAiB;AAAA,EACnC;AACA,SAAO;AACT;AAMA,eAAsB,cACpB,SACA,QAC6B;AAC7B,MAAI,OAAO,WAAW,QAAW;AAC/B,UAAM,IAAI,kBAAkB,SAAS,OAAO,MAAM;AAClD,QAAI,MAAM,QAAW;AACnB,aAAO;AAAA,IACT;AAAA,EACF;AACA,MAAI,OAAO,SAAS,QAAW;AAC7B,UAAM,IAAI,gBAAgB,SAAS,OAAO,IAAI;AAC9C,QAAI,MAAM,QAAW;AACnB,aAAO;AAAA,IACT;AAAA,EACF;AACA,MAAI,OAAO,cAAc,UAAa,OAAO,cAAc,OAAO;AAChE,UAAM,IAAI,qBAAqB,SAAS,OAAO,SAAS;AACxD,QAAI,MAAM,QAAW;AACnB,aAAO;AAAA,IACT;AAAA,EACF;AACA,MAAI,OAAO,QAAQ,QAAW;AAC5B,UAAM,IAAI,MAAM,eAAe,SAAS,OAAO,GAAG;AAClD,QAAI,MAAM,QAAW;AACnB,aAAO;AAAA,IACT;AAAA,EACF;AACA,MAAI,OAAO,WAAW,QAAW;AAC/B,UAAM,IAAI,MAAM,QAAQ,QAAQ,OAAO,OAAO,OAAO,CAAC;AACtD,QAAI,OAAO,MAAM,YAAY,EAAE,SAAS,GAAG;AACzC,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;;;AC3NO,SAAS,cAAc,OAAkD;AAC9E,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAOO,SAAS,gBACd,OACA,KACA,KACoB;AACpB,MAAI,UAAU,QAAW;AACvB,WAAO;AAAA,EACT;AACA,QAAM,SAAS,OAAO,KAAK;AAC3B,MAAI,CAAC,OAAO,SAAS,MAAM,KAAK,SAAS,KAAK;AAC5C,WAAO;AAAA,EACT;AACA,SAAO,KAAK,IAAI,KAAK,MAAM,MAAM,GAAG,GAAG;AACzC;;;AChBA,IAAM,mBAAmB;AAEzB,SAAS,gBAAgB,QAA4B;AACnD,SAAO;AAAA,IACL,GAAG;AAAA,IACH,WACE,OAAO,qBAAqB,OACxB,OAAO,UAAU,YAAY,IAC7B,OAAO;AAAA,EACf;AACF;AAEO,SAAS,6BACd,KAC0B;AAC1B,SAAO;AAAA,IACL;AAAA,MACE,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,oBAAoB;AAAA,MACpB,MAAM,QAAQ,SAAgC;AAC5C,YAAI;AACF,gBAAM,UAA+C,CAAC;AACtD,cAAI,QAAQ,MAAM,UAAU,QAAW;AACrC,kBAAM,QAAQ,gBAAgB,QAAQ,MAAM,OAAO,GAAG,GAAI;AAC1D,gBAAI,UAAU,QAAW;AACvB,qBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,yDAAyD,EAAiC;AAAA,YACjI;AACA,oBAAQ,QAAQ;AAAA,UAClB;AACA,cAAI,QAAQ,MAAM,WAAW,QAAW;AACtC,kBAAM,SAAS,gBAAgB,QAAQ,MAAM,QAAQ,GAAG,OAAO,gBAAgB;AAC/E,gBAAI,WAAW,QAAW;AACxB,qBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,mDAAmD,EAAiC;AAAA,YAC3H;AACA,oBAAQ,SAAS;AAAA,UACnB;AACA,gBAAM,UAAU,MAAM,IAAI,YAAY,OAAO;AAC7C,iBAAO,EAAE,QAAQ,KAAK,MAAM,QAAQ,IAAI,eAAe,EAAyB;AAAA,QAClF,QAAQ;AACN,iBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,wBAAwB,EAAiC;AAAA,QAChG;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,oBAAoB;AAAA,MACpB,MAAM,QAAQ,SAAgC;AAC5C,YAAI;AACF,gBAAM,KAAK,QAAQ,OAAO,IAAI,KAAK;AACnC,cAAI,CAAC,IAAI;AACP,mBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,oBAAoB,EAAiC;AAAA,UAC5F;AACA,gBAAM,SAAS,MAAM,IAAI,UAAU,EAAE;AACrC,cAAI,CAAC,QAAQ;AACX,mBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,mBAAmB,EAAiC;AAAA,UAC3F;AACA,iBAAO,EAAE,QAAQ,KAAK,MAAM,gBAAgB,MAAM,EAAuB;AAAA,QAC3E,QAAQ;AACN,iBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,wBAAwB,EAAiC;AAAA,QAChG;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,oBAAoB;AAAA,MACpB,MAAM,QAAQ,SAAgC;AAC5C,YAAI;AACF,cAAI,CAAC,cAAc,QAAQ,IAAI,GAAG;AAChC,mBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,2BAA2B,EAAiC;AAAA,UACnG;AACA,gBAAM,OAAO,OAAO,QAAQ,KAAK,SAAS,WAAW,QAAQ,KAAK,OAAO;AACzE,gBAAM,OAAO,OAAO,QAAQ,KAAK,SAAS,WAAW,QAAQ,KAAK,OAAO;AACzE,cAAI,CAAC,KAAK,KAAK,KAAK,CAAC,KAAK,KAAK,GAAG;AAChC,mBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,6BAA6B,EAAiC;AAAA,UACrG;AACA,cAAI,KAAK,SAAS,oBAAoB,KAAK,SAAS,kBAAkB;AACpE,mBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,+CAA+C,EAAiC;AAAA,UACvH;AACA,gBAAM,SAAS,MAAM,IAAI,aAAa,EAAE,MAAM,KAAK,CAAC;AACpD,iBAAO,EAAE,QAAQ,KAAK,MAAM,gBAAgB,MAAM,EAAuB;AAAA,QAC3E,QAAQ;AACN,iBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,wBAAwB,EAAiC;AAAA,QAChG;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,oBAAoB;AAAA,MACpB,MAAM,QAAQ,SAAgC;AAC5C,YAAI;AACF,gBAAM,KAAK,QAAQ,OAAO,IAAI,KAAK;AACnC,cAAI,CAAC,IAAI;AACP,mBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,oBAAoB,EAAiC;AAAA,UAC5F;AACA,cAAI,CAAC,cAAc,QAAQ,IAAI,GAAG;AAChC,mBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,2BAA2B,EAAiC;AAAA,UACnG;AACA,gBAAM,OAAyC,CAAC;AAChD,cAAI,OAAO,QAAQ,KAAK,SAAS,UAAU;AACzC,gBAAI,QAAQ,KAAK,KAAK,SAAS,kBAAkB;AAC/C,qBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,sCAAsC,EAAiC;AAAA,YAC9G;AACA,iBAAK,OAAO,QAAQ,KAAK;AAAA,UAC3B;AACA,cAAI,OAAO,QAAQ,KAAK,SAAS,UAAU;AACzC,gBAAI,QAAQ,KAAK,KAAK,SAAS,kBAAkB;AAC/C,qBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,sCAAsC,EAAiC;AAAA,YAC9G;AACA,iBAAK,OAAO,QAAQ,KAAK;AAAA,UAC3B;AACA,gBAAM,SAAS,MAAM,IAAI,aAAa,IAAI,IAAI;AAC9C,iBAAO,EAAE,QAAQ,KAAK,MAAM,gBAAgB,MAAM,EAAuB;AAAA,QAC3E,QAAQ;AACN,iBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,wBAAwB,EAAiC;AAAA,QAChG;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,oBAAoB;AAAA,MACpB,MAAM,QAAQ,SAAgC;AAC5C,YAAI;AACF,gBAAM,KAAK,QAAQ,OAAO,IAAI,KAAK;AACnC,cAAI,CAAC,IAAI;AACP,mBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,oBAAoB,EAAiC;AAAA,UAC5F;AACA,gBAAM,IAAI,aAAa,EAAE;AACzB,iBAAO,EAAE,QAAQ,KAAK,MAAM,KAAK;AAAA,QACnC,QAAQ;AACN,iBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,wBAAwB,EAAiC;AAAA,QAChG;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,oBAAoB;AAAA,MACpB,MAAM,UAAU;AACd,YAAI;AACF,gBAAM,cAAc,MAAM,IAAI,aAAa;AAC3C,iBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,YAAY,EAAgC;AAAA,QAC5E,QAAQ;AACN,iBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,wBAAwB,EAAiC;AAAA,QAChG;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;;;AC7IA,IAAM,UACJ;AAUF,eAAe,sBACb,YACA,gBACA,SACA,qBAC6B;AAC7B,MAAI,eAAe,aAAa;AAC9B,WAAO,eAAe,YAAY,UAAU;AAAA,EAC9C;AACA,MAAI,QAAQ,KAAK,UAAU,GAAG;AAC5B,WAAO;AAAA,EACT;AACA,MAAI,QAAQ,aAAa;AACvB,UAAM,SAAS,MAAM,QAAQ;AAAA,MAAY,CAAC,aACxC,oBAAoB,QAAQ,EAAE,UAAU,UAAU;AAAA,IACpD;AACA,WAAO,QAAQ;AAAA,EACjB;AACA,SAAO;AACT;AAqCO,SAAS,aACd,QACgC;AAChC,QAAM,EAAE,UAAU,gBAAgB,WAAW,IAAI;AACjD,QAAM,EAAE,SAAS,oBAAoB,IAAI;AAEzC,oBAAkB,QAAQ,OAAO,SAAS;AAE1C,QAAM,MAAM,gBAAgB,SAAS,mBAAmB;AAExD,QAAM,kCAGJ,eAAe,QACX,EAAE,YAAY,MAAe,oBAAoB,IACjD;AAEN,QAAM,qBAAqB,mBAAmB,cAAc;AAG5D,iBAAe,oBACb,SAC6B;AAC7B,UAAM,MAAM,MAAM,cAAc,SAAS,cAAc;AACvD,QAAI,CAAC,IAAK,QAAO;AACjB,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,MAAI,OAAO,SAAS;AAClB,UAAM,YAAY,6BAA6B,GAAG;AAClD,WAAO,QAAQ,gBAAgB;AAAA,MAC7B,IAAI;AAAA,MACJ,MAAM;AAAA,MACN;AAAA,IACF,CAAC;AAAA,EACH;AAEA,SAAO;AAAA,IACL;AAAA,IACA,aAAa,MAAM,YAAY;AAAA,IAC/B;AAAA,IACA,OAAO,CAAC,UAAU,OAChB;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACF,aAAa,CAAI,OACf,YAAuB,SAAS,EAAE;AAAA,IACpC,eAAe;AAAA,IACf;AAAA,IACA,eAAe,CAAC,SAAS,MAAM,YAC7B,cAAoB,SAAS,MAAM;AAAA,MACjC,GAAG;AAAA,MACH,eAAe;AAAA,MACf;AAAA,IACF,CAAC;AAAA,IACH;AAAA,EACF;AACF;;;AC/IA,SAAS,eAAe,OAAkC;AACxD,SAAO,OAAO,YAAY,eAAe,iBAAiB;AAC5D;AAEA,SAAS,cAAc,KAA6C;AAClE,MAAI,CAAC,KAAK;AACR,WAAO;AAAA,EACT;AACA,QAAM,QAAQ,IAAI,MAAM,GAAG,EAAE,CAAC,GAAG,KAAK;AACtC,SAAO,SAAS;AAClB;AAEA,SAAS,iBACP,SACa;AACb,MAAI,CAAC,SAAS;AACZ,WAAO,CAAC;AAAA,EACV;AACA,QAAM,aAA0B,CAAC;AACjC,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,OAAO,GAAG;AAClD,UAAM,gBAAgB,IAAI,YAAY;AACtC,QAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,iBAAW,aAAa,IAAI,MAAM,IAAI,CAAC,SAAS,OAAO,IAAI,CAAC;AAC5D;AAAA,IACF;AACA,QAAI,UAAU,QAAW;AACvB,iBAAW,aAAa,IAAI;AAC5B;AAAA,IACF;AACA,eAAW,aAAa,IAAI,OAAO,KAAK;AAAA,EAC1C;AACA,SAAO;AACT;AAEA,SAAS,iBAAiB,OAA+C;AACvE,MAAI,CAAC,OAAO;AACV,WAAO;AAAA,EACT;AACA,QAAM,CAAC,QAAQ,IAAI,MAAM,MAAM,GAAG;AAClC,SAAO,YAAY;AACrB;AAEO,SAAS,oBACd,SACmB;AACnB,MAAI,eAAe,OAAO,GAAG;AAC3B,UAAM,MAAM,QAAQ;AACpB,QAAIC;AACJ,QAAIC;AACJ,QAAI;AACF,YAAM,YAAY,IAAI,IAAI,GAAG;AAC7B,MAAAD,QAAO,cAAc,UAAU,IAAI;AACnC,MAAAC,QAAO,UAAU,YAAY;AAAA,IAC/B,QAAQ;AACN,MAAAD,QAAO;AACP,MAAAC,QAAO;AAAA,IACT;AACA,UAAMC,YAA8B;AAAA,MAClC,SAAS,QAAQ;AAAA,MACjB;AAAA,MACA,QAAQ,QAAQ;AAAA,IAClB;AACA,QAAID,UAAS,QAAW;AACtB,MAAAC,UAAS,OAAOD;AAAA,IAClB;AACA,QAAID,UAAS,QAAW;AACtB,MAAAE,UAAS,OAAOF;AAAA,IAClB;AACA,WAAOE;AAAA,EACT;AAEA,QAAM,UAAU,iBAAiB,QAAQ,OAAO;AAChD,QAAM,kBAAkB,QAAQ;AAChC,QAAM,YAAY,MAAM,QAAQ,eAAe,IAC3C,gBAAgB,CAAC,IACjB;AACJ,QAAM,OAAO,cAAc,QAAQ,YAAY,QAAQ,QAAQ,SAAS;AACxE,QAAM,OAAO;AAAA,IACX,QAAQ,QAAQ,QAAQ,eAAe,QAAQ;AAAA,EACjD;AAEA,QAAM,WAA8B;AAAA,IAClC;AAAA,EACF;AACA,MAAI,SAAS,QAAW;AACtB,aAAS,OAAO;AAAA,EAClB;AACA,MAAI,SAAS,QAAW;AACtB,aAAS,OAAO;AAAA,EAClB;AACA,MAAI,QAAQ,WAAW,QAAW;AAChC,aAAS,SAAS,QAAQ;AAAA,EAC5B;AACA,SAAO;AACT;","names":["v","runAsSystem","value","host","path","resolved"]}
1
+ {"version":3,"sources":["../src/telemetry.ts","../src/context.ts","../src/adapter.ts","../src/errors.ts","../src/handle-request.ts","../src/api.ts","../src/resolver.ts","../../../shared/console-utils/src/index.ts","../src/console-endpoints.ts","../src/better-tenant.ts","../src/request.ts"],"sourcesContent":["/**\n * Anonymous telemetry for Better Tenant.\n * On by default, opt-out via BETTER_TENANT_TELEMETRY=0 or telemetry: { enabled: false }.\n * See docs/TELEMETRY.md.\n */\n\nimport { createHash } from \"node:crypto\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { platform, release, arch, cpus, totalmem } from \"node:os\";\nimport type { BetterTenantConfig } from \"./types.js\";\n\n/** Subset of BetterTenantConfig used by telemetry (avoids contravariance issues with generic DB types). */\ntype TelemetryConfigInput = Pick<\n BetterTenantConfig,\n \"tenantResolver\" | \"basePath\" | \"plugins\" | \"loadTenant\" | \"telemetry\"\n>;\n\nconst TELEMETRY_ENDPOINT = \"https://telemetry.usebetter.dev/v1/events\";\nconst LIBRARY_ID = \"better-tenant\";\n\n// --- Redacted config types ---\n\nexport interface TelemetryTenantConfig {\n resolver: {\n header: boolean;\n path: boolean;\n subdomain: boolean;\n jwt: boolean;\n custom: boolean;\n };\n tenantTablesCount: number;\n loadTenant: boolean | undefined;\n basePathSet: boolean;\n plugins: string[];\n}\n\nexport interface TelemetryCliConfig {\n tenantTablesCount: number;\n hasSchemaDir: boolean;\n hasMigrationsDir: boolean;\n}\n\nexport interface TelemetryPayload {\n library: string;\n type: string;\n timestamp: string;\n anonymousId?: string;\n runtime?: { name: string; version: string };\n environment?: string;\n framework?: { name: string; version?: string };\n database?: { name: string; version?: string };\n system?: {\n platform: string;\n release: string;\n arch: string;\n cpus: number;\n totalMemoryMb: number;\n isDocker?: boolean;\n isWSL?: boolean;\n };\n packageManager?: { name: string; version?: string };\n config?: TelemetryTenantConfig | TelemetryCliConfig;\n outcome?: string;\n}\n\n// --- Telemetry options ---\n\nexport interface TelemetryOptions {\n /** Override enabled (default: true). Set false to opt out. */\n enabled?: boolean;\n /** Debug mode: log to console only, do not send. */\n debug?: boolean;\n /** When true, return Promise that resolves when send completes. Use before process.exit. */\n wait?: boolean;\n}\n\n// --- Redaction ---\n\nexport function getTelemetryTenantConfig(\n config: TelemetryConfigInput,\n): TelemetryTenantConfig {\n const r = config.tenantResolver ?? {};\n return {\n resolver: {\n header: !!r.header,\n path: !!r.path,\n subdomain: !!r.subdomain,\n jwt: !!r.jwt,\n custom: !!r.custom,\n },\n tenantTablesCount: 0,\n loadTenant: config.loadTenant,\n basePathSet: !!config.basePath,\n plugins: (config.plugins ?? []).map((p) => String(p.id)),\n };\n}\n\nexport function getTelemetryCliConfig(config: {\n tenantTables: string[];\n schemaDir?: string;\n migrationsDir?: string;\n}): TelemetryCliConfig {\n return {\n tenantTablesCount: config.tenantTables?.length ?? 0,\n hasSchemaDir: !!config.schemaDir,\n hasMigrationsDir: !!config.migrationsDir,\n };\n}\n\n// --- Detection ---\n\nfunction getAnonymousId(cwd: string): string | undefined {\n try {\n const pkgPath = join(cwd, \"package.json\");\n if (!existsSync(pkgPath)) {\n return undefined;\n }\n\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\")) as {\n name?: string;\n betterTenant?: { basePath?: string };\n };\n const name = typeof pkg?.name === \"string\" ? pkg.name : \"\";\n const basePath =\n typeof pkg?.betterTenant?.basePath === \"string\"\n ? pkg.betterTenant.basePath\n : \"\";\n const input = `${name}:${basePath}`.trim() || \"unknown\";\n return createHash(\"sha256\").update(input).digest(\"hex\").slice(0, 16);\n } catch {\n return undefined;\n }\n}\n\nfunction detectRuntime(): { name: string; version: string } {\n const g = globalThis as Record<string, unknown>;\n if (typeof g.Bun !== \"undefined\") {\n const bun = g.Bun as { version?: string };\n return {\n name: \"bun\",\n version: typeof bun?.version === \"string\" ? bun.version : \"unknown\",\n };\n }\n if (typeof g.Deno !== \"undefined\") {\n const deno = g.Deno as { version?: { deno?: string } };\n const v = deno?.version?.deno;\n return { name: \"deno\", version: typeof v === \"string\" ? v : \"unknown\" };\n }\n const v = (typeof process !== \"undefined\" && process.versions?.node) || \"\";\n return { name: \"node\", version: v || \"unknown\" };\n}\n\nfunction detectEnvironment(): string {\n const env = process.env.NODE_ENV || \"development\";\n if (env === \"test\") {\n return \"test\";\n }\n\n // CI check before NODE_ENV so CI is detected even when NODE_ENV=production\n if (\n process.env.CI === \"true\" ||\n process.env.GITHUB_ACTIONS === \"true\" ||\n process.env.GITLAB_CI === \"true\" ||\n process.env.CIRCLECI === \"true\"\n ) {\n return \"ci\";\n }\n if (env === \"production\") {\n return \"production\";\n }\n\n return \"development\";\n}\n\nfunction detectFramework(\n cwd: string,\n): { name: string; version?: string } | undefined {\n try {\n const pkgPath = join(cwd, \"package.json\");\n if (!existsSync(pkgPath)) {\n return undefined;\n }\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\")) as {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n };\n const deps = { ...pkg?.dependencies, ...pkg?.devDependencies };\n if (deps[\"next\"]) {\n return { name: \"next\", version: deps[\"next\"] };\n }\n if (deps[\"hono\"]) {\n return { name: \"hono\", version: deps[\"hono\"] };\n }\n if (deps[\"express\"]) {\n return { name: \"express\", version: deps[\"express\"] };\n }\n return undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction detectDatabase(\n cwd: string,\n): { name: string; version?: string } | undefined {\n try {\n const pkgPath = join(cwd, \"package.json\");\n if (!existsSync(pkgPath)) {\n return undefined;\n }\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\")) as {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n };\n const deps = { ...pkg?.dependencies, ...pkg?.devDependencies };\n if (deps[\"drizzle-orm\"]) {\n return { name: \"drizzle\", version: deps[\"drizzle-orm\"] };\n }\n if (deps[\"prisma\"]) {\n return { name: \"prisma\", version: deps[\"prisma\"] };\n }\n return undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction detectSystem(): NonNullable<TelemetryPayload[\"system\"]> {\n const isDocker = existsSync(\"/.dockerenv\");\n const isWSL =\n typeof process.env.WSL_DISTRO_NAME === \"string\" ||\n (typeof process.env.WSL_INTEROP === \"string\" &&\n process.env.WSL_INTEROP.length > 0);\n return {\n platform: platform(),\n release: release(),\n arch: arch(),\n cpus: cpus().length,\n totalMemoryMb: Math.round(totalmem() / 1024 / 1024),\n isDocker,\n isWSL,\n };\n}\n\nfunction detectPackageManager():\n | { name: string; version?: string }\n | undefined {\n const ua = process.env.npm_config_user_agent;\n if (!ua || typeof ua !== \"string\") {\n return undefined;\n }\n const match = ua.match(/^(.+?)\\/(\\d+\\.\\d+\\.\\d+.*?)(?:\\s|$)/);\n if (match) {\n const name = (match[1] ?? \"unknown\").toLowerCase();\n const version = match[2];\n return version ? { name, version } : { name };\n }\n if (ua.includes(\"pnpm\")) {\n return { name: \"pnpm\" };\n }\n if (ua.includes(\"yarn\")) {\n return { name: \"yarn\" };\n }\n return { name: \"npm\" };\n}\n\n// --- Send ---\n\nfunction isTelemetryEnabled(options?: TelemetryOptions): boolean {\n if (process.env.NODE_ENV === \"test\") {\n return false;\n }\n const env = process.env.BETTER_TENANT_TELEMETRY;\n if (env === \"0\" || env?.toLowerCase() === \"false\") {\n return false;\n }\n if (env === \"1\" || env?.toLowerCase() === \"true\") {\n return true;\n }\n return options?.enabled !== false;\n}\n\nfunction isDebugMode(options?: TelemetryOptions): boolean {\n if (process.env.BETTER_TENANT_TELEMETRY_DEBUG === \"1\") {\n return true;\n }\n return options?.debug === true;\n}\n\n/**\n * Send telemetry event. Fire-and-forget by default; use options.wait for process-exit paths.\n * Skips when NODE_ENV=test, when disabled via env/config, or when debug mode logs only.\n */\nexport function sendTelemetry(\n type: string,\n payload: Omit<TelemetryPayload, \"library\" | \"type\" | \"timestamp\">,\n options?: TelemetryOptions,\n): void | Promise<void> {\n if (!isTelemetryEnabled(options)) {\n return options?.wait ? Promise.resolve() : undefined;\n }\n const fullPayload: TelemetryPayload = {\n library: LIBRARY_ID,\n type,\n timestamp: new Date().toISOString(),\n ...payload,\n };\n if (isDebugMode(options)) {\n console.log(\n \"[better-tenant telemetry]\",\n JSON.stringify(fullPayload, null, 2),\n );\n return options?.wait ? Promise.resolve() : undefined;\n }\n const doSend = () =>\n fetch(TELEMETRY_ENDPOINT, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(fullPayload),\n }).catch(() => {\n // Silently ignore send failures\n });\n\n if (options?.wait) {\n return new Promise<void>((resolve) => {\n setImmediate(async () => {\n await doSend();\n resolve();\n });\n });\n }\n\n setImmediate(() => doSend());\n}\n\n/**\n * Build and send init telemetry (call from betterTenant()).\n */\nexport function sendInitTelemetry(\n config: TelemetryConfigInput,\n options?: TelemetryOptions,\n): void {\n const cwd = process.cwd();\n const payload: Omit<TelemetryPayload, \"library\" | \"type\" | \"timestamp\"> = {\n runtime: detectRuntime(),\n environment: detectEnvironment(),\n config: getTelemetryTenantConfig(config),\n };\n const anonymousId = getAnonymousId(cwd);\n if (anonymousId) payload.anonymousId = anonymousId;\n const framework = detectFramework(cwd);\n if (framework) payload.framework = framework;\n const database = detectDatabase(cwd);\n if (database) payload.database = database;\n payload.system = detectSystem();\n const pkgMgr = detectPackageManager();\n if (pkgMgr) payload.packageManager = pkgMgr;\n sendTelemetry(\"init\", payload, options ?? config.telemetry);\n}\n\n/** Raw CLI config shape (subset needed for telemetry). */\nexport interface CliConfigForTelemetry {\n tenantTables: string[];\n schemaDir?: string;\n migrationsDir?: string;\n}\n\n/**\n * Build and send CLI telemetry. Use from CLI commands.\n * Accepts raw config; redaction happens internally.\n * Use options.wait: true before process.exit so the send completes.\n */\nexport function sendCliTelemetry(\n type: \"cli_generate\" | \"cli_migrate\" | \"cli_check\" | \"cli_seed\" | \"cli_init\",\n outcome: string,\n config?: CliConfigForTelemetry,\n options?: { wait?: boolean },\n): void | Promise<void> {\n const cwd = process.cwd();\n const redactedConfig = config ? getTelemetryCliConfig(config) : undefined;\n const payload: Omit<TelemetryPayload, \"library\" | \"type\" | \"timestamp\"> = {\n runtime: detectRuntime(),\n environment: detectEnvironment(),\n outcome,\n };\n if (redactedConfig) payload.config = redactedConfig;\n payload.system = detectSystem();\n const anonymousId = getAnonymousId(cwd);\n if (anonymousId) payload.anonymousId = anonymousId;\n const framework = detectFramework(cwd);\n if (framework) payload.framework = framework;\n const database = detectDatabase(cwd);\n if (database) payload.database = database;\n const pkgMgr = detectPackageManager();\n if (pkgMgr) payload.packageManager = pkgMgr;\n return sendTelemetry(type, payload, options);\n}\n","import type { TenantContext } from \"./types.js\";\nimport { AsyncLocalStorage } from \"node:async_hooks\";\n\nconst storage = new AsyncLocalStorage<TenantContext>();\n\n/**\n * Returns the current tenant context, or undefined when not inside runWithTenant / runWithTenantAndDatabase.\n */\nexport function getContext(): TenantContext | undefined {\n return storage.getStore();\n}\n\n/**\n * Runs fn inside a scope where getContext() returns { tenantId }.\n * No adapter/DB involved; use for tests or when adapter is not configured.\n * If tenantId is empty string, it is treated as undefined (no tenant).\n */\nexport function runWithTenant<T>(\n tenantId: string,\n fn: () => T | Promise<T>,\n): Promise<T> {\n const normalized = tenantId.trim() || undefined;\n if (normalized === undefined) {\n return Promise.reject(\n new Error(\"better-tenant: tenantId must be a non-empty string\"),\n );\n }\n return Promise.resolve(\n storage.run({ tenantId: normalized }, () => fn()),\n );\n}\n\n/**\n * Internal: set context with optional database handle. Used by runWithTenantAndDatabase.\n */\nexport function runWithContext<T>(\n context: TenantContext,\n fn: () => T | Promise<T>,\n): Promise<T> {\n return Promise.resolve(storage.run(context, () => fn()));\n}\n\n","import type {\n TenantAdapter,\n TenantContext,\n RunWithTenantAndDatabaseOptions,\n} from \"./types.js\";\nimport { getContext, runWithContext } from \"./context.js\";\n\n/**\n * Returns the tenant-scoped database handle when inside a runWithTenantAndDatabase (or runAs) scope.\n *\n * Use only the handle from getDatabase() for tenant-scoped tables. Outside scope, returns undefined.\n * Config requires an adapter when tenant-scoped DB is used; getDatabase() is then available inside\n * request handlers that ran via runWithTenantAndDatabase(tenantId, adapter, next).\n */\nexport function getDatabase(): unknown {\n const context = getContext();\n return context?.database;\n}\n\n/**\n * Sets AsyncLocalStorage context and runs fn with the adapter's tenant-scoped DB.\n *\n * (1) Sets AsyncLocalStorage context with tenantId and database.\n * (2) Calls adapter.runWithTenant(tenantId, (database) => fn(database)).\n * (3) Stores the database handle in context so getDatabase() returns it.\n *\n * Middleware should resolve tenantId from the request, then call\n * runWithTenantAndDatabase(tenantId, adapter, next) so both context and DB handle are available.\n *\n * When options.loadTenant is true and options.getTenantRepository and adapter.runAsSystem are set,\n * loads the full Tenant row into context so getContext().tenant is available (or undefined if not found).\n */\nexport async function runWithTenantAndDatabase<TDb, SDb, T>(\n tenantId: string,\n adapter: TenantAdapter<TDb, SDb>,\n fn: (database: TDb) => Promise<T>,\n options?: RunWithTenantAndDatabaseOptions<SDb>,\n): Promise<T> {\n const result = await adapter.runWithTenant(tenantId, async (database) => {\n let context: TenantContext = { tenantId, database };\n const getTenantRepository = options?.getTenantRepository;\n if (\n options?.loadTenant &&\n getTenantRepository &&\n adapter.runAsSystem\n ) {\n const tenant = await adapter.runAsSystem((systemDb) =>\n getTenantRepository(systemDb).getById(tenantId),\n );\n context = tenant != null ? { ...context, tenant } : context;\n }\n return runWithContext(context, () => fn(database));\n });\n return result;\n}\n","export class TenantNotResolvedError extends Error {\n constructor(message = \"better-tenant: tenant could not be resolved from request\") {\n super(message);\n this.name = \"TenantNotResolvedError\";\n }\n}\n\nexport class TenantMiddlewareError extends Error {\n constructor(\n message = \"better-tenant: failed to run tenant middleware\",\n options?: { cause?: unknown },\n ) {\n super(message, options);\n this.name = \"TenantMiddlewareError\";\n }\n}\n","import { runWithTenantAndDatabase } from \"./adapter.js\";\nimport { TenantMiddlewareError, TenantNotResolvedError } from \"./errors.js\";\nimport type { TenantAdapter } from \"./types.js\";\n\ntype MaybePromise<T> = T | Promise<T>;\n\nexport interface HandleRequestOptions<Req, Result> {\n resolveTenant: (request: Req) => MaybePromise<string | undefined>;\n adapter: TenantAdapter;\n onMissingTenant?: (request: Req) => MaybePromise<Result>;\n onError?: (error: unknown, request: Req) => MaybePromise<Result>;\n}\n\n/**\n * Generic request helper for framework adapters.\n *\n * It resolves a tenant id from the framework request, then runs the request handler\n * inside runWithTenantAndDatabase so both getContext() and getDatabase() are available.\n */\nexport async function handleRequest<Req, Result>(\n request: Req,\n next: () => Promise<Result>,\n options: HandleRequestOptions<Req, Result>,\n): Promise<Result> {\n const tenantId = await options.resolveTenant(request);\n const normalizedTenantId = tenantId?.trim();\n if (!normalizedTenantId) {\n if (options.onMissingTenant) {\n return options.onMissingTenant(request);\n }\n\n const error = new TenantNotResolvedError();\n if (options.onError) {\n return options.onError(error, request);\n }\n throw error;\n }\n\n try {\n return await runWithTenantAndDatabase(\n normalizedTenantId,\n options.adapter,\n async () => next(),\n );\n } catch (error) {\n if (options.onError) {\n return options.onError(error, request);\n }\n\n if (\n error instanceof TenantNotResolvedError ||\n error instanceof TenantMiddlewareError\n ) {\n throw error;\n }\n\n throw new TenantMiddlewareError(undefined, { cause: error });\n }\n}\n","import type { TenantAdapter, Tenant, TenantRepository } from \"./types.js\";\nimport { runWithContext } from \"./context.js\";\nimport { runWithTenantAndDatabase } from \"./adapter.js\";\n\nconst DEFAULT_LIST_LIMIT = 50;\n\nexport interface CreateTenantData {\n name: string;\n slug: string;\n}\n\nexport interface UpdateTenantData {\n name?: string;\n slug?: string;\n}\n\nexport interface ListTenantsOptions {\n limit?: number;\n offset?: number;\n}\n\nfunction requireRunAsSystem<TDb, SDb>(\n adapter: TenantAdapter<TDb, SDb>,\n): <T>(fn: (database: SDb) => Promise<T>) => Promise<T> {\n if (!adapter.runAsSystem) {\n throw new Error(\n \"better-tenant: tenant.api and runAsSystem require adapter.runAsSystem; this adapter does not implement it\",\n );\n }\n return adapter.runAsSystem;\n}\n\n/**\n * Tenant CRUD API. All methods run via adapter.runAsSystem and getTenantRepository.\n * The runAsSystem check is deferred to call time so that betterTenant() can be\n * constructed with adapters that don't implement runAsSystem (e.g. test mocks).\n */\nexport function createTenantApi<TDb, SDb>(\n adapter: TenantAdapter<TDb, SDb>,\n getTenantRepository: (database: SDb) => TenantRepository,\n) {\n return {\n async createTenant(data: CreateTenantData): Promise<Tenant> {\n if (!data.name?.trim()) {\n throw new Error(\"better-tenant: createTenant requires name\");\n }\n if (!data.slug?.trim()) {\n throw new Error(\"better-tenant: createTenant requires slug\");\n }\n const runAsSystem = requireRunAsSystem(adapter);\n return runAsSystem((database) =>\n getTenantRepository(database).create({\n name: data.name.trim(),\n slug: data.slug.trim(),\n }),\n );\n },\n\n async updateTenant(\n tenantId: string,\n data: UpdateTenantData,\n ): Promise<Tenant> {\n if (!tenantId?.trim()) {\n throw new Error(\"better-tenant: updateTenant requires tenantId\");\n }\n const runAsSystem = requireRunAsSystem(adapter);\n return runAsSystem((database) =>\n getTenantRepository(database).update(tenantId, {\n ...(data.name !== undefined && { name: data.name }),\n ...(data.slug !== undefined && { slug: data.slug }),\n }),\n );\n },\n\n async listTenants(options: ListTenantsOptions = {}): Promise<Tenant[]> {\n const limit = options.limit ?? DEFAULT_LIST_LIMIT;\n const offset = Math.max(0, options.offset ?? 0);\n const runAsSystem = requireRunAsSystem(adapter);\n return runAsSystem((database) =>\n getTenantRepository(database).list({ limit, offset }),\n );\n },\n\n async deleteTenant(tenantId: string): Promise<void> {\n if (!tenantId?.trim()) {\n throw new Error(\"better-tenant: deleteTenant requires tenantId\");\n }\n const runAsSystem = requireRunAsSystem(adapter);\n return runAsSystem((database) =>\n getTenantRepository(database).delete(tenantId),\n );\n },\n\n async getTenant(tenantId: string): Promise<Tenant | null> {\n if (!tenantId?.trim()) {\n throw new Error(\"better-tenant: getTenant requires tenantId\");\n }\n const runAsSystem = requireRunAsSystem(adapter);\n return runAsSystem((database) =>\n getTenantRepository(database).getById(tenantId),\n );\n },\n\n async countTenants(): Promise<number> {\n const runAsSystem = requireRunAsSystem(adapter);\n return runAsSystem((database) =>\n getTenantRepository(database).count(),\n );\n },\n };\n}\n\n/**\n * runAs(tenantId, fn): same as request flow — set context + run inside adapter.runWithTenant\n * so code can use getDatabase() and run tenant-scoped queries. Use for cron, per-tenant migrations.\n */\nexport async function runAs<TDb, T>(\n tenantId: string,\n adapter: TenantAdapter<TDb>,\n fn: (database: TDb) => Promise<T>,\n): Promise<T> {\n return runWithTenantAndDatabase(tenantId, adapter, fn);\n}\n\n/**\n * runAsSystem(fn): run fn with a DB handle that has RLS bypass.\n * Optionally set context so getContext() reflects system mode.\n */\nexport async function runAsSystem<SDb, T>(\n adapter: TenantAdapter<unknown, SDb>,\n fn: (database: SDb) => Promise<T>,\n): Promise<T> {\n const run = requireRunAsSystem(adapter);\n return runWithContext({ isSystem: true }, () => run(fn));\n}\n","import type {\n ResolvableRequest,\n TenantResolverConfig,\n JwtResolverConfig,\n PathResolverConfig,\n SubdomainResolverConfig,\n} from \"./types.js\";\n\nfunction getHeader(\n headers: ResolvableRequest[\"headers\"],\n name: string,\n): string | undefined {\n const key = name.toLowerCase();\n if (headers instanceof Headers) {\n const value = headers.get(key);\n return value?.trim() || undefined;\n }\n const raw = headers[key] ?? headers[name];\n if (raw === undefined) {\n return undefined;\n }\n const value = Array.isArray(raw) ? raw[0] : raw;\n return (typeof value === \"string\" ? value : \"\").trim() || undefined;\n}\n\nfunction resolveFromHeader(\n request: ResolvableRequest,\n headerName: string,\n): string | undefined {\n if (!headerName) {\n return undefined;\n }\n return getHeader(request.headers, headerName);\n}\n\nfunction resolveFromPath(\n request: ResolvableRequest,\n pathConfig: string | PathResolverConfig,\n): string | undefined {\n const pathOrUrl = request.path ?? request.url;\n if (!pathOrUrl) {\n return undefined;\n }\n\n let path: string;\n try {\n path = pathOrUrl.startsWith(\"http\")\n ? new URL(pathOrUrl).pathname\n : pathOrUrl;\n } catch {\n path = pathOrUrl;\n }\n\n const pattern =\n typeof pathConfig === \"string\" ? pathConfig : pathConfig.pattern;\n const segmentIndex =\n typeof pathConfig === \"object\" && pathConfig.segmentIndex !== undefined\n ? pathConfig.segmentIndex\n : parseTenantSegmentIndex(pattern);\n\n const segments = path.split(\"/\").filter(Boolean);\n const value = segments[segmentIndex];\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n\n/** e.g. \"/t/:tenantId/*\" -> segment 1 (0-based). */\nfunction parseTenantSegmentIndex(pattern: string): number {\n const segments = pattern.split(\"/\").filter(Boolean);\n const idx = segments.indexOf(\":tenantId\");\n return idx >= 0 ? idx : 0;\n}\n\nfunction resolveFromSubdomain(\n request: ResolvableRequest,\n config: SubdomainResolverConfig,\n): string | undefined {\n const host = request.host ?? (request.url ? new URL(request.url).host : \"\");\n if (!host) {\n return undefined;\n }\n const hostname = host.split(\":\")[0];\n if (!hostname) {\n return undefined;\n }\n const parts = hostname.split(\".\");\n // Only one segment (e.g. \"localhost\") or domain.tld (e.g. \"example.com\") = no subdomain\n if (parts.length <= 2) {\n return undefined;\n }\n const index =\n config === true\n ? 0\n : typeof config === \"object\" && config.segmentIndex !== undefined\n ? config.segmentIndex\n : 0;\n const value = parts[index];\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n\nfunction decodeJwtPayload(token: string): Record<string, unknown> | null {\n try {\n const parts = token.split(\".\");\n if (parts.length < 2) {\n return null;\n }\n const payload = parts[1];\n if (!payload) {\n return null;\n }\n const decoded = atob(payload.replace(/-/g, \"+\").replace(/_/g, \"/\"));\n const parsed: unknown = JSON.parse(decoded);\n if (typeof parsed !== \"object\" || parsed === null) {\n return null;\n }\n return parsed as Record<string, unknown>;\n } catch {\n return null;\n }\n}\n\nasync function resolveFromJwt(\n request: ResolvableRequest,\n config: string | JwtResolverConfig,\n): Promise<string | undefined> {\n const getToken = request.getToken;\n if (!getToken) {\n return undefined;\n }\n const token = typeof getToken === \"function\" ? getToken() : getToken;\n const value = token instanceof Promise ? await token : token;\n const resolved = value ?? undefined;\n if (!resolved) {\n return undefined;\n }\n\n const claim = typeof config === \"string\" ? config : config.claim;\n if (!claim) {\n return undefined;\n }\n\n const verifyToken =\n typeof config === \"object\" ? config.verifyToken : undefined;\n\n let payload: Record<string, unknown> | null;\n if (verifyToken) {\n payload = await verifyToken(resolved);\n } else {\n payload = decodeJwtPayload(resolved);\n }\n\n if (!payload) {\n return undefined;\n }\n\n const claimValue = payload[claim];\n return typeof claimValue === \"string\" && claimValue.length > 0\n ? claimValue\n : undefined;\n}\n\n/**\n * Returns human-readable descriptions of the configured resolution strategies.\n * Useful for error messages when tenant resolution fails.\n */\nexport function describeStrategies(config: TenantResolverConfig): string[] {\n const strategies: string[] = [];\n if (config.header !== undefined) {\n strategies.push(`header '${config.header}'`);\n }\n if (config.path !== undefined) {\n const pattern =\n typeof config.path === \"string\" ? config.path : config.path.pattern;\n strategies.push(`path '${pattern}'`);\n }\n if (config.subdomain !== undefined && config.subdomain !== false) {\n strategies.push(\"subdomain\");\n }\n if (config.jwt !== undefined) {\n const claim =\n typeof config.jwt === \"string\" ? config.jwt : config.jwt.claim;\n strategies.push(`jwt claim '${claim}'`);\n }\n if (config.custom !== undefined) {\n strategies.push(\"custom resolver\");\n }\n return strategies;\n}\n\n/**\n * Resolution order: header → path → subdomain → jwt → custom.\n * Returns the first defined tenant id.\n */\nexport async function resolveTenant(\n request: ResolvableRequest,\n config: TenantResolverConfig,\n): Promise<string | undefined> {\n if (config.header !== undefined) {\n const v = resolveFromHeader(request, config.header);\n if (v !== undefined) {\n return v;\n }\n }\n if (config.path !== undefined) {\n const v = resolveFromPath(request, config.path);\n if (v !== undefined) {\n return v;\n }\n }\n if (config.subdomain !== undefined && config.subdomain !== false) {\n const v = resolveFromSubdomain(request, config.subdomain);\n if (v !== undefined) {\n return v;\n }\n }\n if (config.jwt !== undefined) {\n const v = await resolveFromJwt(request, config.jwt);\n if (v !== undefined) {\n return v;\n }\n }\n if (config.custom !== undefined) {\n const v = await Promise.resolve(config.custom(request));\n if (typeof v === \"string\" && v.length > 0) {\n return v;\n }\n }\n return undefined;\n}\n","/**\n * Shared parse and validation utilities for console endpoint handlers.\n *\n * These are small, pure, zero-dep helpers used by product endpoint handlers\n * (audit, tenant) to validate and parse incoming request data.\n */\n\n/** Type guard that narrows `unknown` to a plain object (not array, not null). */\nexport function isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/**\n * Parse a string to an integer within [min, max].\n * Returns `undefined` when `value` is `undefined` (param absent),\n * not a finite number, or below `min`.\n */\nexport function parseBoundedInt(\n value: string | undefined,\n min: number,\n max: number,\n): number | undefined {\n if (value === undefined) {\n return undefined;\n }\n const parsed = Number(value);\n if (!Number.isFinite(parsed) || parsed < min) {\n return undefined;\n }\n return Math.min(Math.floor(parsed), max);\n}\n\n/**\n * Parse an ISO-8601 date string.\n * Returns `undefined` when `value` is `undefined` or not a valid date.\n */\nexport function parseIsoDate(value: string | undefined): Date | undefined {\n if (value === undefined) {\n return undefined;\n }\n const date = new Date(value);\n if (Number.isNaN(date.getTime())) {\n return undefined;\n }\n return date;\n}\n","import type {\n ConsoleProductEndpoint,\n ConsoleProductRequest,\n ConsoleErrorResponse,\n TenantWire,\n TenantStatsResponse,\n} from \"@usebetterdev/contract\";\nimport {\n isPlainObject,\n parseBoundedInt,\n} from \"@usebetterdev/console-utils\";\nimport type { TenantApi } from \"./better-tenant.js\";\nimport type { Tenant } from \"./types.js\";\n\nconst MAX_FIELD_LENGTH = 255;\n\nfunction serializeTenant(tenant: Tenant): TenantWire {\n return {\n ...tenant,\n createdAt:\n tenant.createdAt instanceof Date\n ? tenant.createdAt.toISOString()\n : tenant.createdAt,\n };\n}\n\nexport function createTenantConsoleEndpoints(\n api: TenantApi,\n): ConsoleProductEndpoint[] {\n return [\n {\n method: \"GET\",\n path: \"/tenants\",\n requiredPermission: \"read\",\n async handler(request: ConsoleProductRequest) {\n try {\n const options: { limit?: number; offset?: number } = {};\n if (request.query.limit !== undefined) {\n const limit = parseBoundedInt(request.query.limit, 1, 1000);\n if (limit === undefined) {\n return { status: 400, body: { error: \"Invalid 'limit': must be a positive integer (max 1000)\" } satisfies ConsoleErrorResponse };\n }\n options.limit = limit;\n }\n if (request.query.offset !== undefined) {\n const offset = parseBoundedInt(request.query.offset, 0, Number.MAX_SAFE_INTEGER);\n if (offset === undefined) {\n return { status: 400, body: { error: \"Invalid 'offset': must be a non-negative integer\" } satisfies ConsoleErrorResponse };\n }\n options.offset = offset;\n }\n const tenants = await api.listTenants(options);\n return { status: 200, body: tenants.map(serializeTenant) satisfies TenantWire[] };\n } catch {\n return { status: 500, body: { error: \"Internal server error\" } satisfies ConsoleErrorResponse };\n }\n },\n },\n {\n method: \"GET\",\n path: \"/tenants/:id\",\n requiredPermission: \"read\",\n async handler(request: ConsoleProductRequest) {\n try {\n const id = request.params.id?.trim();\n if (!id) {\n return { status: 400, body: { error: \"Missing tenant id\" } satisfies ConsoleErrorResponse };\n }\n const tenant = await api.getTenant(id);\n if (!tenant) {\n return { status: 404, body: { error: \"Tenant not found\" } satisfies ConsoleErrorResponse };\n }\n return { status: 200, body: serializeTenant(tenant) satisfies TenantWire };\n } catch {\n return { status: 500, body: { error: \"Internal server error\" } satisfies ConsoleErrorResponse };\n }\n },\n },\n {\n method: \"POST\",\n path: \"/tenants\",\n requiredPermission: \"write\",\n async handler(request: ConsoleProductRequest) {\n try {\n if (!isPlainObject(request.body)) {\n return { status: 400, body: { error: \"Request body is required\" } satisfies ConsoleErrorResponse };\n }\n const name = typeof request.body.name === \"string\" ? request.body.name : \"\";\n const slug = typeof request.body.slug === \"string\" ? request.body.slug : \"\";\n if (!name.trim() || !slug.trim()) {\n return { status: 400, body: { error: \"name and slug are required\" } satisfies ConsoleErrorResponse };\n }\n if (name.length > MAX_FIELD_LENGTH || slug.length > MAX_FIELD_LENGTH) {\n return { status: 400, body: { error: \"name and slug must not exceed 255 characters\" } satisfies ConsoleErrorResponse };\n }\n const tenant = await api.createTenant({ name, slug });\n return { status: 201, body: serializeTenant(tenant) satisfies TenantWire };\n } catch {\n return { status: 500, body: { error: \"Internal server error\" } satisfies ConsoleErrorResponse };\n }\n },\n },\n {\n method: \"PATCH\",\n path: \"/tenants/:id\",\n requiredPermission: \"write\",\n async handler(request: ConsoleProductRequest) {\n try {\n const id = request.params.id?.trim();\n if (!id) {\n return { status: 400, body: { error: \"Missing tenant id\" } satisfies ConsoleErrorResponse };\n }\n if (!isPlainObject(request.body)) {\n return { status: 400, body: { error: \"Request body is required\" } satisfies ConsoleErrorResponse };\n }\n const data: { name?: string; slug?: string } = {};\n if (typeof request.body.name === \"string\") {\n if (request.body.name.length > MAX_FIELD_LENGTH) {\n return { status: 400, body: { error: \"name must not exceed 255 characters\" } satisfies ConsoleErrorResponse };\n }\n data.name = request.body.name;\n }\n if (typeof request.body.slug === \"string\") {\n if (request.body.slug.length > MAX_FIELD_LENGTH) {\n return { status: 400, body: { error: \"slug must not exceed 255 characters\" } satisfies ConsoleErrorResponse };\n }\n data.slug = request.body.slug;\n }\n const tenant = await api.updateTenant(id, data);\n return { status: 200, body: serializeTenant(tenant) satisfies TenantWire };\n } catch {\n return { status: 500, body: { error: \"Internal server error\" } satisfies ConsoleErrorResponse };\n }\n },\n },\n {\n method: \"DELETE\",\n path: \"/tenants/:id\",\n requiredPermission: \"admin\",\n async handler(request: ConsoleProductRequest) {\n try {\n const id = request.params.id?.trim();\n if (!id) {\n return { status: 400, body: { error: \"Missing tenant id\" } satisfies ConsoleErrorResponse };\n }\n await api.deleteTenant(id);\n return { status: 204, body: null };\n } catch {\n return { status: 500, body: { error: \"Internal server error\" } satisfies ConsoleErrorResponse };\n }\n },\n },\n {\n method: \"GET\",\n path: \"/stats\",\n requiredPermission: \"read\",\n async handler() {\n try {\n const tenantCount = await api.countTenants();\n return { status: 200, body: { tenantCount } satisfies TenantStatsResponse };\n } catch {\n return { status: 500, body: { error: \"Internal server error\" } satisfies ConsoleErrorResponse };\n }\n },\n },\n ];\n}\n","import type {\n BetterTenantConfig,\n Tenant,\n TenantAdapter,\n TenantRepository,\n TenantResolverConfig,\n ResolvableRequest,\n TenantContext,\n RunWithTenantAndDatabaseOptions,\n} from \"./types.js\";\nimport { sendInitTelemetry } from \"./telemetry.js\";\nimport { getContext, runWithTenant } from \"./context.js\";\nimport { getDatabase, runWithTenantAndDatabase } from \"./adapter.js\";\nimport {\n handleRequest as handleTenantRequest,\n type HandleRequestOptions,\n} from \"./handle-request.js\";\nimport {\n createTenantApi,\n runAsSystem as runAsSystemWithAdapter,\n} from \"./api.js\";\nimport { resolveTenant, describeStrategies } from \"./resolver.js\";\nimport { createTenantConsoleEndpoints } from \"./console-endpoints.js\";\n\n/** UUID v4 pattern for detecting whether an identifier is already a UUID. */\nconst UUID_RE =\n /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\n/**\n * Normalize a resolved identifier to a tenant UUID.\n *\n * - If resolveToId is configured, call it (takes full precedence).\n * - If the identifier is already a UUID, pass through.\n * - If adapter.runAsSystem is available, look up by slug via getTenantRepository.\n * - Otherwise, return as-is (will likely fail at DB level).\n */\nasync function resolveIdentifierToId(\n identifier: string,\n resolverConfig: TenantResolverConfig,\n adapter: TenantAdapter,\n getTenantRepository: (db: unknown) => TenantRepository,\n): Promise<string | undefined> {\n if (resolverConfig.resolveToId) {\n return resolverConfig.resolveToId(identifier);\n }\n if (UUID_RE.test(identifier)) {\n return identifier;\n }\n if (adapter.runAsSystem) {\n const tenant = await adapter.runAsSystem((systemDb: unknown) =>\n getTenantRepository(systemDb).getBySlug(identifier),\n );\n return tenant?.id;\n }\n return identifier;\n}\n\nexport interface TenantApi {\n createTenant(data: { name: string; slug: string }): Promise<Tenant>;\n updateTenant(\n tenantId: string,\n data: { name?: string; slug?: string },\n ): Promise<Tenant>;\n listTenants(options?: { limit?: number; offset?: number }): Promise<Tenant[]>;\n deleteTenant(tenantId: string): Promise<void>;\n getTenant(tenantId: string): Promise<Tenant | null>;\n countTenants(): Promise<number>;\n}\n\nexport interface BetterTenantInstance<TDb = unknown, SDb = unknown> {\n getContext: () => TenantContext | undefined;\n getDatabase: () => TDb | undefined;\n runWithTenant: typeof runWithTenant;\n runAs: <T>(tenantId: string, fn: (database: TDb) => Promise<T>) => Promise<T>;\n runAsSystem: <T>(fn: (database: SDb) => Promise<T>) => Promise<T>;\n resolveTenant: (request: ResolvableRequest) => Promise<string | undefined>;\n /** Human-readable descriptions of the configured resolution strategies. */\n resolverStrategies: string[];\n handleRequest: <Req extends ResolvableRequest, Result>(\n request: Req,\n next: () => Promise<Result>,\n options?: Omit<\n HandleRequestOptions<Req, Result>,\n \"resolveTenant\" | \"adapter\"\n >,\n ) => Promise<Result>;\n api: TenantApi;\n}\n\n/**\n * Creates the Better Tenant instance. Config must include adapter, tenantResolver, and getTenantRepository.\n */\nexport function betterTenant<TDb, SDb>(\n config: BetterTenantConfig<TDb, SDb>,\n): BetterTenantInstance<TDb, SDb> {\n const { database, tenantResolver, loadTenant } = config;\n const { adapter, getTenantRepository } = database;\n\n sendInitTelemetry(config, config.telemetry);\n\n const api = createTenantApi(adapter, getTenantRepository);\n\n const runWithTenantAndDatabaseOptions:\n | RunWithTenantAndDatabaseOptions<SDb>\n | undefined =\n loadTenant !== false\n ? { loadTenant: true as const, getTenantRepository }\n : undefined;\n\n const resolverStrategies = describeStrategies(tenantResolver);\n\n /** Resolve raw identifier from request, then normalize to UUID. */\n async function resolveAndNormalize(\n request: ResolvableRequest,\n ): Promise<string | undefined> {\n const raw = await resolveTenant(request, tenantResolver);\n if (!raw) return undefined;\n return resolveIdentifierToId(\n raw,\n tenantResolver,\n adapter,\n getTenantRepository as (db: unknown) => TenantRepository,\n );\n }\n\n if (config.console) {\n const endpoints = createTenantConsoleEndpoints(api);\n config.console.registerProduct({\n id: \"tenant\",\n name: \"Better Tenant\",\n endpoints,\n });\n }\n\n return {\n getContext,\n getDatabase: () => getDatabase() as TDb | undefined,\n runWithTenant,\n runAs: (tenantId, fn) =>\n runWithTenantAndDatabase(\n tenantId,\n adapter,\n fn,\n runWithTenantAndDatabaseOptions,\n ),\n runAsSystem: <T>(fn: (database: SDb) => Promise<T>) =>\n runAsSystemWithAdapter(adapter, fn),\n resolveTenant: resolveAndNormalize,\n resolverStrategies,\n handleRequest: (request, next, options) =>\n handleTenantRequest(request, next, {\n ...options,\n resolveTenant: resolveAndNormalize,\n adapter,\n }),\n api,\n };\n}\n","import type { ResolvableRequest } from \"./types.js\";\n\ntype NodeHeaders = Record<string, string | string[] | undefined>;\n\nexport interface NodeLikeRequest {\n headers?: Record<string, string | string[] | number | undefined>;\n url?: string;\n originalUrl?: string;\n path?: string;\n hostname?: string;\n host?: string;\n method?: string;\n}\n\nfunction isFetchRequest(input: unknown): input is Request {\n return typeof Request !== \"undefined\" && input instanceof Request;\n}\n\nfunction normalizeHost(raw: string | undefined): string | undefined {\n if (!raw) {\n return undefined;\n }\n const value = raw.split(\":\")[0]?.trim();\n return value || undefined;\n}\n\nfunction normalizeHeaders(\n headers: Record<string, string | string[] | number | undefined> | undefined,\n): NodeHeaders {\n if (!headers) {\n return {};\n }\n const normalized: NodeHeaders = {};\n for (const [key, value] of Object.entries(headers)) {\n const normalizedKey = key.toLowerCase();\n if (Array.isArray(value)) {\n normalized[normalizedKey] = value.map((part) => String(part));\n continue;\n }\n if (value === undefined) {\n normalized[normalizedKey] = undefined;\n continue;\n }\n normalized[normalizedKey] = String(value);\n }\n return normalized;\n}\n\nfunction pathWithoutQuery(value: string | undefined): string | undefined {\n if (!value) {\n return undefined;\n }\n const [pathname] = value.split(\"?\");\n return pathname || undefined;\n}\n\nexport function toResolvableRequest(\n request: Request | NodeLikeRequest,\n): ResolvableRequest {\n if (isFetchRequest(request)) {\n const url = request.url;\n let host: string | undefined;\n let path: string | undefined;\n try {\n const parsedUrl = new URL(url);\n host = normalizeHost(parsedUrl.host);\n path = parsedUrl.pathname || undefined;\n } catch {\n host = undefined;\n path = undefined;\n }\n const resolved: ResolvableRequest = {\n headers: request.headers,\n url,\n method: request.method,\n };\n if (path !== undefined) {\n resolved.path = path;\n }\n if (host !== undefined) {\n resolved.host = host;\n }\n return resolved;\n }\n\n const headers = normalizeHeaders(request.headers);\n const hostFromHeaders = headers.host;\n const hostValue = Array.isArray(hostFromHeaders)\n ? hostFromHeaders[0]\n : hostFromHeaders;\n const host = normalizeHost(request.hostname ?? request.host ?? hostValue);\n const path = pathWithoutQuery(\n request.path ?? request.originalUrl ?? request.url,\n );\n\n const resolved: ResolvableRequest = {\n headers,\n };\n if (path !== undefined) {\n resolved.path = path;\n }\n if (host !== undefined) {\n resolved.host = host;\n }\n if (request.method !== undefined) {\n resolved.method = request.method;\n }\n return resolved;\n}\n"],"mappings":";AAMA,SAAS,kBAAkB;AAC3B,SAAS,YAAY,oBAAoB;AACzC,SAAS,YAAY;AACrB,SAAS,UAAU,SAAS,MAAM,MAAM,gBAAgB;AASxD,IAAM,qBAAqB;AAC3B,IAAM,aAAa;AA4DZ,SAAS,yBACd,QACuB;AACvB,QAAM,IAAI,OAAO,kBAAkB,CAAC;AACpC,SAAO;AAAA,IACL,UAAU;AAAA,MACR,QAAQ,CAAC,CAAC,EAAE;AAAA,MACZ,MAAM,CAAC,CAAC,EAAE;AAAA,MACV,WAAW,CAAC,CAAC,EAAE;AAAA,MACf,KAAK,CAAC,CAAC,EAAE;AAAA,MACT,QAAQ,CAAC,CAAC,EAAE;AAAA,IACd;AAAA,IACA,mBAAmB;AAAA,IACnB,YAAY,OAAO;AAAA,IACnB,aAAa,CAAC,CAAC,OAAO;AAAA,IACtB,UAAU,OAAO,WAAW,CAAC,GAAG,IAAI,CAAC,MAAM,OAAO,EAAE,EAAE,CAAC;AAAA,EACzD;AACF;AAEO,SAAS,sBAAsB,QAIf;AACrB,SAAO;AAAA,IACL,mBAAmB,OAAO,cAAc,UAAU;AAAA,IAClD,cAAc,CAAC,CAAC,OAAO;AAAA,IACvB,kBAAkB,CAAC,CAAC,OAAO;AAAA,EAC7B;AACF;AAIA,SAAS,eAAe,KAAiC;AACvD,MAAI;AACF,UAAM,UAAU,KAAK,KAAK,cAAc;AACxC,QAAI,CAAC,WAAW,OAAO,GAAG;AACxB,aAAO;AAAA,IACT;AAEA,UAAM,MAAM,KAAK,MAAM,aAAa,SAAS,OAAO,CAAC;AAIrD,UAAM,OAAO,OAAO,KAAK,SAAS,WAAW,IAAI,OAAO;AACxD,UAAM,WACJ,OAAO,KAAK,cAAc,aAAa,WACnC,IAAI,aAAa,WACjB;AACN,UAAM,QAAQ,GAAG,IAAI,IAAI,QAAQ,GAAG,KAAK,KAAK;AAC9C,WAAO,WAAW,QAAQ,EAAE,OAAO,KAAK,EAAE,OAAO,KAAK,EAAE,MAAM,GAAG,EAAE;AAAA,EACrE,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,gBAAmD;AAC1D,QAAM,IAAI;AACV,MAAI,OAAO,EAAE,QAAQ,aAAa;AAChC,UAAM,MAAM,EAAE;AACd,WAAO;AAAA,MACL,MAAM;AAAA,MACN,SAAS,OAAO,KAAK,YAAY,WAAW,IAAI,UAAU;AAAA,IAC5D;AAAA,EACF;AACA,MAAI,OAAO,EAAE,SAAS,aAAa;AACjC,UAAM,OAAO,EAAE;AACf,UAAMA,KAAI,MAAM,SAAS;AACzB,WAAO,EAAE,MAAM,QAAQ,SAAS,OAAOA,OAAM,WAAWA,KAAI,UAAU;AAAA,EACxE;AACA,QAAM,IAAK,OAAO,YAAY,eAAe,QAAQ,UAAU,QAAS;AACxE,SAAO,EAAE,MAAM,QAAQ,SAAS,KAAK,UAAU;AACjD;AAEA,SAAS,oBAA4B;AACnC,QAAM,MAAM,QAAQ,IAAI,YAAY;AACpC,MAAI,QAAQ,QAAQ;AAClB,WAAO;AAAA,EACT;AAGA,MACE,QAAQ,IAAI,OAAO,UACnB,QAAQ,IAAI,mBAAmB,UAC/B,QAAQ,IAAI,cAAc,UAC1B,QAAQ,IAAI,aAAa,QACzB;AACA,WAAO;AAAA,EACT;AACA,MAAI,QAAQ,cAAc;AACxB,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEA,SAAS,gBACP,KACgD;AAChD,MAAI;AACF,UAAM,UAAU,KAAK,KAAK,cAAc;AACxC,QAAI,CAAC,WAAW,OAAO,GAAG;AACxB,aAAO;AAAA,IACT;AACA,UAAM,MAAM,KAAK,MAAM,aAAa,SAAS,OAAO,CAAC;AAIrD,UAAM,OAAO,EAAE,GAAG,KAAK,cAAc,GAAG,KAAK,gBAAgB;AAC7D,QAAI,KAAK,MAAM,GAAG;AAChB,aAAO,EAAE,MAAM,QAAQ,SAAS,KAAK,MAAM,EAAE;AAAA,IAC/C;AACA,QAAI,KAAK,MAAM,GAAG;AAChB,aAAO,EAAE,MAAM,QAAQ,SAAS,KAAK,MAAM,EAAE;AAAA,IAC/C;AACA,QAAI,KAAK,SAAS,GAAG;AACnB,aAAO,EAAE,MAAM,WAAW,SAAS,KAAK,SAAS,EAAE;AAAA,IACrD;AACA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,eACP,KACgD;AAChD,MAAI;AACF,UAAM,UAAU,KAAK,KAAK,cAAc;AACxC,QAAI,CAAC,WAAW,OAAO,GAAG;AACxB,aAAO;AAAA,IACT;AACA,UAAM,MAAM,KAAK,MAAM,aAAa,SAAS,OAAO,CAAC;AAIrD,UAAM,OAAO,EAAE,GAAG,KAAK,cAAc,GAAG,KAAK,gBAAgB;AAC7D,QAAI,KAAK,aAAa,GAAG;AACvB,aAAO,EAAE,MAAM,WAAW,SAAS,KAAK,aAAa,EAAE;AAAA,IACzD;AACA,QAAI,KAAK,QAAQ,GAAG;AAClB,aAAO,EAAE,MAAM,UAAU,SAAS,KAAK,QAAQ,EAAE;AAAA,IACnD;AACA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,eAAwD;AAC/D,QAAM,WAAW,WAAW,aAAa;AACzC,QAAM,QACJ,OAAO,QAAQ,IAAI,oBAAoB,YACtC,OAAO,QAAQ,IAAI,gBAAgB,YAClC,QAAQ,IAAI,YAAY,SAAS;AACrC,SAAO;AAAA,IACL,UAAU,SAAS;AAAA,IACnB,SAAS,QAAQ;AAAA,IACjB,MAAM,KAAK;AAAA,IACX,MAAM,KAAK,EAAE;AAAA,IACb,eAAe,KAAK,MAAM,SAAS,IAAI,OAAO,IAAI;AAAA,IAClD;AAAA,IACA;AAAA,EACF;AACF;AAEA,SAAS,uBAEK;AACZ,QAAM,KAAK,QAAQ,IAAI;AACvB,MAAI,CAAC,MAAM,OAAO,OAAO,UAAU;AACjC,WAAO;AAAA,EACT;AACA,QAAM,QAAQ,GAAG,MAAM,oCAAoC;AAC3D,MAAI,OAAO;AACT,UAAM,QAAQ,MAAM,CAAC,KAAK,WAAW,YAAY;AACjD,UAAM,UAAU,MAAM,CAAC;AACvB,WAAO,UAAU,EAAE,MAAM,QAAQ,IAAI,EAAE,KAAK;AAAA,EAC9C;AACA,MAAI,GAAG,SAAS,MAAM,GAAG;AACvB,WAAO,EAAE,MAAM,OAAO;AAAA,EACxB;AACA,MAAI,GAAG,SAAS,MAAM,GAAG;AACvB,WAAO,EAAE,MAAM,OAAO;AAAA,EACxB;AACA,SAAO,EAAE,MAAM,MAAM;AACvB;AAIA,SAAS,mBAAmB,SAAqC;AAC/D,MAAI,QAAQ,IAAI,aAAa,QAAQ;AACnC,WAAO;AAAA,EACT;AACA,QAAM,MAAM,QAAQ,IAAI;AACxB,MAAI,QAAQ,OAAO,KAAK,YAAY,MAAM,SAAS;AACjD,WAAO;AAAA,EACT;AACA,MAAI,QAAQ,OAAO,KAAK,YAAY,MAAM,QAAQ;AAChD,WAAO;AAAA,EACT;AACA,SAAO,SAAS,YAAY;AAC9B;AAEA,SAAS,YAAY,SAAqC;AACxD,MAAI,QAAQ,IAAI,kCAAkC,KAAK;AACrD,WAAO;AAAA,EACT;AACA,SAAO,SAAS,UAAU;AAC5B;AAMO,SAAS,cACd,MACA,SACA,SACsB;AACtB,MAAI,CAAC,mBAAmB,OAAO,GAAG;AAChC,WAAO,SAAS,OAAO,QAAQ,QAAQ,IAAI;AAAA,EAC7C;AACA,QAAM,cAAgC;AAAA,IACpC,SAAS;AAAA,IACT;AAAA,IACA,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IAClC,GAAG;AAAA,EACL;AACA,MAAI,YAAY,OAAO,GAAG;AACxB,YAAQ;AAAA,MACN;AAAA,MACA,KAAK,UAAU,aAAa,MAAM,CAAC;AAAA,IACrC;AACA,WAAO,SAAS,OAAO,QAAQ,QAAQ,IAAI;AAAA,EAC7C;AACA,QAAM,SAAS,MACb,MAAM,oBAAoB;AAAA,IACxB,QAAQ;AAAA,IACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,IAC9C,MAAM,KAAK,UAAU,WAAW;AAAA,EAClC,CAAC,EAAE,MAAM,MAAM;AAAA,EAEf,CAAC;AAEH,MAAI,SAAS,MAAM;AACjB,WAAO,IAAI,QAAc,CAAC,YAAY;AACpC,mBAAa,YAAY;AACvB,cAAM,OAAO;AACb,gBAAQ;AAAA,MACV,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAEA,eAAa,MAAM,OAAO,CAAC;AAC7B;AAKO,SAAS,kBACd,QACA,SACM;AACN,QAAM,MAAM,QAAQ,IAAI;AACxB,QAAM,UAAoE;AAAA,IACxE,SAAS,cAAc;AAAA,IACvB,aAAa,kBAAkB;AAAA,IAC/B,QAAQ,yBAAyB,MAAM;AAAA,EACzC;AACA,QAAM,cAAc,eAAe,GAAG;AACtC,MAAI,YAAa,SAAQ,cAAc;AACvC,QAAM,YAAY,gBAAgB,GAAG;AACrC,MAAI,UAAW,SAAQ,YAAY;AACnC,QAAM,WAAW,eAAe,GAAG;AACnC,MAAI,SAAU,SAAQ,WAAW;AACjC,UAAQ,SAAS,aAAa;AAC9B,QAAM,SAAS,qBAAqB;AACpC,MAAI,OAAQ,SAAQ,iBAAiB;AACrC,gBAAc,QAAQ,SAAS,WAAW,OAAO,SAAS;AAC5D;AAcO,SAAS,iBACd,MACA,SACA,QACA,SACsB;AACtB,QAAM,MAAM,QAAQ,IAAI;AACxB,QAAM,iBAAiB,SAAS,sBAAsB,MAAM,IAAI;AAChE,QAAM,UAAoE;AAAA,IACxE,SAAS,cAAc;AAAA,IACvB,aAAa,kBAAkB;AAAA,IAC/B;AAAA,EACF;AACA,MAAI,eAAgB,SAAQ,SAAS;AACrC,UAAQ,SAAS,aAAa;AAC9B,QAAM,cAAc,eAAe,GAAG;AACtC,MAAI,YAAa,SAAQ,cAAc;AACvC,QAAM,YAAY,gBAAgB,GAAG;AACrC,MAAI,UAAW,SAAQ,YAAY;AACnC,QAAM,WAAW,eAAe,GAAG;AACnC,MAAI,SAAU,SAAQ,WAAW;AACjC,QAAM,SAAS,qBAAqB;AACpC,MAAI,OAAQ,SAAQ,iBAAiB;AACrC,SAAO,cAAc,MAAM,SAAS,OAAO;AAC7C;;;AC5YA,SAAS,yBAAyB;AAElC,IAAM,UAAU,IAAI,kBAAiC;AAK9C,SAAS,aAAwC;AACtD,SAAO,QAAQ,SAAS;AAC1B;AAOO,SAAS,cACd,UACA,IACY;AACZ,QAAM,aAAa,SAAS,KAAK,KAAK;AACtC,MAAI,eAAe,QAAW;AAC5B,WAAO,QAAQ;AAAA,MACb,IAAI,MAAM,oDAAoD;AAAA,IAChE;AAAA,EACF;AACA,SAAO,QAAQ;AAAA,IACb,QAAQ,IAAI,EAAE,UAAU,WAAW,GAAG,MAAM,GAAG,CAAC;AAAA,EAClD;AACF;AAKO,SAAS,eACd,SACA,IACY;AACZ,SAAO,QAAQ,QAAQ,QAAQ,IAAI,SAAS,MAAM,GAAG,CAAC,CAAC;AACzD;;;AC1BO,SAAS,cAAuB;AACrC,QAAM,UAAU,WAAW;AAC3B,SAAO,SAAS;AAClB;AAeA,eAAsB,yBACpB,UACA,SACA,IACA,SACY;AACZ,QAAM,SAAS,MAAM,QAAQ,cAAc,UAAU,OAAO,aAAa;AACvE,QAAI,UAAyB,EAAE,UAAU,SAAS;AAClD,UAAM,sBAAsB,SAAS;AACrC,QACE,SAAS,cACT,uBACA,QAAQ,aACR;AACA,YAAM,SAAS,MAAM,QAAQ;AAAA,QAAY,CAAC,aACxC,oBAAoB,QAAQ,EAAE,QAAQ,QAAQ;AAAA,MAChD;AACA,gBAAU,UAAU,OAAO,EAAE,GAAG,SAAS,OAAO,IAAI;AAAA,IACtD;AACA,WAAO,eAAe,SAAS,MAAM,GAAG,QAAQ,CAAC;AAAA,EACnD,CAAC;AACD,SAAO;AACT;;;ACtDO,IAAM,yBAAN,cAAqC,MAAM;AAAA,EAChD,YAAY,UAAU,4DAA4D;AAChF,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,wBAAN,cAAoC,MAAM;AAAA,EAC/C,YACE,UAAU,kDACV,SACA;AACA,UAAM,SAAS,OAAO;AACtB,SAAK,OAAO;AAAA,EACd;AACF;;;ACIA,eAAsB,cACpB,SACA,MACA,SACiB;AACjB,QAAM,WAAW,MAAM,QAAQ,cAAc,OAAO;AACpD,QAAM,qBAAqB,UAAU,KAAK;AAC1C,MAAI,CAAC,oBAAoB;AACvB,QAAI,QAAQ,iBAAiB;AAC3B,aAAO,QAAQ,gBAAgB,OAAO;AAAA,IACxC;AAEA,UAAM,QAAQ,IAAI,uBAAuB;AACzC,QAAI,QAAQ,SAAS;AACnB,aAAO,QAAQ,QAAQ,OAAO,OAAO;AAAA,IACvC;AACA,UAAM;AAAA,EACR;AAEA,MAAI;AACF,WAAO,MAAM;AAAA,MACX;AAAA,MACA,QAAQ;AAAA,MACR,YAAY,KAAK;AAAA,IACnB;AAAA,EACF,SAAS,OAAO;AACd,QAAI,QAAQ,SAAS;AACnB,aAAO,QAAQ,QAAQ,OAAO,OAAO;AAAA,IACvC;AAEA,QACE,iBAAiB,0BACjB,iBAAiB,uBACjB;AACA,YAAM;AAAA,IACR;AAEA,UAAM,IAAI,sBAAsB,QAAW,EAAE,OAAO,MAAM,CAAC;AAAA,EAC7D;AACF;;;ACtDA,IAAM,qBAAqB;AAiB3B,SAAS,mBACP,SACsD;AACtD,MAAI,CAAC,QAAQ,aAAa;AACxB,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,SAAO,QAAQ;AACjB;AAOO,SAAS,gBACd,SACA,qBACA;AACA,SAAO;AAAA,IACL,MAAM,aAAa,MAAyC;AAC1D,UAAI,CAAC,KAAK,MAAM,KAAK,GAAG;AACtB,cAAM,IAAI,MAAM,2CAA2C;AAAA,MAC7D;AACA,UAAI,CAAC,KAAK,MAAM,KAAK,GAAG;AACtB,cAAM,IAAI,MAAM,2CAA2C;AAAA,MAC7D;AACA,YAAMC,eAAc,mBAAmB,OAAO;AAC9C,aAAOA;AAAA,QAAY,CAAC,aAClB,oBAAoB,QAAQ,EAAE,OAAO;AAAA,UACnC,MAAM,KAAK,KAAK,KAAK;AAAA,UACrB,MAAM,KAAK,KAAK,KAAK;AAAA,QACvB,CAAC;AAAA,MACH;AAAA,IACF;AAAA,IAEA,MAAM,aACJ,UACA,MACiB;AACjB,UAAI,CAAC,UAAU,KAAK,GAAG;AACrB,cAAM,IAAI,MAAM,+CAA+C;AAAA,MACjE;AACA,YAAMA,eAAc,mBAAmB,OAAO;AAC9C,aAAOA;AAAA,QAAY,CAAC,aAClB,oBAAoB,QAAQ,EAAE,OAAO,UAAU;AAAA,UAC7C,GAAI,KAAK,SAAS,UAAa,EAAE,MAAM,KAAK,KAAK;AAAA,UACjD,GAAI,KAAK,SAAS,UAAa,EAAE,MAAM,KAAK,KAAK;AAAA,QACnD,CAAC;AAAA,MACH;AAAA,IACF;AAAA,IAEA,MAAM,YAAY,UAA8B,CAAC,GAAsB;AACrE,YAAM,QAAQ,QAAQ,SAAS;AAC/B,YAAM,SAAS,KAAK,IAAI,GAAG,QAAQ,UAAU,CAAC;AAC9C,YAAMA,eAAc,mBAAmB,OAAO;AAC9C,aAAOA;AAAA,QAAY,CAAC,aAClB,oBAAoB,QAAQ,EAAE,KAAK,EAAE,OAAO,OAAO,CAAC;AAAA,MACtD;AAAA,IACF;AAAA,IAEA,MAAM,aAAa,UAAiC;AAClD,UAAI,CAAC,UAAU,KAAK,GAAG;AACrB,cAAM,IAAI,MAAM,+CAA+C;AAAA,MACjE;AACA,YAAMA,eAAc,mBAAmB,OAAO;AAC9C,aAAOA;AAAA,QAAY,CAAC,aAClB,oBAAoB,QAAQ,EAAE,OAAO,QAAQ;AAAA,MAC/C;AAAA,IACF;AAAA,IAEA,MAAM,UAAU,UAA0C;AACxD,UAAI,CAAC,UAAU,KAAK,GAAG;AACrB,cAAM,IAAI,MAAM,4CAA4C;AAAA,MAC9D;AACA,YAAMA,eAAc,mBAAmB,OAAO;AAC9C,aAAOA;AAAA,QAAY,CAAC,aAClB,oBAAoB,QAAQ,EAAE,QAAQ,QAAQ;AAAA,MAChD;AAAA,IACF;AAAA,IAEA,MAAM,eAAgC;AACpC,YAAMA,eAAc,mBAAmB,OAAO;AAC9C,aAAOA;AAAA,QAAY,CAAC,aAClB,oBAAoB,QAAQ,EAAE,MAAM;AAAA,MACtC;AAAA,IACF;AAAA,EACF;AACF;AAMA,eAAsB,MACpB,UACA,SACA,IACY;AACZ,SAAO,yBAAyB,UAAU,SAAS,EAAE;AACvD;AAMA,eAAsB,YACpB,SACA,IACY;AACZ,QAAM,MAAM,mBAAmB,OAAO;AACtC,SAAO,eAAe,EAAE,UAAU,KAAK,GAAG,MAAM,IAAI,EAAE,CAAC;AACzD;;;AC9HA,SAAS,UACP,SACA,MACoB;AACpB,QAAM,MAAM,KAAK,YAAY;AAC7B,MAAI,mBAAmB,SAAS;AAC9B,UAAMC,SAAQ,QAAQ,IAAI,GAAG;AAC7B,WAAOA,QAAO,KAAK,KAAK;AAAA,EAC1B;AACA,QAAM,MAAM,QAAQ,GAAG,KAAK,QAAQ,IAAI;AACxC,MAAI,QAAQ,QAAW;AACrB,WAAO;AAAA,EACT;AACA,QAAM,QAAQ,MAAM,QAAQ,GAAG,IAAI,IAAI,CAAC,IAAI;AAC5C,UAAQ,OAAO,UAAU,WAAW,QAAQ,IAAI,KAAK,KAAK;AAC5D;AAEA,SAAS,kBACP,SACA,YACoB;AACpB,MAAI,CAAC,YAAY;AACf,WAAO;AAAA,EACT;AACA,SAAO,UAAU,QAAQ,SAAS,UAAU;AAC9C;AAEA,SAAS,gBACP,SACA,YACoB;AACpB,QAAM,YAAY,QAAQ,QAAQ,QAAQ;AAC1C,MAAI,CAAC,WAAW;AACd,WAAO;AAAA,EACT;AAEA,MAAI;AACJ,MAAI;AACF,WAAO,UAAU,WAAW,MAAM,IAC9B,IAAI,IAAI,SAAS,EAAE,WACnB;AAAA,EACN,QAAQ;AACN,WAAO;AAAA,EACT;AAEA,QAAM,UACJ,OAAO,eAAe,WAAW,aAAa,WAAW;AAC3D,QAAM,eACJ,OAAO,eAAe,YAAY,WAAW,iBAAiB,SAC1D,WAAW,eACX,wBAAwB,OAAO;AAErC,QAAM,WAAW,KAAK,MAAM,GAAG,EAAE,OAAO,OAAO;AAC/C,QAAM,QAAQ,SAAS,YAAY;AACnC,SAAO,OAAO,UAAU,YAAY,MAAM,SAAS,IAAI,QAAQ;AACjE;AAGA,SAAS,wBAAwB,SAAyB;AACxD,QAAM,WAAW,QAAQ,MAAM,GAAG,EAAE,OAAO,OAAO;AAClD,QAAM,MAAM,SAAS,QAAQ,WAAW;AACxC,SAAO,OAAO,IAAI,MAAM;AAC1B;AAEA,SAAS,qBACP,SACA,QACoB;AACpB,QAAM,OAAO,QAAQ,SAAS,QAAQ,MAAM,IAAI,IAAI,QAAQ,GAAG,EAAE,OAAO;AACxE,MAAI,CAAC,MAAM;AACT,WAAO;AAAA,EACT;AACA,QAAM,WAAW,KAAK,MAAM,GAAG,EAAE,CAAC;AAClC,MAAI,CAAC,UAAU;AACb,WAAO;AAAA,EACT;AACA,QAAM,QAAQ,SAAS,MAAM,GAAG;AAEhC,MAAI,MAAM,UAAU,GAAG;AACrB,WAAO;AAAA,EACT;AACA,QAAM,QACJ,WAAW,OACP,IACA,OAAO,WAAW,YAAY,OAAO,iBAAiB,SACpD,OAAO,eACP;AACR,QAAM,QAAQ,MAAM,KAAK;AACzB,SAAO,OAAO,UAAU,YAAY,MAAM,SAAS,IAAI,QAAQ;AACjE;AAEA,SAAS,iBAAiB,OAA+C;AACvE,MAAI;AACF,UAAM,QAAQ,MAAM,MAAM,GAAG;AAC7B,QAAI,MAAM,SAAS,GAAG;AACpB,aAAO;AAAA,IACT;AACA,UAAM,UAAU,MAAM,CAAC;AACvB,QAAI,CAAC,SAAS;AACZ,aAAO;AAAA,IACT;AACA,UAAM,UAAU,KAAK,QAAQ,QAAQ,MAAM,GAAG,EAAE,QAAQ,MAAM,GAAG,CAAC;AAClE,UAAM,SAAkB,KAAK,MAAM,OAAO;AAC1C,QAAI,OAAO,WAAW,YAAY,WAAW,MAAM;AACjD,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAe,eACb,SACA,QAC6B;AAC7B,QAAM,WAAW,QAAQ;AACzB,MAAI,CAAC,UAAU;AACb,WAAO;AAAA,EACT;AACA,QAAM,QAAQ,OAAO,aAAa,aAAa,SAAS,IAAI;AAC5D,QAAM,QAAQ,iBAAiB,UAAU,MAAM,QAAQ;AACvD,QAAM,WAAW,SAAS;AAC1B,MAAI,CAAC,UAAU;AACb,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ,OAAO,WAAW,WAAW,SAAS,OAAO;AAC3D,MAAI,CAAC,OAAO;AACV,WAAO;AAAA,EACT;AAEA,QAAM,cACJ,OAAO,WAAW,WAAW,OAAO,cAAc;AAEpD,MAAI;AACJ,MAAI,aAAa;AACf,cAAU,MAAM,YAAY,QAAQ;AAAA,EACtC,OAAO;AACL,cAAU,iBAAiB,QAAQ;AAAA,EACrC;AAEA,MAAI,CAAC,SAAS;AACZ,WAAO;AAAA,EACT;AAEA,QAAM,aAAa,QAAQ,KAAK;AAChC,SAAO,OAAO,eAAe,YAAY,WAAW,SAAS,IACzD,aACA;AACN;AAMO,SAAS,mBAAmB,QAAwC;AACzE,QAAM,aAAuB,CAAC;AAC9B,MAAI,OAAO,WAAW,QAAW;AAC/B,eAAW,KAAK,WAAW,OAAO,MAAM,GAAG;AAAA,EAC7C;AACA,MAAI,OAAO,SAAS,QAAW;AAC7B,UAAM,UACJ,OAAO,OAAO,SAAS,WAAW,OAAO,OAAO,OAAO,KAAK;AAC9D,eAAW,KAAK,SAAS,OAAO,GAAG;AAAA,EACrC;AACA,MAAI,OAAO,cAAc,UAAa,OAAO,cAAc,OAAO;AAChE,eAAW,KAAK,WAAW;AAAA,EAC7B;AACA,MAAI,OAAO,QAAQ,QAAW;AAC5B,UAAM,QACJ,OAAO,OAAO,QAAQ,WAAW,OAAO,MAAM,OAAO,IAAI;AAC3D,eAAW,KAAK,cAAc,KAAK,GAAG;AAAA,EACxC;AACA,MAAI,OAAO,WAAW,QAAW;AAC/B,eAAW,KAAK,iBAAiB;AAAA,EACnC;AACA,SAAO;AACT;AAMA,eAAsB,cACpB,SACA,QAC6B;AAC7B,MAAI,OAAO,WAAW,QAAW;AAC/B,UAAM,IAAI,kBAAkB,SAAS,OAAO,MAAM;AAClD,QAAI,MAAM,QAAW;AACnB,aAAO;AAAA,IACT;AAAA,EACF;AACA,MAAI,OAAO,SAAS,QAAW;AAC7B,UAAM,IAAI,gBAAgB,SAAS,OAAO,IAAI;AAC9C,QAAI,MAAM,QAAW;AACnB,aAAO;AAAA,IACT;AAAA,EACF;AACA,MAAI,OAAO,cAAc,UAAa,OAAO,cAAc,OAAO;AAChE,UAAM,IAAI,qBAAqB,SAAS,OAAO,SAAS;AACxD,QAAI,MAAM,QAAW;AACnB,aAAO;AAAA,IACT;AAAA,EACF;AACA,MAAI,OAAO,QAAQ,QAAW;AAC5B,UAAM,IAAI,MAAM,eAAe,SAAS,OAAO,GAAG;AAClD,QAAI,MAAM,QAAW;AACnB,aAAO;AAAA,IACT;AAAA,EACF;AACA,MAAI,OAAO,WAAW,QAAW;AAC/B,UAAM,IAAI,MAAM,QAAQ,QAAQ,OAAO,OAAO,OAAO,CAAC;AACtD,QAAI,OAAO,MAAM,YAAY,EAAE,SAAS,GAAG;AACzC,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;;;AC3NO,SAAS,cAAc,OAAkD;AAC9E,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAOO,SAAS,gBACd,OACA,KACA,KACoB;AACpB,MAAI,UAAU,QAAW;AACvB,WAAO;AAAA,EACT;AACA,QAAM,SAAS,OAAO,KAAK;AAC3B,MAAI,CAAC,OAAO,SAAS,MAAM,KAAK,SAAS,KAAK;AAC5C,WAAO;AAAA,EACT;AACA,SAAO,KAAK,IAAI,KAAK,MAAM,MAAM,GAAG,GAAG;AACzC;;;AChBA,IAAM,mBAAmB;AAEzB,SAAS,gBAAgB,QAA4B;AACnD,SAAO;AAAA,IACL,GAAG;AAAA,IACH,WACE,OAAO,qBAAqB,OACxB,OAAO,UAAU,YAAY,IAC7B,OAAO;AAAA,EACf;AACF;AAEO,SAAS,6BACd,KAC0B;AAC1B,SAAO;AAAA,IACL;AAAA,MACE,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,oBAAoB;AAAA,MACpB,MAAM,QAAQ,SAAgC;AAC5C,YAAI;AACF,gBAAM,UAA+C,CAAC;AACtD,cAAI,QAAQ,MAAM,UAAU,QAAW;AACrC,kBAAM,QAAQ,gBAAgB,QAAQ,MAAM,OAAO,GAAG,GAAI;AAC1D,gBAAI,UAAU,QAAW;AACvB,qBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,yDAAyD,EAAiC;AAAA,YACjI;AACA,oBAAQ,QAAQ;AAAA,UAClB;AACA,cAAI,QAAQ,MAAM,WAAW,QAAW;AACtC,kBAAM,SAAS,gBAAgB,QAAQ,MAAM,QAAQ,GAAG,OAAO,gBAAgB;AAC/E,gBAAI,WAAW,QAAW;AACxB,qBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,mDAAmD,EAAiC;AAAA,YAC3H;AACA,oBAAQ,SAAS;AAAA,UACnB;AACA,gBAAM,UAAU,MAAM,IAAI,YAAY,OAAO;AAC7C,iBAAO,EAAE,QAAQ,KAAK,MAAM,QAAQ,IAAI,eAAe,EAAyB;AAAA,QAClF,QAAQ;AACN,iBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,wBAAwB,EAAiC;AAAA,QAChG;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,oBAAoB;AAAA,MACpB,MAAM,QAAQ,SAAgC;AAC5C,YAAI;AACF,gBAAM,KAAK,QAAQ,OAAO,IAAI,KAAK;AACnC,cAAI,CAAC,IAAI;AACP,mBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,oBAAoB,EAAiC;AAAA,UAC5F;AACA,gBAAM,SAAS,MAAM,IAAI,UAAU,EAAE;AACrC,cAAI,CAAC,QAAQ;AACX,mBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,mBAAmB,EAAiC;AAAA,UAC3F;AACA,iBAAO,EAAE,QAAQ,KAAK,MAAM,gBAAgB,MAAM,EAAuB;AAAA,QAC3E,QAAQ;AACN,iBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,wBAAwB,EAAiC;AAAA,QAChG;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,oBAAoB;AAAA,MACpB,MAAM,QAAQ,SAAgC;AAC5C,YAAI;AACF,cAAI,CAAC,cAAc,QAAQ,IAAI,GAAG;AAChC,mBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,2BAA2B,EAAiC;AAAA,UACnG;AACA,gBAAM,OAAO,OAAO,QAAQ,KAAK,SAAS,WAAW,QAAQ,KAAK,OAAO;AACzE,gBAAM,OAAO,OAAO,QAAQ,KAAK,SAAS,WAAW,QAAQ,KAAK,OAAO;AACzE,cAAI,CAAC,KAAK,KAAK,KAAK,CAAC,KAAK,KAAK,GAAG;AAChC,mBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,6BAA6B,EAAiC;AAAA,UACrG;AACA,cAAI,KAAK,SAAS,oBAAoB,KAAK,SAAS,kBAAkB;AACpE,mBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,+CAA+C,EAAiC;AAAA,UACvH;AACA,gBAAM,SAAS,MAAM,IAAI,aAAa,EAAE,MAAM,KAAK,CAAC;AACpD,iBAAO,EAAE,QAAQ,KAAK,MAAM,gBAAgB,MAAM,EAAuB;AAAA,QAC3E,QAAQ;AACN,iBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,wBAAwB,EAAiC;AAAA,QAChG;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,oBAAoB;AAAA,MACpB,MAAM,QAAQ,SAAgC;AAC5C,YAAI;AACF,gBAAM,KAAK,QAAQ,OAAO,IAAI,KAAK;AACnC,cAAI,CAAC,IAAI;AACP,mBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,oBAAoB,EAAiC;AAAA,UAC5F;AACA,cAAI,CAAC,cAAc,QAAQ,IAAI,GAAG;AAChC,mBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,2BAA2B,EAAiC;AAAA,UACnG;AACA,gBAAM,OAAyC,CAAC;AAChD,cAAI,OAAO,QAAQ,KAAK,SAAS,UAAU;AACzC,gBAAI,QAAQ,KAAK,KAAK,SAAS,kBAAkB;AAC/C,qBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,sCAAsC,EAAiC;AAAA,YAC9G;AACA,iBAAK,OAAO,QAAQ,KAAK;AAAA,UAC3B;AACA,cAAI,OAAO,QAAQ,KAAK,SAAS,UAAU;AACzC,gBAAI,QAAQ,KAAK,KAAK,SAAS,kBAAkB;AAC/C,qBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,sCAAsC,EAAiC;AAAA,YAC9G;AACA,iBAAK,OAAO,QAAQ,KAAK;AAAA,UAC3B;AACA,gBAAM,SAAS,MAAM,IAAI,aAAa,IAAI,IAAI;AAC9C,iBAAO,EAAE,QAAQ,KAAK,MAAM,gBAAgB,MAAM,EAAuB;AAAA,QAC3E,QAAQ;AACN,iBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,wBAAwB,EAAiC;AAAA,QAChG;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,oBAAoB;AAAA,MACpB,MAAM,QAAQ,SAAgC;AAC5C,YAAI;AACF,gBAAM,KAAK,QAAQ,OAAO,IAAI,KAAK;AACnC,cAAI,CAAC,IAAI;AACP,mBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,oBAAoB,EAAiC;AAAA,UAC5F;AACA,gBAAM,IAAI,aAAa,EAAE;AACzB,iBAAO,EAAE,QAAQ,KAAK,MAAM,KAAK;AAAA,QACnC,QAAQ;AACN,iBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,wBAAwB,EAAiC;AAAA,QAChG;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,oBAAoB;AAAA,MACpB,MAAM,UAAU;AACd,YAAI;AACF,gBAAM,cAAc,MAAM,IAAI,aAAa;AAC3C,iBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,YAAY,EAAgC;AAAA,QAC5E,QAAQ;AACN,iBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,wBAAwB,EAAiC;AAAA,QAChG;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;;;AC7IA,IAAM,UACJ;AAUF,eAAe,sBACb,YACA,gBACA,SACA,qBAC6B;AAC7B,MAAI,eAAe,aAAa;AAC9B,WAAO,eAAe,YAAY,UAAU;AAAA,EAC9C;AACA,MAAI,QAAQ,KAAK,UAAU,GAAG;AAC5B,WAAO;AAAA,EACT;AACA,MAAI,QAAQ,aAAa;AACvB,UAAM,SAAS,MAAM,QAAQ;AAAA,MAAY,CAAC,aACxC,oBAAoB,QAAQ,EAAE,UAAU,UAAU;AAAA,IACpD;AACA,WAAO,QAAQ;AAAA,EACjB;AACA,SAAO;AACT;AAqCO,SAAS,aACd,QACgC;AAChC,QAAM,EAAE,UAAU,gBAAgB,WAAW,IAAI;AACjD,QAAM,EAAE,SAAS,oBAAoB,IAAI;AAEzC,oBAAkB,QAAQ,OAAO,SAAS;AAE1C,QAAM,MAAM,gBAAgB,SAAS,mBAAmB;AAExD,QAAM,kCAGJ,eAAe,QACX,EAAE,YAAY,MAAe,oBAAoB,IACjD;AAEN,QAAM,qBAAqB,mBAAmB,cAAc;AAG5D,iBAAe,oBACb,SAC6B;AAC7B,UAAM,MAAM,MAAM,cAAc,SAAS,cAAc;AACvD,QAAI,CAAC,IAAK,QAAO;AACjB,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,MAAI,OAAO,SAAS;AAClB,UAAM,YAAY,6BAA6B,GAAG;AAClD,WAAO,QAAQ,gBAAgB;AAAA,MAC7B,IAAI;AAAA,MACJ,MAAM;AAAA,MACN;AAAA,IACF,CAAC;AAAA,EACH;AAEA,SAAO;AAAA,IACL;AAAA,IACA,aAAa,MAAM,YAAY;AAAA,IAC/B;AAAA,IACA,OAAO,CAAC,UAAU,OAChB;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACF,aAAa,CAAI,OACf,YAAuB,SAAS,EAAE;AAAA,IACpC,eAAe;AAAA,IACf;AAAA,IACA,eAAe,CAAC,SAAS,MAAM,YAC7B,cAAoB,SAAS,MAAM;AAAA,MACjC,GAAG;AAAA,MACH,eAAe;AAAA,MACf;AAAA,IACF,CAAC;AAAA,IACH;AAAA,EACF;AACF;;;AC/IA,SAAS,eAAe,OAAkC;AACxD,SAAO,OAAO,YAAY,eAAe,iBAAiB;AAC5D;AAEA,SAAS,cAAc,KAA6C;AAClE,MAAI,CAAC,KAAK;AACR,WAAO;AAAA,EACT;AACA,QAAM,QAAQ,IAAI,MAAM,GAAG,EAAE,CAAC,GAAG,KAAK;AACtC,SAAO,SAAS;AAClB;AAEA,SAAS,iBACP,SACa;AACb,MAAI,CAAC,SAAS;AACZ,WAAO,CAAC;AAAA,EACV;AACA,QAAM,aAA0B,CAAC;AACjC,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,OAAO,GAAG;AAClD,UAAM,gBAAgB,IAAI,YAAY;AACtC,QAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,iBAAW,aAAa,IAAI,MAAM,IAAI,CAAC,SAAS,OAAO,IAAI,CAAC;AAC5D;AAAA,IACF;AACA,QAAI,UAAU,QAAW;AACvB,iBAAW,aAAa,IAAI;AAC5B;AAAA,IACF;AACA,eAAW,aAAa,IAAI,OAAO,KAAK;AAAA,EAC1C;AACA,SAAO;AACT;AAEA,SAAS,iBAAiB,OAA+C;AACvE,MAAI,CAAC,OAAO;AACV,WAAO;AAAA,EACT;AACA,QAAM,CAAC,QAAQ,IAAI,MAAM,MAAM,GAAG;AAClC,SAAO,YAAY;AACrB;AAEO,SAAS,oBACd,SACmB;AACnB,MAAI,eAAe,OAAO,GAAG;AAC3B,UAAM,MAAM,QAAQ;AACpB,QAAIC;AACJ,QAAIC;AACJ,QAAI;AACF,YAAM,YAAY,IAAI,IAAI,GAAG;AAC7B,MAAAD,QAAO,cAAc,UAAU,IAAI;AACnC,MAAAC,QAAO,UAAU,YAAY;AAAA,IAC/B,QAAQ;AACN,MAAAD,QAAO;AACP,MAAAC,QAAO;AAAA,IACT;AACA,UAAMC,YAA8B;AAAA,MAClC,SAAS,QAAQ;AAAA,MACjB;AAAA,MACA,QAAQ,QAAQ;AAAA,IAClB;AACA,QAAID,UAAS,QAAW;AACtB,MAAAC,UAAS,OAAOD;AAAA,IAClB;AACA,QAAID,UAAS,QAAW;AACtB,MAAAE,UAAS,OAAOF;AAAA,IAClB;AACA,WAAOE;AAAA,EACT;AAEA,QAAM,UAAU,iBAAiB,QAAQ,OAAO;AAChD,QAAM,kBAAkB,QAAQ;AAChC,QAAM,YAAY,MAAM,QAAQ,eAAe,IAC3C,gBAAgB,CAAC,IACjB;AACJ,QAAM,OAAO,cAAc,QAAQ,YAAY,QAAQ,QAAQ,SAAS;AACxE,QAAM,OAAO;AAAA,IACX,QAAQ,QAAQ,QAAQ,eAAe,QAAQ;AAAA,EACjD;AAEA,QAAM,WAA8B;AAAA,IAClC;AAAA,EACF;AACA,MAAI,SAAS,QAAW;AACtB,aAAS,OAAO;AAAA,EAClB;AACA,MAAI,SAAS,QAAW;AACtB,aAAS,OAAO;AAAA,EAClB;AACA,MAAI,QAAQ,WAAW,QAAW;AAChC,aAAS,SAAS,QAAQ;AAAA,EAC5B;AACA,SAAO;AACT;","names":["v","runAsSystem","value","host","path","resolved"]}
package/dist/types.d.ts CHANGED
@@ -71,16 +71,10 @@ export interface TenantRepository {
71
71
  delete(tenantId: string): Promise<void>;
72
72
  count(): Promise<number>;
73
73
  }
74
- /** Path resolver: pattern e.g. "/t/:tenantId/*" or "/t/:tenantId". */
75
- export interface PathResolverConfig {
76
- pattern: string;
77
- /** Segment index for :tenantId (default derived from pattern). */
78
- segmentIndex?: number;
79
- }
80
- /** Subdomain resolver: use segment index (default 0 = first segment). */
81
- export type SubdomainResolverConfig = boolean | {
82
- segmentIndex?: number;
83
- };
74
+ import type { PathResolverConfig, SubdomainResolverConfig, TelemetryConfig } from "@usebetterdev/contract/config-types";
75
+ export type { PathResolverConfig, SubdomainResolverConfig, TelemetryConfig } from "@usebetterdev/contract/config-types";
76
+ import type { ConsoleRegistration } from "@usebetterdev/contract";
77
+ export type { ConsoleRegistration } from "@usebetterdev/contract";
84
78
  /**
85
79
  * JWT resolver: claim key to read from payload (e.g. "tenant_id").
86
80
  *
@@ -127,13 +121,6 @@ export interface BetterTenantPlugin {
127
121
  schema?: Record<string, unknown>;
128
122
  hooks?: Record<string, unknown>;
129
123
  }
130
- /** Telemetry options. On by default; set enabled: false to opt out. */
131
- export interface TelemetryConfig {
132
- enabled?: boolean;
133
- debug?: boolean;
134
- }
135
- import type { ConsoleRegistration } from "@usebetterdev/console-contract";
136
- export type { ConsoleRegistration } from "@usebetterdev/console-contract";
137
124
  export interface BetterTenantConfig<TDb = unknown, SDb = unknown> {
138
125
  database: DatabaseProvider<TDb, SDb>;
139
126
  tenantResolver: TenantResolverConfig;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,WAAW,MAAM;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,IAAI,GAAG,MAAM,CAAC;IACzB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;;;;GAKG;AACH,MAAM,MAAM,oBAAoB,GAAG,OAAO,CAAC;AAE3C;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,OAAO,CAAC;AAErC;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,oEAAoE;IACpE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uFAAuF;IACvF,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,oCAAoC;IACpC,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,aAAa,CAAC,GAAG,GAAG,OAAO,EAAE,GAAG,GAAG,OAAO;IACzD,aAAa,CAAC,CAAC,EACb,QAAQ,EAAE,MAAM,EAChB,EAAE,EAAE,CAAC,QAAQ,EAAE,GAAG,KAAK,OAAO,CAAC,CAAC,CAAC,GAChC,OAAO,CAAC,CAAC,CAAC,CAAC;IACd,uFAAuF;IACvF,WAAW,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,QAAQ,EAAE,GAAG,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CAChE;AAED,+DAA+D;AAC/D,MAAM,WAAW,gBAAgB,CAAC,GAAG,GAAG,OAAO,EAAE,GAAG,GAAG,OAAO;IAC5D,OAAO,EAAE,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IACjC,mBAAmB,EAAE,CAAC,QAAQ,EAAE,GAAG,KAAK,gBAAgB,CAAC;CAC1D;AAED,wGAAwG;AACxG,MAAM,WAAW,gBAAgB;IAC/B,MAAM,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC9D,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAClD,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAChD,MAAM,CACJ,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC,GAC3C,OAAO,CAAC,MAAM,CAAC,CAAC;IACnB,IAAI,CAAC,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACvE,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;CAC1B;AAED,sEAAsE;AACtE,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,kEAAkE;IAClE,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,yEAAyE;AACzE,MAAM,MAAM,uBAAuB,GAAG,OAAO,GAAG;IAAE,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1E;;;;;;GAMG;AACH,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,WAAW,CAAC,EAAE,CACZ,KAAK,EAAE,MAAM,KAEX,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACvB,IAAI,GACJ,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC;CAC7C;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,GAAG,kBAAkB,CAAC;IACnC,SAAS,CAAC,EAAE,uBAAuB,CAAC;IACpC,kIAAkI;IAClI,GAAG,CAAC,EAAE,MAAM,GAAG,iBAAiB,CAAC;IACjC,MAAM,CAAC,EAAE,CACP,OAAO,EAAE,iBAAiB,KACvB,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACtD,wOAAwO;IACxO,WAAW,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;CACxF;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC;IACjE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,MAAM,GAAG,IAAI,CAAC;CACzD;AAED,iFAAiF;AACjF,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED,uEAAuE;AACvE,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAC1E,YAAY,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAE1E,MAAM,WAAW,kBAAkB,CAAC,GAAG,GAAG,OAAO,EAAE,GAAG,GAAG,OAAO;IAC9D,QAAQ,EAAE,gBAAgB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IACrC,cAAc,EAAE,oBAAoB,CAAC;IACrC,OAAO,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8IAA8I;IAC9I,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,mGAAmG;IACnG,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,gGAAgG;IAChG,OAAO,CAAC,EAAE,mBAAmB,CAAC;CAC/B;AAED,uFAAuF;AACvF,MAAM,WAAW,+BAA+B,CAAC,GAAG,GAAG,OAAO;IAC5D,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,mBAAmB,EAAE,CAAC,QAAQ,EAAE,GAAG,KAAK,gBAAgB,CAAC;CAC1D"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@usebetterdev/tenant-core",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
4
4
  "repository": "github:usebetter-dev/usebetter",
5
5
  "bugs": "https://github.com/usebetter-dev/usebetter/issues",
6
6
  "homepage": "https://github.com/usebetter-dev/usebetter#readme",
@@ -28,7 +28,7 @@
28
28
  "tsup": "^8.3.5",
29
29
  "typescript": "~5.7.2",
30
30
  "vitest": "^2.1.6",
31
- "@usebetterdev/console-contract": "0.5.0",
31
+ "@usebetterdev/contract": "0.6.0",
32
32
  "@usebetterdev/console-utils": "0.5.0-beta.1"
33
33
  },
34
34
  "engines": {