@objectstack/rest 4.0.5 → 4.1.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.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/route-manager.ts","../src/rest-server.ts","../src/package-routes.ts","../src/rest-api-plugin.ts"],"sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { RouteHandler, IHttpServer } from '@objectstack/core';\nimport * as System from '@objectstack/spec/system';\nimport * as Shared from '@objectstack/spec/shared';\nimport { z } from 'zod';\n\ntype RouteHandlerMetadata = System.RouteHandlerMetadata;\ntype HttpMethod = z.infer<typeof Shared.HttpMethod>;\n\n/**\n * Route Entry\n * Internal representation of registered routes\n */\nexport interface RouteEntry {\n method: HttpMethod;\n path: string;\n handler: RouteHandler;\n metadata?: RouteHandlerMetadata['metadata'];\n security?: RouteHandlerMetadata['security'];\n}\n\n/**\n * RouteManager\n * \n * Manages route registration and organization for HTTP servers.\n * Provides:\n * - Route registration with metadata\n * - Route lookup and querying\n * - Bulk route registration\n * - Route grouping by prefix\n * \n * @example\n * const manager = new RouteManager(server);\n * \n * // Register individual route\n * manager.register({\n * method: 'GET',\n * path: '/api/users/:id',\n * handler: getUserHandler,\n * metadata: {\n * summary: 'Get user by ID',\n * tags: ['users']\n * }\n * });\n * \n * // Register route group\n * manager.group('/api/users', (group) => {\n * group.get('/', listUsersHandler);\n * group.post('/', createUserHandler);\n * group.get('/:id', getUserHandler);\n * });\n */\nexport class RouteManager {\n private server: IHttpServer;\n private routes: Map<string, RouteEntry>;\n \n constructor(server: IHttpServer) {\n this.server = server;\n this.routes = new Map();\n }\n \n /**\n * Register a route\n * @param entry - Route entry with method, path, handler, and metadata\n */\n register(entry: Omit<RouteEntry, 'handler'> & { handler: RouteHandler | string }): void {\n // Validate handler type - string handlers not yet supported\n if (typeof entry.handler === 'string') {\n throw new Error(\n `String-based route handlers are not supported yet. ` +\n `Received handler identifier \"${entry.handler}\". ` +\n `Please provide a RouteHandler function instead.`\n );\n }\n \n const handler: RouteHandler = entry.handler;\n \n const routeEntry: RouteEntry = {\n method: entry.method,\n path: entry.path,\n handler,\n metadata: entry.metadata,\n security: entry.security,\n };\n \n const key = this.getRouteKey(entry.method, entry.path);\n this.routes.set(key, routeEntry);\n \n // Register with underlying server\n this.registerWithServer(routeEntry);\n }\n \n /**\n * Register multiple routes\n * @param entries - Array of route entries\n */\n registerMany(entries: Array<Omit<RouteEntry, 'handler'> & { handler: RouteHandler | string }>): void {\n entries.forEach(entry => this.register(entry));\n }\n \n /**\n * Unregister a route\n * @param method - HTTP method\n * @param path - Route path\n */\n unregister(method: HttpMethod, path: string): void {\n const key = this.getRouteKey(method, path);\n this.routes.delete(key);\n // Note: Most server frameworks don't support unregistering routes at runtime\n // This just removes it from our registry\n }\n \n /**\n * Get route by method and path\n * @param method - HTTP method\n * @param path - Route path\n */\n get(method: HttpMethod, path: string): RouteEntry | undefined {\n const key = this.getRouteKey(method, path);\n return this.routes.get(key);\n }\n \n /**\n * Get all routes\n */\n getAll(): RouteEntry[] {\n return Array.from(this.routes.values());\n }\n \n /**\n * Get routes by method\n * @param method - HTTP method\n */\n getByMethod(method: HttpMethod): RouteEntry[] {\n return this.getAll().filter(route => route.method === method);\n }\n \n /**\n * Get routes by path prefix\n * @param prefix - Path prefix\n */\n getByPrefix(prefix: string): RouteEntry[] {\n return this.getAll().filter(route => route.path.startsWith(prefix));\n }\n \n /**\n * Get routes by tag\n * @param tag - Tag name\n */\n getByTag(tag: string): RouteEntry[] {\n return this.getAll().filter(route => \n route.metadata?.tags?.includes(tag)\n );\n }\n \n /**\n * Create a route group with common prefix\n * @param prefix - Common path prefix\n * @param configure - Function to configure routes in the group\n */\n group(prefix: string, configure: (group: RouteGroupBuilder) => void): void {\n const builder = new RouteGroupBuilder(this, prefix);\n configure(builder);\n }\n \n /**\n * Get route count\n */\n count(): number {\n return this.routes.size;\n }\n \n /**\n * Clear all routes\n */\n clear(): void {\n this.routes.clear();\n }\n \n /**\n * Get route key for storage\n */\n private getRouteKey(method: HttpMethod, path: string): string {\n return `${method}:${path}`;\n }\n \n /**\n * Register route with underlying server\n */\n private registerWithServer(entry: RouteEntry): void {\n const { method, path, handler } = entry;\n \n switch (method) {\n case 'GET':\n this.server.get(path, handler);\n break;\n case 'POST':\n this.server.post(path, handler);\n break;\n case 'PUT':\n this.server.put(path, handler);\n break;\n case 'DELETE':\n this.server.delete(path, handler);\n break;\n case 'PATCH':\n this.server.patch(path, handler);\n break;\n default:\n throw new Error(`Unsupported HTTP method: ${method}`);\n }\n }\n}\n\n/**\n * RouteGroupBuilder\n * \n * Builder for creating route groups with common prefix\n */\nexport class RouteGroupBuilder {\n private manager: RouteManager;\n private prefix: string;\n \n constructor(manager: RouteManager, prefix: string) {\n this.manager = manager;\n this.prefix = prefix;\n }\n \n /**\n * Register GET route in group\n */\n get(path: string, handler: RouteHandler, metadata?: RouteHandlerMetadata['metadata']): this {\n this.manager.register({\n method: 'GET',\n path: this.resolvePath(path),\n handler,\n metadata,\n });\n return this;\n }\n \n /**\n * Register POST route in group\n */\n post(path: string, handler: RouteHandler, metadata?: RouteHandlerMetadata['metadata']): this {\n this.manager.register({\n method: 'POST',\n path: this.resolvePath(path),\n handler,\n metadata,\n });\n return this;\n }\n \n /**\n * Register PUT route in group\n */\n put(path: string, handler: RouteHandler, metadata?: RouteHandlerMetadata['metadata']): this {\n this.manager.register({\n method: 'PUT',\n path: this.resolvePath(path),\n handler,\n metadata,\n });\n return this;\n }\n \n /**\n * Register PATCH route in group\n */\n patch(path: string, handler: RouteHandler, metadata?: RouteHandlerMetadata['metadata']): this {\n this.manager.register({\n method: 'PATCH',\n path: this.resolvePath(path),\n handler,\n metadata,\n });\n return this;\n }\n \n /**\n * Register DELETE route in group\n */\n delete(path: string, handler: RouteHandler, metadata?: RouteHandlerMetadata['metadata']): this {\n this.manager.register({\n method: 'DELETE',\n path: this.resolvePath(path),\n handler,\n metadata,\n });\n return this;\n }\n \n /**\n * Resolve full path with prefix\n */\n private resolvePath(path: string): string {\n // Normalize slashes\n const normalizedPrefix = this.prefix.endsWith('/') \n ? this.prefix.slice(0, -1) \n : this.prefix;\n const normalizedPath = path.startsWith('/') \n ? path \n : '/' + path;\n \n return normalizedPrefix + normalizedPath;\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { IHttpServer } from '@objectstack/core';\nimport { RouteManager } from './route-manager.js';\nimport { RestServerConfig, RestApiConfig, CrudEndpointsConfig, MetadataEndpointsConfig, BatchEndpointsConfig, RouteGenerationConfig } from '@objectstack/spec/api';\nimport { ObjectStackProtocol } from '@objectstack/spec/api';\n\n// Node-safe logger — avoids importing 'console' which is absent from ES2020 lib typings.\nconst logError = (...args: unknown[]) => (globalThis as any).console?.error(...args);\n\n/**\n * Map a data-layer error to a clean HTTP response. Unknown-object errors\n * (SQLite \"no such table\", PG \"relation does not exist\", protocol\n * \"object not found\", etc.) are surfaced as a 404 with `code: 'object_not_found'`\n * so clients can distinguish \"object isn't registered\" from real server\n * faults. Anything else becomes a 400 (bad request) preserving prior\n * behavior. Genuine 500s are still logged.\n *\n * `PermissionDeniedError` (thrown by `SecurityPlugin`) MUST be caught\n * before the unknown-object heuristic, otherwise its message —\n * \"[Security] Access denied: operation 'insert' on object 'sys_user' is\n * not permitted …\" — trips the `'<obj>' … not` substring check and\n * returns a misleading 404.\n */\nfunction mapDataError(error: any, object?: string): { status: number; body: Record<string, unknown> } {\n // Short-circuit: explicit security denial → 403. Match by `code` /\n // `name` to avoid pulling a runtime dependency on plugin-security.\n if (\n error?.code === 'PERMISSION_DENIED' ||\n error?.name === 'PermissionDeniedError' ||\n (typeof error?.message === 'string' && error.message.startsWith('[Security] Access denied'))\n ) {\n return {\n status: 403,\n body: {\n error: error?.message ?? 'Permission denied',\n code: 'PERMISSION_DENIED',\n ...(object ? { object } : {}),\n },\n };\n }\n const raw = String(error?.message ?? error ?? '');\n const lower = raw.toLowerCase();\n\n // ProjectKernelFactory: project missing database_url/driver — typically\n // means provisioning is in flight or the project record was never\n // fully provisioned. 503 (with Retry-After implied) is more accurate\n // than the default 400/500: clients can poll until the project is\n // active.\n if (\n raw.includes('[ProjectKernelFactory]') &&\n (lower.includes('missing database_url') || lower.includes('not found'))\n ) {\n const isProvisioning = lower.includes(\"status='provisioning'\") || lower.includes(\"status='pending'\");\n const isFailed = lower.includes(\"status='failed'\");\n return {\n status: isProvisioning ? 503 : isFailed ? 502 : 404,\n body: {\n error: raw,\n code: isProvisioning\n ? 'PROJECT_PROVISIONING'\n : isFailed\n ? 'PROJECT_PROVISIONING_FAILED'\n : 'PROJECT_NOT_FOUND',\n },\n };\n }\n\n const looksLikeUnknownObject =\n lower.includes('no such table') ||\n lower.includes('relation') && lower.includes('does not exist') ||\n lower.includes('table not found') ||\n lower.includes('unknown object') ||\n lower.includes('object not found') ||\n lower.includes('no driver available') ||\n (object !== undefined && lower.includes(`'${object.toLowerCase()}'`) && lower.includes('not'));\n if (looksLikeUnknownObject) {\n return {\n status: 404,\n body: {\n error: object ? `Object '${object}' is not registered` : 'Object not found',\n code: 'object_not_found',\n object,\n },\n };\n }\n return { status: 400, body: { error: raw || 'Bad request' } };\n}\n\n/**\n * Whether a mapped data-error status represents an *expected* client/lifecycle\n * outcome (and therefore shouldn't be logged as \"[REST] Unhandled error\").\n * - 403 PERMISSION_DENIED is a normal RBAC denial\n * - 404 unknown object / project not found is a normal client mistake\n * - 502/503 mean the underlying project is provisioning or failed; the\n * handler will emit the response and the operator can inspect\n * sys_project.metadata.provisioningError if needed.\n */\nfunction isExpectedDataStatus(status: number): boolean {\n return status === 403 || status === 404 || status === 502 || status === 503;\n}\n\n/**\n * Structural subset of `KernelManager` that RestServer needs in order to\n * resolve a per-project protocol at request time. Typed locally to avoid\n * an @objectstack/runtime → @objectstack/rest → @objectstack/runtime\n * package cycle.\n */\nexport interface RestKernelManager {\n getOrCreate(projectId: string): Promise<{\n getServiceAsync<T = unknown>(name: string): Promise<T>;\n }>;\n}\n\n/**\n * Normalized REST Server Configuration\n * All nested properties are required after normalization\n */\ntype NormalizedRestServerConfig = {\n api: {\n version: string;\n basePath: string;\n apiPath: string | undefined;\n enableCrud: boolean;\n enableMetadata: boolean;\n enableUi: boolean;\n enableBatch: boolean;\n enableDiscovery: boolean;\n enableProjectScoping: boolean;\n projectResolution: 'required' | 'optional' | 'auto';\n documentation: RestApiConfig['documentation'];\n responseFormat: RestApiConfig['responseFormat'];\n };\n crud: {\n operations: {\n create: boolean;\n read: boolean;\n update: boolean;\n delete: boolean;\n list: boolean;\n };\n patterns: CrudEndpointsConfig['patterns'];\n dataPrefix: string;\n objectParamStyle: 'path' | 'query';\n };\n metadata: {\n prefix: string;\n enableCache: boolean;\n cacheTtl: number;\n endpoints: {\n types: boolean;\n items: boolean;\n item: boolean;\n schema: boolean;\n };\n };\n batch: {\n maxBatchSize: number;\n enableBatchEndpoint: boolean;\n operations: {\n createMany: boolean;\n updateMany: boolean;\n deleteMany: boolean;\n upsertMany: boolean;\n };\n defaultAtomic: boolean;\n };\n routes: {\n includeObjects: string[] | undefined;\n excludeObjects: string[] | undefined;\n nameTransform: 'none' | 'plural' | 'kebab-case' | 'camelCase';\n overrides: RouteGenerationConfig['overrides'];\n };\n};\n\n/**\n * RestServer\n * \n * Provides automatic REST API endpoint generation for ObjectStack.\n * Generates standard RESTful CRUD endpoints, metadata endpoints, and batch operations\n * based on the configured protocol provider.\n * \n * Features:\n * - Automatic CRUD endpoint generation (GET, POST, PUT, PATCH, DELETE)\n * - Metadata API endpoints (/meta)\n * - Batch operation endpoints (/batch, /createMany, /updateMany, /deleteMany)\n * - Discovery endpoint\n * - Configurable path prefixes and patterns\n * \n * @example\n * const restServer = new RestServer(httpServer, protocolProvider, {\n * api: {\n * version: 'v1',\n * basePath: '/api'\n * },\n * crud: {\n * dataPrefix: '/data'\n * }\n * });\n * \n * restServer.registerRoutes();\n */\n/**\n * Minimal env registry shape consumed by the REST server for hostname →\n * projectId resolution and `X-Project-Id` header validation on unscoped\n * routes. Mirrors the surface of `EnvironmentDriverRegistry` defined in\n * `@objectstack/service-cloud`.\n */\nexport interface RestEnvRegistry {\n resolveByHostname(hostname: string): Promise<{ projectId: string } | null | undefined>;\n /**\n * Look up a project by id. Returns a truthy value (typically an\n * `IDataDriver`) when the project exists and is bound, `null` when\n * unknown. The REST server only uses the truthiness; it does not\n * touch the driver itself (the actual driver is loaded later via\n * `KernelManager.getOrCreate(projectId)`).\n */\n resolveById?(projectId: string): Promise<unknown | null>;\n}\n\nexport class RestServer {\n private protocol: ObjectStackProtocol;\n private config: NormalizedRestServerConfig;\n private routeManager: RouteManager;\n private kernelManager?: RestKernelManager;\n private envRegistry?: RestEnvRegistry;\n private defaultProjectIdProvider?: () => string | undefined;\n private authServiceProvider?: (projectId?: string) => Promise<any | undefined>;\n private objectQLProvider?: (projectId?: string) => Promise<any | undefined>;\n\n constructor(\n server: IHttpServer,\n protocol: ObjectStackProtocol,\n config: RestServerConfig = {},\n kernelManager?: RestKernelManager,\n envRegistry?: RestEnvRegistry,\n defaultProjectIdProvider?: () => string | undefined,\n authServiceProvider?: (projectId?: string) => Promise<any | undefined>,\n objectQLProvider?: (projectId?: string) => Promise<any | undefined>,\n ) {\n this.protocol = protocol;\n this.config = this.normalizeConfig(config);\n this.routeManager = new RouteManager(server);\n this.kernelManager = kernelManager;\n this.envRegistry = envRegistry;\n this.defaultProjectIdProvider = defaultProjectIdProvider;\n this.authServiceProvider = authServiceProvider;\n this.objectQLProvider = objectQLProvider;\n }\n\n /**\n * Resolve the protocol for a given request. When `projectId` is present\n * and a KernelManager is wired, fetch the per-project kernel's\n * `protocol` service so metadata / data / UI reads hit the project's\n * own registry and datastore.\n *\n * When `projectId` is absent on an unscoped route and an `envRegistry`\n * is wired (runtime mode), the resolution chain is:\n * 1. Hostname → projectId (`envRegistry.resolveByHostname`)\n * 2. `X-Project-Id` header → projectId (`envRegistry.resolveById`)\n * 3. Default-project fallback (`defaultProjectIdProvider`, set by\n * `createSingleProjectPlugin`)\n * 4. Control-plane protocol captured at boot.\n *\n * Special case: `projectId === 'platform'` is a reserved virtual id used\n * by Studio to address the control plane through the regular project\n * URL shape (`/projects/platform/...`). It is NOT a row in the projects\n * table, so we must never call `KernelManager.getOrCreate('platform')`.\n * Instead, return the control-plane protocol directly. This lets Studio\n * (and any other client) speak a single, uniform URL family without\n * duplicating route logic for the platform surface.\n */\n private async resolveProtocol(projectId?: string, req?: any): Promise<ObjectStackProtocol> {\n if (projectId === 'platform') return this.protocol;\n if (!projectId && req && this.envRegistry && this.kernelManager) {\n const host = this.extractHostname(req);\n if (host) {\n try {\n const result = await this.envRegistry.resolveByHostname(host);\n if (result?.projectId) projectId = result.projectId;\n } catch {\n // fall through to next strategy\n }\n }\n // 2. `X-Project-Id` request header → projectId. Lets clients\n // explicitly target a project when the URL is unscoped and\n // no hostname binding exists (e.g. a single shared origin\n // serving multiple compiled bundles via OS_PROJECT_ARTIFACTS).\n // We validate the id through the env registry to avoid\n // routing to a non-existent kernel.\n if (!projectId && typeof this.envRegistry.resolveById === 'function') {\n const headerVal = this.extractProjectIdHeader(req);\n if (headerVal) {\n try {\n const driver = await this.envRegistry.resolveById(headerVal);\n if (driver) projectId = headerVal;\n } catch {\n // fall through to default fallback\n }\n }\n }\n }\n // 3. Single-project default fallback. Registered by\n // `createSingleProjectPlugin()` so bare `/api/v1/data/...` URLs\n // (no `/projects/<id>` prefix, no hostname mapping, no header)\n // resolve to the lone project's kernel rather than the control\n // plane.\n if (!projectId && this.defaultProjectIdProvider) {\n try {\n const def = this.defaultProjectIdProvider();\n if (def) projectId = def;\n } catch { /* fall through */ }\n }\n if (!projectId || !this.kernelManager) return this.protocol;\n const kernel = await this.kernelManager.getOrCreate(projectId);\n return kernel.getServiceAsync<ObjectStackProtocol>('protocol');\n }\n\n /**\n * Resolve the i18n service for the request's project (or control plane\n * when no project id is in scope). Returns `undefined` when no service is\n * registered, so callers can short-circuit and skip translation rather\n * than failing.\n *\n * Mirrors `resolveProtocol`'s lookup chain: explicit `projectId` from the\n * route → kernel-managed `i18n` service. Control-plane / unscoped\n * requests intentionally return `undefined` because the platform kernel\n * does not own per-app translation bundles.\n */\n private async resolveI18nService(projectId?: string): Promise<any | undefined> {\n if (!projectId || projectId === 'platform' || !this.kernelManager) return undefined;\n try {\n const kernel = await this.kernelManager.getOrCreate(projectId);\n return await kernel.getServiceAsync<any>('i18n');\n } catch {\n return undefined;\n }\n }\n\n /**\n * Resolve the request's execution context (RBAC/RLS/FLS) by looking up\n * the better-auth session via the project's `auth` service. Returns\n * `undefined` for anonymous requests so callers can pass `context` as-is\n * to the protocol layer (the SecurityPlugin treats undefined as anon).\n */\n private async resolveExecCtx(projectId: string | undefined, req: any): Promise<any | undefined> {\n try {\n // Look up the auth service in the right kernel. For unscoped\n // single-project apps the kernelManager will hand us the lone\n // tenant kernel; for multi-project hosts we use the resolved\n // projectId.\n let authService: any;\n let kernel: any;\n if (projectId && projectId !== 'platform' && this.kernelManager) {\n kernel = await this.kernelManager.getOrCreate(projectId);\n authService = await kernel.getServiceAsync('auth').catch(() => undefined);\n }\n if (!authService && this.defaultProjectIdProvider && this.kernelManager) {\n try {\n const def = this.defaultProjectIdProvider();\n if (def) {\n kernel = await this.kernelManager.getOrCreate(def);\n authService = await kernel.getServiceAsync('auth').catch(() => undefined);\n }\n } catch { /* fall through */ }\n }\n // Single-kernel deployment fallback — no kernelManager, but\n // the plugin wired an `authServiceProvider` that hits the\n // local kernel directly.\n if (!authService && this.authServiceProvider) {\n authService = await this.authServiceProvider(projectId).catch(() => undefined);\n }\n if (!authService) return undefined;\n // The auth service may be the AuthManager wrapper (which exposes\n // `getApi()`) or the raw better-auth instance (which exposes\n // `.api` directly). Normalize to the raw API object.\n let api: any = authService.api;\n if (!api && typeof authService.getApi === 'function') {\n api = await authService.getApi();\n }\n if (!api?.getSession) return undefined;\n\n // better-auth's `getSession` requires a Web `Headers` instance\n // (it calls `headers.get('cookie')`). Adapter req.headers may\n // already be one, or a plain object — normalize.\n const rawHeaders: any = req?.headers;\n let headers: any;\n if (rawHeaders && typeof rawHeaders.get === 'function') {\n headers = rawHeaders;\n } else if (rawHeaders && typeof rawHeaders === 'object') {\n headers = new (globalThis as any).Headers();\n for (const [k, v] of Object.entries(rawHeaders)) {\n if (Array.isArray(v)) v.forEach((x) => headers.append(k, String(x)));\n else if (v != null) headers.set(k, String(v));\n }\n } else {\n return undefined;\n }\n\n const session = await api.getSession({ headers });\n if (!session?.user?.id) return undefined;\n const userId = session.user.id;\n const tenantId = session.session?.activeOrganizationId ?? undefined;\n const permissions: string[] = [];\n const roles: string[] = [];\n // Look up the link tables to surface roles + permission set names.\n // Skipping this lookup would silently ignore admin/role grants —\n // including the platform-admin promotion seeded by\n // `bootstrapPlatformAdmin` — and force every authenticated user\n // through the `member_default` fallback path.\n try {\n let ql: any;\n if (kernel) {\n ql = await kernel.getServiceAsync('objectql').catch(() => undefined);\n }\n if (!ql && this.objectQLProvider) {\n ql = await this.objectQLProvider(projectId).catch(() => undefined);\n }\n if (ql && typeof ql.find === 'function') {\n const sysOpts = { context: { isSystem: true } };\n const memberRows = await ql.find('sys_member', {\n where: tenantId ? { user_id: userId, organization_id: tenantId } : { user_id: userId },\n limit: 50,\n ...sysOpts,\n } as any).catch(() => []);\n for (const m of (memberRows ?? []) as any[]) {\n if (typeof m.role === 'string') {\n for (const r of m.role.split(',').map((s: string) => s.trim()).filter(Boolean)) {\n if (!roles.includes(r)) roles.push(r);\n }\n }\n }\n const upsRows = await ql.find('sys_user_permission_set', {\n where: { user_id: userId },\n limit: 100,\n ...sysOpts,\n } as any).catch(() => []);\n const psIds = new Set<string>();\n for (const r of (upsRows ?? []) as any[]) {\n const orgScope = r.organization_id ?? null;\n if (!orgScope || (tenantId && orgScope === tenantId)) {\n const pid = r.permission_set_id ?? r.permissionSetId;\n if (pid) psIds.add(pid);\n }\n }\n if (psIds.size > 0) {\n const psRows = await ql.find('sys_permission_set', {\n where: { id: { $in: Array.from(psIds) } },\n limit: 500,\n ...sysOpts,\n } as any).catch(() => []);\n for (const ps of (psRows ?? []) as any[]) {\n if (ps.name && !permissions.includes(ps.name)) permissions.push(ps.name);\n }\n }\n }\n } catch { /* fall through with empty perms */ }\n return {\n userId,\n tenantId,\n roles,\n permissions,\n isSystem: false,\n };\n } catch {\n return undefined;\n }\n }\n\n /**\n * Build a `TranslationBundle` (`Record<locale, TranslationData>`) from an\n * `II18nService` instance. Returns `undefined` when no locales are\n * registered so callers can avoid translation work.\n */\n private buildTranslationBundle(i18n: any): any | undefined {\n if (!i18n || typeof i18n.getLocales !== 'function' || typeof i18n.getTranslations !== 'function') {\n return undefined;\n }\n const locales: string[] = i18n.getLocales();\n if (!locales.length) return undefined;\n const bundle: Record<string, any> = {};\n for (const locale of locales) {\n const data = i18n.getTranslations(locale);\n if (data && typeof data === 'object') bundle[locale] = data;\n }\n return Object.keys(bundle).length ? bundle : undefined;\n }\n\n /**\n * Parse the highest-priority locale from an `Accept-Language` header.\n * Falls back to a `?locale=` query parameter, then to the i18n service's\n * default locale. Returns `undefined` when no preference is expressed\n * (callers will then return untranslated metadata).\n */\n private extractLocale(req: any, i18n?: any): string | undefined {\n const headers = req?.headers;\n let header: string | undefined;\n if (headers) {\n header = typeof headers.get === 'function'\n ? headers.get('accept-language') ?? undefined\n : headers['accept-language'] ?? headers['Accept-Language'];\n }\n if (typeof header === 'string' && header.length > 0) {\n const top = header.split(',')[0]?.split(';')[0]?.trim();\n if (top) return top;\n }\n const queryLocale = req?.query?.locale;\n if (typeof queryLocale === 'string' && queryLocale.length > 0) return queryLocale;\n if (i18n && typeof i18n.getDefaultLocale === 'function') {\n const def = i18n.getDefaultLocale();\n if (typeof def === 'string' && def.length > 0) return def;\n }\n return undefined;\n }\n\n /**\n * Translate a single metadata document (view or action) when an i18n\n * service is registered for the request's project and the requested\n * locale yields a match. Falls through unchanged for unsupported types\n * or missing translations.\n */\n private async translateMetaItem(req: any, type: string, projectId: string | undefined, item: any): Promise<any> {\n if (!item || typeof item !== 'object') return item;\n if (type !== 'view' && type !== 'action') return item;\n const i18n = await this.resolveI18nService(projectId);\n const bundle = this.buildTranslationBundle(i18n);\n if (!bundle) return item;\n const locale = this.extractLocale(req, i18n);\n if (!locale) return item;\n const { translateMetadataDocument } = await import('@objectstack/spec/system');\n return translateMetadataDocument(type, item, bundle, { locale });\n }\n\n /**\n * Translate a list of metadata documents using `translateMetaItem`.\n */\n private async translateMetaItems(req: any, type: string, projectId: string | undefined, items: any): Promise<any> {\n if (!Array.isArray(items)) return items;\n if (type !== 'view' && type !== 'action') return items;\n const i18n = await this.resolveI18nService(projectId);\n const bundle = this.buildTranslationBundle(i18n);\n if (!bundle) return items;\n const locale = this.extractLocale(req, i18n);\n if (!locale) return items;\n const { translateMetadataDocument } = await import('@objectstack/spec/system');\n return items.map((item) => translateMetadataDocument(type, item, bundle, { locale }));\n }\n\n /**\n * Pull the request hostname (without port) from a Node-style `req` or\n * a Fetch-style request wrapper. Returns undefined when no Host header\n * is available.\n */\n private extractHostname(req: any): string | undefined {\n const headers = req?.headers;\n let host: string | undefined;\n if (headers) {\n if (typeof headers.get === 'function') {\n host = headers.get('host') ?? undefined;\n } else {\n host = headers.host ?? headers.Host;\n }\n }\n if (!host && typeof req?.hostname === 'string') host = req.hostname;\n if (!host && typeof req?.url === 'string') {\n // Fetch-style requests expose the hostname via `req.url` even\n // when the (forbidden) `Host` header has been stripped by the\n // runtime. This branch keeps hostname-routing working when\n // tests build a `Request` object through `app.fetch(...)`.\n try {\n host = new (globalThis as any).URL(req.url).host;\n } catch { /* ignore */ }\n }\n if (!host) return undefined;\n return String(host).split(':')[0].toLowerCase();\n }\n\n /**\n * Pull the `X-Project-Id` header from a Node- or Fetch-style request.\n * Header names are case-insensitive; we probe both casings to cover\n * adapters that don't normalize headers (e.g. raw Node http).\n */\n private extractProjectIdHeader(req: any): string | undefined {\n const headers = req?.headers;\n if (!headers) return undefined;\n let val: unknown;\n if (typeof headers.get === 'function') {\n val = headers.get('x-project-id') ?? headers.get('X-Project-Id');\n } else {\n val = headers['x-project-id'] ?? headers['X-Project-Id'];\n }\n if (Array.isArray(val)) val = val[0];\n if (typeof val !== 'string') return undefined;\n const trimmed = val.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n }\n \n /**\n * Normalize configuration with defaults\n */\n private normalizeConfig(config: RestServerConfig): NormalizedRestServerConfig {\n const api = (config.api ?? {}) as Partial<RestApiConfig>;\n const crud = (config.crud ?? {}) as Partial<CrudEndpointsConfig>;\n const metadata = (config.metadata ?? {}) as Partial<MetadataEndpointsConfig>;\n const batch = (config.batch ?? {}) as Partial<BatchEndpointsConfig>;\n const routes = (config.routes ?? {}) as Partial<RouteGenerationConfig>;\n \n return {\n api: {\n version: api.version ?? 'v1',\n basePath: api.basePath ?? '/api',\n apiPath: api.apiPath,\n enableCrud: api.enableCrud ?? true,\n enableMetadata: api.enableMetadata ?? true,\n enableUi: api.enableUi ?? true,\n enableBatch: api.enableBatch ?? true,\n enableDiscovery: api.enableDiscovery ?? true,\n enableProjectScoping: api.enableProjectScoping ?? false,\n projectResolution: api.projectResolution ?? 'auto',\n documentation: api.documentation,\n responseFormat: api.responseFormat,\n },\n crud: {\n operations: crud.operations ?? {\n create: true,\n read: true,\n update: true,\n delete: true,\n list: true,\n },\n patterns: crud.patterns,\n dataPrefix: crud.dataPrefix ?? '/data',\n objectParamStyle: crud.objectParamStyle ?? 'path',\n },\n metadata: {\n prefix: metadata.prefix ?? '/meta',\n enableCache: metadata.enableCache ?? true,\n cacheTtl: metadata.cacheTtl ?? 3600,\n endpoints: metadata.endpoints ?? {\n types: true,\n items: true,\n item: true,\n schema: true,\n },\n },\n batch: {\n maxBatchSize: batch.maxBatchSize ?? 200,\n enableBatchEndpoint: batch.enableBatchEndpoint ?? true,\n operations: batch.operations ?? {\n createMany: true,\n updateMany: true,\n deleteMany: true,\n upsertMany: true,\n },\n defaultAtomic: batch.defaultAtomic ?? true,\n },\n routes: {\n includeObjects: routes.includeObjects,\n excludeObjects: routes.excludeObjects,\n nameTransform: routes.nameTransform ?? 'none',\n overrides: routes.overrides,\n },\n };\n }\n \n /**\n * Get the full API base path\n */\n private getApiBasePath(): string {\n const { api } = this.config;\n return api.apiPath ?? `${api.basePath}/${api.version}`;\n }\n\n /**\n * Get the project-scoped base path for a given unscoped base.\n * Example: `/api/v1` → `/api/v1/projects/:projectId`.\n */\n private getScopedBasePath(basePath: string): string {\n return `${basePath}/projects/:projectId`;\n }\n\n /**\n * Register all REST API routes\n *\n * When `enableProjectScoping` is true, routes are registered under\n * `/api/v1/projects/:projectId/...`. The `projectResolution` strategy\n * controls whether unscoped legacy routes remain available:\n * - `required` → only scoped routes registered.\n * - `optional` / `auto` → both scoped and unscoped routes registered.\n */\n registerRoutes(): void {\n const basePath = this.getApiBasePath();\n const { enableProjectScoping, projectResolution } = this.config.api;\n\n const registerForBase = (bp: string) => {\n if (this.config.api.enableDiscovery) {\n this.registerDiscoveryEndpoints(bp);\n }\n if (this.config.api.enableMetadata) {\n this.registerMetadataEndpoints(bp);\n }\n if (this.config.api.enableUi) {\n this.registerUiEndpoints(bp);\n }\n if (this.config.api.enableCrud) {\n this.registerCrudEndpoints(bp);\n }\n if (this.config.api.enableBatch) {\n this.registerBatchEndpoints(bp);\n }\n };\n\n if (enableProjectScoping) {\n const scopedBase = this.getScopedBasePath(basePath);\n if (projectResolution === 'required') {\n // Strict: only scoped routes\n registerForBase(scopedBase);\n } else {\n // 'optional' | 'auto' — keep both so legacy callers keep working\n registerForBase(basePath);\n registerForBase(scopedBase);\n }\n } else {\n registerForBase(basePath);\n }\n }\n \n /**\n * Register discovery endpoints\n */\n private registerDiscoveryEndpoints(basePath: string): void {\n const isScoped = basePath.includes('/projects/:projectId');\n const discoveryHandler = async (req: any, res: any) => {\n try {\n const discovery = await this.protocol.getDiscovery();\n\n // Override discovery information with actual server configuration\n discovery.version = this.config.api.version;\n\n // Substitute the resolved projectId into the advertised routes so\n // clients can consume them verbatim (e.g. /api/v1/projects/abc/data).\n const realBase = isScoped\n ? basePath.replace(':projectId', req.params?.projectId ?? ':projectId')\n : basePath;\n\n if (discovery.routes) {\n // Ensure routes match the actual mounted paths\n if (this.config.api.enableCrud) {\n discovery.routes.data = `${realBase}${this.config.crud.dataPrefix}`;\n }\n\n if (this.config.api.enableMetadata) {\n discovery.routes.metadata = `${realBase}${this.config.metadata.prefix}`;\n }\n\n if (this.config.api.enableUi) {\n discovery.routes.ui = `${realBase}/ui`;\n }\n\n // Align auth route with the versioned base path if present.\n // Auth is a control-plane concern, so use the unscoped base.\n if (discovery.routes.auth) {\n const unscopedBase = isScoped\n ? basePath.replace(/\\/projects\\/:projectId$/, '')\n : basePath;\n discovery.routes.auth = `${unscopedBase}/auth`;\n }\n }\n\n // Attach scoping metadata so clients can detect dual-mode routing.\n (discovery as any).scoping = {\n enabled: this.config.api.enableProjectScoping,\n resolution: this.config.api.projectResolution,\n scoped: isScoped,\n projectId: isScoped ? req.params?.projectId : undefined,\n };\n\n res.json(discovery);\n } catch (error: any) {\n logError(\"[REST] Unhandled error:\", error);\n res.status(500).json({ error: error.message });\n }\n };\n\n // Register at basePath (e.g. /api/v1)\n this.routeManager.register({\n method: 'GET',\n path: basePath,\n handler: discoveryHandler,\n metadata: {\n summary: 'Get API discovery information',\n tags: ['discovery'],\n },\n });\n\n // Register at basePath/discovery (e.g. /api/v1/discovery)\n this.routeManager.register({\n method: 'GET',\n path: `${basePath}/discovery`,\n handler: discoveryHandler,\n metadata: {\n summary: 'Get API discovery information',\n tags: ['discovery'],\n },\n });\n }\n \n /**\n * Register metadata endpoints\n */\n private registerMetadataEndpoints(basePath: string): void {\n const { metadata } = this.config;\n const metaPath = `${basePath}${metadata.prefix}`;\n const isScoped = basePath.includes('/projects/:projectId');\n\n // GET /meta - List all metadata types\n if (metadata.endpoints.types !== false) {\n this.routeManager.register({\n method: 'GET',\n path: metaPath,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const p = await this.resolveProtocol(projectId, req);\n const types = await p.getMetaTypes();\n res.json(types);\n } catch (error: any) {\n logError(\"[REST] Unhandled error:\", error);\n res.status(500).json({ error: error.message });\n }\n },\n metadata: {\n summary: 'List all metadata types',\n tags: ['metadata'],\n },\n });\n }\n\n // GET /meta/:type - List items of a type\n if (metadata.endpoints.items !== false) {\n this.routeManager.register({\n method: 'GET',\n path: `${metaPath}/:type`,\n handler: async (req: any, res: any) => {\n try {\n const packageId = req.query?.package || undefined;\n const projectId = isScoped ? req.params?.projectId : undefined;\n const p = await this.resolveProtocol(projectId, req);\n const items = await p.getMetaItems({\n type: req.params.type,\n packageId,\n ...(projectId ? { projectId } : {}),\n } as any);\n const translated = await this.translateMetaItems(req, req.params.type, projectId, items);\n res.header('Vary', 'Accept-Language');\n res.json(translated);\n } catch (error: any) {\n logError(\"[REST] Unhandled error:\", error);\n res.status(404).json({ error: error.message });\n }\n },\n metadata: {\n summary: 'List metadata items of a type',\n tags: ['metadata'],\n },\n });\n }\n\n // GET /meta/:type/:name - Get specific item\n if (metadata.endpoints.item !== false) {\n this.routeManager.register({\n method: 'GET',\n path: `${metaPath}/:type/:name`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const p = await this.resolveProtocol(projectId, req);\n // Check if cached version is available\n if (metadata.enableCache && p.getMetaItemCached) {\n const cacheRequest = {\n ifNoneMatch: req.headers['if-none-match'] as string,\n ifModifiedSince: req.headers['if-modified-since'] as string,\n };\n\n const result = await p.getMetaItemCached({\n type: req.params.type,\n name: req.params.name,\n cacheRequest,\n ...(projectId ? { projectId } : {}),\n } as any);\n\n if (result.notModified) {\n res.status(304).send();\n return;\n }\n\n // Set cache headers\n if (result.etag) {\n const etagValue = result.etag.weak\n ? `W/\"${result.etag.value}\"`\n : `\"${result.etag.value}\"`;\n res.header('ETag', etagValue);\n }\n if (result.lastModified) {\n res.header('Last-Modified', new Date(result.lastModified).toUTCString());\n }\n if (result.cacheControl) {\n const directives = result.cacheControl.directives.join(', ');\n const maxAge = result.cacheControl.maxAge\n ? `, max-age=${result.cacheControl.maxAge}`\n : '';\n res.header('Cache-Control', directives + maxAge);\n }\n\n res.header('Vary', 'Accept-Language');\n res.json(await this.translateMetaItem(req, req.params.type, projectId, result.data));\n } else {\n // Non-cached version\n const packageId = req.query?.package || undefined;\n const item = await p.getMetaItem({\n type: req.params.type,\n name: req.params.name,\n packageId,\n } as any);\n res.header('Vary', 'Accept-Language');\n res.json(await this.translateMetaItem(req, req.params.type, projectId, item));\n }\n } catch (error: any) {\n logError(\"[REST] Unhandled error:\", error);\n res.status(404).json({ error: error.message });\n }\n },\n metadata: {\n summary: 'Get specific metadata item',\n tags: ['metadata'],\n },\n });\n }\n\n // PUT /meta/:type/:name - Save metadata item\n // We always register this route, but return 501 if protocol doesn't support it\n // This makes it discoverable even if not implemented\n this.routeManager.register({\n method: 'PUT',\n path: `${metaPath}/:type/:name`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const p = await this.resolveProtocol(projectId, req);\n if (!p.saveMetaItem) {\n res.status(501).json({ error: 'Save operation not supported by protocol implementation' });\n return;\n }\n\n const result = await p.saveMetaItem({\n type: req.params.type,\n name: req.params.name,\n item: req.body,\n ...(projectId ? { projectId } : {}),\n } as any);\n res.json(result);\n } catch (error: any) {\n logError(\"[REST] Unhandled error:\", error);\n res.status(400).json({ error: error.message });\n }\n },\n metadata: {\n summary: 'Save specific metadata item',\n tags: ['metadata'],\n },\n });\n }\n\n /**\n * Register UI endpoints\n */\n private registerUiEndpoints(basePath: string): void {\n const uiPath = `${basePath}/ui`;\n const isScoped = basePath.includes('/projects/:projectId');\n\n // GET /ui/view/:object/:type - Resolve view for object\n this.routeManager.register({\n method: 'GET',\n path: `${uiPath}/view/:object/:type`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const p = await this.resolveProtocol(projectId, req);\n if (p.getUiView) {\n const view = await p.getUiView({\n object: req.params.object,\n type: req.params.type as any,\n ...(projectId ? { projectId } : {}),\n } as any);\n res.json(view);\n } else {\n res.status(501).json({ error: 'UI View resolution not supported by protocol implementation' });\n }\n } catch (error: any) {\n logError(\"[REST] Unhandled error:\", error);\n res.status(404).json({ error: error.message });\n }\n },\n metadata: {\n summary: 'Resolve UI View for object',\n tags: ['ui'],\n },\n });\n }\n \n /**\n * Register CRUD endpoints for data operations\n */\n private registerCrudEndpoints(basePath: string): void {\n const { crud } = this.config;\n const dataPath = `${basePath}${crud.dataPrefix}`;\n const isScoped = basePath.includes('/projects/:projectId');\n\n const operations = crud.operations;\n\n // GET /data/:object - List/query records\n if (operations.list) {\n this.routeManager.register({\n method: 'GET',\n path: `${dataPath}/:object`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const p = await this.resolveProtocol(projectId, req);\n const context = await this.resolveExecCtx(projectId, req);\n const result = await p.findData({\n object: req.params.object,\n query: req.query,\n ...(projectId ? { projectId } : {}),\n ...(context ? { context } : {}),\n } as any);\n res.json(result);\n } catch (error: any) {\n const mapped = mapDataError(error, req.params?.object);\n if (mapped.status === 404 || mapped.status === 503 || mapped.status === 502) {\n res.status(mapped.status).json(mapped.body);\n } else {\n logError(\"[REST] Unhandled error:\", error);\n res.status(mapped.status).json(mapped.body);\n }\n }\n },\n metadata: {\n summary: 'Query records',\n tags: ['data', 'crud'],\n },\n });\n }\n\n // GET /data/:object/:id - Get single record\n if (operations.read) {\n this.routeManager.register({\n method: 'GET',\n path: `${dataPath}/:object/:id`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const p = await this.resolveProtocol(projectId, req);\n const { select, expand } = req.query || {};\n const context = await this.resolveExecCtx(projectId, req);\n const result = await p.getData({\n object: req.params.object,\n id: req.params.id,\n ...(select != null ? { select } : {}),\n ...(expand != null ? { expand } : {}),\n ...(projectId ? { projectId } : {}),\n ...(context ? { context } : {}),\n } as any);\n res.json(result);\n } catch (error: any) {\n const mapped = mapDataError(error, req.params?.object);\n if (!isExpectedDataStatus(mapped.status)) logError(\"[REST] Unhandled error:\", error);\n res.status(mapped.status === 400 ? 404 : mapped.status).json(mapped.body);\n }\n },\n metadata: {\n summary: 'Get record by ID',\n tags: ['data', 'crud'],\n },\n });\n }\n\n // POST /data/:object - Create record\n if (operations.create) {\n this.routeManager.register({\n method: 'POST',\n path: `${dataPath}/:object`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const p = await this.resolveProtocol(projectId, req);\n const context = await this.resolveExecCtx(projectId, req);\n const result = await p.createData({\n object: req.params.object,\n data: req.body,\n ...(projectId ? { projectId } : {}),\n ...(context ? { context } : {}),\n } as any);\n res.status(201).json(result);\n } catch (error: any) {\n const mapped = mapDataError(error, req.params?.object);\n if (!isExpectedDataStatus(mapped.status)) logError(\"[REST] Unhandled error:\", error);\n res.status(mapped.status).json(mapped.body);\n }\n },\n metadata: {\n summary: 'Create record',\n tags: ['data', 'crud'],\n },\n });\n }\n\n // PATCH /data/:object/:id - Update record\n if (operations.update) {\n this.routeManager.register({\n method: 'PATCH',\n path: `${dataPath}/:object/:id`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const p = await this.resolveProtocol(projectId, req);\n const context = await this.resolveExecCtx(projectId, req);\n const result = await p.updateData({\n object: req.params.object,\n id: req.params.id,\n data: req.body,\n ...(projectId ? { projectId } : {}),\n ...(context ? { context } : {}),\n } as any);\n res.json(result);\n } catch (error: any) {\n const mapped = mapDataError(error, req.params?.object);\n if (!isExpectedDataStatus(mapped.status)) logError(\"[REST] Unhandled error:\", error);\n res.status(mapped.status).json(mapped.body);\n }\n },\n metadata: {\n summary: 'Update record',\n tags: ['data', 'crud'],\n },\n });\n }\n\n // DELETE /data/:object/:id - Delete record\n if (operations.delete) {\n this.routeManager.register({\n method: 'DELETE',\n path: `${dataPath}/:object/:id`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const p = await this.resolveProtocol(projectId, req);\n const context = await this.resolveExecCtx(projectId, req);\n const result = await p.deleteData({\n object: req.params.object,\n id: req.params.id,\n ...(projectId ? { projectId } : {}),\n ...(context ? { context } : {}),\n } as any);\n res.json(result);\n } catch (error: any) {\n const mapped = mapDataError(error, req.params?.object);\n if (!isExpectedDataStatus(mapped.status)) logError(\"[REST] Unhandled error:\", error);\n res.status(mapped.status).json(mapped.body);\n }\n },\n metadata: {\n summary: 'Delete record',\n tags: ['data', 'crud'],\n },\n });\n }\n }\n \n /**\n * Register batch operation endpoints\n */\n private registerBatchEndpoints(basePath: string): void {\n const { crud, batch } = this.config;\n const dataPath = `${basePath}${crud.dataPrefix}`;\n const isScoped = basePath.includes('/projects/:projectId');\n\n const operations = batch.operations;\n\n // POST /data/:object/batch - Generic batch endpoint\n if (batch.enableBatchEndpoint && this.protocol.batchData) {\n this.routeManager.register({\n method: 'POST',\n path: `${dataPath}/:object/batch`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const p = await this.resolveProtocol(projectId, req);\n const result = await p.batchData!({\n object: req.params.object,\n request: req.body,\n ...(projectId ? { projectId } : {}),\n } as any);\n res.json(result);\n } catch (error: any) {\n logError(\"[REST] Unhandled error:\", error);\n res.status(400).json({ error: error.message });\n }\n },\n metadata: {\n summary: 'Batch operations',\n tags: ['data', 'batch'],\n },\n });\n }\n\n // POST /data/:object/createMany - Bulk create\n if (operations.createMany && this.protocol.createManyData) {\n this.routeManager.register({\n method: 'POST',\n path: `${dataPath}/:object/createMany`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const p = await this.resolveProtocol(projectId, req);\n const result = await p.createManyData!({\n object: req.params.object,\n records: req.body || [],\n ...(projectId ? { projectId } : {}),\n } as any);\n res.status(201).json(result);\n } catch (error: any) {\n logError(\"[REST] Unhandled error:\", error);\n res.status(400).json({ error: error.message });\n }\n },\n metadata: {\n summary: 'Create multiple records',\n tags: ['data', 'batch'],\n },\n });\n }\n\n // POST /data/:object/updateMany - Bulk update\n if (operations.updateMany && this.protocol.updateManyData) {\n this.routeManager.register({\n method: 'POST',\n path: `${dataPath}/:object/updateMany`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const p = await this.resolveProtocol(projectId, req);\n const result = await p.updateManyData!({\n object: req.params.object,\n ...req.body,\n ...(projectId ? { projectId } : {}),\n } as any);\n res.json(result);\n } catch (error: any) {\n logError(\"[REST] Unhandled error:\", error);\n res.status(400).json({ error: error.message });\n }\n },\n metadata: {\n summary: 'Update multiple records',\n tags: ['data', 'batch'],\n },\n });\n }\n\n // POST /data/:object/deleteMany - Bulk delete\n if (operations.deleteMany && this.protocol.deleteManyData) {\n this.routeManager.register({\n method: 'POST',\n path: `${dataPath}/:object/deleteMany`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const p = await this.resolveProtocol(projectId, req);\n const result = await p.deleteManyData!({\n object: req.params.object,\n ...req.body,\n ...(projectId ? { projectId } : {}),\n } as any);\n res.json(result);\n } catch (error: any) {\n logError(\"[REST] Unhandled error:\", error);\n res.status(400).json({ error: error.message });\n }\n },\n metadata: {\n summary: 'Delete multiple records',\n tags: ['data', 'batch'],\n },\n });\n }\n }\n\n \n /**\n * Get the route manager\n */\n getRouteManager(): RouteManager {\n return this.routeManager;\n }\n \n /**\n * Get all registered routes\n */\n getRoutes() {\n return this.routeManager.getAll();\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { IHttpServer } from '@objectstack/core';\nimport type { PackageService } from '@objectstack/service-package';\n\n/**\n * Options for package route registration.\n */\nexport interface PackageRoutesOptions {\n /**\n * Protocol service (ObjectStackProtocol) — provides access to in-memory\n * SchemaRegistry packages loaded via defineStack()/AppPlugin at boot time.\n */\n protocol?: { getMetaItems?(req: { type: string }): Promise<{ items: any[] }> };\n}\n\n/**\n * Register package management API routes\n *\n * Provides endpoints for publishing, retrieving, and managing packages.\n * Routes:\n * - POST /api/v1/packages - Publish a package\n * - GET /api/v1/packages - List all packages (merges registry + database)\n * - GET /api/v1/packages/:id - Get a specific package\n * - DELETE /api/v1/packages/:id - Delete a package\n */\nexport function registerPackageRoutes(\n server: IHttpServer,\n packageService: PackageService,\n basePath: string = '/api/v1',\n options: PackageRoutesOptions = {},\n) {\n const packagesPath = `${basePath}/packages`;\n\n // POST /api/v1/packages - Publish a package\n server.post(packagesPath, async (req, res) => {\n try {\n const { manifest, metadata } = req.body || {};\n\n if (!manifest || !metadata) {\n res.status(400).json({ error: 'Missing required fields: manifest, metadata' });\n return;\n }\n\n if (!manifest.id || !manifest.version) {\n res.status(400).json({ error: 'Invalid manifest: id and version are required' });\n return;\n }\n\n const result = await packageService.publish({ manifest, metadata });\n\n if (result.success) {\n res.json({\n success: true,\n message: `Published ${manifest.id}@${manifest.version}`,\n package: {\n id: manifest.id,\n version: manifest.version,\n },\n });\n return;\n }\n\n res.status(400).json({ success: false, error: result.error });\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n // GET /api/v1/packages - List all packages (merges registry + database)\n server.get(packagesPath, async (_req, res) => {\n try {\n // Merge two sources:\n // 1. Registry packages (in-memory, loaded at boot via defineStack/AppPlugin)\n // 2. Database packages (published via POST /packages)\n const packagesMap = new Map<string, any>();\n\n // Registry packages (via protocol service → SchemaRegistry)\n if (options.protocol && typeof options.protocol.getMetaItems === 'function') {\n try {\n const result = await options.protocol.getMetaItems({ type: 'package' });\n if (result?.items) {\n for (const item of result.items) {\n const id = item.manifest?.id || item.id;\n if (id) {\n packagesMap.set(id, {\n ...item,\n source: 'registry',\n });\n }\n }\n }\n } catch {\n // Protocol unavailable — continue with database only\n }\n }\n\n // Database packages (published artifacts)\n try {\n const dbPackages = await packageService.list();\n for (const pkg of dbPackages) {\n const id = pkg.manifest?.id || pkg.id;\n if (id) {\n // Database entry takes precedence (has richer metadata from publish)\n packagesMap.set(id, {\n ...packagesMap.get(id),\n ...pkg,\n source: packagesMap.has(id) ? 'both' : 'database',\n });\n }\n }\n } catch {\n // Database query failed — continue with registry-only packages\n }\n\n const packages = Array.from(packagesMap.values());\n res.json({ packages, total: packages.length });\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n // GET /api/v1/packages/:id - Get a specific package\n server.get(`${packagesPath}/:id`, async (req, res) => {\n try {\n const packageId = req.params.id;\n const version = req.query?.version || 'latest';\n\n // Try database first (richer data from publish)\n const pkg = await packageService.get(packageId, version);\n if (pkg) {\n res.json({ package: { ...pkg, source: 'database' } });\n return;\n }\n\n // Fall back to registry (in-memory loaded packages)\n if (options.protocol && typeof options.protocol.getMetaItems === 'function') {\n try {\n const result = await options.protocol.getMetaItems({ type: 'package' });\n const match = result?.items?.find((item: any) =>\n (item.manifest?.id || item.id) === packageId\n );\n if (match) {\n res.json({ package: { ...match, source: 'registry' } });\n return;\n }\n } catch {\n // Protocol unavailable\n }\n }\n\n res.status(404).json({ error: 'Package not found' });\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n // DELETE /api/v1/packages/:id - Delete a package\n server.delete(`${packagesPath}/:id`, async (req, res) => {\n try {\n const packageId = req.params.id;\n const version = req.query?.version;\n\n const result = await packageService.delete(packageId, version);\n\n if (result.success) {\n res.json({\n success: true,\n message: `Deleted ${packageId}${version ? `@${version}` : ''}`,\n });\n return;\n }\n\n res.status(400).json({ success: false });\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { Plugin, PluginContext, IHttpServer } from '@objectstack/core';\nimport { RestServer, RestKernelManager } from './rest-server.js';\nimport { ObjectStackProtocol, RestServerConfig } from '@objectstack/spec/api';\nimport { registerPackageRoutes } from './package-routes.js';\nimport type { PackageService } from '@objectstack/service-package';\n\nexport interface RestApiPluginConfig {\n serverServiceName?: string;\n protocolServiceName?: string;\n /**\n * Optional override for the kernel-manager service name. When the service\n * is registered (by @objectstack/runtime's MultiProjectPlugin), scoped\n * routes resolve per-project protocols at request time.\n */\n kernelManagerServiceName?: string;\n api?: RestServerConfig;\n}\n\n/**\n * REST API Plugin\n * \n * Responsibilities:\n * 1. Consumes 'http.server' (or configured service)\n * 2. Consumes 'protocol' (ObjectStackProtocol)\n * 3. Instantiates RestServer to auto-generate routes\n */\nexport function createRestApiPlugin(config: RestApiPluginConfig = {}): Plugin {\n return {\n name: 'com.objectstack.rest.api',\n version: '1.0.0',\n \n init: async (_ctx: PluginContext) => {\n // No service registration, this is a consumer plugin\n },\n \n start: async (ctx: PluginContext) => {\n const serverService = config.serverServiceName || 'http.server';\n const protocolService = config.protocolServiceName || 'protocol';\n \n let server: IHttpServer | undefined;\n let protocol: ObjectStackProtocol | undefined;\n\n try {\n server = ctx.getService<IHttpServer>(serverService);\n } catch (e) {\n // Ignore missing service\n }\n\n try {\n protocol = ctx.getService<ObjectStackProtocol>(protocolService);\n } catch (e) {\n // Ignore missing service\n }\n\n // Optional — only present when MultiProjectPlugin is mounted. When\n // available, RestServer will resolve a per-project protocol at\n // request time for scoped (`/projects/:projectId/...`) routes.\n let kernelManager: RestKernelManager | undefined;\n const kernelManagerService = config.kernelManagerServiceName || 'kernel-manager';\n try {\n kernelManager = ctx.getService<RestKernelManager>(kernelManagerService);\n } catch (e) {\n // Single-kernel deployment — fall back to the control protocol\n }\n\n // Optional — only present in runtime mode. When available,\n // RestServer will resolve hostname → projectId on unscoped\n // routes so a remote runtime node can dispatch every request\n // to the matching per-project kernel without requiring callers\n // to know the projectId.\n let envRegistry: any;\n try {\n envRegistry = ctx.getService<any>('env-registry');\n } catch (e) {\n // Not running in runtime/multi-project mode — fine.\n }\n\n // Optional default-project provider — registered by\n // `createSingleProjectPlugin` in single-project local mode.\n // Lets RestServer route bare `/api/v1/data/...` URLs into the\n // lone project's kernel.\n const defaultProjectIdProvider = (): string | undefined => {\n try {\n const dp: any = ctx.getService('default-project');\n return dp?.projectId;\n } catch { return undefined; }\n };\n\n // Auth service resolver — used by RestServer.resolveExecCtx in\n // single-kernel deployments where there is no kernelManager.\n // Multi-kernel paths look up auth via kernelManager.getOrCreate,\n // so this provider is the single-kernel fallback.\n const authServiceProvider = async (_projectId?: string): Promise<any | undefined> => {\n try {\n return ctx.getService<any>('auth');\n } catch { return undefined; }\n };\n\n // ObjectQL resolver — single-kernel fallback so resolveExecCtx\n // can run sys_member / sys_user_permission_set lookups when\n // there is no kernelManager wired (e.g. `pnpm dev:crm`).\n const objectQLProvider = async (_projectId?: string): Promise<any | undefined> => {\n try {\n return ctx.getService<any>('objectql');\n } catch { return undefined; }\n };\n\n if (!server) {\n ctx.logger.warn(`RestApiPlugin: HTTP Server service '${serverService}' not found. REST routes skipped.`);\n return;\n }\n \n if (!protocol) {\n ctx.logger.warn(`RestApiPlugin: Protocol service '${protocolService}' not found. REST routes skipped.`);\n return;\n }\n \n ctx.logger.info('Hydrating REST API from Protocol...');\n \n try {\n const restServer = new RestServer(server, protocol, config.api as any, kernelManager, envRegistry, defaultProjectIdProvider, authServiceProvider, objectQLProvider);\n restServer.registerRoutes();\n\n ctx.logger.info('REST API successfully registered');\n } catch (err: any) {\n ctx.logger.error('Failed to register REST API routes', { error: err.message } as any);\n throw err;\n }\n\n // Register package management routes if service is available\n try {\n const packageService = ctx.getService<PackageService>('package');\n if (packageService) {\n const basePath = config.api?.api?.basePath || '/api';\n const version = config.api?.api?.version || 'v1';\n const versionedBase = `${basePath}/${version}`;\n const enableProjectScoping = config.api?.api?.enableProjectScoping ?? false;\n const projectResolution = config.api?.api?.projectResolution ?? 'auto';\n\n if (enableProjectScoping && projectResolution === 'required') {\n // Only register the scoped variant\n registerPackageRoutes(server, packageService, `${versionedBase}/projects/:projectId`, {\n protocol,\n });\n } else {\n registerPackageRoutes(server, packageService, versionedBase, { protocol });\n if (enableProjectScoping) {\n registerPackageRoutes(server, packageService, `${versionedBase}/projects/:projectId`, {\n protocol,\n });\n }\n }\n ctx.logger.info('Package management routes registered');\n }\n } catch (e) {\n // Package service not available, skip\n ctx.logger.debug('Package service not available, package routes skipped');\n }\n }\n };\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/route-manager.ts","../src/rest-server.ts","../src/package-routes.ts","../src/rest-api-plugin.ts"],"sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { RouteHandler, IHttpServer } from '@objectstack/core';\nimport * as System from '@objectstack/spec/system';\nimport * as Shared from '@objectstack/spec/shared';\nimport { z } from 'zod';\n\ntype RouteHandlerMetadata = System.RouteHandlerMetadata;\ntype HttpMethod = z.infer<typeof Shared.HttpMethod>;\n\n/**\n * Route Entry\n * Internal representation of registered routes\n */\nexport interface RouteEntry {\n method: HttpMethod;\n path: string;\n handler: RouteHandler;\n metadata?: RouteHandlerMetadata['metadata'];\n security?: RouteHandlerMetadata['security'];\n}\n\n/**\n * RouteManager\n * \n * Manages route registration and organization for HTTP servers.\n * Provides:\n * - Route registration with metadata\n * - Route lookup and querying\n * - Bulk route registration\n * - Route grouping by prefix\n * \n * @example\n * const manager = new RouteManager(server);\n * \n * // Register individual route\n * manager.register({\n * method: 'GET',\n * path: '/api/users/:id',\n * handler: getUserHandler,\n * metadata: {\n * summary: 'Get user by ID',\n * tags: ['users']\n * }\n * });\n * \n * // Register route group\n * manager.group('/api/users', (group) => {\n * group.get('/', listUsersHandler);\n * group.post('/', createUserHandler);\n * group.get('/:id', getUserHandler);\n * });\n */\nexport class RouteManager {\n private server: IHttpServer;\n private routes: Map<string, RouteEntry>;\n \n constructor(server: IHttpServer) {\n this.server = server;\n this.routes = new Map();\n }\n \n /**\n * Register a route\n * @param entry - Route entry with method, path, handler, and metadata\n */\n register(entry: Omit<RouteEntry, 'handler'> & { handler: RouteHandler | string }): void {\n // Validate handler type - string handlers not yet supported\n if (typeof entry.handler === 'string') {\n throw new Error(\n `String-based route handlers are not supported yet. ` +\n `Received handler identifier \"${entry.handler}\". ` +\n `Please provide a RouteHandler function instead.`\n );\n }\n \n const handler: RouteHandler = entry.handler;\n \n const routeEntry: RouteEntry = {\n method: entry.method,\n path: entry.path,\n handler,\n metadata: entry.metadata,\n security: entry.security,\n };\n \n const key = this.getRouteKey(entry.method, entry.path);\n this.routes.set(key, routeEntry);\n \n // Register with underlying server\n this.registerWithServer(routeEntry);\n }\n \n /**\n * Register multiple routes\n * @param entries - Array of route entries\n */\n registerMany(entries: Array<Omit<RouteEntry, 'handler'> & { handler: RouteHandler | string }>): void {\n entries.forEach(entry => this.register(entry));\n }\n \n /**\n * Unregister a route\n * @param method - HTTP method\n * @param path - Route path\n */\n unregister(method: HttpMethod, path: string): void {\n const key = this.getRouteKey(method, path);\n this.routes.delete(key);\n // Note: Most server frameworks don't support unregistering routes at runtime\n // This just removes it from our registry\n }\n \n /**\n * Get route by method and path\n * @param method - HTTP method\n * @param path - Route path\n */\n get(method: HttpMethod, path: string): RouteEntry | undefined {\n const key = this.getRouteKey(method, path);\n return this.routes.get(key);\n }\n \n /**\n * Get all routes\n */\n getAll(): RouteEntry[] {\n return Array.from(this.routes.values());\n }\n \n /**\n * Get routes by method\n * @param method - HTTP method\n */\n getByMethod(method: HttpMethod): RouteEntry[] {\n return this.getAll().filter(route => route.method === method);\n }\n \n /**\n * Get routes by path prefix\n * @param prefix - Path prefix\n */\n getByPrefix(prefix: string): RouteEntry[] {\n return this.getAll().filter(route => route.path.startsWith(prefix));\n }\n \n /**\n * Get routes by tag\n * @param tag - Tag name\n */\n getByTag(tag: string): RouteEntry[] {\n return this.getAll().filter(route => \n route.metadata?.tags?.includes(tag)\n );\n }\n \n /**\n * Create a route group with common prefix\n * @param prefix - Common path prefix\n * @param configure - Function to configure routes in the group\n */\n group(prefix: string, configure: (group: RouteGroupBuilder) => void): void {\n const builder = new RouteGroupBuilder(this, prefix);\n configure(builder);\n }\n \n /**\n * Get route count\n */\n count(): number {\n return this.routes.size;\n }\n \n /**\n * Clear all routes\n */\n clear(): void {\n this.routes.clear();\n }\n \n /**\n * Get route key for storage\n */\n private getRouteKey(method: HttpMethod, path: string): string {\n return `${method}:${path}`;\n }\n \n /**\n * Register route with underlying server\n */\n private registerWithServer(entry: RouteEntry): void {\n const { method, path, handler } = entry;\n \n switch (method) {\n case 'GET':\n this.server.get(path, handler);\n break;\n case 'POST':\n this.server.post(path, handler);\n break;\n case 'PUT':\n this.server.put(path, handler);\n break;\n case 'DELETE':\n this.server.delete(path, handler);\n break;\n case 'PATCH':\n this.server.patch(path, handler);\n break;\n default:\n throw new Error(`Unsupported HTTP method: ${method}`);\n }\n }\n}\n\n/**\n * RouteGroupBuilder\n * \n * Builder for creating route groups with common prefix\n */\nexport class RouteGroupBuilder {\n private manager: RouteManager;\n private prefix: string;\n \n constructor(manager: RouteManager, prefix: string) {\n this.manager = manager;\n this.prefix = prefix;\n }\n \n /**\n * Register GET route in group\n */\n get(path: string, handler: RouteHandler, metadata?: RouteHandlerMetadata['metadata']): this {\n this.manager.register({\n method: 'GET',\n path: this.resolvePath(path),\n handler,\n metadata,\n });\n return this;\n }\n \n /**\n * Register POST route in group\n */\n post(path: string, handler: RouteHandler, metadata?: RouteHandlerMetadata['metadata']): this {\n this.manager.register({\n method: 'POST',\n path: this.resolvePath(path),\n handler,\n metadata,\n });\n return this;\n }\n \n /**\n * Register PUT route in group\n */\n put(path: string, handler: RouteHandler, metadata?: RouteHandlerMetadata['metadata']): this {\n this.manager.register({\n method: 'PUT',\n path: this.resolvePath(path),\n handler,\n metadata,\n });\n return this;\n }\n \n /**\n * Register PATCH route in group\n */\n patch(path: string, handler: RouteHandler, metadata?: RouteHandlerMetadata['metadata']): this {\n this.manager.register({\n method: 'PATCH',\n path: this.resolvePath(path),\n handler,\n metadata,\n });\n return this;\n }\n \n /**\n * Register DELETE route in group\n */\n delete(path: string, handler: RouteHandler, metadata?: RouteHandlerMetadata['metadata']): this {\n this.manager.register({\n method: 'DELETE',\n path: this.resolvePath(path),\n handler,\n metadata,\n });\n return this;\n }\n \n /**\n * Resolve full path with prefix\n */\n private resolvePath(path: string): string {\n // Normalize slashes\n const normalizedPrefix = this.prefix.endsWith('/') \n ? this.prefix.slice(0, -1) \n : this.prefix;\n const normalizedPath = path.startsWith('/') \n ? path \n : '/' + path;\n \n return normalizedPrefix + normalizedPath;\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { IHttpServer } from '@objectstack/core';\nimport { RouteManager } from './route-manager.js';\nimport { RestServerConfig, RestApiConfig, CrudEndpointsConfig, MetadataEndpointsConfig, BatchEndpointsConfig, RouteGenerationConfig } from '@objectstack/spec/api';\nimport { ObjectStackProtocol } from '@objectstack/spec/api';\n\n// Node-safe logger — avoids importing 'console' which is absent from ES2020 lib typings.\nconst logError = (...args: unknown[]) => (globalThis as any).console?.error(...args);\n\n/**\n * Map a data-layer error to a clean HTTP response. Unknown-object errors\n * (SQLite \"no such table\", PG \"relation does not exist\", protocol\n * \"object not found\", etc.) are surfaced as a 404 with `code: 'object_not_found'`\n * so clients can distinguish \"object isn't registered\" from real server\n * faults. Anything else becomes a 400 (bad request) preserving prior\n * behavior. Genuine 500s are still logged.\n *\n * `PermissionDeniedError` (thrown by `SecurityPlugin`) MUST be caught\n * before the unknown-object heuristic, otherwise its message —\n * \"[Security] Access denied: operation 'insert' on object 'sys_user' is\n * not permitted …\" — trips the `'<obj>' … not` substring check and\n * returns a misleading 404.\n */\nfunction mapDataError(error: any, object?: string): { status: number; body: Record<string, unknown> } {\n // Validation failures → 400 with per-field envelope. Handled FIRST\n // because the validator throws a typed error before any SQL ever\n // runs, and we want callers to differentiate \"your payload was\n // invalid\" (fixable client-side) from generic 400s.\n if (error?.code === 'VALIDATION_FAILED' || error?.name === 'ValidationError') {\n return {\n status: 400,\n body: {\n error: error?.message ?? 'Validation failed',\n code: 'VALIDATION_FAILED',\n fields: Array.isArray(error?.fields) ? error.fields : [],\n ...(object ? { object } : {}),\n },\n };\n }\n // Short-circuit: explicit security denial → 403. Match by `code` /\n // `name` to avoid pulling a runtime dependency on plugin-security.\n if (\n error?.code === 'PERMISSION_DENIED' ||\n error?.name === 'PermissionDeniedError' ||\n (typeof error?.message === 'string' && error.message.startsWith('[Security] Access denied'))\n ) {\n return {\n status: 403,\n body: {\n error: error?.message ?? 'Permission denied',\n code: 'PERMISSION_DENIED',\n ...(object ? { object } : {}),\n },\n };\n }\n const raw = String(error?.message ?? error ?? '');\n const lower = raw.toLowerCase();\n\n // ProjectKernelFactory: project missing database_url/driver — typically\n // means provisioning is in flight or the project record was never\n // fully provisioned. 503 (with Retry-After implied) is more accurate\n // than the default 400/500: clients can poll until the project is\n // active.\n if (\n raw.includes('[ProjectKernelFactory]') &&\n (lower.includes('missing database_url') || lower.includes('not found'))\n ) {\n const isProvisioning = lower.includes(\"status='provisioning'\") || lower.includes(\"status='pending'\");\n const isFailed = lower.includes(\"status='failed'\");\n return {\n status: isProvisioning ? 503 : isFailed ? 502 : 404,\n body: {\n error: raw,\n code: isProvisioning\n ? 'PROJECT_PROVISIONING'\n : isFailed\n ? 'PROJECT_PROVISIONING_FAILED'\n : 'PROJECT_NOT_FOUND',\n },\n };\n }\n\n // Record-level not-found from ObjectQL (`getData` / `updateData` /\n // `deleteData`). These are normal client mistakes (stale UI link,\n // hand-typed id, deleted record) and should be a quiet 404 — not\n // a \"[REST] Unhandled error\" log entry that scares operators.\n if (\n error?.code === 'RECORD_NOT_FOUND' ||\n /^Record\\s+\\S+\\s+not found in\\s+\\S+/i.test(raw)\n ) {\n return {\n status: 404,\n body: {\n error: raw,\n code: 'RECORD_NOT_FOUND',\n ...(object ? { object } : {}),\n },\n };\n }\n\n const looksLikeUnknownObject =\n lower.includes('no such table') ||\n lower.includes('relation') && lower.includes('does not exist') ||\n lower.includes('table not found') ||\n lower.includes('unknown object') ||\n lower.includes('object not found') ||\n lower.includes('no driver available') ||\n (object !== undefined && lower.includes(`'${object.toLowerCase()}'`) && lower.includes('not'));\n if (looksLikeUnknownObject) {\n return {\n status: 404,\n body: {\n error: object ? `Object '${object}' is not registered` : 'Object not found',\n code: 'object_not_found',\n object,\n },\n };\n }\n // Default: do NOT leak raw SQL or driver internals. If the message\n // looks like a SQL/driver dump, replace it with a generic envelope\n // and rely on server logs for the full diagnostic.\n const looksLikeSqlLeak =\n lower.includes('sqlite_') ||\n lower.includes('sqlstate') ||\n lower.startsWith('insert into ') ||\n lower.startsWith('update ') ||\n lower.startsWith('select ') ||\n lower.startsWith('delete from ') ||\n lower.includes('constraint failed') ||\n lower.includes('unique constraint') ||\n lower.includes('foreign key');\n if (looksLikeSqlLeak) {\n // Surface unique-constraint violations as a structured 409 so\n // the UI can map them to \"this value already exists\".\n if (lower.includes('unique constraint') || lower.includes('unique violation')) {\n return {\n status: 409,\n body: {\n error: 'A record with this value already exists',\n code: 'UNIQUE_VIOLATION',\n ...(object ? { object } : {}),\n },\n };\n }\n return {\n status: 500,\n body: { error: 'Internal data error', code: 'DATABASE_ERROR' },\n };\n }\n return { status: 400, body: { error: raw || 'Bad request' } };\n}\n\n/**\n * Centralized error responder for all REST handlers. Ensures raw driver\n * messages (SQLite/Postgres dumps, stack traces, unique-constraint\n * payloads with table names, etc.) never reach clients. Honors\n * structured errors that already carry an explicit `status` so callers\n * can surface domain-specific codes (e.g. 422 from a metadata save\n * validator), and routes everything else through `mapDataError` so the\n * security / validation / SQL-leak / unknown-object envelopes apply\n * uniformly across CRUD, batch, metadata, UI and discovery routes.\n */\nfunction sendError(res: any, error: any, object?: string): void {\n if (typeof error?.status === 'number' && error.status >= 400 && error.status < 600) {\n const safeMsg = typeof error.message === 'string' && error.message.length < 500\n ? error.message\n : 'Request failed';\n res.status(error.status).json({\n error: safeMsg,\n ...(error.code ? { code: error.code } : {}),\n });\n return;\n }\n const mapped = mapDataError(error, object);\n res.status(mapped.status).json(mapped.body);\n}\n\n/**\n * Whether a mapped data-error status represents an *expected* client/lifecycle\n * outcome (and therefore shouldn't be logged as \"[REST] Unhandled error\").\n * - 403 PERMISSION_DENIED is a normal RBAC denial\n * - 404 unknown object / project not found is a normal client mistake\n * - 502/503 mean the underlying project is provisioning or failed; the\n * handler will emit the response and the operator can inspect\n * sys_project.metadata.provisioningError if needed.\n */\nfunction isExpectedDataStatus(status: number): boolean {\n return status === 403 || status === 404 || status === 409 || status === 502 || status === 503;\n}\n\n/**\n * Minimal RFC-4180-style CSV parser used by the bulk-import endpoint\n * (M10.9). Handles quoted fields (including embedded quotes via \"\" and\n * embedded commas/newlines) and both CRLF and LF line endings.\n *\n * The first non-empty line is treated as the header row. Header names\n * can be re-mapped to canonical field names via the optional `mapping`\n * argument (e.g. `{ \"First Name\": \"first_name\" }`); unmapped headers\n * pass through unchanged. Empty cells become empty strings.\n *\n * Kept dependency-free so REST stays runtime-portable (Hono / Express\n * adapters both consume this without pulling a CSV lib transitively).\n */\nfunction parseCsvToRows(csv: string, mapping: Record<string, string> = {}): Array<Record<string, any>> {\n const text = csv.replace(/^\\uFEFF/, ''); // strip BOM\n const cells: string[][] = [];\n let cur = '';\n let row: string[] = [];\n let inQuotes = false;\n for (let i = 0; i < text.length; i++) {\n const ch = text[i];\n if (inQuotes) {\n if (ch === '\"') {\n if (text[i + 1] === '\"') { cur += '\"'; i++; }\n else { inQuotes = false; }\n } else {\n cur += ch;\n }\n continue;\n }\n if (ch === '\"') { inQuotes = true; continue; }\n if (ch === ',') { row.push(cur); cur = ''; continue; }\n if (ch === '\\r') { continue; }\n if (ch === '\\n') {\n row.push(cur); cur = '';\n cells.push(row); row = [];\n continue;\n }\n cur += ch;\n }\n if (cur.length > 0 || row.length > 0) { row.push(cur); cells.push(row); }\n\n // Drop fully-empty trailing rows so a stray newline at EOF doesn't\n // produce a phantom empty record.\n while (cells.length > 0 && cells[cells.length - 1].every(c => c === '')) cells.pop();\n if (cells.length < 2) return [];\n\n const header = cells[0].map(h => h.trim());\n const fields = header.map(h => mapping[h] ?? h);\n const out: Array<Record<string, any>> = [];\n for (let r = 1; r < cells.length; r++) {\n const row = cells[r];\n const obj: Record<string, any> = {};\n for (let c = 0; c < fields.length; c++) {\n const key = fields[c];\n if (!key) continue;\n const raw = row[c] ?? '';\n obj[key] = raw;\n }\n out.push(obj);\n }\n return out;\n}\n\n/**\n * Escape a single value into an RFC-4180 CSV cell. Values containing\n * commas, quotes, CR, or LF are wrapped in double-quotes with embedded\n * quotes doubled. `null` / `undefined` become an empty cell. Objects and\n * arrays are serialised as compact JSON so nested data round-trips\n * without flattening surprises.\n */\nfunction formatCsvCell(value: any): string {\n if (value === null || value === undefined) return '';\n let s: string;\n if (typeof value === 'string') s = value;\n else if (typeof value === 'number' || typeof value === 'boolean' || typeof value === 'bigint') s = String(value);\n else if (value instanceof Date) s = value.toISOString();\n else { try { s = JSON.stringify(value); } catch { s = String(value); } }\n if (/[\",\\r\\n]/.test(s)) {\n return `\"${s.replace(/\"/g, '\"\"')}\"`;\n }\n return s;\n}\n\n/**\n * Serialise a list of rows to RFC-4180 CSV text. Caller supplies the\n * ordered list of field names; unknown fields produce empty cells.\n */\nfunction rowsToCsv(fields: string[], rows: Array<Record<string, any>>, includeHeader: boolean): string {\n const lines: string[] = [];\n if (includeHeader) lines.push(fields.map(formatCsvCell).join(','));\n for (const row of rows) {\n lines.push(fields.map(f => formatCsvCell(row?.[f])).join(','));\n }\n return lines.join('\\r\\n') + (lines.length > 0 ? '\\r\\n' : '');\n}\n\n/**\n * Structural subset of `KernelManager` that RestServer needs in order to\n * resolve a per-project protocol at request time. Typed locally to avoid\n * an @objectstack/runtime → @objectstack/rest → @objectstack/runtime\n * package cycle.\n */\nexport interface RestKernelManager {\n getOrCreate(projectId: string): Promise<{\n getServiceAsync<T = unknown>(name: string): Promise<T>;\n }>;\n}\n\n/**\n * Normalized REST Server Configuration\n * All nested properties are required after normalization\n */\ntype NormalizedRestServerConfig = {\n api: {\n version: string;\n basePath: string;\n apiPath: string | undefined;\n enableCrud: boolean;\n enableMetadata: boolean;\n enableUi: boolean;\n enableBatch: boolean;\n enableDiscovery: boolean;\n enableSearch?: boolean;\n enableProjectScoping: boolean;\n projectResolution: 'required' | 'optional' | 'auto';\n requireAuth: boolean;\n documentation: RestApiConfig['documentation'];\n responseFormat: RestApiConfig['responseFormat'];\n };\n crud: {\n operations: {\n create: boolean;\n read: boolean;\n update: boolean;\n delete: boolean;\n list: boolean;\n };\n patterns: CrudEndpointsConfig['patterns'];\n dataPrefix: string;\n objectParamStyle: 'path' | 'query';\n };\n metadata: {\n prefix: string;\n enableCache: boolean;\n cacheTtl: number;\n endpoints: {\n types: boolean;\n items: boolean;\n item: boolean;\n schema: boolean;\n };\n };\n batch: {\n maxBatchSize: number;\n enableBatchEndpoint: boolean;\n operations: {\n createMany: boolean;\n updateMany: boolean;\n deleteMany: boolean;\n upsertMany: boolean;\n };\n defaultAtomic: boolean;\n };\n routes: {\n includeObjects: string[] | undefined;\n excludeObjects: string[] | undefined;\n nameTransform: 'none' | 'plural' | 'kebab-case' | 'camelCase';\n overrides: RouteGenerationConfig['overrides'];\n };\n};\n\n/**\n * RestServer\n * \n * Provides automatic REST API endpoint generation for ObjectStack.\n * Generates standard RESTful CRUD endpoints, metadata endpoints, and batch operations\n * based on the configured protocol provider.\n * \n * Features:\n * - Automatic CRUD endpoint generation (GET, POST, PUT, PATCH, DELETE)\n * - Metadata API endpoints (/meta)\n * - Batch operation endpoints (/batch, /createMany, /updateMany, /deleteMany)\n * - Discovery endpoint\n * - Configurable path prefixes and patterns\n * \n * @example\n * const restServer = new RestServer(httpServer, protocolProvider, {\n * api: {\n * version: 'v1',\n * basePath: '/api'\n * },\n * crud: {\n * dataPrefix: '/data'\n * }\n * });\n * \n * restServer.registerRoutes();\n */\n/**\n * Minimal env registry shape consumed by the REST server for hostname →\n * projectId resolution and `X-Project-Id` header validation on unscoped\n * routes. Mirrors the surface of `EnvironmentDriverRegistry` defined in\n * `@objectstack/service-cloud`.\n */\nexport interface RestEnvRegistry {\n resolveByHostname(hostname: string): Promise<{ projectId: string } | null | undefined>;\n /**\n * Look up a project by id. Returns a truthy value (typically an\n * `IDataDriver`) when the project exists and is bound, `null` when\n * unknown. The REST server only uses the truthiness; it does not\n * touch the driver itself (the actual driver is loaded later via\n * `KernelManager.getOrCreate(projectId)`).\n */\n resolveById?(projectId: string): Promise<unknown | null>;\n}\n\nexport class RestServer {\n private protocol: ObjectStackProtocol;\n private config: NormalizedRestServerConfig;\n private routeManager: RouteManager;\n private kernelManager?: RestKernelManager;\n private envRegistry?: RestEnvRegistry;\n private defaultProjectIdProvider?: () => string | undefined;\n private authServiceProvider?: (projectId?: string) => Promise<any | undefined>;\n private objectQLProvider?: (projectId?: string) => Promise<any | undefined>;\n private emailServiceProvider?: (projectId?: string) => Promise<any | undefined>;\n private sharingServiceProvider?: (projectId?: string) => Promise<any | undefined>;\n private reportsServiceProvider?: (projectId?: string) => Promise<any | undefined>;\n private approvalsServiceProvider?: (projectId?: string) => Promise<any | undefined>;\n private sharingRulesServiceProvider?: (projectId?: string) => Promise<any | undefined>;\n private i18nServiceProvider?: (projectId?: string) => Promise<any | undefined>;\n\n constructor(\n server: IHttpServer,\n protocol: ObjectStackProtocol,\n config: RestServerConfig = {},\n kernelManager?: RestKernelManager,\n envRegistry?: RestEnvRegistry,\n defaultProjectIdProvider?: () => string | undefined,\n authServiceProvider?: (projectId?: string) => Promise<any | undefined>,\n objectQLProvider?: (projectId?: string) => Promise<any | undefined>,\n emailServiceProvider?: (projectId?: string) => Promise<any | undefined>,\n sharingServiceProvider?: (projectId?: string) => Promise<any | undefined>,\n reportsServiceProvider?: (projectId?: string) => Promise<any | undefined>,\n approvalsServiceProvider?: (projectId?: string) => Promise<any | undefined>,\n sharingRulesServiceProvider?: (projectId?: string) => Promise<any | undefined>,\n i18nServiceProvider?: (projectId?: string) => Promise<any | undefined>,\n ) {\n this.protocol = protocol;\n this.config = this.normalizeConfig(config);\n this.routeManager = new RouteManager(server);\n this.kernelManager = kernelManager;\n this.envRegistry = envRegistry;\n this.defaultProjectIdProvider = defaultProjectIdProvider;\n this.authServiceProvider = authServiceProvider;\n this.objectQLProvider = objectQLProvider;\n this.emailServiceProvider = emailServiceProvider;\n this.sharingServiceProvider = sharingServiceProvider;\n this.reportsServiceProvider = reportsServiceProvider;\n this.approvalsServiceProvider = approvalsServiceProvider;\n this.sharingRulesServiceProvider = sharingRulesServiceProvider;\n this.i18nServiceProvider = i18nServiceProvider;\n }\n\n /**\n * Resolve the protocol for a given request. When `projectId` is present\n * and a KernelManager is wired, fetch the per-project kernel's\n * `protocol` service so metadata / data / UI reads hit the project's\n * own registry and datastore.\n *\n * When `projectId` is absent on an unscoped route and an `envRegistry`\n * is wired (runtime mode), the resolution chain is:\n * 1. Hostname → projectId (`envRegistry.resolveByHostname`)\n * 2. `X-Project-Id` header → projectId (`envRegistry.resolveById`)\n * 3. Default-project fallback (`defaultProjectIdProvider`, set by\n * `createSingleProjectPlugin`)\n * 4. Control-plane protocol captured at boot.\n *\n * Special case: `projectId === 'platform'` is a reserved virtual id used\n * by Studio to address the control plane through the regular project\n * URL shape (`/projects/platform/...`). It is NOT a row in the projects\n * table, so we must never call `KernelManager.getOrCreate('platform')`.\n * Instead, return the control-plane protocol directly. This lets Studio\n * (and any other client) speak a single, uniform URL family without\n * duplicating route logic for the platform surface.\n */\n private async resolveProtocol(projectId?: string, req?: any): Promise<ObjectStackProtocol> {\n if (projectId === 'platform') return this.protocol;\n if (!projectId && req && this.envRegistry && this.kernelManager) {\n const host = this.extractHostname(req);\n if (host) {\n try {\n const result = await this.envRegistry.resolveByHostname(host);\n if (result?.projectId) projectId = result.projectId;\n } catch {\n // fall through to next strategy\n }\n }\n // 2. `X-Project-Id` request header → projectId. Lets clients\n // explicitly target a project when the URL is unscoped and\n // no hostname binding exists (e.g. a single shared origin\n // serving multiple compiled bundles via OS_PROJECT_ARTIFACTS).\n // We validate the id through the env registry to avoid\n // routing to a non-existent kernel.\n if (!projectId && typeof this.envRegistry.resolveById === 'function') {\n const headerVal = this.extractProjectIdHeader(req);\n if (headerVal) {\n try {\n const driver = await this.envRegistry.resolveById(headerVal);\n if (driver) projectId = headerVal;\n } catch {\n // fall through to default fallback\n }\n }\n }\n }\n // 3. Single-project default fallback. Registered by\n // `createSingleProjectPlugin()` so bare `/api/v1/data/...` URLs\n // (no `/projects/<id>` prefix, no hostname mapping, no header)\n // resolve to the lone project's kernel rather than the control\n // plane.\n if (!projectId && this.defaultProjectIdProvider) {\n try {\n const def = this.defaultProjectIdProvider();\n if (def) projectId = def;\n } catch { /* fall through */ }\n }\n if (!projectId || !this.kernelManager) return this.protocol;\n const kernel = await this.kernelManager.getOrCreate(projectId);\n return kernel.getServiceAsync<ObjectStackProtocol>('protocol');\n }\n\n /**\n * Resolve the i18n service for the request's project (or control plane\n * when no project id is in scope). Returns `undefined` when no service is\n * registered, so callers can short-circuit and skip translation rather\n * than failing.\n *\n * Mirrors `resolveProtocol`'s lookup chain: explicit `projectId` from the\n * route → kernel-managed `i18n` service. Control-plane / unscoped\n * requests intentionally return `undefined` because the platform kernel\n * does not own per-app translation bundles.\n */\n private async resolveI18nService(projectId?: string, req?: any): Promise<any | undefined> {\n if (projectId === 'platform') return undefined;\n // Mirror resolveProtocol's fallback chain so unscoped routes (single-\n // project dev servers, hostname-routed multi-tenants, X-Project-Id\n // headers) can still pick up per-project translation bundles.\n if (!projectId && req && this.envRegistry && this.kernelManager) {\n const host = this.extractHostname(req);\n if (host) {\n try {\n const result = await this.envRegistry.resolveByHostname(host);\n if (result?.projectId) projectId = result.projectId;\n } catch { /* fall through */ }\n }\n if (!projectId && typeof this.envRegistry.resolveById === 'function') {\n const headerVal = this.extractProjectIdHeader(req);\n if (headerVal) {\n try {\n const driver = await this.envRegistry.resolveById(headerVal);\n if (driver) projectId = headerVal;\n } catch { /* fall through */ }\n }\n }\n }\n if (!projectId && this.defaultProjectIdProvider) {\n try {\n const def = this.defaultProjectIdProvider();\n if (def) projectId = def;\n } catch { /* fall through */ }\n }\n // Multi-tenant kernel lookup first; falls back to the single-kernel\n // provider supplied by RestApiPlugin in dev / standalone mode.\n if (projectId && this.kernelManager) {\n try {\n const kernel = await this.kernelManager.getOrCreate(projectId);\n const svc = await kernel.getServiceAsync<any>('i18n');\n if (svc) return svc;\n } catch { /* fall through */ }\n }\n if (this.i18nServiceProvider) {\n try {\n return await this.i18nServiceProvider(projectId);\n } catch { return undefined; }\n }\n return undefined;\n }\n\n /**\n * Reject anonymous requests with HTTP 401 when `api.requireAuth` is set.\n * Returns `true` if the response was sent and the caller should stop\n * processing. Returns `false` to continue.\n *\n * The check is intentionally narrow: only `context?.userId` counts as\n * \"authenticated\". `isSystem` flags are never set on inbound HTTP\n * requests (they're internal-only), so they cannot bypass this gate.\n */\n private enforceAuth(req: any, res: any, context: any): boolean {\n if (!this.config.api.requireAuth) return false;\n if (context?.userId) return false;\n if (req?.method === 'OPTIONS') return false;\n res.status(401).json({\n error: 'unauthenticated',\n message: 'Authentication is required to access this endpoint.',\n });\n return true;\n }\n\n /**\n * Resolve the request's execution context (RBAC/RLS/FLS) by looking up\n * the better-auth session via the project's `auth` service. Returns\n * `undefined` for anonymous requests so callers can pass `context` as-is\n * to the protocol layer (the SecurityPlugin treats undefined as anon).\n */\n private async resolveExecCtx(projectId: string | undefined, req: any): Promise<any | undefined> {\n try {\n // For multi-tenant hosts (objectos), incoming requests on unscoped\n // URLs like `/api/v1/data/:object` arrive with `projectId === undefined`.\n // The route's protocol resolver already maps hostname → projectId\n // (see resolveProtocol). We mirror that here so getSession() can\n // find the right per-project auth service. Without this, the\n // hostname-routed requests fall through to defaultProjectIdProvider/\n // authServiceProvider (neither of which is wired in objectos) and\n // every authenticated user sees 401.\n if (!projectId && req && this.envRegistry && this.kernelManager) {\n const host = this.extractHostname(req);\n if (host) {\n try {\n const result = await this.envRegistry.resolveByHostname(host);\n if (result?.projectId) projectId = result.projectId;\n } catch { /* fall through */ }\n }\n if (!projectId && typeof this.envRegistry.resolveById === 'function') {\n const headerVal = this.extractProjectIdHeader(req);\n if (headerVal) {\n try {\n const driver = await this.envRegistry.resolveById(headerVal);\n if (driver) projectId = headerVal;\n } catch { /* fall through */ }\n }\n }\n }\n // Look up the auth service in the right kernel. For unscoped\n // single-project apps the kernelManager will hand us the lone\n // tenant kernel; for multi-project hosts we use the resolved\n // projectId.\n let authService: any;\n let kernel: any;\n if (projectId && projectId !== 'platform' && this.kernelManager) {\n kernel = await this.kernelManager.getOrCreate(projectId);\n authService = await kernel.getServiceAsync('auth').catch(() => undefined);\n }\n if (!authService && this.defaultProjectIdProvider && this.kernelManager) {\n try {\n const def = this.defaultProjectIdProvider();\n if (def) {\n kernel = await this.kernelManager.getOrCreate(def);\n authService = await kernel.getServiceAsync('auth').catch(() => undefined);\n }\n } catch { /* fall through */ }\n }\n // Single-kernel deployment fallback — no kernelManager, but\n // the plugin wired an `authServiceProvider` that hits the\n // local kernel directly.\n if (!authService && this.authServiceProvider) {\n authService = await this.authServiceProvider(projectId).catch(() => undefined);\n }\n if (!authService) return undefined;\n // The auth service may be the AuthManager wrapper (which exposes\n // `getApi()`) or the raw better-auth instance (which exposes\n // `.api` directly). Normalize to the raw API object.\n let api: any = authService.api;\n if (!api && typeof authService.getApi === 'function') {\n api = await authService.getApi();\n }\n if (!api?.getSession) return undefined;\n\n // better-auth's `getSession` requires a Web `Headers` instance\n // (it calls `headers.get('cookie')`). Adapter req.headers may\n // already be one, or a plain object — normalize.\n const rawHeaders: any = req?.headers;\n let headers: any;\n if (rawHeaders && typeof rawHeaders.get === 'function') {\n headers = rawHeaders;\n } else if (rawHeaders && typeof rawHeaders === 'object') {\n headers = new (globalThis as any).Headers();\n for (const [k, v] of Object.entries(rawHeaders)) {\n if (Array.isArray(v)) v.forEach((x) => headers.append(k, String(x)));\n else if (v != null) headers.set(k, String(v));\n }\n } else {\n return undefined;\n }\n\n const session = await api.getSession({ headers });\n if (!session?.user?.id) return undefined;\n const userId = session.user.id;\n const tenantId = session.session?.activeOrganizationId ?? undefined;\n const permissions: string[] = [];\n const roles: string[] = [];\n // Look up the link tables to surface roles + permission set names.\n // Skipping this lookup would silently ignore admin/role grants —\n // including the platform-admin promotion seeded by\n // `bootstrapPlatformAdmin` — and force every authenticated user\n // through the `member_default` fallback path.\n try {\n let ql: any;\n if (kernel) {\n ql = await kernel.getServiceAsync('objectql').catch(() => undefined);\n }\n if (!ql && this.objectQLProvider) {\n ql = await this.objectQLProvider(projectId).catch(() => undefined);\n }\n if (ql && typeof ql.find === 'function') {\n const sysOpts = { context: { isSystem: true } };\n const memberRows = await ql.find('sys_member', {\n where: tenantId ? { user_id: userId, organization_id: tenantId } : { user_id: userId },\n limit: 50,\n ...sysOpts,\n } as any).catch(() => []);\n for (const m of (memberRows ?? []) as any[]) {\n if (typeof m.role === 'string') {\n for (const r of m.role.split(',').map((s: string) => s.trim()).filter(Boolean)) {\n if (!roles.includes(r)) roles.push(r);\n }\n }\n }\n const upsRows = await ql.find('sys_user_permission_set', {\n where: { user_id: userId },\n limit: 100,\n ...sysOpts,\n } as any).catch(() => []);\n const psIds = new Set<string>();\n for (const r of (upsRows ?? []) as any[]) {\n const orgScope = r.organization_id ?? null;\n if (!orgScope || (tenantId && orgScope === tenantId)) {\n const pid = r.permission_set_id ?? r.permissionSetId;\n if (pid) psIds.add(pid);\n }\n }\n if (psIds.size > 0) {\n const psRows = await ql.find('sys_permission_set', {\n where: { id: { $in: Array.from(psIds) } },\n limit: 500,\n ...sysOpts,\n } as any).catch(() => []);\n for (const ps of (psRows ?? []) as any[]) {\n if (ps.name && !permissions.includes(ps.name)) permissions.push(ps.name);\n }\n }\n }\n } catch { /* fall through with empty perms */ }\n return {\n userId,\n tenantId,\n roles,\n permissions,\n isSystem: false,\n };\n } catch {\n return undefined;\n }\n }\n\n /**\n * Build a `TranslationBundle` (`Record<locale, TranslationData>`) from an\n * `II18nService` instance. Returns `undefined` when no locales are\n * registered so callers can avoid translation work.\n */\n private buildTranslationBundle(i18n: any): any | undefined {\n if (!i18n || typeof i18n.getLocales !== 'function' || typeof i18n.getTranslations !== 'function') {\n return undefined;\n }\n const locales: string[] = i18n.getLocales();\n if (!locales.length) return undefined;\n const bundle: Record<string, any> = {};\n for (const locale of locales) {\n const data = i18n.getTranslations(locale);\n if (data && typeof data === 'object') bundle[locale] = data;\n }\n return Object.keys(bundle).length ? bundle : undefined;\n }\n\n /**\n * Parse the highest-priority locale from an `Accept-Language` header.\n * Falls back to a `?locale=` query parameter, then to the i18n service's\n * default locale. Returns `undefined` when no preference is expressed\n * (callers will then return untranslated metadata).\n */\n private extractLocale(req: any, i18n?: any): string | undefined {\n const headers = req?.headers;\n let header: string | undefined;\n if (headers) {\n header = typeof headers.get === 'function'\n ? headers.get('accept-language') ?? undefined\n : headers['accept-language'] ?? headers['Accept-Language'];\n }\n if (typeof header === 'string' && header.length > 0) {\n const top = header.split(',')[0]?.split(';')[0]?.trim();\n if (top) return top;\n }\n const queryLocale = req?.query?.locale;\n if (typeof queryLocale === 'string' && queryLocale.length > 0) return queryLocale;\n if (i18n && typeof i18n.getDefaultLocale === 'function') {\n const def = i18n.getDefaultLocale();\n if (typeof def === 'string' && def.length > 0) return def;\n }\n return undefined;\n }\n\n /**\n * Translate a single metadata document (view or action) when an i18n\n * service is registered for the request's project and the requested\n * locale yields a match. Falls through unchanged for unsupported types\n * or missing translations.\n */\n private async translateMetaItem(req: any, type: string, projectId: string | undefined, item: any): Promise<any> {\n if (!item || typeof item !== 'object') return item;\n if (type !== 'view' && type !== 'action' && type !== 'object') return item;\n const i18n = await this.resolveI18nService(projectId, req);\n const bundle = this.buildTranslationBundle(i18n);\n if (!bundle) return item;\n const locale = this.extractLocale(req, i18n);\n if (!locale) return item;\n const { translateMetadataDocument } = await import('@objectstack/spec/system');\n return translateMetadataDocument(type, item, bundle, { locale });\n }\n\n /**\n * Translate a list of metadata documents using `translateMetaItem`.\n */\n private async translateMetaItems(req: any, type: string, projectId: string | undefined, items: any): Promise<any> {\n if (!Array.isArray(items)) return items;\n if (type !== 'view' && type !== 'action' && type !== 'object') return items;\n const i18n = await this.resolveI18nService(projectId, req);\n const bundle = this.buildTranslationBundle(i18n);\n if (!bundle) return items;\n const locale = this.extractLocale(req, i18n);\n if (!locale) return items;\n const { translateMetadataDocument } = await import('@objectstack/spec/system');\n return items.map((item) => translateMetadataDocument(type, item, bundle, { locale }));\n }\n\n /**\n * Pull the request hostname (without port) from a Node-style `req` or\n * a Fetch-style request wrapper. Returns undefined when no Host header\n * is available.\n */\n private extractHostname(req: any): string | undefined {\n const headers = req?.headers;\n let host: string | undefined;\n if (headers) {\n if (typeof headers.get === 'function') {\n host = headers.get('host') ?? undefined;\n } else {\n host = headers.host ?? headers.Host;\n }\n }\n if (!host && typeof req?.hostname === 'string') host = req.hostname;\n if (!host && typeof req?.url === 'string') {\n // Fetch-style requests expose the hostname via `req.url` even\n // when the (forbidden) `Host` header has been stripped by the\n // runtime. This branch keeps hostname-routing working when\n // tests build a `Request` object through `app.fetch(...)`.\n try {\n host = new (globalThis as any).URL(req.url).host;\n } catch { /* ignore */ }\n }\n if (!host) return undefined;\n return String(host).split(':')[0].toLowerCase();\n }\n\n /**\n * Pull the `X-Project-Id` header from a Node- or Fetch-style request.\n * Header names are case-insensitive; we probe both casings to cover\n * adapters that don't normalize headers (e.g. raw Node http).\n */\n private extractProjectIdHeader(req: any): string | undefined {\n const headers = req?.headers;\n if (!headers) return undefined;\n let val: unknown;\n if (typeof headers.get === 'function') {\n val = headers.get('x-project-id') ?? headers.get('X-Project-Id');\n } else {\n val = headers['x-project-id'] ?? headers['X-Project-Id'];\n }\n if (Array.isArray(val)) val = val[0];\n if (typeof val !== 'string') return undefined;\n const trimmed = val.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n }\n \n /**\n * Normalize configuration with defaults\n */\n private normalizeConfig(config: RestServerConfig): NormalizedRestServerConfig {\n const api = (config.api ?? {}) as Partial<RestApiConfig>;\n const crud = (config.crud ?? {}) as Partial<CrudEndpointsConfig>;\n const metadata = (config.metadata ?? {}) as Partial<MetadataEndpointsConfig>;\n const batch = (config.batch ?? {}) as Partial<BatchEndpointsConfig>;\n const routes = (config.routes ?? {}) as Partial<RouteGenerationConfig>;\n \n return {\n api: {\n version: api.version ?? 'v1',\n basePath: api.basePath ?? '/api',\n apiPath: api.apiPath,\n enableCrud: api.enableCrud ?? true,\n enableMetadata: api.enableMetadata ?? true,\n enableUi: api.enableUi ?? true,\n enableBatch: api.enableBatch ?? true,\n enableDiscovery: api.enableDiscovery ?? true,\n enableSearch: (api as any).enableSearch ?? true,\n enableProjectScoping: api.enableProjectScoping ?? false,\n projectResolution: api.projectResolution ?? 'auto',\n requireAuth: (api as any).requireAuth ?? false,\n documentation: api.documentation,\n responseFormat: api.responseFormat,\n },\n crud: {\n operations: crud.operations ?? {\n create: true,\n read: true,\n update: true,\n delete: true,\n list: true,\n },\n patterns: crud.patterns,\n dataPrefix: crud.dataPrefix ?? '/data',\n objectParamStyle: crud.objectParamStyle ?? 'path',\n },\n metadata: {\n prefix: metadata.prefix ?? '/meta',\n enableCache: metadata.enableCache ?? true,\n cacheTtl: metadata.cacheTtl ?? 3600,\n endpoints: metadata.endpoints ?? {\n types: true,\n items: true,\n item: true,\n schema: true,\n },\n },\n batch: {\n maxBatchSize: batch.maxBatchSize ?? 200,\n enableBatchEndpoint: batch.enableBatchEndpoint ?? true,\n operations: batch.operations ?? {\n createMany: true,\n updateMany: true,\n deleteMany: true,\n upsertMany: true,\n },\n defaultAtomic: batch.defaultAtomic ?? true,\n },\n routes: {\n includeObjects: routes.includeObjects,\n excludeObjects: routes.excludeObjects,\n nameTransform: routes.nameTransform ?? 'none',\n overrides: routes.overrides,\n },\n };\n }\n \n /**\n * Get the full API base path\n */\n private getApiBasePath(): string {\n const { api } = this.config;\n return api.apiPath ?? `${api.basePath}/${api.version}`;\n }\n\n /**\n * Get the project-scoped base path for a given unscoped base.\n * Example: `/api/v1` → `/api/v1/projects/:projectId`.\n */\n private getScopedBasePath(basePath: string): string {\n return `${basePath}/projects/:projectId`;\n }\n\n /**\n * Register all REST API routes\n *\n * When `enableProjectScoping` is true, routes are registered under\n * `/api/v1/projects/:projectId/...`. The `projectResolution` strategy\n * controls whether unscoped legacy routes remain available:\n * - `required` → only scoped routes registered.\n * - `optional` / `auto` → both scoped and unscoped routes registered.\n */\n registerRoutes(): void {\n const basePath = this.getApiBasePath();\n const { enableProjectScoping, projectResolution } = this.config.api;\n\n const registerForBase = (bp: string) => {\n if (this.config.api.enableDiscovery) {\n this.registerDiscoveryEndpoints(bp);\n }\n if (this.config.api.enableMetadata) {\n this.registerMetadataEndpoints(bp);\n }\n if (this.config.api.enableUi) {\n this.registerUiEndpoints(bp);\n }\n if (this.config.api.enableSearch ?? true) {\n this.registerSearchEndpoints(bp);\n }\n this.registerEmailEndpoints(bp);\n // Public (anonymous) form endpoints — opt-in via FormView.sharing.\n // Registered BEFORE the greedy `/data/:object` matcher so the\n // `/forms/:slug` and `/forms/:slug/submit` paths can't be\n // shadowed by a literal object named \"forms\".\n this.registerFormEndpoints(bp);\n // Capability routes (sharing rules, reports, approvals) live at\n // the top of the API surface (`/api/v1/{capability}/...`) rather\n // than under `/data/`, so they don't collide with the greedy\n // CRUD `/:object` matcher and don't pretend to be records on a\n // single object.\n this.registerSharingEndpoints(bp);\n this.registerSharingRuleEndpoints(bp);\n this.registerReportsEndpoints(bp);\n this.registerApprovalsEndpoints(bp);\n if (this.config.api.enableCrud) {\n this.registerCrudEndpoints(bp);\n }\n this.registerDataActionEndpoints(bp);\n if (this.config.api.enableBatch) {\n this.registerBatchEndpoints(bp);\n }\n };\n\n if (enableProjectScoping) {\n const scopedBase = this.getScopedBasePath(basePath);\n if (projectResolution === 'required') {\n // Strict: only scoped routes\n registerForBase(scopedBase);\n } else {\n // 'optional' | 'auto' — keep both so legacy callers keep working\n registerForBase(basePath);\n registerForBase(scopedBase);\n }\n } else {\n registerForBase(basePath);\n }\n }\n \n /**\n * Register discovery endpoints\n */\n private registerDiscoveryEndpoints(basePath: string): void {\n const isScoped = basePath.includes('/projects/:projectId');\n const discoveryHandler = async (req: any, res: any) => {\n try {\n const discovery = await this.protocol.getDiscovery();\n\n // Override discovery information with actual server configuration\n discovery.version = this.config.api.version;\n\n // Substitute the resolved projectId into the advertised routes so\n // clients can consume them verbatim (e.g. /api/v1/projects/abc/data).\n const realBase = isScoped\n ? basePath.replace(':projectId', req.params?.projectId ?? ':projectId')\n : basePath;\n\n if (discovery.routes) {\n // Ensure routes match the actual mounted paths\n if (this.config.api.enableCrud) {\n discovery.routes.data = `${realBase}${this.config.crud.dataPrefix}`;\n }\n\n if (this.config.api.enableMetadata) {\n discovery.routes.metadata = `${realBase}${this.config.metadata.prefix}`;\n }\n\n if (this.config.api.enableUi) {\n discovery.routes.ui = `${realBase}/ui`;\n }\n\n // Align auth route with the versioned base path if present.\n // Auth is a control-plane concern, so use the unscoped base.\n if (discovery.routes.auth) {\n const unscopedBase = isScoped\n ? basePath.replace(/\\/projects\\/:projectId$/, '')\n : basePath;\n discovery.routes.auth = `${unscopedBase}/auth`;\n }\n }\n\n // Attach scoping metadata so clients can detect dual-mode routing.\n (discovery as any).scoping = {\n enabled: this.config.api.enableProjectScoping,\n resolution: this.config.api.projectResolution,\n scoped: isScoped,\n projectId: isScoped ? req.params?.projectId : undefined,\n };\n\n res.json(discovery);\n } catch (error: any) {\n logError(\"[REST] Unhandled error:\", error);\n sendError(res, error);\n }\n };\n\n // Register at basePath (e.g. /api/v1)\n this.routeManager.register({\n method: 'GET',\n path: basePath,\n handler: discoveryHandler,\n metadata: {\n summary: 'Get API discovery information',\n tags: ['discovery'],\n },\n });\n\n // Register at basePath/discovery (e.g. /api/v1/discovery)\n this.routeManager.register({\n method: 'GET',\n path: `${basePath}/discovery`,\n handler: discoveryHandler,\n metadata: {\n summary: 'Get API discovery information',\n tags: ['discovery'],\n },\n });\n }\n \n /**\n * Register metadata endpoints\n */\n private registerMetadataEndpoints(basePath: string): void {\n const { metadata } = this.config;\n const metaPath = `${basePath}${metadata.prefix}`;\n const isScoped = basePath.includes('/projects/:projectId');\n\n // GET /meta - List all metadata types\n if (metadata.endpoints.types !== false) {\n this.routeManager.register({\n method: 'GET',\n path: metaPath,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const p = await this.resolveProtocol(projectId, req);\n const types = await p.getMetaTypes();\n res.json(types);\n } catch (error: any) {\n logError(\"[REST] Unhandled error:\", error);\n sendError(res, error);\n }\n },\n metadata: {\n summary: 'List all metadata types',\n tags: ['metadata'],\n },\n });\n }\n\n // GET /meta/:type - List items of a type\n if (metadata.endpoints.items !== false) {\n this.routeManager.register({\n method: 'GET',\n path: `${metaPath}/:type`,\n handler: async (req: any, res: any) => {\n try {\n const packageId = req.query?.package || undefined;\n const projectId = isScoped ? req.params?.projectId : undefined;\n const p = await this.resolveProtocol(projectId, req);\n const items = await p.getMetaItems({\n type: req.params.type,\n packageId,\n ...(projectId ? { projectId } : {}),\n } as any);\n const translated = await this.translateMetaItems(req, req.params.type, projectId, items);\n res.header('Vary', 'Accept-Language');\n res.json(translated);\n } catch (error: any) {\n logError(\"[REST] Unhandled error:\", error);\n sendError(res, error);\n }\n },\n metadata: {\n summary: 'List metadata items of a type',\n tags: ['metadata'],\n },\n });\n }\n\n // GET /meta/:type/:name - Get specific item\n if (metadata.endpoints.item !== false) {\n this.routeManager.register({\n method: 'GET',\n path: `${metaPath}/:type/:name`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const p = await this.resolveProtocol(projectId, req);\n // Check if cached version is available\n if (metadata.enableCache && p.getMetaItemCached) {\n const cacheRequest = {\n ifNoneMatch: req.headers['if-none-match'] as string,\n ifModifiedSince: req.headers['if-modified-since'] as string,\n };\n\n const result = await p.getMetaItemCached({\n type: req.params.type,\n name: req.params.name,\n cacheRequest,\n ...(projectId ? { projectId } : {}),\n } as any);\n\n if (result.notModified) {\n res.status(304).send();\n return;\n }\n\n // Set cache headers\n if (result.etag) {\n const etagValue = result.etag.weak\n ? `W/\"${result.etag.value}\"`\n : `\"${result.etag.value}\"`;\n res.header('ETag', etagValue);\n }\n if (result.lastModified) {\n res.header('Last-Modified', new Date(result.lastModified).toUTCString());\n }\n if (result.cacheControl) {\n const directives = result.cacheControl.directives.join(', ');\n const maxAge = result.cacheControl.maxAge\n ? `, max-age=${result.cacheControl.maxAge}`\n : '';\n res.header('Cache-Control', directives + maxAge);\n }\n\n res.header('Vary', 'Accept-Language');\n res.json(await this.translateMetaItem(req, req.params.type, projectId, result.data));\n } else {\n // Non-cached version\n const packageId = req.query?.package || undefined;\n const item = await p.getMetaItem({\n type: req.params.type,\n name: req.params.name,\n packageId,\n } as any);\n res.header('Vary', 'Accept-Language');\n res.json(await this.translateMetaItem(req, req.params.type, projectId, item));\n }\n } catch (error: any) {\n logError(\"[REST] Unhandled error:\", error);\n sendError(res, error);\n }\n },\n metadata: {\n summary: 'Get specific metadata item',\n tags: ['metadata'],\n },\n });\n }\n\n // PUT /meta/:type/:name - Save metadata item\n // We always register this route, but return 501 if protocol doesn't support it\n // This makes it discoverable even if not implemented\n this.routeManager.register({\n method: 'PUT',\n path: `${metaPath}/:type/:name`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const p = await this.resolveProtocol(projectId, req);\n if (!p.saveMetaItem) {\n res.status(501).json({ error: 'Save operation not supported by protocol implementation' });\n return;\n }\n\n // Accept both `{ ...itemFields }` (bare) and `{ metadata: {...} }`\n // / `{ item: {...} }` envelope shapes. Studio and direct API\n // callers historically use either; ADR-0005 settles on\n // unwrapping to a single payload before persistence.\n const body = req.body ?? {};\n const item = (body && typeof body === 'object' && 'metadata' in body)\n ? (body as any).metadata\n : (body && typeof body === 'object' && 'item' in body)\n ? (body as any).item\n : body;\n\n const result = await p.saveMetaItem({\n type: req.params.type,\n name: req.params.name,\n item,\n ...(projectId ? { projectId } : {}),\n } as any);\n res.json(result);\n } catch (error: any) {\n logError(\"[REST] Unhandled error:\", error);\n sendError(res, error);\n }\n },\n metadata: {\n summary: 'Save specific metadata item',\n tags: ['metadata'],\n },\n });\n\n // DELETE /meta/:type/:name - Reset metadata item to artifact default\n // Removes a customization overlay row from sys_metadata (ADR-0005).\n // Returns 200 even when no overlay existed (idempotent reset).\n this.routeManager.register({\n method: 'DELETE',\n path: `${metaPath}/:type/:name`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const p = await this.resolveProtocol(projectId, req);\n if (!(p as any).deleteMetaItem) {\n res.status(501).json({\n error: 'Reset operation not supported by protocol implementation',\n });\n return;\n }\n const result = await (p as any).deleteMetaItem({\n type: req.params.type,\n name: req.params.name,\n ...(projectId ? { projectId } : {}),\n });\n res.json(result);\n } catch (error: any) {\n logError(\"[REST] Unhandled error:\", error);\n sendError(res, error);\n }\n },\n metadata: {\n summary: 'Reset metadata item to artifact default (deletes customization overlay)',\n tags: ['metadata'],\n },\n });\n\n // GET /meta/:type/:section/:name - Get specific item with compound name\n // Compound names express sub-resources of a type (e.g. a view of an\n // object, a flow under an automation). The protocol layer treats\n // `<section>/<name>` as a single opaque key.\n if (metadata.endpoints.item !== false) {\n this.routeManager.register({\n method: 'GET',\n path: `${metaPath}/:type/:section/:name`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const p = await this.resolveProtocol(projectId, req);\n const compoundName = `${req.params.section}/${req.params.name}`;\n const packageId = req.query?.package || undefined;\n const item = await p.getMetaItem({\n type: req.params.type,\n name: compoundName,\n packageId,\n } as any);\n res.header('Vary', 'Accept-Language');\n res.json(await this.translateMetaItem(req, req.params.type, projectId, item));\n } catch (error: any) {\n logError(\"[REST] Unhandled error:\", error);\n sendError(res, error);\n }\n },\n metadata: {\n summary: 'Get specific metadata item by compound name',\n tags: ['metadata'],\n },\n });\n }\n\n // PUT /meta/:type/:section/:name - Save metadata item with compound name\n this.routeManager.register({\n method: 'PUT',\n path: `${metaPath}/:type/:section/:name`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const p = await this.resolveProtocol(projectId, req);\n if (!p.saveMetaItem) {\n res.status(501).json({ error: 'Save operation not supported by protocol implementation' });\n return;\n }\n\n const compoundName = `${req.params.section}/${req.params.name}`;\n const result = await p.saveMetaItem({\n type: req.params.type,\n name: compoundName,\n item: req.body,\n ...(projectId ? { projectId } : {}),\n } as any);\n res.json(result);\n } catch (error: any) {\n logError(\"[REST] Unhandled error:\", error);\n sendError(res, error);\n }\n },\n metadata: {\n summary: 'Save specific metadata item by compound name',\n tags: ['metadata'],\n },\n });\n }\n\n /**\n * Register UI endpoints\n */\n private registerUiEndpoints(basePath: string): void {\n const uiPath = `${basePath}/ui`;\n const isScoped = basePath.includes('/projects/:projectId');\n\n // GET /ui/view/:object/:type - Resolve view for object\n this.routeManager.register({\n method: 'GET',\n path: `${uiPath}/view/:object/:type`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const p = await this.resolveProtocol(projectId, req);\n if (p.getUiView) {\n const view = await p.getUiView({\n object: req.params.object,\n type: req.params.type as any,\n ...(projectId ? { projectId } : {}),\n } as any);\n res.json(view);\n } else {\n res.status(501).json({ error: 'UI View resolution not supported by protocol implementation' });\n }\n } catch (error: any) {\n logError(\"[REST] Unhandled error:\", error);\n sendError(res, error, req.params?.object);\n }\n },\n metadata: {\n summary: 'Resolve UI View for object',\n tags: ['ui'],\n },\n });\n }\n \n /**\n * Register CRUD endpoints for data operations\n */\n private registerCrudEndpoints(basePath: string): void {\n const { crud } = this.config;\n const dataPath = `${basePath}${crud.dataPrefix}`;\n const isScoped = basePath.includes('/projects/:projectId');\n\n const operations = crud.operations;\n\n // GET /data/:object - List/query records\n if (operations.list) {\n this.routeManager.register({\n method: 'GET',\n path: `${dataPath}/:object`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const p = await this.resolveProtocol(projectId, req);\n const context = await this.resolveExecCtx(projectId, req);\n if (this.enforceAuth(req, res, context)) return;\n const result = await p.findData({\n object: req.params.object,\n query: req.query,\n ...(projectId ? { projectId } : {}),\n ...(context ? { context } : {}),\n } as any);\n res.json(result);\n } catch (error: any) {\n const mapped = mapDataError(error, req.params?.object);\n if (mapped.status === 404 || mapped.status === 503 || mapped.status === 502) {\n res.status(mapped.status).json(mapped.body);\n } else {\n logError(\"[REST] Unhandled error:\", error);\n res.status(mapped.status).json(mapped.body);\n }\n }\n },\n metadata: {\n summary: 'Query records',\n tags: ['data', 'crud'],\n },\n });\n }\n\n // GET /data/:object/:id - Get single record\n if (operations.read) {\n this.routeManager.register({\n method: 'GET',\n path: `${dataPath}/:object/:id`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const p = await this.resolveProtocol(projectId, req);\n const { select, expand } = req.query || {};\n const context = await this.resolveExecCtx(projectId, req);\n if (this.enforceAuth(req, res, context)) return;\n const result = await p.getData({\n object: req.params.object,\n id: req.params.id,\n ...(select != null ? { select } : {}),\n ...(expand != null ? { expand } : {}),\n ...(projectId ? { projectId } : {}),\n ...(context ? { context } : {}),\n } as any);\n res.json(result);\n } catch (error: any) {\n const mapped = mapDataError(error, req.params?.object);\n if (!isExpectedDataStatus(mapped.status) && mapped.body?.code !== \"VALIDATION_FAILED\") logError(\"[REST] Unhandled error:\", error);\n res.status(mapped.status === 400 ? 404 : mapped.status).json(mapped.body);\n }\n },\n metadata: {\n summary: 'Get record by ID',\n tags: ['data', 'crud'],\n },\n });\n }\n\n // POST /data/:object - Create record\n if (operations.create) {\n this.routeManager.register({\n method: 'POST',\n path: `${dataPath}/:object`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const p = await this.resolveProtocol(projectId, req);\n const context = await this.resolveExecCtx(projectId, req);\n if (this.enforceAuth(req, res, context)) return;\n const result = await p.createData({\n object: req.params.object,\n data: req.body,\n ...(projectId ? { projectId } : {}),\n ...(context ? { context } : {}),\n } as any);\n res.status(201).json(result);\n } catch (error: any) {\n const mapped = mapDataError(error, req.params?.object);\n if (!isExpectedDataStatus(mapped.status) && mapped.body?.code !== \"VALIDATION_FAILED\") logError(\"[REST] Unhandled error:\", error);\n res.status(mapped.status).json(mapped.body);\n }\n },\n metadata: {\n summary: 'Create record',\n tags: ['data', 'crud'],\n },\n });\n }\n\n // POST /data/:object/query — Spec-shape advanced query (QueryAST in body).\n // Supports server-side aggregation via { groupBy, aggregations, where, ... }\n // per spec/data/query.zod.ts. Mirrors what `client.data.query()` posts.\n // Returns FindDataResponse = { object, records, total? }.\n if (operations.list) {\n this.routeManager.register({\n method: 'POST',\n path: `${dataPath}/:object/query`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const p = await this.resolveProtocol(projectId, req);\n const context = await this.resolveExecCtx(projectId, req);\n if (this.enforceAuth(req, res, context)) return;\n const result = await p.findData({\n object: req.params.object,\n query: req.body || {},\n ...(projectId ? { projectId } : {}),\n ...(context ? { context } : {}),\n } as any);\n res.json(result);\n } catch (error: any) {\n const mapped = mapDataError(error, req.params?.object);\n if (!isExpectedDataStatus(mapped.status)) logError(\"[REST] Unhandled error:\", error);\n res.status(mapped.status).json(mapped.body);\n }\n },\n metadata: {\n summary: 'Advanced query (QueryAST in body)',\n tags: ['data', 'crud'],\n },\n });\n }\n\n // PATCH /data/:object/:id - Update record\n if (operations.update) {\n this.routeManager.register({\n method: 'PATCH',\n path: `${dataPath}/:object/:id`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const p = await this.resolveProtocol(projectId, req);\n const context = await this.resolveExecCtx(projectId, req);\n if (this.enforceAuth(req, res, context)) return;\n const result = await p.updateData({\n object: req.params.object,\n id: req.params.id,\n data: req.body,\n ...(projectId ? { projectId } : {}),\n ...(context ? { context } : {}),\n } as any);\n res.json(result);\n } catch (error: any) {\n const mapped = mapDataError(error, req.params?.object);\n if (!isExpectedDataStatus(mapped.status) && mapped.body?.code !== \"VALIDATION_FAILED\") logError(\"[REST] Unhandled error:\", error);\n res.status(mapped.status).json(mapped.body);\n }\n },\n metadata: {\n summary: 'Update record',\n tags: ['data', 'crud'],\n },\n });\n }\n\n // DELETE /data/:object/:id - Delete record\n if (operations.delete) {\n this.routeManager.register({\n method: 'DELETE',\n path: `${dataPath}/:object/:id`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const p = await this.resolveProtocol(projectId, req);\n const context = await this.resolveExecCtx(projectId, req);\n if (this.enforceAuth(req, res, context)) return;\n const result = await p.deleteData({\n object: req.params.object,\n id: req.params.id,\n ...(projectId ? { projectId } : {}),\n ...(context ? { context } : {}),\n } as any);\n res.json(result);\n } catch (error: any) {\n const mapped = mapDataError(error, req.params?.object);\n if (!isExpectedDataStatus(mapped.status) && mapped.body?.code !== \"VALIDATION_FAILED\") logError(\"[REST] Unhandled error:\", error);\n res.status(mapped.status).json(mapped.body);\n }\n },\n metadata: {\n summary: 'Delete record',\n tags: ['data', 'crud'],\n },\n });\n }\n }\n \n /**\n * Register object-specific action endpoints that don't fit the\n * generic CRUD shape. These are domain operations (Salesforce\n * convertLead, etc.) where the protocol implementation does its own\n * multi-record orchestration and we just need a thin HTTP route.\n *\n * POST {basePath}/data/lead/:id/convert — M10.6 lead conversion.\n */\n private registerDataActionEndpoints(basePath: string): void {\n const isScoped = basePath.includes('/projects/:projectId');\n const { crud } = this.config;\n const dataPath = `${basePath}${crud.dataPrefix}`;\n\n // POST /data/lead/:id/convert\n this.routeManager.register({\n method: 'POST',\n path: `${dataPath}/lead/:id/convert`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const p = await this.resolveProtocol(projectId, req);\n const context = await this.resolveExecCtx(projectId, req);\n if (this.enforceAuth(req, res, context)) return;\n const convertLead = (p as any).convertLead;\n if (typeof convertLead !== 'function') {\n res.status(501).json({ code: 'NOT_IMPLEMENTED', error: 'Lead convert not supported by this protocol' });\n return;\n }\n const body = req.body ?? {};\n const result = await convertLead.call(p, {\n leadId: req.params.id,\n accountId: body.accountId,\n contactId: body.contactId,\n createOpportunity: body.createOpportunity,\n opportunity: body.opportunity,\n convertedStatus: body.convertedStatus,\n ...(context ? { context } : {}),\n });\n res.json(result);\n } catch (error: any) {\n logError('[REST] Unhandled error:', error);\n sendError(res, error, 'lead');\n }\n },\n metadata: {\n summary: 'Convert a Lead into Account + Contact (+ optional Opportunity)',\n tags: ['data', 'lead'],\n },\n });\n // POST /data/:object/import — bulk CSV/JSON ingestion (M10.9)\n //\n // Body shapes:\n // { format: 'csv', csv: '...header,row,...', dryRun?: boolean, mapping?: {<csvCol>:<field>} }\n // { format: 'json', rows: [...], dryRun?: boolean }\n //\n // Returns per-row outcome so a UI can present an import report.\n this.routeManager.register({\n method: 'POST',\n path: `${dataPath}/:object/import`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const p = await this.resolveProtocol(projectId, req);\n const context = await this.resolveExecCtx(projectId, req);\n if (this.enforceAuth(req, res, context)) return;\n const objectName = String(req.params.object || '');\n if (!objectName) {\n res.status(400).json({ code: 'INVALID_REQUEST', error: 'object is required' });\n return;\n }\n const body = req.body ?? {};\n const dryRun = body.dryRun === true;\n const mapping: Record<string, string> = body.mapping ?? {};\n\n // Build rows[] from either explicit JSON array or CSV text.\n let rows: Array<Record<string, any>> = [];\n if (body.format === 'json' && Array.isArray(body.rows)) {\n rows = body.rows as Array<Record<string, any>>;\n } else if ((body.format === 'csv' || typeof body.csv === 'string') && typeof body.csv === 'string') {\n rows = parseCsvToRows(body.csv, mapping);\n } else if (Array.isArray(body)) {\n // Permissive: a bare JSON array at the top level.\n rows = body as Array<Record<string, any>>;\n } else {\n res.status(400).json({\n code: 'INVALID_REQUEST',\n error: 'Provide either format:\"csv\" with csv text or format:\"json\" with rows[]',\n });\n return;\n }\n\n const max = 5000;\n if (rows.length > max) {\n res.status(413).json({\n code: 'PAYLOAD_TOO_LARGE',\n error: `Import limit is ${max} rows per request (got ${rows.length})`,\n });\n return;\n }\n\n const results: Array<{ row: number; ok: boolean; id?: string; error?: string; code?: string }> = [];\n let okCount = 0;\n let errCount = 0;\n\n for (let i = 0; i < rows.length; i++) {\n const data = rows[i];\n try {\n if (dryRun) {\n // Validate via protocol's metadata layer when available, else\n // best-effort: treat any non-empty row as syntactically OK.\n const validate = (p as any).validate;\n if (typeof validate === 'function') {\n await validate.call(p, { object: objectName, data, context });\n }\n results.push({ row: i + 1, ok: true });\n okCount++;\n } else {\n const created = await (p as any).createData({ object: objectName, data, context });\n const id = (created as any)?.id ?? (created as any)?.record?.id;\n results.push({ row: i + 1, ok: true, id });\n okCount++;\n }\n } catch (err: any) {\n errCount++;\n const code = err?.code ?? 'IMPORT_ROW_FAILED';\n const message = typeof err?.message === 'string' ? err.message.slice(0, 300) : 'Row failed';\n results.push({ row: i + 1, ok: false, error: message, code });\n }\n }\n\n res.json({\n object: objectName,\n dryRun,\n total: rows.length,\n ok: okCount,\n errors: errCount,\n results,\n });\n } catch (error: any) {\n logError('[REST] Unhandled error:', error);\n sendError(res, error, String(req.params?.object || ''));\n }\n },\n metadata: {\n summary: 'Bulk-import rows into an object (CSV or JSON, with optional dry-run)',\n tags: ['data', 'import'],\n },\n });\n\n // GET /data/:object/export — streaming export (M10.21 / C.21)\n //\n // Query params:\n // format=csv|json (default: csv. json emits a JSON array.)\n // fields=a,b,c (default: derive from object schema; falls back to keys of the first row)\n // filter=<json> ($filter as URL-encoded JSON, same shape as list endpoint)\n // orderby=field:desc (optional ordering, mirrors $orderby semantics)\n // limit=<n> (default 10000, hard cap 50000)\n // page=<n> (driver chunk size, default 500, max 5000)\n //\n // Streams the response so 50k-row exports do not buffer in memory.\n // Filename suggests `${object}-${YYYY-MM-DD}.${ext}` for browsers.\n this.routeManager.register({\n method: 'GET',\n path: `${dataPath}/:object/export`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const p = await this.resolveProtocol(projectId, req);\n const context = await this.resolveExecCtx(projectId, req);\n if (this.enforceAuth(req, res, context)) return;\n const objectName = String(req.params.object || '');\n if (!objectName) {\n res.status(400).json({ code: 'INVALID_REQUEST', error: 'object is required' });\n return;\n }\n const q = req.query ?? {};\n const format = (String(q.format ?? 'csv')).toLowerCase() === 'json' ? 'json' : 'csv';\n const HARD_CAP = 50_000;\n const MAX_CHUNK = 5_000;\n const requestedLimit = q.limit != null ? Math.max(1, Number(q.limit) || 0) : 10_000;\n const limit = Math.min(requestedLimit, HARD_CAP);\n const chunkSize = Math.min(MAX_CHUNK, Math.max(50, q.page != null ? Number(q.page) || 500 : 500));\n\n let filter: any = undefined;\n if (typeof q.filter === 'string' && q.filter.length > 0) {\n try { filter = JSON.parse(q.filter); }\n catch {\n res.status(400).json({ code: 'INVALID_REQUEST', error: 'filter must be JSON' });\n return;\n }\n } else if (q.filter && typeof q.filter === 'object') {\n filter = q.filter;\n }\n\n let orderby: any = undefined;\n if (typeof q.orderby === 'string' && q.orderby.length > 0) {\n // Accept \"field:dir,field2:dir\" shorthand or a JSON object.\n if (q.orderby.startsWith('{') || q.orderby.startsWith('[')) {\n try { orderby = JSON.parse(q.orderby); } catch { /* leave undefined */ }\n } else {\n const obj: Record<string, 'asc' | 'desc'> = {};\n for (const part of q.orderby.split(',')) {\n const [field, dir] = part.split(':').map((s: string) => s.trim());\n if (field) obj[field] = dir?.toLowerCase() === 'desc' ? 'desc' : 'asc';\n }\n if (Object.keys(obj).length > 0) orderby = obj;\n }\n }\n\n // Resolve fields: explicit param > schema fields > derived from first row.\n let fields: string[] | undefined;\n if (typeof q.fields === 'string' && q.fields.length > 0) {\n fields = q.fields.split(',').map((s: string) => s.trim()).filter(Boolean);\n } else if (Array.isArray(q.fields)) {\n fields = q.fields.filter((s: any) => typeof s === 'string' && s.length > 0);\n }\n if (!fields || fields.length === 0) {\n try {\n const schema = await (p as any).getObjectSchema?.(objectName, projectId);\n const schemaFields = schema?.fields;\n if (Array.isArray(schemaFields)) {\n fields = schemaFields.map((f: any) => f.name).filter((n: any) => typeof n === 'string');\n }\n } catch { /* fall back to first-row derivation */ }\n }\n\n // Prepare streaming response. Set headers BEFORE first write.\n const stamp = new Date().toISOString().slice(0, 10);\n const safeObj = objectName.replace(/[^A-Za-z0-9_.-]/g, '_');\n if (format === 'csv') {\n res.header('Content-Type', 'text/csv; charset=utf-8');\n res.header('Content-Disposition', `attachment; filename=\"${safeObj}-${stamp}.csv\"`);\n } else {\n res.header('Content-Type', 'application/json; charset=utf-8');\n res.header('Content-Disposition', `attachment; filename=\"${safeObj}-${stamp}.json\"`);\n }\n res.header('X-Export-Format', format);\n res.header('X-Export-Limit', String(limit));\n res.header('Cache-Control', 'no-store');\n\n let exported = 0;\n let firstChunk = true;\n let skip = 0;\n if (format === 'json') res.write('[');\n\n while (exported < limit) {\n const take = Math.min(chunkSize, limit - exported);\n const findArgs: any = {\n object: objectName,\n query: {\n ...(filter ? { $filter: filter } : {}),\n ...(orderby ? { $orderby: orderby } : {}),\n $top: take,\n $skip: skip,\n },\n ...(projectId ? { projectId } : {}),\n ...(context ? { context } : {}),\n };\n const result: any = await (p as any).findData(findArgs);\n const rows: any[] = Array.isArray(result?.data) ? result.data\n : Array.isArray(result?.rows) ? result.rows\n : Array.isArray(result) ? result : [];\n\n if (rows.length === 0) break;\n\n if (format === 'csv') {\n // Derive fields from the first row if schema lookup failed.\n if ((!fields || fields.length === 0) && firstChunk) {\n fields = Object.keys(rows[0] ?? {});\n }\n const text = rowsToCsv(fields ?? [], rows, firstChunk);\n res.write(text);\n } else {\n for (let i = 0; i < rows.length; i++) {\n const prefix = (firstChunk && i === 0) ? '' : ',';\n res.write(prefix + JSON.stringify(rows[i]));\n }\n }\n firstChunk = false;\n exported += rows.length;\n skip += rows.length;\n if (rows.length < take) break;\n }\n if (format === 'json') res.write(']');\n res.end();\n } catch (error: any) {\n logError('[REST] Unhandled error:', error);\n // Best-effort error envelope; if headers already sent the\n // client receives a truncated stream which signals failure.\n try { sendError(res, error, String(req.params?.object || '')); }\n catch { try { res.end(); } catch { /* swallow */ } }\n }\n },\n metadata: {\n summary: 'Streaming export of object rows (CSV or JSON)',\n tags: ['data', 'export'],\n },\n });\n }\n\n /**\n * Register global cross-object search endpoint (M10.5).\n * GET {basePath}/search?q=acme&objects=lead,account&limit=20&perObject=5\n */\n private registerSearchEndpoints(basePath: string): void {\n const isScoped = basePath.includes('/projects/:projectId');\n this.routeManager.register({\n method: 'GET',\n path: `${basePath}/search`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const p = await this.resolveProtocol(projectId, req);\n const context = await this.resolveExecCtx(projectId, req);\n if (this.enforceAuth(req, res, context)) return;\n const searchAll = (p as any).searchAll;\n if (typeof searchAll !== 'function') {\n res.status(501).json({ code: 'NOT_IMPLEMENTED', message: 'Search not supported by this protocol' });\n return;\n }\n const q = String(req.query?.q ?? req.query?.query ?? '');\n const objectsParam = req.query?.objects;\n const objects = typeof objectsParam === 'string'\n ? objectsParam.split(',').map((s: string) => s.trim()).filter(Boolean)\n : Array.isArray(objectsParam) ? objectsParam : undefined;\n const result = await searchAll.call(p, {\n q,\n objects,\n limit: req.query?.limit ? Number(req.query.limit) : undefined,\n perObject: req.query?.perObject ? Number(req.query.perObject) : undefined,\n ...(context ? { context } : {}),\n });\n res.json(result);\n } catch (error: any) {\n const mapped = mapDataError(error);\n if (!isExpectedDataStatus(mapped.status) && mapped.body?.code !== 'VALIDATION_FAILED') {\n logError('[REST] Unhandled error:', error);\n }\n res.status(mapped.status).json(mapped.body);\n }\n },\n metadata: {\n summary: 'Global cross-object search',\n tags: ['search'],\n },\n });\n }\n\n /**\n * Register email endpoints (M11.B1 / M10.7).\n *\n * POST {basePath}/email/send — send a transactional email via the\n * `IEmailService` provider registered by EmailServicePlugin. Returns\n * 501 when no provider is wired so deployments without email\n * configured fail cleanly.\n *\n * Request body:\n * {\n * to: \"a@b.com\" | [\"a@b.com\", { name, address }],\n * from?: ..., cc?: ..., bcc?: ..., replyTo?: ...,\n * subject: string,\n * text?: string, html?: string, // at least one required\n * attachments?: [{ filename, content, contentType?, cid? }],\n * headers?: { [name]: value },\n * relatedObject?: string, relatedId?: string,\n * }\n */\n private registerEmailEndpoints(basePath: string): void {\n const isScoped = basePath.includes('/projects/:projectId');\n this.routeManager.register({\n method: 'POST',\n path: `${basePath}/email/send`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const context = await this.resolveExecCtx(projectId, req);\n if (this.enforceAuth(req, res, context)) return;\n\n if (!this.emailServiceProvider) {\n res.status(501).json({\n code: 'NOT_IMPLEMENTED',\n message: 'Email service is not configured on this deployment',\n });\n return;\n }\n const emailService = await this.emailServiceProvider(projectId).catch(() => undefined);\n if (!emailService || typeof emailService.send !== 'function') {\n res.status(501).json({\n code: 'NOT_IMPLEMENTED',\n message: 'Email service is not configured on this deployment',\n });\n return;\n }\n\n const body = req.body ?? {};\n if (!body || typeof body !== 'object') {\n res.status(400).json({ code: 'INVALID_REQUEST', error: 'JSON body required' });\n return;\n }\n // Stamp sentBy from the authenticated context when caller didn't supply one.\n const input = {\n ...body,\n ...(body.sentBy === undefined && (context as any)?.userId\n ? { sentBy: (context as any).userId }\n : {}),\n };\n\n try {\n const result = await emailService.send(input);\n if (result?.status === 'sent') {\n res.status(200).json(result);\n } else {\n // failed / queued — still surface to client with 200 so clients can branch on status.\n res.status(200).json(result);\n }\n } catch (err: any) {\n // Validation errors from normalizeMessage are surfaced as 400.\n const message = String(err?.message ?? err ?? 'send failed');\n if (message.startsWith('VALIDATION_FAILED')) {\n res.status(400).json({\n code: 'VALIDATION_FAILED',\n error: message.replace(/^VALIDATION_FAILED:\\s*/, ''),\n });\n return;\n }\n throw err;\n }\n } catch (error: any) {\n logError('[REST] Email send unhandled error:', error);\n res.status(500).json({\n code: 'EMAIL_SEND_FAILED',\n error: String(error?.message ?? error ?? 'send failed').slice(0, 500),\n });\n }\n },\n metadata: {\n summary: 'Send a transactional email via the configured EmailService',\n tags: ['email'],\n },\n });\n }\n\n /**\n * Register public (anonymous) form endpoints.\n *\n * Public forms are opt-in: a `FormView` becomes accessible to anonymous\n * visitors only when `sharing.allowAnonymous === true` AND a\n * `sharing.publicLink` slug is configured. Two routes are registered:\n *\n * GET {basePath}/forms/:slug → resolved form spec\n * POST {basePath}/forms/:slug/submit → INSERT record (no auth required)\n *\n * Both routes bypass `enforceAuth` even when `requireAuth=true` on the\n * deployment (e.g. ObjectOS multi-tenant). Security is delegated to the\n * `guest_portal` permission set carried on the execution context — the\n * SecurityPlugin enforces INSERT-only access to the target object. If\n * the deployment hasn't registered a `guest_portal` profile, the\n * security middleware falls open with `permissions: []` (no userId),\n * matching the existing anonymous-access semantics; deployers must\n * keep `requireAuth=true` deployments paired with a `guest_portal`\n * profile (the CRM example does this) to enforce the INSERT-only\n * contract.\n *\n * The matched FormView's parent ViewSchema is found by scanning\n * `protocol.getMetaItems({ type: 'view' })`. For each entry we inspect\n * `form.sharing` and every entry in `formViews`; the first FormView\n * whose `sharing.publicLink` matches `/forms/:slug` (or just `:slug`)\n * wins. The response carries the matched form view under `form` and\n * the inferred target object, matching what the frontend's\n * `mapViewSpecToEmbeddableConfig` expects.\n */\n private registerFormEndpoints(basePath: string): void {\n const isScoped = basePath.includes('/projects/:projectId');\n\n const slugMatchesPublicLink = (publicLink: string | undefined, slug: string): boolean => {\n if (!publicLink || typeof publicLink !== 'string') return false;\n // Accept `/forms/:slug`, `forms/:slug`, or a bare slug.\n const normalized = publicLink.replace(/^\\/+/, '').replace(/^forms\\//, '');\n return normalized === slug;\n };\n\n const findPublicFormView = (views: any[], slug: string): { view: any; form: any; object: string } | null => {\n for (const view of views ?? []) {\n if (!view || typeof view !== 'object') continue;\n const candidates: Array<{ form: any; key?: string }> = [];\n if (view.form && view.form.sharing) candidates.push({ form: view.form });\n const formViews = view.formViews;\n if (formViews && typeof formViews === 'object') {\n for (const [key, fv] of Object.entries(formViews)) {\n if (fv && typeof fv === 'object' && (fv as any).sharing) {\n candidates.push({ form: fv as any, key });\n }\n }\n }\n for (const c of candidates) {\n const sharing = c.form?.sharing;\n if (!sharing || sharing.allowAnonymous !== true) continue;\n if (!slugMatchesPublicLink(sharing.publicLink, slug)) continue;\n const objectName =\n c.form?.data?.object ??\n view?.list?.data?.object ??\n view?.form?.data?.object ??\n view?.object;\n if (!objectName) continue;\n return { view, form: c.form, object: objectName };\n }\n }\n return null;\n };\n\n const resolveFormBySlug = async (\n projectId: string | undefined,\n req: any,\n slug: string,\n ): Promise<{ view: any; form: any; object: string } | null> => {\n const p = await this.resolveProtocol(projectId, req);\n if (typeof (p as any).getMetaItems !== 'function') return null;\n const result: any = await (p as any).getMetaItems({\n type: 'view',\n ...(projectId ? { projectId } : {}),\n });\n const items: any[] = Array.isArray(result?.items)\n ? result.items\n : Array.isArray(result)\n ? result\n : [];\n return findPublicFormView(items, slug);\n };\n\n // GET /forms/:slug — resolve and return the public form spec\n this.routeManager.register({\n method: 'GET',\n path: `${basePath}/forms/:slug`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const slug = String(req.params?.slug ?? '').trim();\n if (!slug) {\n res.status(400).json({ code: 'INVALID_REQUEST', error: 'slug is required' });\n return;\n }\n const match = await resolveFormBySlug(projectId, req, slug);\n if (!match) {\n res.status(404).json({\n code: 'FORM_NOT_FOUND',\n error: `No public form configured at /forms/${slug}`,\n });\n return;\n }\n // Embed the target object's schema (limited to fields\n // referenced by the form) so anonymous front-ends can\n // render the form without a separate, auth-protected\n // meta lookup. The submit handler still enforces the\n // field whitelist server-side.\n let objectSchema: any = null;\n try {\n const p = await this.resolveProtocol(projectId, req);\n if (typeof (p as any).getMetaItems === 'function') {\n const r: any = await (p as any).getMetaItems({\n type: 'object',\n ...(projectId ? { projectId } : {}),\n });\n const items: any[] = Array.isArray(r?.items) ? r.items : Array.isArray(r) ? r : [];\n const obj = items.find((o: any) => o?.name === match.object);\n if (obj && obj.fields && typeof obj.fields === 'object') {\n const allowed = new Set<string>();\n for (const sec of match.form?.sections ?? []) {\n for (const f of sec?.fields ?? []) {\n if (typeof f === 'string') allowed.add(f);\n else if (f?.field) allowed.add(f.field);\n }\n }\n const fields: Record<string, any> = {};\n for (const [name, def] of Object.entries(obj.fields)) {\n if (allowed.size === 0 || allowed.has(name)) {\n fields[name] = def;\n }\n }\n objectSchema = { name: obj.name, label: obj.label, fields };\n // Localize labels / help text / option labels so anonymous\n // clients render in the visitor's preferred language. The\n // form payload is otherwise un-translated (resolveFormBySlug\n // returns the raw view spec), so we hydrate the schema here.\n try {\n const i18n = await this.resolveI18nService(projectId, req);\n const bundle = this.buildTranslationBundle(i18n);\n const locale = this.extractLocale(req, i18n);\n if (bundle && locale) {\n const { translateMetadataDocument } = await import('@objectstack/spec/system');\n objectSchema = translateMetadataDocument('object', objectSchema, bundle, { locale });\n }\n } catch (e: any) {\n logError('[REST] Public form schema translation failed:', e);\n }\n }\n }\n } catch (e: any) {\n logError('[REST] Public form schema load failed:', e);\n }\n // Anonymous public forms must NEVER include a lookup or\n // master-detail field unless the form designer has\n // explicitly opted-in via `publicPicker` on that field's\n // section entry (mirroring Airtable's \"Allow linking to\n // existing records\" toggle). Strip non-conforming\n // lookups defensively here so a stray spec mistake can\n // never expose unrestricted record search to the\n // internet — the related `/forms/:slug/lookup/:field`\n // endpoint also re-validates `publicPicker` server-side.\n const safeForm = (() => {\n if (!match.form || !Array.isArray(match.form.sections)) return match.form;\n const allow = (name: string, cfg: any): boolean => {\n const def = objectSchema?.fields?.[name];\n const t = def?.type;\n if (t !== 'lookup' && t !== 'master_detail') return true;\n return !!cfg?.publicPicker;\n };\n const sections = match.form.sections.map((sec: any) => {\n const fields = (sec?.fields ?? []).filter((f: any) => {\n const name = typeof f === 'string' ? f : f?.field;\n if (!name) return false;\n const cfg = typeof f === 'string' ? {} : f;\n return allow(name, cfg);\n });\n return { ...sec, fields };\n });\n return { ...match.form, sections };\n })();\n res.header('Vary', 'Accept-Language');\n res.json({\n slug,\n object: match.object,\n label: match.view?.label ?? match.form?.label,\n form: safeForm,\n objectSchema,\n });\n } catch (error: any) {\n logError('[REST] Public form resolve error:', error);\n res.status(500).json({\n code: 'FORM_RESOLVE_FAILED',\n error: String(error?.message ?? error ?? 'resolve failed').slice(0, 500),\n });\n }\n },\n metadata: {\n summary: 'Resolve a public form spec by slug (anonymous)',\n tags: ['forms', 'public'],\n },\n });\n\n // POST /forms/:slug/submit — INSERT a record on the target object\n // with the `guest_portal` permission set attached.\n this.routeManager.register({\n method: 'POST',\n path: `${basePath}/forms/:slug/submit`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const slug = String(req.params?.slug ?? '').trim();\n if (!slug) {\n res.status(400).json({ code: 'INVALID_REQUEST', error: 'slug is required' });\n return;\n }\n const match = await resolveFormBySlug(projectId, req, slug);\n if (!match) {\n res.status(404).json({\n code: 'FORM_NOT_FOUND',\n error: `No public form configured at /forms/${slug}`,\n });\n return;\n }\n\n // Only allow the fields declared on the matched FormView.\n // This prevents a public visitor from stuffing privileged\n // columns (owner_id, status, internal_notes, …) into the\n // row. Object hooks (`beforeInsert`) are still responsible\n // for stamping server-side defaults — see the CRM\n // `lead.hook.ts` / `case.hook.ts` for the canonical pattern.\n const allowedFields = new Set<string>();\n for (const section of match.form?.sections ?? []) {\n for (const f of section?.fields ?? []) {\n if (typeof f === 'string') allowedFields.add(f);\n else if (f?.field) allowedFields.add(f.field);\n }\n }\n const rawBody = (req.body && typeof req.body === 'object') ? req.body : {};\n const filteredData: Record<string, unknown> = {};\n if (allowedFields.size > 0) {\n for (const [k, v] of Object.entries(rawBody)) {\n if (allowedFields.has(k)) filteredData[k] = v;\n }\n } else {\n Object.assign(filteredData, rawBody);\n }\n\n // Anonymous execution context. Carries the `guest_portal`\n // permission set name so the SecurityPlugin resolves it\n // and enforces INSERT-only on the target object.\n // Leaving `userId` undefined keeps `ctx.user?.id` falsy\n // in object hooks (the canonical guest-detection check).\n const context: any = {\n permissions: ['guest_portal'],\n anonymous: true,\n };\n\n const p = await this.resolveProtocol(projectId, req);\n const result = await p.createData({\n object: match.object,\n data: filteredData,\n ...(projectId ? { projectId } : {}),\n context,\n } as any);\n res.status(201).json(result);\n } catch (error: any) {\n const mapped = mapDataError(error);\n if (!isExpectedDataStatus(mapped.status) && mapped.body?.code !== 'VALIDATION_FAILED') {\n logError('[REST] Public form submit error:', error);\n }\n res.status(mapped.status).json(mapped.body);\n }\n },\n metadata: {\n summary: 'Submit an anonymous public form',\n tags: ['forms', 'public'],\n },\n });\n\n // GET /forms/:slug/lookup/:field — scoped picker for public-form\n // lookup widgets. Mirrors Airtable's per-form linked-record search:\n // the field MUST be declared in the form spec with an explicit\n // `publicPicker` block; otherwise the request is rejected with 403.\n // Records are projected to `publicPicker.displayFields`, capped at\n // `publicPicker.maxResults` (hard ceiling 50), and pre-filtered by\n // `publicPicker.filter`. Anonymous visitors can search but cannot\n // enumerate / paginate, so a leaked endpoint cannot exfiltrate the\n // table.\n this.routeManager.register({\n method: 'GET',\n path: `${basePath}/forms/:slug/lookup/:field`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const slug = String(req.params?.slug ?? '').trim();\n const fieldName = String(req.params?.field ?? '').trim();\n if (!slug || !fieldName) {\n res.status(400).json({ code: 'INVALID_REQUEST', error: 'slug and field are required' });\n return;\n }\n const match = await resolveFormBySlug(projectId, req, slug);\n if (!match) {\n res.status(404).json({\n code: 'FORM_NOT_FOUND',\n error: `No public form configured at /forms/${slug}`,\n });\n return;\n }\n\n // Locate the field config and require an opt-in\n // `publicPicker` block. Without it the lookup is\n // considered private — return 403, not 404, so a\n // misconfigured form is loud rather than silent.\n let fieldCfg: any = null;\n for (const sec of match.form?.sections ?? []) {\n for (const f of sec?.fields ?? []) {\n const name = typeof f === 'string' ? f : f?.field;\n if (name === fieldName) {\n fieldCfg = typeof f === 'string' ? {} : f;\n break;\n }\n }\n if (fieldCfg) break;\n }\n const picker = fieldCfg?.publicPicker;\n if (!picker) {\n res.status(403).json({\n code: 'LOOKUP_NOT_PUBLIC',\n error: `Field \"${fieldName}\" is not enabled for public lookup on this form`,\n });\n return;\n }\n\n // Resolve the referenced object — prefer the explicit\n // `publicPicker.object` override, fall back to the\n // field def on the parent object.\n const p = await this.resolveProtocol(projectId, req);\n let referenceTo: string | undefined = picker.object;\n if (!referenceTo && typeof (p as any).getMetaItems === 'function') {\n try {\n const r: any = await (p as any).getMetaItems({\n type: 'object',\n ...(projectId ? { projectId } : {}),\n });\n const items: any[] = Array.isArray(r?.items) ? r.items : Array.isArray(r) ? r : [];\n const obj = items.find((o: any) => o?.name === match.object);\n const def = obj?.fields?.[fieldName];\n referenceTo = def?.referenceTo ?? def?.target ?? def?.options?.objectName;\n } catch {/* ignore */}\n }\n if (!referenceTo) {\n res.status(500).json({\n code: 'LOOKUP_TARGET_MISSING',\n error: `Could not resolve referenced object for \"${fieldName}\"`,\n });\n return;\n }\n\n const displayFields: string[] = Array.isArray(picker.displayFields) && picker.displayFields.length > 0\n ? picker.displayFields.slice(0, 5)\n : ['name'];\n const hardCap = 50;\n const maxResults = Math.min(Math.max(1, Number(picker.maxResults) || 20), hardCap);\n const q = String(req.query?.q ?? '').trim().slice(0, 100);\n\n // Compose filters: form-defined static filter first,\n // then the search predicate over displayFields. The\n // search predicate uses `contains` on the first\n // display field so non-indexed columns still work.\n const filters: any[] = [];\n if (Array.isArray(picker.filter)) filters.push(...picker.filter);\n if (q) filters.push({ field: displayFields[0], operator: 'contains', value: q });\n\n const context: any = {\n permissions: ['guest_portal'],\n anonymous: true,\n };\n\n const result: any = await (p as any).findData({\n object: referenceTo,\n query: {\n limit: maxResults,\n offset: 0,\n filters,\n select: ['id', ...displayFields],\n sort: picker.sort ?? [{ field: displayFields[0], order: 'asc' }],\n },\n ...(projectId ? { projectId } : {}),\n context,\n } as any);\n\n // Project the response server-side too — never trust\n // that the driver respected `select`.\n const rows: any[] = Array.isArray(result?.data) ? result.data : Array.isArray(result?.items) ? result.items : [];\n const projected = rows.slice(0, maxResults).map((row: any) => {\n const out: any = { id: row?.id };\n for (const f of displayFields) {\n if (row && Object.prototype.hasOwnProperty.call(row, f)) out[f] = row[f];\n }\n return out;\n });\n res.json({\n data: projected,\n total: projected.length,\n truncated: rows.length >= maxResults,\n displayFields,\n });\n } catch (error: any) {\n const mapped = mapDataError(error);\n if (!isExpectedDataStatus(mapped.status)) {\n logError('[REST] Public form lookup error:', error);\n }\n res.status(mapped.status).json(mapped.body);\n }\n },\n metadata: {\n summary: 'Scoped lookup picker for a public form field (anonymous)',\n tags: ['forms', 'public'],\n },\n });\n }\n\n /**\n * Register record-level sharing endpoints (M11.C17).\n *\n * Surfaces `ISharingService` over HTTP so the UI can list, create\n * and revoke per-record grants without going through ObjectQL. The\n * three routes mirror the share-management drawer in Salesforce /\n * ServiceNow:\n *\n * GET {basePath}/data/:object/:id/shares\n * POST {basePath}/data/:object/:id/shares\n * DELETE {basePath}/data/:object/:id/shares/:shareId\n *\n * All three resolve via `sharingServiceProvider`; routes return 501\n * when no sharing service is configured so a deployment without the\n * `@objectstack/plugin-sharing` plugin fails cleanly.\n */\n private registerSharingEndpoints(basePath: string): void {\n const { crud } = this.config;\n const dataPath = `${basePath}${crud.dataPrefix}`;\n const isScoped = basePath.includes('/projects/:projectId');\n\n const resolveService = async (projectId?: string) => {\n if (!this.sharingServiceProvider) return undefined;\n try { return await this.sharingServiceProvider(projectId); }\n catch { return undefined; }\n };\n const respond501 = (res: any) => res.status(501).json({\n code: 'NOT_IMPLEMENTED',\n message: 'Sharing service is not configured on this deployment',\n });\n\n // GET — list shares on a record.\n this.routeManager.register({\n method: 'GET',\n path: `${dataPath}/:object/:id/shares`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const context = await this.resolveExecCtx(projectId, req);\n if (this.enforceAuth(req, res, context)) return;\n const svc = await resolveService(projectId);\n if (!svc) return respond501(res);\n const rows = await svc.listShares(req.params.object, req.params.id, context ?? {});\n res.json({ data: rows });\n } catch (error: any) {\n logError('[REST] List shares error:', error);\n res.status(500).json({ code: 'SHARES_LIST_FAILED', error: String(error?.message ?? error).slice(0, 500) });\n }\n },\n metadata: { summary: 'List per-record sharing grants', tags: ['sharing'] },\n });\n\n // POST — grant access.\n this.routeManager.register({\n method: 'POST',\n path: `${dataPath}/:object/:id/shares`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const context = await this.resolveExecCtx(projectId, req);\n if (this.enforceAuth(req, res, context)) return;\n const svc = await resolveService(projectId);\n if (!svc) return respond501(res);\n const body = req.body ?? {};\n const input = {\n object: req.params.object,\n recordId: req.params.id,\n recipientType: body.recipientType ?? body.recipient_type,\n recipientId: body.recipientId ?? body.recipient_id,\n accessLevel: body.accessLevel ?? body.access_level,\n source: body.source,\n sourceId: body.sourceId ?? body.source_id,\n reason: body.reason,\n };\n try {\n const row = await svc.grant(input, context ?? {});\n res.status(201).json(row);\n } catch (err: any) {\n const msg = String(err?.message ?? err ?? '');\n if (msg.startsWith('VALIDATION_FAILED')) {\n res.status(400).json({\n code: 'VALIDATION_FAILED',\n error: msg.replace(/^VALIDATION_FAILED:\\s*/, ''),\n });\n return;\n }\n throw err;\n }\n } catch (error: any) {\n logError('[REST] Grant share error:', error);\n res.status(500).json({ code: 'SHARE_GRANT_FAILED', error: String(error?.message ?? error).slice(0, 500) });\n }\n },\n metadata: { summary: 'Grant a per-record share to a principal', tags: ['sharing'] },\n });\n\n // DELETE — revoke a share by id.\n this.routeManager.register({\n method: 'DELETE',\n path: `${dataPath}/:object/:id/shares/:shareId`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const context = await this.resolveExecCtx(projectId, req);\n if (this.enforceAuth(req, res, context)) return;\n const svc = await resolveService(projectId);\n if (!svc) return respond501(res);\n await svc.revoke(req.params.shareId, context ?? {});\n res.status(204).end();\n } catch (error: any) {\n logError('[REST] Revoke share error:', error);\n res.status(500).json({ code: 'SHARE_REVOKE_FAILED', error: String(error?.message ?? error).slice(0, 500) });\n }\n },\n metadata: { summary: 'Revoke a per-record share by id', tags: ['sharing'] },\n });\n }\n\n /**\n * Register sharing-rule endpoints (M10.17). Mirrors the existing\n * sharing endpoints but operates on `sys_sharing_rule` rows.\n *\n * GET {basePath}/sharing/rules?object=&activeOnly=\n * POST {basePath}/sharing/rules\n * GET {basePath}/sharing/rules/:idOrName\n * DELETE {basePath}/sharing/rules/:idOrName\n * POST {basePath}/sharing/rules/:idOrName/evaluate\n *\n * Returns 501 when no sharing-rule service is configured.\n */\n private registerSharingRuleEndpoints(basePath: string): void {\n // Sharing-rule routes live at the top of the API surface (e.g.\n // `/api/v1/sharing/rules`) — they administer rules across the whole\n // tenant rather than acting on a single CRUD object, so anchoring\n // them on `basePath` keeps them out of the `/data/:object` namespace\n // where greedy CRUD matchers would otherwise swallow them.\n const dataPath = basePath;\n const isScoped = basePath.includes('/projects/:projectId');\n\n const resolveService = async (projectId?: string) => {\n if (!this.sharingRulesServiceProvider) return undefined;\n try { return await this.sharingRulesServiceProvider(projectId); }\n catch { return undefined; }\n };\n const respond501 = (res: any) => res.status(501).json({\n code: 'NOT_IMPLEMENTED',\n message: 'Sharing-rule service is not configured on this deployment',\n });\n const handleError = (err: any, res: any, defaultCode: string) => {\n const msg = String(err?.message ?? err ?? '');\n if (msg.startsWith('VALIDATION_FAILED')) {\n return res.status(400).json({ code: 'VALIDATION_FAILED', error: msg.replace(/^VALIDATION_FAILED:\\s*/, '') });\n }\n if (msg.startsWith('RULE_NOT_FOUND')) {\n return res.status(404).json({ code: 'RULE_NOT_FOUND', error: msg.replace(/^RULE_NOT_FOUND:?\\s*/, '') });\n }\n logError(`[REST] sharing-rule ${defaultCode}:`, err);\n return res.status(500).json({ code: defaultCode, error: msg.slice(0, 500) });\n };\n\n // LIST\n this.routeManager.register({\n method: 'GET',\n path: `${dataPath}/sharing/rules`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const context = await this.resolveExecCtx(projectId, req);\n if (this.enforceAuth(req, res, context)) return;\n const svc = await resolveService(projectId);\n if (!svc) return respond501(res);\n const rows = await svc.listRules({\n object: req.query?.object,\n activeOnly: req.query?.activeOnly === 'true' || req.query?.activeOnly === true,\n }, context ?? {});\n res.json({ data: rows });\n } catch (err: any) { handleError(err, res, 'RULE_LIST_FAILED'); }\n },\n metadata: { summary: 'List sharing rules', tags: ['sharing'] },\n });\n\n // CREATE / UPSERT\n this.routeManager.register({\n method: 'POST',\n path: `${dataPath}/sharing/rules`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const context = await this.resolveExecCtx(projectId, req);\n if (this.enforceAuth(req, res, context)) return;\n const svc = await resolveService(projectId);\n if (!svc) return respond501(res);\n const body = req.body ?? {};\n const input = {\n name: body.name,\n label: body.label,\n description: body.description,\n object: body.object ?? body.object_name,\n criteria: body.criteria,\n recipientType: body.recipientType ?? body.recipient_type,\n recipientId: body.recipientId ?? body.recipient_id,\n accessLevel: body.accessLevel ?? body.access_level,\n active: body.active,\n };\n const row = await svc.defineRule(input, context ?? {});\n res.status(201).json(row);\n } catch (err: any) { handleError(err, res, 'RULE_DEFINE_FAILED'); }\n },\n metadata: { summary: 'Create or upsert a sharing rule', tags: ['sharing'] },\n });\n\n // GET\n this.routeManager.register({\n method: 'GET',\n path: `${dataPath}/sharing/rules/:idOrName`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const context = await this.resolveExecCtx(projectId, req);\n if (this.enforceAuth(req, res, context)) return;\n const svc = await resolveService(projectId);\n if (!svc) return respond501(res);\n const row = await svc.getRule(req.params.idOrName, context ?? {});\n if (!row) return res.status(404).json({ code: 'RULE_NOT_FOUND' });\n res.json(row);\n } catch (err: any) { handleError(err, res, 'RULE_GET_FAILED'); }\n },\n metadata: { summary: 'Get a sharing rule by id or name', tags: ['sharing'] },\n });\n\n // DELETE\n this.routeManager.register({\n method: 'DELETE',\n path: `${dataPath}/sharing/rules/:idOrName`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const context = await this.resolveExecCtx(projectId, req);\n if (this.enforceAuth(req, res, context)) return;\n const svc = await resolveService(projectId);\n if (!svc) return respond501(res);\n await svc.deleteRule(req.params.idOrName, context ?? {});\n res.status(204).end();\n } catch (err: any) { handleError(err, res, 'RULE_DELETE_FAILED'); }\n },\n metadata: { summary: 'Delete a sharing rule and its materialised grants', tags: ['sharing'] },\n });\n\n // EVALUATE\n this.routeManager.register({\n method: 'POST',\n path: `${dataPath}/sharing/rules/:idOrName/evaluate`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const context = await this.resolveExecCtx(projectId, req);\n if (this.enforceAuth(req, res, context)) return;\n const svc = await resolveService(projectId);\n if (!svc) return respond501(res);\n const result = await svc.evaluateRule(req.params.idOrName, context ?? {});\n res.json(result);\n } catch (err: any) { handleError(err, res, 'RULE_EVALUATE_FAILED'); }\n },\n metadata: { summary: 'Re-evaluate a sharing rule and reconcile grants', tags: ['sharing'] },\n });\n }\n\n /**\n * Register saved-report + scheduled-digest endpoints (M11.C16).\n *\n * Surfaces `IReportService` over HTTP so the UI can build,\n * run, and schedule reports without dropping to ObjectQL. Routes\n * live at the top of the API surface (alongside `/approvals` and\n * `/sharing`) — reports are a tenant-wide capability, not a record\n * on a specific CRUD object:\n *\n * GET {basePath}/reports?object=&ownerId=\n * POST {basePath}/reports\n * GET {basePath}/reports/:id\n * DELETE {basePath}/reports/:id\n * POST {basePath}/reports/:id/run\n * POST {basePath}/reports/:id/schedule\n * GET {basePath}/reports/:id/schedules\n * DELETE {basePath}/reports/schedules/:scheduleId\n *\n * All routes return 501 when `reportsServiceProvider` is unset so\n * a deployment without `@objectstack/plugin-reports` fails cleanly.\n */\n private registerReportsEndpoints(basePath: string): void {\n // Reports live at the top of the API surface (e.g. `/api/v1/reports`)\n // rather than under `/data/`, because a report is a first-class\n // capability whose definition is tenant-wide (not a record on a\n // particular object).\n const dataPath = basePath;\n const isScoped = basePath.includes('/projects/:projectId');\n\n const resolveService = async (projectId?: string) => {\n if (!this.reportsServiceProvider) return undefined;\n try { return await this.reportsServiceProvider(projectId); }\n catch { return undefined; }\n };\n const respond501 = (res: any) => res.status(501).json({\n code: 'NOT_IMPLEMENTED',\n message: 'Reports service is not configured on this deployment',\n });\n const handleValidation = (res: any, err: any): boolean => {\n const msg = String(err?.message ?? err ?? '');\n if (msg.startsWith('VALIDATION_FAILED')) {\n res.status(400).json({\n code: 'VALIDATION_FAILED',\n error: msg.replace(/^VALIDATION_FAILED:\\s*/, ''),\n });\n return true;\n }\n if (msg.startsWith('REPORT_NOT_FOUND')) {\n res.status(404).json({ code: 'REPORT_NOT_FOUND', error: msg });\n return true;\n }\n return false;\n };\n\n // GET — list reports.\n this.routeManager.register({\n method: 'GET',\n path: `${dataPath}/reports`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const context = await this.resolveExecCtx(projectId, req);\n if (this.enforceAuth(req, res, context)) return;\n const svc = await resolveService(projectId);\n if (!svc) return respond501(res);\n const q = req.query ?? {};\n const rows = await svc.listReports({ object: q.object, ownerId: q.ownerId }, context ?? {});\n res.json({ data: rows });\n } catch (error: any) {\n logError('[REST] List reports error:', error);\n res.status(500).json({ code: 'REPORTS_LIST_FAILED', error: String(error?.message ?? error).slice(0, 500) });\n }\n },\n metadata: { summary: 'List saved reports', tags: ['reports'] },\n });\n\n // POST — save (upsert) a report.\n this.routeManager.register({\n method: 'POST',\n path: `${dataPath}/reports`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const context = await this.resolveExecCtx(projectId, req);\n if (this.enforceAuth(req, res, context)) return;\n const svc = await resolveService(projectId);\n if (!svc) return respond501(res);\n try {\n const row = await svc.saveReport(req.body ?? {}, context ?? {});\n res.status(201).json(row);\n } catch (err: any) {\n if (handleValidation(res, err)) return;\n throw err;\n }\n } catch (error: any) {\n logError('[REST] Save report error:', error);\n res.status(500).json({ code: 'REPORT_SAVE_FAILED', error: String(error?.message ?? error).slice(0, 500) });\n }\n },\n metadata: { summary: 'Create or update a saved report', tags: ['reports'] },\n });\n\n // GET — single report.\n this.routeManager.register({\n method: 'GET',\n path: `${dataPath}/reports/:id`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const context = await this.resolveExecCtx(projectId, req);\n if (this.enforceAuth(req, res, context)) return;\n const svc = await resolveService(projectId);\n if (!svc) return respond501(res);\n const row = await svc.getReport(req.params.id, context ?? {});\n if (!row) {\n res.status(404).json({ code: 'REPORT_NOT_FOUND', error: `Report ${req.params.id} not found` });\n return;\n }\n res.json(row);\n } catch (error: any) {\n logError('[REST] Get report error:', error);\n res.status(500).json({ code: 'REPORT_GET_FAILED', error: String(error?.message ?? error).slice(0, 500) });\n }\n },\n metadata: { summary: 'Get a saved report by id', tags: ['reports'] },\n });\n\n // DELETE — drop report + cascade schedules.\n this.routeManager.register({\n method: 'DELETE',\n path: `${dataPath}/reports/:id`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const context = await this.resolveExecCtx(projectId, req);\n if (this.enforceAuth(req, res, context)) return;\n const svc = await resolveService(projectId);\n if (!svc) return respond501(res);\n await svc.deleteReport(req.params.id, context ?? {});\n res.status(204).end();\n } catch (error: any) {\n logError('[REST] Delete report error:', error);\n res.status(500).json({ code: 'REPORT_DELETE_FAILED', error: String(error?.message ?? error).slice(0, 500) });\n }\n },\n metadata: { summary: 'Delete a saved report (cascades schedules)', tags: ['reports'] },\n });\n\n // POST — execute a report by id.\n this.routeManager.register({\n method: 'POST',\n path: `${dataPath}/reports/:id/run`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const context = await this.resolveExecCtx(projectId, req);\n if (this.enforceAuth(req, res, context)) return;\n const svc = await resolveService(projectId);\n if (!svc) return respond501(res);\n try {\n const result = await svc.run(req.params.id, context ?? {});\n res.json(result);\n } catch (err: any) {\n if (handleValidation(res, err)) return;\n throw err;\n }\n } catch (error: any) {\n logError('[REST] Run report error:', error);\n res.status(500).json({ code: 'REPORT_RUN_FAILED', error: String(error?.message ?? error).slice(0, 500) });\n }\n },\n metadata: { summary: 'Execute a saved report and return rendered output', tags: ['reports'] },\n });\n\n // POST — schedule a report.\n this.routeManager.register({\n method: 'POST',\n path: `${dataPath}/reports/:id/schedule`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const context = await this.resolveExecCtx(projectId, req);\n if (this.enforceAuth(req, res, context)) return;\n const svc = await resolveService(projectId);\n if (!svc) return respond501(res);\n const body = req.body ?? {};\n try {\n const row = await svc.scheduleReport({\n reportId: req.params.id,\n recipients: body.recipients ?? [],\n name: body.name,\n intervalMinutes: body.intervalMinutes ?? body.interval_minutes,\n cronExpression: body.cronExpression ?? body.cron_expression,\n timezone: body.timezone,\n format: body.format,\n subjectTemplate: body.subjectTemplate ?? body.subject_template,\n ownerId: body.ownerId ?? body.owner_id,\n active: body.active,\n }, context ?? {});\n res.status(201).json(row);\n } catch (err: any) {\n if (handleValidation(res, err)) return;\n throw err;\n }\n } catch (error: any) {\n logError('[REST] Schedule report error:', error);\n res.status(500).json({ code: 'REPORT_SCHEDULE_FAILED', error: String(error?.message ?? error).slice(0, 500) });\n }\n },\n metadata: { summary: 'Create a recurring email schedule for a report', tags: ['reports'] },\n });\n\n // GET — list schedules for a report.\n this.routeManager.register({\n method: 'GET',\n path: `${dataPath}/reports/:id/schedules`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const context = await this.resolveExecCtx(projectId, req);\n if (this.enforceAuth(req, res, context)) return;\n const svc = await resolveService(projectId);\n if (!svc) return respond501(res);\n const rows = await svc.listSchedules({ reportId: req.params.id }, context ?? {});\n res.json({ data: rows });\n } catch (error: any) {\n logError('[REST] List schedules error:', error);\n res.status(500).json({ code: 'SCHEDULES_LIST_FAILED', error: String(error?.message ?? error).slice(0, 500) });\n }\n },\n metadata: { summary: 'List schedules for a report', tags: ['reports'] },\n });\n\n // DELETE — drop a schedule.\n this.routeManager.register({\n method: 'DELETE',\n path: `${dataPath}/reports/schedules/:scheduleId`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const context = await this.resolveExecCtx(projectId, req);\n if (this.enforceAuth(req, res, context)) return;\n const svc = await resolveService(projectId);\n if (!svc) return respond501(res);\n await svc.unscheduleReport(req.params.scheduleId, context ?? {});\n res.status(204).end();\n } catch (error: any) {\n logError('[REST] Unschedule report error:', error);\n res.status(500).json({ code: 'SCHEDULE_DELETE_FAILED', error: String(error?.message ?? error).slice(0, 500) });\n }\n },\n metadata: { summary: 'Delete a report schedule by id', tags: ['reports'] },\n });\n }\n\n /**\n * Register approval engine endpoints.\n *\n * Routes (all under {basePath}/approvals):\n * GET /processes — list approval processes\n * POST /processes — upsert (defineProcess)\n * GET /processes/:id — get by id or name\n * DELETE /processes/:id — delete process\n * POST /requests — submit\n * GET /requests — list (filters: status, object, recordId, approverId, submitterId)\n * GET /requests/:id — get request\n * POST /requests/:id/approve — approve current step\n * POST /requests/:id/reject — reject current step\n * POST /requests/:id/recall — recall (submitter only)\n * GET /requests/:id/actions — audit trail\n *\n * Returns 501 when `approvalsServiceProvider` is unset so deployments\n * without `@objectstack/plugin-approvals` fail cleanly.\n */\n private registerApprovalsEndpoints(basePath: string): void {\n // Approval routes live at the top of the API surface (e.g.\n // `/api/v1/approvals/processes`, `/api/v1/approvals/requests/:id/approve`).\n // Approvals are a cross-cutting capability — a request is not a\n // record on a single CRUD object, so anchoring it on `basePath`\n // (instead of `${basePath}/data`) keeps the URL semantics honest.\n const dataPath = basePath;\n const isScoped = basePath.includes('/projects/:projectId');\n\n const resolveService = async (projectId?: string) => {\n if (!this.approvalsServiceProvider) return undefined;\n try { return await this.approvalsServiceProvider(projectId); }\n catch { return undefined; }\n };\n const respond501 = (res: any) => res.status(501).json({\n code: 'NOT_IMPLEMENTED',\n message: 'Approvals service is not configured on this deployment',\n });\n const handleApprovalError = (res: any, err: any): boolean => {\n const msg = String(err?.message ?? err ?? '');\n const mapping: Array<[RegExp, number, string]> = [\n [/^VALIDATION_FAILED/, 400, 'VALIDATION_FAILED'],\n [/^DUPLICATE_REQUEST/, 409, 'DUPLICATE_REQUEST'],\n [/^INVALID_STATE/, 409, 'INVALID_STATE'],\n [/^FORBIDDEN/, 403, 'FORBIDDEN'],\n [/^NO_ACTIVE_PROCESS/, 404, 'NO_ACTIVE_PROCESS'],\n [/^PROCESS_NOT_FOUND/, 404, 'PROCESS_NOT_FOUND'],\n [/^REQUEST_NOT_FOUND/, 404, 'REQUEST_NOT_FOUND'],\n ];\n for (const [re, status, code] of mapping) {\n if (re.test(msg)) {\n res.status(status).json({ code, error: msg.replace(/^[A-Z_]+:\\s*/, '') });\n return true;\n }\n }\n return false;\n };\n\n // ── Processes ─────────────────────────────────────────────\n this.routeManager.register({\n method: 'GET',\n path: `${dataPath}/approvals/processes`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const context = await this.resolveExecCtx(projectId, req);\n if (this.enforceAuth(req, res, context)) return;\n const svc = await resolveService(projectId);\n if (!svc) return respond501(res);\n const q = req.query ?? {};\n const rows = await svc.listProcesses({\n object: q.object,\n activeOnly: q.activeOnly === 'true' || q.activeOnly === true,\n }, context ?? {});\n res.json({ data: rows });\n } catch (error: any) {\n logError('[REST] List approval processes error:', error);\n res.status(500).json({ code: 'APPROVAL_PROCESS_LIST_FAILED', error: String(error?.message ?? error).slice(0, 500) });\n }\n },\n metadata: { summary: 'List approval processes', tags: ['approvals'] },\n });\n\n this.routeManager.register({\n method: 'POST',\n path: `${dataPath}/approvals/processes`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const context = await this.resolveExecCtx(projectId, req);\n if (this.enforceAuth(req, res, context)) return;\n const svc = await resolveService(projectId);\n if (!svc) return respond501(res);\n try {\n const row = await svc.defineProcess(req.body ?? {}, context ?? {});\n res.status(201).json(row);\n } catch (err: any) {\n if (handleApprovalError(res, err)) return;\n throw err;\n }\n } catch (error: any) {\n logError('[REST] Define approval process error:', error);\n res.status(500).json({ code: 'APPROVAL_PROCESS_DEFINE_FAILED', error: String(error?.message ?? error).slice(0, 500) });\n }\n },\n metadata: { summary: 'Define (upsert) an approval process', tags: ['approvals'] },\n });\n\n this.routeManager.register({\n method: 'GET',\n path: `${dataPath}/approvals/processes/:id`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const context = await this.resolveExecCtx(projectId, req);\n if (this.enforceAuth(req, res, context)) return;\n const svc = await resolveService(projectId);\n if (!svc) return respond501(res);\n const row = await svc.getProcess(req.params.id, context ?? {});\n if (!row) {\n res.status(404).json({ code: 'PROCESS_NOT_FOUND', error: `Approval process '${req.params.id}' not found` });\n return;\n }\n res.json(row);\n } catch (error: any) {\n logError('[REST] Get approval process error:', error);\n res.status(500).json({ code: 'APPROVAL_PROCESS_GET_FAILED', error: String(error?.message ?? error).slice(0, 500) });\n }\n },\n metadata: { summary: 'Get an approval process by id or name', tags: ['approvals'] },\n });\n\n this.routeManager.register({\n method: 'DELETE',\n path: `${dataPath}/approvals/processes/:id`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const context = await this.resolveExecCtx(projectId, req);\n if (this.enforceAuth(req, res, context)) return;\n const svc = await resolveService(projectId);\n if (!svc) return respond501(res);\n await svc.deleteProcess(req.params.id, context ?? {});\n res.status(204).end();\n } catch (error: any) {\n logError('[REST] Delete approval process error:', error);\n res.status(500).json({ code: 'APPROVAL_PROCESS_DELETE_FAILED', error: String(error?.message ?? error).slice(0, 500) });\n }\n },\n metadata: { summary: 'Delete an approval process', tags: ['approvals'] },\n });\n\n // ── Requests ──────────────────────────────────────────────\n this.routeManager.register({\n method: 'POST',\n path: `${dataPath}/approvals/requests`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const context = await this.resolveExecCtx(projectId, req);\n if (this.enforceAuth(req, res, context)) return;\n const svc = await resolveService(projectId);\n if (!svc) return respond501(res);\n const body = req.body ?? {};\n try {\n const row = await svc.submit({\n object: body.object,\n recordId: body.recordId ?? body.record_id,\n processName: body.processName ?? body.process_name,\n submitterId: body.submitterId ?? body.submitter_id ?? context?.userId,\n comment: body.comment,\n payload: body.payload,\n }, context ?? {});\n res.status(201).json(row);\n } catch (err: any) {\n if (handleApprovalError(res, err)) return;\n throw err;\n }\n } catch (error: any) {\n logError('[REST] Submit approval error:', error);\n res.status(500).json({ code: 'APPROVAL_SUBMIT_FAILED', error: String(error?.message ?? error).slice(0, 500) });\n }\n },\n metadata: { summary: 'Submit a record for approval', tags: ['approvals'] },\n });\n\n this.routeManager.register({\n method: 'GET',\n path: `${dataPath}/approvals/requests`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const context = await this.resolveExecCtx(projectId, req);\n if (this.enforceAuth(req, res, context)) return;\n const svc = await resolveService(projectId);\n if (!svc) {\n // No approvals plugin loaded — return empty list rather than 501\n // so Console badge polls don't spam the error log on deployments\n // that don't run an approvals workflow.\n res.json({ data: [] });\n return;\n }\n const q = req.query ?? {};\n const rows = await svc.listRequests({\n object: q.object,\n recordId: q.recordId ?? q.record_id,\n status: q.status,\n approverId: q.approverId ?? q.approver_id,\n submitterId: q.submitterId ?? q.submitter_id,\n }, context ?? {});\n res.json({ data: rows });\n } catch (error: any) {\n logError('[REST] List approval requests error:', error);\n res.status(500).json({ code: 'APPROVAL_REQUEST_LIST_FAILED', error: String(error?.message ?? error).slice(0, 500) });\n }\n },\n metadata: { summary: 'List approval requests', tags: ['approvals'] },\n });\n\n this.routeManager.register({\n method: 'GET',\n path: `${dataPath}/approvals/requests/:id`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const context = await this.resolveExecCtx(projectId, req);\n if (this.enforceAuth(req, res, context)) return;\n const svc = await resolveService(projectId);\n if (!svc) return respond501(res);\n const row = await svc.getRequest(req.params.id, context ?? {});\n if (!row) {\n res.status(404).json({ code: 'REQUEST_NOT_FOUND', error: `Approval request '${req.params.id}' not found` });\n return;\n }\n res.json(row);\n } catch (error: any) {\n logError('[REST] Get approval request error:', error);\n res.status(500).json({ code: 'APPROVAL_REQUEST_GET_FAILED', error: String(error?.message ?? error).slice(0, 500) });\n }\n },\n metadata: { summary: 'Get an approval request by id', tags: ['approvals'] },\n });\n\n const decisionRoute = (suffix: 'approve' | 'reject' | 'recall', method: 'approve' | 'reject' | 'recall') => {\n this.routeManager.register({\n method: 'POST',\n path: `${dataPath}/approvals/requests/:id/${suffix}`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const context = await this.resolveExecCtx(projectId, req);\n if (this.enforceAuth(req, res, context)) return;\n const svc = await resolveService(projectId);\n if (!svc) return respond501(res);\n const body = req.body ?? {};\n try {\n const out = await svc[method](req.params.id, {\n actorId: body.actorId ?? body.actor_id ?? context?.userId,\n comment: body.comment,\n }, context ?? {});\n res.json(out);\n } catch (err: any) {\n if (handleApprovalError(res, err)) return;\n throw err;\n }\n } catch (error: any) {\n logError(`[REST] ${suffix} approval error:`, error);\n res.status(500).json({ code: `APPROVAL_${suffix.toUpperCase()}_FAILED`, error: String(error?.message ?? error).slice(0, 500) });\n }\n },\n metadata: { summary: `${suffix[0].toUpperCase()}${suffix.slice(1)} an approval request`, tags: ['approvals'] },\n });\n };\n decisionRoute('approve', 'approve');\n decisionRoute('reject', 'reject');\n decisionRoute('recall', 'recall');\n\n this.routeManager.register({\n method: 'GET',\n path: `${dataPath}/approvals/requests/:id/actions`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const context = await this.resolveExecCtx(projectId, req);\n if (this.enforceAuth(req, res, context)) return;\n const svc = await resolveService(projectId);\n if (!svc) return respond501(res);\n const rows = await svc.listActions(req.params.id, context ?? {});\n res.json({ data: rows });\n } catch (error: any) {\n logError('[REST] List approval actions error:', error);\n res.status(500).json({ code: 'APPROVAL_ACTIONS_FAILED', error: String(error?.message ?? error).slice(0, 500) });\n }\n },\n metadata: { summary: 'List actions (audit trail) for an approval request', tags: ['approvals'] },\n });\n }\n\n /**\n * Register batch operation endpoints\n */\n private registerBatchEndpoints(basePath: string): void {\n const { crud, batch } = this.config;\n const dataPath = `${basePath}${crud.dataPrefix}`;\n const isScoped = basePath.includes('/projects/:projectId');\n\n const operations = batch.operations;\n\n // POST /data/:object/batch - Generic batch endpoint\n if (batch.enableBatchEndpoint && this.protocol.batchData) {\n this.routeManager.register({\n method: 'POST',\n path: `${dataPath}/:object/batch`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const p = await this.resolveProtocol(projectId, req);\n const context = await this.resolveExecCtx(projectId, req);\n if (this.enforceAuth(req, res, context)) return;\n const result = await p.batchData!({\n object: req.params.object,\n request: req.body,\n ...(projectId ? { projectId } : {}),\n ...(context ? { context } : {}),\n } as any);\n res.json(result);\n } catch (error: any) {\n logError(\"[REST] Unhandled error:\", error);\n sendError(res, error, req.params?.object);\n }\n },\n metadata: {\n summary: 'Batch operations',\n tags: ['data', 'batch'],\n },\n });\n }\n\n // POST /data/:object/createMany - Bulk create\n if (operations.createMany && this.protocol.createManyData) {\n this.routeManager.register({\n method: 'POST',\n path: `${dataPath}/:object/createMany`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const p = await this.resolveProtocol(projectId, req);\n const context = await this.resolveExecCtx(projectId, req);\n if (this.enforceAuth(req, res, context)) return;\n const result = await p.createManyData!({\n object: req.params.object,\n records: req.body || [],\n ...(projectId ? { projectId } : {}),\n ...(context ? { context } : {}),\n } as any);\n res.status(201).json(result);\n } catch (error: any) {\n logError(\"[REST] Unhandled error:\", error);\n sendError(res, error, req.params?.object);\n }\n },\n metadata: {\n summary: 'Create multiple records',\n tags: ['data', 'batch'],\n },\n });\n }\n\n // POST /data/:object/updateMany - Bulk update\n if (operations.updateMany && this.protocol.updateManyData) {\n this.routeManager.register({\n method: 'POST',\n path: `${dataPath}/:object/updateMany`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const p = await this.resolveProtocol(projectId, req);\n const context = await this.resolveExecCtx(projectId, req);\n if (this.enforceAuth(req, res, context)) return;\n const result = await p.updateManyData!({\n object: req.params.object,\n ...req.body,\n ...(projectId ? { projectId } : {}),\n ...(context ? { context } : {}),\n } as any);\n res.json(result);\n } catch (error: any) {\n logError(\"[REST] Unhandled error:\", error);\n sendError(res, error, req.params?.object);\n }\n },\n metadata: {\n summary: 'Update multiple records',\n tags: ['data', 'batch'],\n },\n });\n }\n\n // POST /data/:object/deleteMany - Bulk delete\n if (operations.deleteMany && this.protocol.deleteManyData) {\n this.routeManager.register({\n method: 'POST',\n path: `${dataPath}/:object/deleteMany`,\n handler: async (req: any, res: any) => {\n try {\n const projectId = isScoped ? req.params?.projectId : undefined;\n const p = await this.resolveProtocol(projectId, req);\n const context = await this.resolveExecCtx(projectId, req);\n if (this.enforceAuth(req, res, context)) return;\n const result = await p.deleteManyData!({\n object: req.params.object,\n ...req.body,\n ...(projectId ? { projectId } : {}),\n ...(context ? { context } : {}),\n } as any);\n res.json(result);\n } catch (error: any) {\n logError(\"[REST] Unhandled error:\", error);\n sendError(res, error, req.params?.object);\n }\n },\n metadata: {\n summary: 'Delete multiple records',\n tags: ['data', 'batch'],\n },\n });\n }\n }\n\n \n /**\n * Get the route manager\n */\n getRouteManager(): RouteManager {\n return this.routeManager;\n }\n \n /**\n * Get all registered routes\n */\n getRoutes() {\n return this.routeManager.getAll();\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { IHttpServer } from '@objectstack/core';\nimport type { PackageService } from '@objectstack/service-package';\n\n/**\n * Options for package route registration.\n */\nexport interface PackageRoutesOptions {\n /**\n * Protocol service (ObjectStackProtocol) — provides access to in-memory\n * SchemaRegistry packages loaded via defineStack()/AppPlugin at boot time.\n */\n protocol?: { getMetaItems?(req: { type: string }): Promise<{ items: any[] }> };\n}\n\n/**\n * Register package management API routes\n *\n * Provides endpoints for publishing, retrieving, and managing packages.\n * Routes:\n * - POST /api/v1/packages - Publish a package\n * - GET /api/v1/packages - List all packages (merges registry + database)\n * - GET /api/v1/packages/:id - Get a specific package\n * - DELETE /api/v1/packages/:id - Delete a package\n */\nexport function registerPackageRoutes(\n server: IHttpServer,\n packageService: PackageService,\n basePath: string = '/api/v1',\n options: PackageRoutesOptions = {},\n) {\n const packagesPath = `${basePath}/packages`;\n\n // POST /api/v1/packages - Publish a package\n server.post(packagesPath, async (req, res) => {\n try {\n const { manifest, metadata } = req.body || {};\n\n if (!manifest || !metadata) {\n res.status(400).json({ error: 'Missing required fields: manifest, metadata' });\n return;\n }\n\n if (!manifest.id || !manifest.version) {\n res.status(400).json({ error: 'Invalid manifest: id and version are required' });\n return;\n }\n\n const result = await packageService.publish({ manifest, metadata });\n\n if (result.success) {\n res.json({\n success: true,\n message: `Published ${manifest.id}@${manifest.version}`,\n package: {\n id: manifest.id,\n version: manifest.version,\n },\n });\n return;\n }\n\n res.status(400).json({ success: false, error: result.error });\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n // GET /api/v1/packages - List all packages (merges registry + database)\n server.get(packagesPath, async (_req, res) => {\n try {\n // Merge two sources:\n // 1. Registry packages (in-memory, loaded at boot via defineStack/AppPlugin)\n // 2. Database packages (published via POST /packages)\n const packagesMap = new Map<string, any>();\n\n // Registry packages (via protocol service → SchemaRegistry)\n if (options.protocol && typeof options.protocol.getMetaItems === 'function') {\n try {\n const result = await options.protocol.getMetaItems({ type: 'package' });\n if (result?.items) {\n for (const item of result.items) {\n const id = item.manifest?.id || item.id;\n if (id) {\n packagesMap.set(id, {\n ...item,\n source: 'registry',\n });\n }\n }\n }\n } catch {\n // Protocol unavailable — continue with database only\n }\n }\n\n // Database packages (published artifacts)\n try {\n const dbPackages = await packageService.list();\n for (const pkg of dbPackages) {\n const id = pkg.manifest?.id || pkg.id;\n if (id) {\n // Database entry takes precedence (has richer metadata from publish)\n packagesMap.set(id, {\n ...packagesMap.get(id),\n ...pkg,\n source: packagesMap.has(id) ? 'both' : 'database',\n });\n }\n }\n } catch {\n // Database query failed — continue with registry-only packages\n }\n\n const packages = Array.from(packagesMap.values());\n res.json({ packages, total: packages.length });\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n // GET /api/v1/packages/:id - Get a specific package\n server.get(`${packagesPath}/:id`, async (req, res) => {\n try {\n const packageId = req.params.id;\n const version = req.query?.version || 'latest';\n\n // Try database first (richer data from publish)\n const pkg = await packageService.get(packageId, version);\n if (pkg) {\n res.json({ package: { ...pkg, source: 'database' } });\n return;\n }\n\n // Fall back to registry (in-memory loaded packages)\n if (options.protocol && typeof options.protocol.getMetaItems === 'function') {\n try {\n const result = await options.protocol.getMetaItems({ type: 'package' });\n const match = result?.items?.find((item: any) =>\n (item.manifest?.id || item.id) === packageId\n );\n if (match) {\n res.json({ package: { ...match, source: 'registry' } });\n return;\n }\n } catch {\n // Protocol unavailable\n }\n }\n\n res.status(404).json({ error: 'Package not found' });\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n // DELETE /api/v1/packages/:id - Delete a package\n server.delete(`${packagesPath}/:id`, async (req, res) => {\n try {\n const packageId = req.params.id;\n const version = req.query?.version;\n\n const result = await packageService.delete(packageId, version);\n\n if (result.success) {\n res.json({\n success: true,\n message: `Deleted ${packageId}${version ? `@${version}` : ''}`,\n });\n return;\n }\n\n res.status(400).json({ success: false });\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { Plugin, PluginContext, IHttpServer } from '@objectstack/core';\nimport { RestServer, RestKernelManager } from './rest-server.js';\nimport { ObjectStackProtocol, RestServerConfig } from '@objectstack/spec/api';\nimport { registerPackageRoutes } from './package-routes.js';\nimport type { PackageService } from '@objectstack/service-package';\n\nexport interface RestApiPluginConfig {\n serverServiceName?: string;\n protocolServiceName?: string;\n /**\n * Optional override for the kernel-manager service name. When the service\n * is registered (by @objectstack/runtime's MultiProjectPlugin), scoped\n * routes resolve per-project protocols at request time.\n */\n kernelManagerServiceName?: string;\n api?: RestServerConfig;\n}\n\n/**\n * REST API Plugin\n * \n * Responsibilities:\n * 1. Consumes 'http.server' (or configured service)\n * 2. Consumes 'protocol' (ObjectStackProtocol)\n * 3. Instantiates RestServer to auto-generate routes\n */\nexport function createRestApiPlugin(config: RestApiPluginConfig = {}): Plugin {\n return {\n name: 'com.objectstack.rest.api',\n version: '1.0.0',\n \n init: async (_ctx: PluginContext) => {\n // No service registration, this is a consumer plugin\n },\n \n start: async (ctx: PluginContext) => {\n const serverService = config.serverServiceName || 'http.server';\n const protocolService = config.protocolServiceName || 'protocol';\n \n let server: IHttpServer | undefined;\n let protocol: ObjectStackProtocol | undefined;\n\n try {\n server = ctx.getService<IHttpServer>(serverService);\n } catch (e) {\n // Ignore missing service\n }\n\n try {\n protocol = ctx.getService<ObjectStackProtocol>(protocolService);\n } catch (e) {\n // Ignore missing service\n }\n\n // Optional — only present when MultiProjectPlugin is mounted. When\n // available, RestServer will resolve a per-project protocol at\n // request time for scoped (`/projects/:projectId/...`) routes.\n let kernelManager: RestKernelManager | undefined;\n const kernelManagerService = config.kernelManagerServiceName || 'kernel-manager';\n try {\n kernelManager = ctx.getService<RestKernelManager>(kernelManagerService);\n } catch (e) {\n // Single-kernel deployment — fall back to the control protocol\n }\n\n // Optional — only present in runtime mode. When available,\n // RestServer will resolve hostname → projectId on unscoped\n // routes so a remote runtime node can dispatch every request\n // to the matching per-project kernel without requiring callers\n // to know the projectId.\n let envRegistry: any;\n try {\n envRegistry = ctx.getService<any>('env-registry');\n } catch (e) {\n // Not running in runtime/multi-project mode — fine.\n }\n\n // Optional default-project provider — registered by\n // `createSingleProjectPlugin` in single-project local mode.\n // Lets RestServer route bare `/api/v1/data/...` URLs into the\n // lone project's kernel.\n const defaultProjectIdProvider = (): string | undefined => {\n try {\n const dp: any = ctx.getService('default-project');\n return dp?.projectId;\n } catch { return undefined; }\n };\n\n // Auth service resolver — used by RestServer.resolveExecCtx in\n // single-kernel deployments where there is no kernelManager.\n // Multi-kernel paths look up auth via kernelManager.getOrCreate,\n // so this provider is the single-kernel fallback.\n const authServiceProvider = async (_projectId?: string): Promise<any | undefined> => {\n try {\n return ctx.getService<any>('auth');\n } catch { return undefined; }\n };\n\n // ObjectQL resolver — single-kernel fallback so resolveExecCtx\n // can run sys_member / sys_user_permission_set lookups when\n // there is no kernelManager wired (e.g. `pnpm dev:crm`).\n const objectQLProvider = async (_projectId?: string): Promise<any | undefined> => {\n try {\n return ctx.getService<any>('objectql');\n } catch { return undefined; }\n };\n\n // Email service resolver — used by POST /email/send. Single-\n // kernel deployments resolve from the local kernel; multi-\n // tenant paths would resolve via kernelManager.getOrCreate.\n const emailServiceProvider = async (_projectId?: string): Promise<any | undefined> => {\n try {\n return ctx.getService<any>('email');\n } catch { return undefined; }\n };\n\n // Sharing service resolver — used by /data/:object/:id/shares.\n const sharingServiceProvider = async (_projectId?: string): Promise<any | undefined> => {\n try {\n return ctx.getService<any>('sharing');\n } catch { return undefined; }\n };\n\n // Reports service resolver — used by /reports/* routes.\n const reportsServiceProvider = async (_projectId?: string): Promise<any | undefined> => {\n try {\n return ctx.getService<any>('reports');\n } catch { return undefined; }\n };\n\n // Approvals service resolver — used by /approvals/* routes.\n const approvalsServiceProvider = async (_projectId?: string): Promise<any | undefined> => {\n try {\n return ctx.getService<any>('approvals');\n } catch { return undefined; }\n };\n\n // Sharing-rule service resolver — used by /sharing/rules/* routes.\n const sharingRulesServiceProvider = async (_projectId?: string): Promise<any | undefined> => {\n try {\n return ctx.getService<any>('sharingRules');\n } catch { return undefined; }\n };\n\n // i18n service resolver — used to localize view / action / object\n // metadata. Single-kernel fallback so labels and select options\n // get translated even without a full multi-tenant kernelManager.\n const i18nServiceProvider = async (_projectId?: string): Promise<any | undefined> => {\n try {\n return ctx.getService<any>('i18n');\n } catch { return undefined; }\n };\n\n if (!server) {\n ctx.logger.warn(`RestApiPlugin: HTTP Server service '${serverService}' not found. REST routes skipped.`);\n return;\n }\n \n if (!protocol) {\n ctx.logger.warn(`RestApiPlugin: Protocol service '${protocolService}' not found. REST routes skipped.`);\n return;\n }\n \n ctx.logger.info('Hydrating REST API from Protocol...');\n \n try {\n const restServer = new RestServer(server, protocol, config.api as any, kernelManager, envRegistry, defaultProjectIdProvider, authServiceProvider, objectQLProvider, emailServiceProvider, sharingServiceProvider, reportsServiceProvider, approvalsServiceProvider, sharingRulesServiceProvider, i18nServiceProvider);\n restServer.registerRoutes();\n\n ctx.logger.info('REST API successfully registered');\n } catch (err: any) {\n ctx.logger.error('Failed to register REST API routes', { error: err.message } as any);\n throw err;\n }\n\n // Register package management routes if service is available\n try {\n const packageService = ctx.getService<PackageService>('package');\n if (packageService) {\n const basePath = config.api?.api?.basePath || '/api';\n const version = config.api?.api?.version || 'v1';\n const versionedBase = `${basePath}/${version}`;\n const enableProjectScoping = config.api?.api?.enableProjectScoping ?? false;\n const projectResolution = config.api?.api?.projectResolution ?? 'auto';\n\n if (enableProjectScoping && projectResolution === 'required') {\n // Only register the scoped variant\n registerPackageRoutes(server, packageService, `${versionedBase}/projects/:projectId`, {\n protocol,\n });\n } else {\n registerPackageRoutes(server, packageService, versionedBase, { protocol });\n if (enableProjectScoping) {\n registerPackageRoutes(server, packageService, `${versionedBase}/projects/:projectId`, {\n protocol,\n });\n }\n }\n ctx.logger.info('Package management routes registered');\n }\n } catch (e) {\n // Package service not available, skip\n ctx.logger.debug('Package service not available, package routes skipped');\n }\n }\n };\n}\n"],"mappings":"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","names":["row"]}