@open-mercato/shared 0.6.8-develop.6930.1.1e5976efc3 → 0.6.8-develop.6940.1.177ea30c6e

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.
@@ -50,9 +50,9 @@ function readCookieFromHeader(header, name) {
50
50
  function resolveTenantOverride(raw) {
51
51
  if (raw === void 0) return { applied: false, value: null };
52
52
  const decoded = decodeCookieValue(raw);
53
- if (!decoded) return { applied: true, value: null };
53
+ if (!decoded) return { applied: false, value: null };
54
54
  const trimmed = decoded.trim();
55
- if (!trimmed) return { applied: true, value: null };
55
+ if (!trimmed) return { applied: false, value: null };
56
56
  return { applied: true, value: trimmed };
57
57
  }
58
58
  function resolveOrganizationOverride(raw) {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/lib/auth/server.ts"],
4
- "sourcesContent": ["import { cookies } from 'next/headers.js'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { verifyJwt } from './jwt'\nimport { getSharedApiKeyAuthCache } from './apiKeyAuthCache'\nimport { isTransientDbError } from '@open-mercato/shared/lib/db/pg-errors'\n\nconst TENANT_COOKIE_NAME = 'om_selected_tenant'\nconst ORGANIZATION_COOKIE_NAME = 'om_selected_org'\nconst ALL_ORGANIZATIONS_COOKIE_VALUE = '__all__'\nconst SUPERADMIN_ROLE = 'superadmin'\n\nexport type AuthContext = {\n sub: string\n sid?: string | null\n tenantId: string | null\n orgId: string | null\n email?: string\n roles?: string[]\n isApiKey?: boolean\n userId?: string\n keyId?: string\n keyName?: string\n [k: string]: unknown\n} | null\n\ntype CookieOverride = { applied: boolean; value: string | null }\n// 'error' means auth could not be determined because of a transient/unexpected\n// failure (DB unavailable, connection-pool exhaustion, statement timeout, \u2026) \u2014\n// NOT because the token is genuinely invalid. Callers MUST NOT clear the user's\n// session cookies for 'error'; doing so would log everyone out at once during a\n// shared infrastructure blip (issue #4176).\ntype AuthResolutionStatus = 'authenticated' | 'missing' | 'invalid' | 'error'\ntype AuthResolution = {\n auth: AuthContext\n status: AuthResolutionStatus\n}\n\n// Thrown by `resolveCanonicalInteractiveAuthContext` when the canonical auth\n// lookup itself fails unexpectedly (as opposed to resolving to a genuine\n// \"not authorized\" null). Kept distinct so resolvers can map it to the\n// non-destructive 'error' status instead of the cookie-clearing 'invalid'.\nexport class AuthResolutionUnavailableError extends Error {\n constructor(cause?: unknown) {\n super('Auth resolution unavailable')\n this.name = 'AuthResolutionUnavailableError'\n if (cause !== undefined) (this as { cause?: unknown }).cause = cause\n }\n}\n\n// Symbol-keyed trusted auth context. Set on synthetic Request objects by\n// callers that have already authenticated (e.g. the AI in-process operation\n// runner) so downstream auth resolution short-circuits without re-running\n// cookie/JWT/API-key parsing. The hook is fail-open: if absent the normal\n// resolution path runs unchanged.\nexport const TRUSTED_AUTH_CONTEXT_SYMBOL = Symbol.for('open-mercato.auth.trustedContext')\n\nexport type TrustedAuthContextEnvelope = {\n auth: AuthContext\n status?: AuthResolutionStatus\n}\n\nexport function attachTrustedAuthContext(\n request: Request,\n envelope: TrustedAuthContextEnvelope\n): Request {\n ;(request as unknown as Record<symbol, TrustedAuthContextEnvelope>)[TRUSTED_AUTH_CONTEXT_SYMBOL] = envelope\n return request\n}\n\nfunction readTrustedAuthContext(request: Request): TrustedAuthContextEnvelope | null {\n const carrier = request as unknown as Record<symbol, unknown>\n const envelope = carrier[TRUSTED_AUTH_CONTEXT_SYMBOL]\n if (!envelope || typeof envelope !== 'object') return null\n const candidate = envelope as TrustedAuthContextEnvelope\n if (!('auth' in candidate)) return null\n return candidate\n}\n\nfunction decodeCookieValue(raw: string | undefined): string | null {\n if (raw === undefined) return null\n try {\n const decoded = decodeURIComponent(raw)\n return decoded ?? null\n } catch {\n return raw ?? null\n }\n}\n\nfunction readCookieFromHeader(header: string | null | undefined, name: string): string | undefined {\n if (!header) return undefined\n const parts = header.split(';')\n for (const part of parts) {\n const trimmed = part.trim()\n if (trimmed.startsWith(`${name}=`)) {\n return trimmed.slice(name.length + 1)\n }\n }\n return undefined\n}\n\nfunction resolveTenantOverride(raw: string | undefined): CookieOverride {\n if (raw === undefined) return { applied: false, value: null }\n const decoded = decodeCookieValue(raw)\n if (!decoded) return { applied: true, value: null }\n const trimmed = decoded.trim()\n if (!trimmed) return { applied: true, value: null }\n return { applied: true, value: trimmed }\n}\n\nfunction resolveOrganizationOverride(raw: string | undefined): CookieOverride {\n if (raw === undefined) return { applied: false, value: null }\n const decoded = decodeCookieValue(raw)\n if (!decoded || decoded === ALL_ORGANIZATIONS_COOKIE_VALUE) {\n return { applied: true, value: null }\n }\n const trimmed = decoded.trim()\n if (!trimmed || trimmed === ALL_ORGANIZATIONS_COOKIE_VALUE) {\n return { applied: true, value: null }\n }\n return { applied: true, value: trimmed }\n}\n\nfunction isSuperAdminAuth(auth: AuthContext | null | undefined): boolean {\n if (!auth) return false\n return (auth as Record<string, unknown>).isSuperAdmin === true\n}\n\nfunction applySuperAdminScope(\n auth: AuthContext,\n tenantCookie: string | undefined,\n orgCookie: string | undefined\n): AuthContext {\n if (!auth || !isSuperAdminAuth(auth)) return auth\n\n const tenantOverride = resolveTenantOverride(tenantCookie)\n const orgOverride = resolveOrganizationOverride(orgCookie)\n if (!tenantOverride.applied && !orgOverride.applied) return auth\n\n type MutableAuthContext = Exclude<AuthContext, null> & {\n actorTenantId?: string | null\n actorOrgId?: string | null\n }\n const baseAuth = auth as Exclude<AuthContext, null>\n const next: MutableAuthContext = { ...baseAuth }\n if (tenantOverride.applied) {\n if (!('actorTenantId' in next)) next.actorTenantId = auth?.tenantId ?? null\n next.tenantId = tenantOverride.value\n }\n if (orgOverride.applied) {\n if (!('actorOrgId' in next)) next.actorOrgId = auth?.orgId ?? null\n next.orgId = orgOverride.value\n }\n next.isSuperAdmin = true\n const existingRoles = Array.isArray(next.roles) ? next.roles : []\n if (!existingRoles.some((role) => typeof role === 'string' && role.trim().toLowerCase() === SUPERADMIN_ROLE)) {\n next.roles = [...existingRoles, 'superadmin']\n }\n return next\n}\n\nasync function resolveApiKeyAuth(secret: string): Promise<AuthContext> {\n if (!secret) return null\n const cache = getSharedApiKeyAuthCache()\n const cached = cache.get(secret)\n if (cached !== undefined) return cached as AuthContext\n try {\n const { createRequestContainer } = await import('@open-mercato/shared/lib/di/container')\n const container = await createRequestContainer()\n const em = (container.resolve('em') as EntityManager)\n const { findApiKeyBySecret } = await import('@open-mercato/core/modules/api_keys/services/apiKeyService')\n const { Role, RoleAcl, User } = await import('@open-mercato/core/modules/auth/data/entities')\n const { Organization, Tenant } = await import('@open-mercato/core/modules/directory/data/entities')\n\n const record = await findApiKeyBySecret(em, secret)\n if (!record) {\n cache.setMiss(secret)\n return null\n }\n\n const roleIds = Array.isArray(record.rolesJson)\n ? record.rolesJson.filter((value): value is string => typeof value === 'string' && value.length > 0)\n : []\n const roles = roleIds.length\n ? await em.find(Role, { id: { $in: roleIds }, deletedAt: null })\n : []\n const roleNames = roles.map((role) => role.name).filter((name): name is string => typeof name === 'string' && name.length > 0)\n\n let keyIsSuperAdmin = false\n if (roleIds.length) {\n const superAcl = await em.findOne(\n RoleAcl,\n { role: { $in: roleIds } as any, isSuperAdmin: true, deletedAt: null } as any,\n )\n keyIsSuperAdmin = !!(superAcl && (superAcl as { isSuperAdmin?: boolean }).isSuperAdmin)\n }\n\n if (cache.shouldWriteLastUsed(record.id)) {\n try {\n record.lastUsedAt = new Date()\n await em.persist(record).flush()\n } catch {\n // best-effort update; ignore write failures\n }\n }\n\n // For session keys, use sessionUserId; for regular keys, use createdBy\n const actualUserId = record.sessionUserId ?? record.createdBy ?? null\n\n if (actualUserId) {\n const user = await em.findOne(User, { id: actualUserId, deletedAt: null })\n if (!user) {\n cache.setMiss(secret)\n return null\n }\n if ((user.tenantId ?? null) !== (record.tenantId ?? null)) {\n cache.setMiss(secret)\n return null\n }\n if ((user.organizationId ?? null) !== (record.organizationId ?? null)) {\n cache.setMiss(secret)\n return null\n }\n } else {\n if (record.tenantId) {\n const tenant = await em.findOne(Tenant, { id: record.tenantId, deletedAt: null, isActive: true })\n if (!tenant) {\n cache.setMiss(secret)\n return null\n }\n }\n if (record.organizationId) {\n const organization = await em.findOne(Organization, { id: record.organizationId, deletedAt: null, isActive: true })\n if (!organization) {\n cache.setMiss(secret)\n return null\n }\n if (record.tenantId && String(organization.tenant.id) !== record.tenantId) {\n cache.setMiss(secret)\n return null\n }\n }\n }\n\n const auth: Exclude<AuthContext, null> = {\n sub: `api_key:${record.id}`,\n tenantId: record.tenantId ?? null,\n orgId: record.organizationId ?? null,\n roles: roleNames,\n isApiKey: true,\n isSuperAdmin: keyIsSuperAdmin,\n keyId: record.id,\n keyName: record.name,\n ...(actualUserId ? { userId: actualUserId } : {}),\n }\n cache.setSuccess(secret, auth, record.expiresAt ? record.expiresAt.getTime() : null)\n return auth\n } catch (err) {\n // A transient DB failure (pool exhausted, `max_connections` reached, DB\n // restarting) means we could not confirm the key \u2014 NOT that it is invalid.\n // Surface it so callers return a retryable 503 instead of masking it as an\n // auth miss (401). Genuine misses already returned `null` above.\n if (isTransientDbError(err)) {\n throw new AuthResolutionUnavailableError(err)\n }\n return null\n }\n}\n\nfunction extractApiKey(req: Request): string | null {\n const header = (req.headers.get('x-api-key') || '').trim()\n if (header) return header\n const authHeader = (req.headers.get('authorization') || '').trim()\n if (authHeader.toLowerCase().startsWith('apikey ')) {\n return authHeader.slice(7).trim()\n }\n return null\n}\n\nasync function resolveCanonicalInteractiveAuthContext(auth: AuthContext): Promise<AuthContext> {\n if (!auth || auth.isApiKey) return auth\n if (typeof auth.sub !== 'string' || auth.sub.trim().length === 0) return null\n\n try {\n const [{ createRequestContainer }, { resolveCanonicalStaffAuthContext }] = await Promise.all([\n import('@open-mercato/shared/lib/di/container'),\n import('@open-mercato/core/modules/auth/lib/sessionIntegrity'),\n ])\n const container = await createRequestContainer()\n const em = container.resolve('em') as EntityManager\n return await resolveCanonicalStaffAuthContext(em, auth)\n } catch (err) {\n // A thrown error here means we could not check the token against the\n // database (DB down, pool exhausted, timeout). This is NOT the same as the\n // token being invalid \u2014 surface it so callers keep the session intact and\n // fail the request transiently instead of force-logging the user out.\n throw new AuthResolutionUnavailableError(err)\n }\n}\n\nexport async function resolveAuthFromCookiesDetailed(): Promise<AuthResolution> {\n const cookieStore = await cookies()\n const token = cookieStore.get('auth_token')?.value\n if (!token) return { auth: null, status: 'missing' }\n try {\n const payload = verifyJwt(token) as AuthContext\n if (!payload) return { auth: null, status: 'invalid' }\n if (payload.type === 'customer') return { auth: null, status: 'invalid' }\n const canonicalAuth = await resolveCanonicalInteractiveAuthContext(payload)\n if (!canonicalAuth) return { auth: null, status: 'invalid' }\n const tenantCookie = cookieStore.get(TENANT_COOKIE_NAME)?.value\n const orgCookie = cookieStore.get(ORGANIZATION_COOKIE_NAME)?.value\n return {\n auth: applySuperAdminScope(canonicalAuth, tenantCookie, orgCookie),\n status: 'authenticated',\n }\n } catch (err) {\n if (err instanceof AuthResolutionUnavailableError) return { auth: null, status: 'error' }\n return { auth: null, status: 'invalid' }\n }\n}\n\nexport async function getAuthFromCookies(): Promise<AuthContext> {\n return (await resolveAuthFromCookiesDetailed()).auth\n}\n\nexport async function resolveAuthFromRequestDetailed(req: Request): Promise<AuthResolution> {\n const trusted = readTrustedAuthContext(req)\n if (trusted) {\n return {\n auth: trusted.auth,\n status: trusted.status ?? (trusted.auth ? 'authenticated' : 'missing'),\n }\n }\n const cookieHeader = req.headers.get('cookie') || ''\n const tenantCookie = readCookieFromHeader(cookieHeader, TENANT_COOKIE_NAME)\n const orgCookie = readCookieFromHeader(cookieHeader, ORGANIZATION_COOKIE_NAME)\n const authHeader = (req.headers.get('authorization') || '').trim()\n let token: string | undefined\n let hadInvalidInteractiveToken = false\n let hadUnavailableResolution = false\n if (authHeader.toLowerCase().startsWith('bearer ')) token = authHeader.slice(7).trim()\n if (!token) {\n const match = cookieHeader.match(/(?:^|;\\s*)auth_token=([^;]+)/)\n if (match) token = decodeURIComponent(match[1])\n }\n if (token) {\n try {\n const payload = verifyJwt(token) as AuthContext\n if (payload && payload.type === 'customer') return { auth: null, status: 'invalid' }\n if (payload) {\n const canonicalAuth = await resolveCanonicalInteractiveAuthContext(payload)\n if (canonicalAuth) {\n return {\n auth: applySuperAdminScope(canonicalAuth, tenantCookie, orgCookie),\n status: 'authenticated',\n }\n }\n hadInvalidInteractiveToken = true\n }\n } catch (err) {\n // Transient/unexpected canonical-resolution failures must not invalidate\n // the token \u2014 surface them so we return 'error' (retryable) rather than\n // clearing the session cookies.\n if (err instanceof AuthResolutionUnavailableError) hadUnavailableResolution = true\n else hadInvalidInteractiveToken = true\n }\n }\n\n const resolveUnauthenticatedStatus = (): AuthResolutionStatus =>\n hadUnavailableResolution ? 'error' : hadInvalidInteractiveToken ? 'invalid' : 'missing'\n\n const apiKey = extractApiKey(req)\n if (!apiKey) {\n return { auth: null, status: resolveUnauthenticatedStatus() }\n }\n let apiAuth: AuthContext\n try {\n apiAuth = await resolveApiKeyAuth(apiKey)\n } catch (err) {\n // Only a transient canonical-resolution failure maps to 'error' (retryable\n // 503), mirroring the interactive-token path above. Anything else is an\n // unexpected bug \u2014 rethrow so it surfaces as a 500 rather than being masked\n // as an auth failure.\n if (!(err instanceof AuthResolutionUnavailableError)) {\n throw err\n }\n hadUnavailableResolution = true\n return { auth: null, status: resolveUnauthenticatedStatus() }\n }\n if (!apiAuth) {\n return { auth: null, status: resolveUnauthenticatedStatus() }\n }\n return {\n auth: applySuperAdminScope(apiAuth, tenantCookie, orgCookie),\n status: 'authenticated',\n }\n}\n\nexport async function getAuthFromRequest(req: Request): Promise<AuthContext> {\n return (await resolveAuthFromRequestDetailed(req)).auth\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { cookies } from 'next/headers.js'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { verifyJwt } from './jwt'\nimport { getSharedApiKeyAuthCache } from './apiKeyAuthCache'\nimport { isTransientDbError } from '@open-mercato/shared/lib/db/pg-errors'\n\nconst TENANT_COOKIE_NAME = 'om_selected_tenant'\nconst ORGANIZATION_COOKIE_NAME = 'om_selected_org'\nconst ALL_ORGANIZATIONS_COOKIE_VALUE = '__all__'\nconst SUPERADMIN_ROLE = 'superadmin'\n\nexport type AuthContext = {\n sub: string\n sid?: string | null\n tenantId: string | null\n orgId: string | null\n email?: string\n roles?: string[]\n isApiKey?: boolean\n userId?: string\n keyId?: string\n keyName?: string\n [k: string]: unknown\n} | null\n\ntype CookieOverride = { applied: boolean; value: string | null }\n// 'error' means auth could not be determined because of a transient/unexpected\n// failure (DB unavailable, connection-pool exhaustion, statement timeout, \u2026) \u2014\n// NOT because the token is genuinely invalid. Callers MUST NOT clear the user's\n// session cookies for 'error'; doing so would log everyone out at once during a\n// shared infrastructure blip (issue #4176).\ntype AuthResolutionStatus = 'authenticated' | 'missing' | 'invalid' | 'error'\ntype AuthResolution = {\n auth: AuthContext\n status: AuthResolutionStatus\n}\n\n// Thrown by `resolveCanonicalInteractiveAuthContext` when the canonical auth\n// lookup itself fails unexpectedly (as opposed to resolving to a genuine\n// \"not authorized\" null). Kept distinct so resolvers can map it to the\n// non-destructive 'error' status instead of the cookie-clearing 'invalid'.\nexport class AuthResolutionUnavailableError extends Error {\n constructor(cause?: unknown) {\n super('Auth resolution unavailable')\n this.name = 'AuthResolutionUnavailableError'\n if (cause !== undefined) (this as { cause?: unknown }).cause = cause\n }\n}\n\n// Symbol-keyed trusted auth context. Set on synthetic Request objects by\n// callers that have already authenticated (e.g. the AI in-process operation\n// runner) so downstream auth resolution short-circuits without re-running\n// cookie/JWT/API-key parsing. The hook is fail-open: if absent the normal\n// resolution path runs unchanged.\nexport const TRUSTED_AUTH_CONTEXT_SYMBOL = Symbol.for('open-mercato.auth.trustedContext')\n\nexport type TrustedAuthContextEnvelope = {\n auth: AuthContext\n status?: AuthResolutionStatus\n}\n\nexport function attachTrustedAuthContext(\n request: Request,\n envelope: TrustedAuthContextEnvelope\n): Request {\n ;(request as unknown as Record<symbol, TrustedAuthContextEnvelope>)[TRUSTED_AUTH_CONTEXT_SYMBOL] = envelope\n return request\n}\n\nfunction readTrustedAuthContext(request: Request): TrustedAuthContextEnvelope | null {\n const carrier = request as unknown as Record<symbol, unknown>\n const envelope = carrier[TRUSTED_AUTH_CONTEXT_SYMBOL]\n if (!envelope || typeof envelope !== 'object') return null\n const candidate = envelope as TrustedAuthContextEnvelope\n if (!('auth' in candidate)) return null\n return candidate\n}\n\nfunction decodeCookieValue(raw: string | undefined): string | null {\n if (raw === undefined) return null\n try {\n const decoded = decodeURIComponent(raw)\n return decoded ?? null\n } catch {\n return raw ?? null\n }\n}\n\nfunction readCookieFromHeader(header: string | null | undefined, name: string): string | undefined {\n if (!header) return undefined\n const parts = header.split(';')\n for (const part of parts) {\n const trimmed = part.trim()\n if (trimmed.startsWith(`${name}=`)) {\n return trimmed.slice(name.length + 1)\n }\n }\n return undefined\n}\n\n/**\n * A blank `om_selected_tenant` is \"no selection\", not a deliberate \"no tenant\".\n *\n * Unlike the organization cookie there is no all-tenants sentinel to express, and the tenant\n * selector renders with `includeEmptyOption={false}`, so no UI produces a blank value. Treating it\n * as an applied override nulled `tenantId` for the whole super-admin session, which is what turned\n * a cosmetic client bug into `tenantId ?? ''` reaching a NOT NULL uuid column. Reporting the\n * override as not applied instead keeps the tenant carried in the token and remediates an\n * already-poisoned browser on its next request, whatever wrote the cookie.\n */\nfunction resolveTenantOverride(raw: string | undefined): CookieOverride {\n if (raw === undefined) return { applied: false, value: null }\n const decoded = decodeCookieValue(raw)\n if (!decoded) return { applied: false, value: null }\n const trimmed = decoded.trim()\n if (!trimmed) return { applied: false, value: null }\n return { applied: true, value: trimmed }\n}\n\nfunction resolveOrganizationOverride(raw: string | undefined): CookieOverride {\n if (raw === undefined) return { applied: false, value: null }\n const decoded = decodeCookieValue(raw)\n if (!decoded || decoded === ALL_ORGANIZATIONS_COOKIE_VALUE) {\n return { applied: true, value: null }\n }\n const trimmed = decoded.trim()\n if (!trimmed || trimmed === ALL_ORGANIZATIONS_COOKIE_VALUE) {\n return { applied: true, value: null }\n }\n return { applied: true, value: trimmed }\n}\n\nfunction isSuperAdminAuth(auth: AuthContext | null | undefined): boolean {\n if (!auth) return false\n return (auth as Record<string, unknown>).isSuperAdmin === true\n}\n\nfunction applySuperAdminScope(\n auth: AuthContext,\n tenantCookie: string | undefined,\n orgCookie: string | undefined\n): AuthContext {\n if (!auth || !isSuperAdminAuth(auth)) return auth\n\n const tenantOverride = resolveTenantOverride(tenantCookie)\n const orgOverride = resolveOrganizationOverride(orgCookie)\n if (!tenantOverride.applied && !orgOverride.applied) return auth\n\n type MutableAuthContext = Exclude<AuthContext, null> & {\n actorTenantId?: string | null\n actorOrgId?: string | null\n }\n const baseAuth = auth as Exclude<AuthContext, null>\n const next: MutableAuthContext = { ...baseAuth }\n if (tenantOverride.applied) {\n if (!('actorTenantId' in next)) next.actorTenantId = auth?.tenantId ?? null\n next.tenantId = tenantOverride.value\n }\n if (orgOverride.applied) {\n if (!('actorOrgId' in next)) next.actorOrgId = auth?.orgId ?? null\n next.orgId = orgOverride.value\n }\n next.isSuperAdmin = true\n const existingRoles = Array.isArray(next.roles) ? next.roles : []\n if (!existingRoles.some((role) => typeof role === 'string' && role.trim().toLowerCase() === SUPERADMIN_ROLE)) {\n next.roles = [...existingRoles, 'superadmin']\n }\n return next\n}\n\nasync function resolveApiKeyAuth(secret: string): Promise<AuthContext> {\n if (!secret) return null\n const cache = getSharedApiKeyAuthCache()\n const cached = cache.get(secret)\n if (cached !== undefined) return cached as AuthContext\n try {\n const { createRequestContainer } = await import('@open-mercato/shared/lib/di/container')\n const container = await createRequestContainer()\n const em = (container.resolve('em') as EntityManager)\n const { findApiKeyBySecret } = await import('@open-mercato/core/modules/api_keys/services/apiKeyService')\n const { Role, RoleAcl, User } = await import('@open-mercato/core/modules/auth/data/entities')\n const { Organization, Tenant } = await import('@open-mercato/core/modules/directory/data/entities')\n\n const record = await findApiKeyBySecret(em, secret)\n if (!record) {\n cache.setMiss(secret)\n return null\n }\n\n const roleIds = Array.isArray(record.rolesJson)\n ? record.rolesJson.filter((value): value is string => typeof value === 'string' && value.length > 0)\n : []\n const roles = roleIds.length\n ? await em.find(Role, { id: { $in: roleIds }, deletedAt: null })\n : []\n const roleNames = roles.map((role) => role.name).filter((name): name is string => typeof name === 'string' && name.length > 0)\n\n let keyIsSuperAdmin = false\n if (roleIds.length) {\n const superAcl = await em.findOne(\n RoleAcl,\n { role: { $in: roleIds } as any, isSuperAdmin: true, deletedAt: null } as any,\n )\n keyIsSuperAdmin = !!(superAcl && (superAcl as { isSuperAdmin?: boolean }).isSuperAdmin)\n }\n\n if (cache.shouldWriteLastUsed(record.id)) {\n try {\n record.lastUsedAt = new Date()\n await em.persist(record).flush()\n } catch {\n // best-effort update; ignore write failures\n }\n }\n\n // For session keys, use sessionUserId; for regular keys, use createdBy\n const actualUserId = record.sessionUserId ?? record.createdBy ?? null\n\n if (actualUserId) {\n const user = await em.findOne(User, { id: actualUserId, deletedAt: null })\n if (!user) {\n cache.setMiss(secret)\n return null\n }\n if ((user.tenantId ?? null) !== (record.tenantId ?? null)) {\n cache.setMiss(secret)\n return null\n }\n if ((user.organizationId ?? null) !== (record.organizationId ?? null)) {\n cache.setMiss(secret)\n return null\n }\n } else {\n if (record.tenantId) {\n const tenant = await em.findOne(Tenant, { id: record.tenantId, deletedAt: null, isActive: true })\n if (!tenant) {\n cache.setMiss(secret)\n return null\n }\n }\n if (record.organizationId) {\n const organization = await em.findOne(Organization, { id: record.organizationId, deletedAt: null, isActive: true })\n if (!organization) {\n cache.setMiss(secret)\n return null\n }\n if (record.tenantId && String(organization.tenant.id) !== record.tenantId) {\n cache.setMiss(secret)\n return null\n }\n }\n }\n\n const auth: Exclude<AuthContext, null> = {\n sub: `api_key:${record.id}`,\n tenantId: record.tenantId ?? null,\n orgId: record.organizationId ?? null,\n roles: roleNames,\n isApiKey: true,\n isSuperAdmin: keyIsSuperAdmin,\n keyId: record.id,\n keyName: record.name,\n ...(actualUserId ? { userId: actualUserId } : {}),\n }\n cache.setSuccess(secret, auth, record.expiresAt ? record.expiresAt.getTime() : null)\n return auth\n } catch (err) {\n // A transient DB failure (pool exhausted, `max_connections` reached, DB\n // restarting) means we could not confirm the key \u2014 NOT that it is invalid.\n // Surface it so callers return a retryable 503 instead of masking it as an\n // auth miss (401). Genuine misses already returned `null` above.\n if (isTransientDbError(err)) {\n throw new AuthResolutionUnavailableError(err)\n }\n return null\n }\n}\n\nfunction extractApiKey(req: Request): string | null {\n const header = (req.headers.get('x-api-key') || '').trim()\n if (header) return header\n const authHeader = (req.headers.get('authorization') || '').trim()\n if (authHeader.toLowerCase().startsWith('apikey ')) {\n return authHeader.slice(7).trim()\n }\n return null\n}\n\nasync function resolveCanonicalInteractiveAuthContext(auth: AuthContext): Promise<AuthContext> {\n if (!auth || auth.isApiKey) return auth\n if (typeof auth.sub !== 'string' || auth.sub.trim().length === 0) return null\n\n try {\n const [{ createRequestContainer }, { resolveCanonicalStaffAuthContext }] = await Promise.all([\n import('@open-mercato/shared/lib/di/container'),\n import('@open-mercato/core/modules/auth/lib/sessionIntegrity'),\n ])\n const container = await createRequestContainer()\n const em = container.resolve('em') as EntityManager\n return await resolveCanonicalStaffAuthContext(em, auth)\n } catch (err) {\n // A thrown error here means we could not check the token against the\n // database (DB down, pool exhausted, timeout). This is NOT the same as the\n // token being invalid \u2014 surface it so callers keep the session intact and\n // fail the request transiently instead of force-logging the user out.\n throw new AuthResolutionUnavailableError(err)\n }\n}\n\nexport async function resolveAuthFromCookiesDetailed(): Promise<AuthResolution> {\n const cookieStore = await cookies()\n const token = cookieStore.get('auth_token')?.value\n if (!token) return { auth: null, status: 'missing' }\n try {\n const payload = verifyJwt(token) as AuthContext\n if (!payload) return { auth: null, status: 'invalid' }\n if (payload.type === 'customer') return { auth: null, status: 'invalid' }\n const canonicalAuth = await resolveCanonicalInteractiveAuthContext(payload)\n if (!canonicalAuth) return { auth: null, status: 'invalid' }\n const tenantCookie = cookieStore.get(TENANT_COOKIE_NAME)?.value\n const orgCookie = cookieStore.get(ORGANIZATION_COOKIE_NAME)?.value\n return {\n auth: applySuperAdminScope(canonicalAuth, tenantCookie, orgCookie),\n status: 'authenticated',\n }\n } catch (err) {\n if (err instanceof AuthResolutionUnavailableError) return { auth: null, status: 'error' }\n return { auth: null, status: 'invalid' }\n }\n}\n\nexport async function getAuthFromCookies(): Promise<AuthContext> {\n return (await resolveAuthFromCookiesDetailed()).auth\n}\n\nexport async function resolveAuthFromRequestDetailed(req: Request): Promise<AuthResolution> {\n const trusted = readTrustedAuthContext(req)\n if (trusted) {\n return {\n auth: trusted.auth,\n status: trusted.status ?? (trusted.auth ? 'authenticated' : 'missing'),\n }\n }\n const cookieHeader = req.headers.get('cookie') || ''\n const tenantCookie = readCookieFromHeader(cookieHeader, TENANT_COOKIE_NAME)\n const orgCookie = readCookieFromHeader(cookieHeader, ORGANIZATION_COOKIE_NAME)\n const authHeader = (req.headers.get('authorization') || '').trim()\n let token: string | undefined\n let hadInvalidInteractiveToken = false\n let hadUnavailableResolution = false\n if (authHeader.toLowerCase().startsWith('bearer ')) token = authHeader.slice(7).trim()\n if (!token) {\n const match = cookieHeader.match(/(?:^|;\\s*)auth_token=([^;]+)/)\n if (match) token = decodeURIComponent(match[1])\n }\n if (token) {\n try {\n const payload = verifyJwt(token) as AuthContext\n if (payload && payload.type === 'customer') return { auth: null, status: 'invalid' }\n if (payload) {\n const canonicalAuth = await resolveCanonicalInteractiveAuthContext(payload)\n if (canonicalAuth) {\n return {\n auth: applySuperAdminScope(canonicalAuth, tenantCookie, orgCookie),\n status: 'authenticated',\n }\n }\n hadInvalidInteractiveToken = true\n }\n } catch (err) {\n // Transient/unexpected canonical-resolution failures must not invalidate\n // the token \u2014 surface them so we return 'error' (retryable) rather than\n // clearing the session cookies.\n if (err instanceof AuthResolutionUnavailableError) hadUnavailableResolution = true\n else hadInvalidInteractiveToken = true\n }\n }\n\n const resolveUnauthenticatedStatus = (): AuthResolutionStatus =>\n hadUnavailableResolution ? 'error' : hadInvalidInteractiveToken ? 'invalid' : 'missing'\n\n const apiKey = extractApiKey(req)\n if (!apiKey) {\n return { auth: null, status: resolveUnauthenticatedStatus() }\n }\n let apiAuth: AuthContext\n try {\n apiAuth = await resolveApiKeyAuth(apiKey)\n } catch (err) {\n // Only a transient canonical-resolution failure maps to 'error' (retryable\n // 503), mirroring the interactive-token path above. Anything else is an\n // unexpected bug \u2014 rethrow so it surfaces as a 500 rather than being masked\n // as an auth failure.\n if (!(err instanceof AuthResolutionUnavailableError)) {\n throw err\n }\n hadUnavailableResolution = true\n return { auth: null, status: resolveUnauthenticatedStatus() }\n }\n if (!apiAuth) {\n return { auth: null, status: resolveUnauthenticatedStatus() }\n }\n return {\n auth: applySuperAdminScope(apiAuth, tenantCookie, orgCookie),\n status: 'authenticated',\n }\n}\n\nexport async function getAuthFromRequest(req: Request): Promise<AuthContext> {\n return (await resolveAuthFromRequestDetailed(req)).auth\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -233,12 +233,14 @@ function cacheIsValid(appRoot, jsPath, metadataPath, expectedInputHash) {
233
233
  if (!metadata || metadata.inputHash !== expectedInputHash) return false;
234
234
  return contentHash(fs.readFileSync(jsPath)) === metadata.outputHash && dependenciesAreValid(appRoot, metadata.dependencies);
235
235
  }
236
- async function compileAndImport(tsPath, options = {}) {
237
- const allowRecovery = options.allowRecovery ?? true;
238
- const jsPath = options.outFile ?? tsPath.replace(/\.ts$/, ".mjs");
239
- const appRoot = options.appRoot ?? path.dirname(path.dirname(path.dirname(tsPath)));
236
+ async function compileAppSourceFile(tsPath, options) {
237
+ return withEsbuildLifecycle(() => compileAppSourceFileWithActiveEsbuild(tsPath, options));
238
+ }
239
+ async function compileAppSourceFileWithActiveEsbuild(tsPath, options) {
240
+ const { appRoot, outFile } = options;
241
+ const format = options.format ?? "esm";
240
242
  const appTsconfig = path.join(appRoot, "tsconfig.json");
241
- const metadataPath = cacheMetadataPath(jsPath);
243
+ const metadataPath = cacheMetadataPath(outFile);
242
244
  const tsExists = fs.existsSync(tsPath);
243
245
  const tsconfigExists = fs.existsSync(appTsconfig);
244
246
  if (!tsExists) {
@@ -249,35 +251,42 @@ async function compileAndImport(tsPath, options = {}) {
249
251
  }
250
252
  const tsconfigPaths = collectTsconfigPaths(appTsconfig);
251
253
  const expectedInputHash = cacheInputHash(tsPath, appRoot, tsconfigPaths);
252
- const needsCompile = !cacheIsValid(appRoot, jsPath, metadataPath, expectedInputHash);
253
- if (needsCompile) {
254
- fs.mkdirSync(path.dirname(jsPath), { recursive: true });
255
- const esbuild = await getEsbuildRuntime();
256
- const result = await esbuild.build({
257
- entryPoints: [tsPath],
258
- outfile: jsPath,
259
- absWorkingDir: appRoot,
260
- bundle: true,
261
- metafile: true,
262
- format: "esm",
263
- platform: "node",
264
- target: "node18",
265
- tsconfig: appTsconfig,
266
- plugins: createCliBundlePlugins(appRoot),
267
- // Allow JSON imports
268
- loader: { ".json": "json" }
269
- });
270
- const metadata = {
271
- version: DYNAMIC_LOADER_CACHE_VERSION,
272
- inputHash: expectedInputHash,
273
- outputHash: contentHash(fs.readFileSync(jsPath)),
274
- dependencies: {
275
- ...collectDependencyHashes(appRoot, result.metafile.inputs),
276
- ...hashFilesRelativeTo(appRoot, tsconfigPaths)
277
- }
278
- };
279
- fs.writeFileSync(metadataPath, JSON.stringify(metadata));
254
+ if (cacheIsValid(appRoot, outFile, metadataPath, expectedInputHash)) {
255
+ return outFile;
280
256
  }
257
+ fs.mkdirSync(path.dirname(outFile), { recursive: true });
258
+ const esbuild = await getEsbuildRuntime();
259
+ const result = await esbuild.build({
260
+ entryPoints: [tsPath],
261
+ outfile: outFile,
262
+ absWorkingDir: appRoot,
263
+ bundle: true,
264
+ metafile: true,
265
+ format,
266
+ platform: "node",
267
+ target: "node18",
268
+ tsconfig: appTsconfig,
269
+ plugins: createCliBundlePlugins(appRoot),
270
+ // Allow JSON imports
271
+ loader: { ".json": "json" }
272
+ });
273
+ const metadata = {
274
+ version: DYNAMIC_LOADER_CACHE_VERSION,
275
+ inputHash: expectedInputHash,
276
+ outputHash: contentHash(fs.readFileSync(outFile)),
277
+ dependencies: {
278
+ ...collectDependencyHashes(appRoot, result.metafile.inputs),
279
+ ...hashFilesRelativeTo(appRoot, tsconfigPaths)
280
+ }
281
+ };
282
+ fs.writeFileSync(metadataPath, JSON.stringify(metadata));
283
+ return outFile;
284
+ }
285
+ async function compileAndImport(tsPath, options = {}) {
286
+ const allowRecovery = options.allowRecovery ?? true;
287
+ const jsPath = options.outFile ?? tsPath.replace(/\.ts$/, ".mjs");
288
+ const appRoot = options.appRoot ?? path.dirname(path.dirname(path.dirname(tsPath)));
289
+ await compileAppSourceFile(tsPath, { appRoot, outFile: jsPath });
281
290
  try {
282
291
  const outputHash = contentHash(fs.readFileSync(jsPath));
283
292
  const fileUrl = `${pathToFileURL(jsPath).href}?cache=${outputHash}`;
@@ -416,6 +425,7 @@ async function bootstrapFromAppRoot(appRoot) {
416
425
  }
417
426
  export {
418
427
  bootstrapFromAppRoot,
428
+ compileAppSourceFile,
419
429
  createCliBundlePlugins,
420
430
  loadBootstrapData
421
431
  };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/lib/bootstrap/dynamicLoader.ts"],
4
- "sourcesContent": ["import type { BootstrapData } from './types'\nimport type { AppDiRegistrar } from '../di/container'\nimport { findAppRoot, type AppRoot } from './appResolver'\nimport { registerEntityIds } from '../encryption/entityIds'\nimport { createLogger } from '../logger'\nimport {\n ensureMikroOrmV7GeneratedCacheCompatibility,\n recoverMikroOrmV7GeneratedCacheFromImportError,\n} from './generatedCacheRecovery'\nimport { CLIENT_ONLY_STUB_NAMESPACE, createClientOnlyStubPlugin } from './clientOnlyModules'\nimport path from 'node:path'\nimport fs from 'node:fs'\nimport crypto from 'node:crypto'\nimport { createRequire } from 'node:module'\nimport { pathToFileURL } from 'node:url'\n\nlet activeBootstrapLoads = 0\nlet esbuildRuntime: typeof import('esbuild') | null = null\nlet esbuildStopPromise: Promise<void> | null = null\n\nconst logger = createLogger('shared').child({ component: 'bootstrap' })\n\nasync function getEsbuildRuntime(): Promise<typeof import('esbuild')> {\n if (esbuildStopPromise) await esbuildStopPromise\n if (esbuildRuntime) return esbuildRuntime\n\n const loadedRuntime = await import('esbuild')\n esbuildRuntime ??= loadedRuntime\n return esbuildRuntime\n}\n\nasync function withEsbuildLifecycle<T>(load: () => Promise<T>): Promise<T> {\n activeBootstrapLoads += 1\n\n try {\n return await load()\n } finally {\n activeBootstrapLoads -= 1\n if (activeBootstrapLoads === 0 && esbuildRuntime) {\n // esbuild keeps a helper process alive after build(). Bootstrap compilation\n // is a bounded phase, so release it once every concurrent loader is done.\n // A later build() call transparently starts a fresh helper process.\n const runtimeToStop = esbuildRuntime\n esbuildRuntime = null\n const stopPromise = runtimeToStop.stop().catch((err) => {\n logger.warn('Failed to stop the bootstrap compiler service', { err })\n })\n esbuildStopPromise = stopPromise\n try {\n await stopPromise\n } finally {\n if (esbuildStopPromise === stopPromise) esbuildStopPromise = null\n }\n }\n }\n}\n\n/**\n * Thrown when an expected generated source file is absent.\n *\n * Optional registries treat this as the supported compatibility case (an app\n * that never generated the file), which is what makes it distinguishable from\n * a file that exists but fails to compile or import.\n */\nclass GeneratedFileNotFoundError extends Error {\n readonly filePath: string\n\n constructor(filePath: string) {\n super(`Generated file not found: ${filePath}`)\n this.name = 'GeneratedFileNotFoundError'\n this.filePath = filePath\n }\n}\n\n/**\n * esbuild plugins for the CLI bundle, in resolution order. The client-only stub must come\n * first so it wins over the alias and external plugins for `*.client` dynamic imports.\n *\n * Exported so the wiring itself is testable: a test that only exercises\n * `createClientOnlyStubPlugin` in isolation stays green if the plugin is dropped from this\n * list, which would silently reintroduce #4623.\n */\nexport function createCliBundlePlugins(appRoot: string): import('esbuild').Plugin[] {\n // Plugin to resolve the @/ alias the way the app tsconfig maps it:\n // `@/.mercato/*` to the app root, every other `@/*` to the app's src/ directory.\n const aliasPlugin: import('esbuild').Plugin = {\n name: 'alias-resolver',\n setup(build) {\n build.onResolve({ filter: /^@\\// }, (args) => {\n const rest = args.path.slice('@/'.length)\n const bases = rest.startsWith('.mercato/')\n ? [path.join(appRoot, rest)]\n : [path.join(appRoot, 'src', rest), path.join(appRoot, rest)]\n for (const base of bases) {\n if (fs.existsSync(base) && fs.statSync(base).isFile()) {\n return { path: base }\n }\n for (const suffix of ['.ts', '.tsx', '/index.ts', '/index.tsx']) {\n if (fs.existsSync(base + suffix)) {\n return { path: base + suffix }\n }\n }\n }\n // Nothing matched \u2014 hand esbuild the literal mapping so it reports the\n // missing file against the path the app author actually wrote.\n return { path: path.join(appRoot, rest) }\n })\n },\n }\n\n // Plugin to mark non-JSON package imports as external\n const externalNonJsonPlugin: import('esbuild').Plugin = {\n name: 'external-non-json',\n setup(build) {\n // Mark all package imports as external EXCEPT JSON files\n // Filter matches paths that don't start with . or / (package imports like @open-mercato/shared)\n build.onResolve({ filter: /^[^./]/ }, (args) => {\n // Skip Windows absolute paths (e.g., C:\\...) - they're local files, not packages\n if (/^[a-zA-Z]:/.test(args.path)) {\n return null // Let esbuild handle it\n }\n // If it's a JSON file, let esbuild bundle it\n if (args.path.endsWith('.json')) {\n return null // Let esbuild handle it\n }\n // Otherwise mark as external\n return { path: args.path, external: true }\n })\n },\n }\n\n return [createClientOnlyStubPlugin(), aliasPlugin, externalNonJsonPlugin]\n}\n\nconst DYNAMIC_LOADER_CACHE_VERSION = 4\n\ntype DynamicLoaderCacheMetadata = {\n version: number\n inputHash: string\n outputHash: string\n dependencies: Record<string, string>\n}\n\nfunction cacheMetadataPath(jsPath: string): string {\n return `${jsPath}.cache.json`\n}\n\nfunction contentHash(content: Buffer | string): string {\n return crypto.createHash('sha256').update(content).digest('hex')\n}\n\nfunction parseJsonConfig(content: string): unknown {\n let normalized = ''\n let inString = false\n let escaped = false\n\n for (let index = 0; index < content.length; index += 1) {\n const character = content[index]\n const nextCharacter = content[index + 1]\n\n if (inString) {\n normalized += character\n if (escaped) {\n escaped = false\n } else if (character === '\\\\') {\n escaped = true\n } else if (character === '\"') {\n inString = false\n }\n continue\n }\n\n if (character === '\"') {\n inString = true\n normalized += character\n continue\n }\n\n if (character === '/' && nextCharacter === '/') {\n while (index < content.length && content[index] !== '\\n') index += 1\n normalized += '\\n'\n continue\n }\n\n if (character === '/' && nextCharacter === '*') {\n index += 2\n while (index < content.length && !(content[index] === '*' && content[index + 1] === '/')) {\n index += 1\n }\n index += 1\n continue\n }\n\n if (character === ',') {\n let lookahead = index + 1\n while (lookahead < content.length && /\\s/.test(content[lookahead])) lookahead += 1\n if (content[lookahead] === '}' || content[lookahead] === ']') continue\n }\n\n normalized += character\n }\n\n return JSON.parse(normalized)\n}\n\nfunction resolveExistingConfigPath(candidate: string): string | null {\n for (const configPath of [candidate, `${candidate}.json`, path.join(candidate, 'tsconfig.json')]) {\n if (fs.existsSync(configPath) && fs.statSync(configPath).isFile()) return configPath\n }\n return null\n}\n\nfunction resolvePackageConfig(configPath: string, reference: string): string | null {\n try {\n const resolved = createRequire(pathToFileURL(configPath)).resolve(reference)\n return path.extname(resolved) === '.json' ? resolved : null\n } catch {\n return null\n }\n}\n\nfunction resolveExtendedConfig(configPath: string, reference: string): string {\n if (path.isAbsolute(reference) || reference.startsWith('.')) {\n const resolved = resolveExistingConfigPath(path.resolve(path.dirname(configPath), reference))\n if (resolved) return resolved\n } else {\n for (const packageReference of [reference, `${reference}/tsconfig.json`]) {\n const resolved = resolvePackageConfig(configPath, packageReference)\n if (resolved) return resolved\n }\n }\n\n throw new Error(`[internal] TypeScript config extends target not found: ${reference}`)\n}\n\nfunction collectTsconfigPaths(entryPath: string, visited: Set<string> = new Set()): string[] {\n const configPath = path.resolve(entryPath)\n if (visited.has(configPath)) return []\n visited.add(configPath)\n\n const parsed = parseJsonConfig(fs.readFileSync(configPath, 'utf8'))\n if (typeof parsed !== 'object' || parsed === null || !('extends' in parsed)) return [configPath]\n\n const extendsValue = parsed.extends\n const references = typeof extendsValue === 'string'\n ? [extendsValue]\n : Array.isArray(extendsValue) && extendsValue.every((value) => typeof value === 'string')\n ? extendsValue\n : []\n\n return [\n ...references.flatMap((reference) => collectTsconfigPaths(\n resolveExtendedConfig(configPath, reference),\n visited,\n )),\n configPath,\n ]\n}\n\nfunction hashFilesRelativeTo(appRoot: string, filePaths: string[]): Record<string, string> {\n return Object.fromEntries(filePaths.map((filePath) => [\n path.relative(appRoot, filePath).split(path.sep).join('/'),\n contentHash(fs.readFileSync(filePath)),\n ]))\n}\n\nfunction cacheInputHash(tsPath: string, appRoot: string, tsconfigPaths: string[]): string {\n const hash = crypto.createHash('sha256')\n hash.update(JSON.stringify({\n version: DYNAMIC_LOADER_CACHE_VERSION,\n sourceHash: contentHash(fs.readFileSync(tsPath)),\n tsconfigHashes: hashFilesRelativeTo(appRoot, tsconfigPaths),\n }))\n return hash.digest('hex')\n}\n\nfunction dependenciesAreValid(appRoot: string, dependencies: Record<string, string>): boolean {\n return Object.entries(dependencies).every(([relativePath, expectedHash]) => {\n const dependencyPath = path.resolve(appRoot, relativePath)\n return fs.existsSync(dependencyPath)\n && contentHash(fs.readFileSync(dependencyPath)) === expectedHash\n })\n}\n\nfunction collectDependencyHashes(\n appRoot: string,\n inputs: Record<string, unknown>,\n): Record<string, string> {\n return Object.fromEntries(\n Object.keys(inputs)\n .filter((inputPath) => !inputPath.startsWith(`${CLIENT_ONLY_STUB_NAMESPACE}:`))\n .map((inputPath) => {\n const absolutePath = path.isAbsolute(inputPath)\n ? inputPath\n : path.resolve(appRoot, inputPath)\n const relativePath = path.relative(appRoot, absolutePath).split(path.sep).join('/')\n return [relativePath, contentHash(fs.readFileSync(absolutePath))]\n })\n .sort(([left], [right]) => left.localeCompare(right)),\n )\n}\n\nfunction readCacheMetadata(metadataPath: string): DynamicLoaderCacheMetadata | null {\n try {\n const parsed: unknown = JSON.parse(fs.readFileSync(metadataPath, 'utf8'))\n if (\n typeof parsed === 'object'\n && parsed !== null\n && 'version' in parsed\n && parsed.version === DYNAMIC_LOADER_CACHE_VERSION\n && 'inputHash' in parsed\n && typeof parsed.inputHash === 'string'\n && 'outputHash' in parsed\n && typeof parsed.outputHash === 'string'\n && 'dependencies' in parsed\n && typeof parsed.dependencies === 'object'\n && parsed.dependencies !== null\n && Object.values(parsed.dependencies).every((hash) => typeof hash === 'string')\n ) {\n return {\n version: parsed.version,\n inputHash: parsed.inputHash,\n outputHash: parsed.outputHash,\n dependencies: parsed.dependencies as Record<string, string>,\n }\n }\n } catch {\n return null\n }\n return null\n}\n\nfunction cacheIsValid(\n appRoot: string,\n jsPath: string,\n metadataPath: string,\n expectedInputHash: string,\n): boolean {\n if (!fs.existsSync(jsPath)) return false\n const metadata = readCacheMetadata(metadataPath)\n if (!metadata || metadata.inputHash !== expectedInputHash) return false\n return contentHash(fs.readFileSync(jsPath)) === metadata.outputHash\n && dependenciesAreValid(appRoot, metadata.dependencies)\n}\n\n/**\n * Options for `compileAndImport`.\n *\n * Both paths default to the generated-registry layout (`<appRoot>/.mercato/generated/<file>.ts`\n * compiled to a `.mjs` sibling). Sources that live elsewhere in the app \u2014 `src/di.ts` \u2014 MUST pass\n * both explicitly: the default app root is derived by walking three directories up from the source,\n * which only holds inside `.mercato/generated`.\n */\ntype CompileAndImportOptions = {\n appRoot?: string\n outFile?: string\n allowRecovery?: boolean\n}\n\n/**\n * Compile a TypeScript file to JavaScript using esbuild bundler.\n * This bundles the file and all its dependencies, handling JSON imports properly.\n * The compiled file is written next to the source file with a .mjs extension unless\n * `outFile` says otherwise.\n */\nasync function compileAndImport(\n tsPath: string,\n options: CompileAndImportOptions = {},\n): Promise<Record<string, unknown>> {\n const allowRecovery = options.allowRecovery ?? true\n const jsPath = options.outFile ?? tsPath.replace(/\\.ts$/, '.mjs')\n const appRoot = options.appRoot ?? path.dirname(path.dirname(path.dirname(tsPath)))\n const appTsconfig = path.join(appRoot, 'tsconfig.json')\n const metadataPath = cacheMetadataPath(jsPath)\n\n const tsExists = fs.existsSync(tsPath)\n const tsconfigExists = fs.existsSync(appTsconfig)\n\n if (!tsExists) {\n throw new GeneratedFileNotFoundError(tsPath)\n }\n if (!tsconfigExists) {\n throw new Error(`App TypeScript config not found: ${appTsconfig}`)\n }\n\n const tsconfigPaths = collectTsconfigPaths(appTsconfig)\n const expectedInputHash = cacheInputHash(tsPath, appRoot, tsconfigPaths)\n const needsCompile = !cacheIsValid(appRoot, jsPath, metadataPath, expectedInputHash)\n\n if (needsCompile) {\n fs.mkdirSync(path.dirname(jsPath), { recursive: true })\n // Dynamically import esbuild only when needed\n const esbuild = await getEsbuildRuntime()\n\n // Use esbuild.build with bundling to handle JSON imports\n const result = await esbuild.build({\n entryPoints: [tsPath],\n outfile: jsPath,\n absWorkingDir: appRoot,\n bundle: true,\n metafile: true,\n format: 'esm',\n platform: 'node',\n target: 'node18',\n tsconfig: appTsconfig,\n plugins: createCliBundlePlugins(appRoot),\n // Allow JSON imports\n loader: { '.json': 'json' },\n })\n const metadata: DynamicLoaderCacheMetadata = {\n version: DYNAMIC_LOADER_CACHE_VERSION,\n inputHash: expectedInputHash,\n outputHash: contentHash(fs.readFileSync(jsPath)),\n dependencies: {\n ...collectDependencyHashes(appRoot, result.metafile.inputs),\n ...hashFilesRelativeTo(appRoot, tsconfigPaths),\n },\n }\n fs.writeFileSync(metadataPath, JSON.stringify(metadata))\n }\n\n // Import the compiled JavaScript\n try {\n const outputHash = contentHash(fs.readFileSync(jsPath))\n const fileUrl = `${pathToFileURL(jsPath).href}?cache=${outputHash}`\n return await import(fileUrl)\n } catch (error) {\n if (!allowRecovery) {\n throw error\n }\n\n const recovered = recoverMikroOrmV7GeneratedCacheFromImportError(appRoot, error)\n if (!recovered.applied) {\n throw error\n }\n\n return compileAndImport(tsPath, { ...options, allowRecovery: false })\n }\n}\n\n\n/**\n * Load a generated registry that older apps may not have generated yet.\n *\n * An absent source file is the supported compatibility case and resolves to\n * `fallback` quietly. Any other failure \u2014 a compile error, a broken import, a\n * runtime throw at module scope \u2014 still resolves to `fallback` so bootstrap\n * keeps working, but is reported at error level: a registry that silently\n * degrades to nothing is exactly how command interceptors stopped applying in\n * worker/CLI processes (#4327, #4491).\n */\nasync function loadOptionalGeneratedModule(\n tsPath: string,\n fallback: Record<string, unknown>,\n): Promise<Record<string, unknown>> {\n try {\n return await compileAndImport(tsPath)\n } catch (error) {\n if (error instanceof GeneratedFileNotFoundError) {\n logger.debug('Optional generated registry not present, using empty fallback', {\n file: path.basename(tsPath),\n })\n return fallback\n }\n\n logger.error('Failed to load generated registry, continuing without its entries', {\n file: path.basename(tsPath),\n filePath: tsPath,\n err: error,\n })\n return fallback\n }\n}\n\nfunction resolveAppRootOrThrow(appRoot?: string): AppRoot {\n const resolved: AppRoot | null = appRoot\n ? {\n generatedDir: path.join(appRoot, '.mercato', 'generated'),\n appDir: appRoot,\n mercatoDir: path.join(appRoot, '.mercato'),\n }\n : findAppRoot()\n\n if (!resolved) {\n throw new Error(\n 'Could not find app root with .mercato/generated directory. ' +\n 'Make sure you run this command from within a Next.js app directory, ' +\n 'or run \"yarn mercato generate\" first to create the generated files.',\n )\n }\n\n return resolved\n}\n\n/**\n * Load the app-level DI registrar (`src/di.ts`) for the dynamic bootstrap path.\n *\n * The Next.js runtime imports `@/di` statically from its own `src/bootstrap.ts` and hands the\n * registrar to `createBootstrap`. Worker, scheduler and CLI processes bootstrap through\n * `bootstrapFromAppRoot` instead, where the `@/` alias does not exist \u2014 so without this the app's\n * DI registrations silently never ran there, and every request container paid a failed\n * `import('@/di')` resolution (the compatibility fallback in `lib/di/container.ts`).\n *\n * An absent `src/di.ts` is the supported case and resolves to `null` quietly. A file that exists\n * but cannot be compiled, imported, or does not export `register` is reported at error level and\n * still resolves to `null`, so a broken app DI module degrades the same way a broken generated\n * registry does (#4327, #4491) instead of taking the whole process down.\n */\nasync function loadAppDiRegistrar(appDir: string): Promise<AppDiRegistrar | null> {\n const tsPath = path.join(appDir, 'src', 'di.ts')\n if (!fs.existsSync(tsPath)) {\n logger.debug('App-level DI module not present, skipping its registrations', { filePath: tsPath })\n return null\n }\n\n try {\n const appDiModule = await compileAndImport(tsPath, {\n appRoot: appDir,\n outFile: path.join(appDir, '.mercato', 'generated', 'app-di.compiled.mjs'),\n })\n const register = appDiModule.register\n if (typeof register !== 'function') {\n logger.error('App-level DI module exports no register(); its registrations are skipped', {\n filePath: tsPath,\n })\n return null\n }\n return register as AppDiRegistrar\n } catch (error) {\n logger.error('Failed to load the app-level DI module; its registrations are skipped', {\n filePath: tsPath,\n err: error,\n })\n return null\n }\n}\n\n/**\n * Dynamically load bootstrap data from a resolved app directory.\n *\n * IMPORTANT: This only works in unbundled contexts (CLI, tsx).\n * Do NOT use this in Next.js bundled code - use static imports instead.\n *\n * For CLI context, we skip loading modules.generated.ts which has Next.js dependencies.\n * CLI commands are discovered separately via the CLI module system.\n *\n * @param appRoot - Optional explicit app root path. If not provided, will search from cwd.\n * @returns The loaded bootstrap data\n * @throws Error if app root cannot be found or generated files are missing\n */\nasync function loadBootstrapDataWithActiveEsbuild(appRoot?: string): Promise<BootstrapData> {\n const resolved = resolveAppRootOrThrow(appRoot)\n\n const { generatedDir } = resolved\n\n ensureMikroOrmV7GeneratedCacheCompatibility(resolved.appDir)\n\n // IMPORTANT: Load entity IDs FIRST and register them before loading modules.\n // This is because modules (e.g., ce.ts files) use E.xxx.xxx at module scope,\n // and they need entity IDs to be available when they're imported.\n const entityIdsModule = await compileAndImport(path.join(generatedDir, 'entities.ids.generated.ts'))\n registerEntityIds(entityIdsModule.E as BootstrapData['entityIds'])\n\n // Now load the rest of the generated files.\n // modules.cli.generated.ts excludes Next.js-dependent code (routes, APIs, widgets)\n const [\n modulesModule,\n entitiesModule,\n diModule,\n searchModule,\n commandLoadersModule,\n commandInterceptorsModule,\n workflowsModule,\n ] = await Promise.all([\n compileAndImport(path.join(generatedDir, 'modules.cli.generated.ts')),\n compileAndImport(path.join(generatedDir, 'entities.generated.ts')),\n compileAndImport(path.join(generatedDir, 'di.generated.ts')),\n loadOptionalGeneratedModule(path.join(generatedDir, 'search.generated.ts'), { searchModuleConfigs: [] }),\n loadOptionalGeneratedModule(path.join(generatedDir, 'command-loaders.generated.ts'), { commandLoaderEntries: [] }),\n loadOptionalGeneratedModule(path.join(generatedDir, 'command-interceptors.generated.ts'), {\n commandInterceptorEntries: [],\n }),\n loadOptionalGeneratedModule(path.join(generatedDir, 'workflows.generated.ts'), { allCodeWorkflows: [] }),\n ])\n\n return {\n modules: modulesModule.modules as BootstrapData['modules'],\n entities: entitiesModule.entities as BootstrapData['entities'],\n diRegistrars: diModule.diRegistrars as BootstrapData['diRegistrars'],\n entityIds: entityIdsModule.E as BootstrapData['entityIds'],\n // Search configs are needed by workers for indexing\n searchModuleConfigs: (searchModule.searchModuleConfigs ?? []) as BootstrapData['searchModuleConfigs'],\n commandLoaderEntries: (commandLoadersModule.commandLoaderEntries ?? []) as BootstrapData['commandLoaderEntries'],\n // Command interceptors must apply in worker/CLI processes too \u2014 the\n // interceptor registry is per-process, so relying on the Next.js runtime's\n // registration silently no-ops every interceptor for queued/CLI commands\n // (#4327).\n commandInterceptorEntries: (commandInterceptorsModule.commandInterceptorEntries ??\n []) as BootstrapData['commandInterceptorEntries'],\n // Code workflow definitions are needed by workers to resume code-defined instances\n codeWorkflows: (workflowsModule.allCodeWorkflows ?? []) as BootstrapData['codeWorkflows'],\n // Empty UI-related data - not needed for CLI\n dashboardWidgetEntries: [],\n injectionWidgetEntries: [],\n injectionTables: [],\n interceptorEntries: [],\n componentOverrideEntries: [],\n }\n}\n\nexport async function loadBootstrapData(appRoot?: string): Promise<BootstrapData> {\n return withEsbuildLifecycle(() => loadBootstrapDataWithActiveEsbuild(appRoot))\n}\n\n/**\n * Create and execute bootstrap in CLI context.\n *\n * This is a convenience function that finds the app root, loads the generated\n * data dynamically, and runs bootstrap. Use this in CLI entry points.\n *\n * Returns the loaded bootstrap data so the CLI can register modules directly\n * (avoids module resolution issues when importing @open-mercato/cli/mercato).\n *\n * @param appRoot - Optional explicit app root path\n * @returns The loaded bootstrap data (modules, entities, etc.)\n */\nexport async function bootstrapFromAppRoot(appRoot?: string): Promise<BootstrapData> {\n const { createBootstrap, waitForAsyncRegistration } = await import('./factory.js')\n const resolved = resolveAppRootOrThrow(appRoot)\n // Both loads compile through esbuild, so they share one lifecycle scope: without it\n // `loadBootstrapData` releases the esbuild helper process and `loadAppDiRegistrar`\n // silently starts a second one that nothing ever stops.\n const { data, appDiRegistrar } = await withEsbuildLifecycle(async () => ({\n data: await loadBootstrapData(resolved.appDir),\n appDiRegistrar: await loadAppDiRegistrar(resolved.appDir),\n }))\n const bootstrap = createBootstrap(data, appDiRegistrar ? { appDiRegistrar } : {})\n bootstrap()\n // In CLI context, wait for async registrations (UI widgets, search configs, etc.)\n await waitForAsyncRegistration()\n\n return data\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type { BootstrapData } from './types'\nimport type { AppDiRegistrar } from '../di/container'\nimport { findAppRoot, type AppRoot } from './appResolver'\nimport { registerEntityIds } from '../encryption/entityIds'\nimport { createLogger } from '../logger'\nimport {\n ensureMikroOrmV7GeneratedCacheCompatibility,\n recoverMikroOrmV7GeneratedCacheFromImportError,\n} from './generatedCacheRecovery'\nimport { CLIENT_ONLY_STUB_NAMESPACE, createClientOnlyStubPlugin } from './clientOnlyModules'\nimport path from 'node:path'\nimport fs from 'node:fs'\nimport crypto from 'node:crypto'\nimport { createRequire } from 'node:module'\nimport { pathToFileURL } from 'node:url'\n\nlet activeBootstrapLoads = 0\nlet esbuildRuntime: typeof import('esbuild') | null = null\nlet esbuildStopPromise: Promise<void> | null = null\n\nconst logger = createLogger('shared').child({ component: 'bootstrap' })\n\nasync function getEsbuildRuntime(): Promise<typeof import('esbuild')> {\n if (esbuildStopPromise) await esbuildStopPromise\n if (esbuildRuntime) return esbuildRuntime\n\n const loadedRuntime = await import('esbuild')\n esbuildRuntime ??= loadedRuntime\n return esbuildRuntime\n}\n\nasync function withEsbuildLifecycle<T>(load: () => Promise<T>): Promise<T> {\n activeBootstrapLoads += 1\n\n try {\n return await load()\n } finally {\n activeBootstrapLoads -= 1\n if (activeBootstrapLoads === 0 && esbuildRuntime) {\n // esbuild keeps a helper process alive after build(). Bootstrap compilation\n // is a bounded phase, so release it once every concurrent loader is done.\n // A later build() call transparently starts a fresh helper process.\n const runtimeToStop = esbuildRuntime\n esbuildRuntime = null\n const stopPromise = runtimeToStop.stop().catch((err) => {\n logger.warn('Failed to stop the bootstrap compiler service', { err })\n })\n esbuildStopPromise = stopPromise\n try {\n await stopPromise\n } finally {\n if (esbuildStopPromise === stopPromise) esbuildStopPromise = null\n }\n }\n }\n}\n\n/**\n * Thrown when an expected generated source file is absent.\n *\n * Optional registries treat this as the supported compatibility case (an app\n * that never generated the file), which is what makes it distinguishable from\n * a file that exists but fails to compile or import.\n */\nclass GeneratedFileNotFoundError extends Error {\n readonly filePath: string\n\n constructor(filePath: string) {\n super(`Generated file not found: ${filePath}`)\n this.name = 'GeneratedFileNotFoundError'\n this.filePath = filePath\n }\n}\n\n/**\n * esbuild plugins for the CLI bundle, in resolution order. The client-only stub must come\n * first so it wins over the alias and external plugins for `*.client` dynamic imports.\n *\n * Exported so the wiring itself is testable: a test that only exercises\n * `createClientOnlyStubPlugin` in isolation stays green if the plugin is dropped from this\n * list, which would silently reintroduce #4623.\n */\nexport function createCliBundlePlugins(appRoot: string): import('esbuild').Plugin[] {\n // Plugin to resolve the @/ alias the way the app tsconfig maps it:\n // `@/.mercato/*` to the app root, every other `@/*` to the app's src/ directory.\n const aliasPlugin: import('esbuild').Plugin = {\n name: 'alias-resolver',\n setup(build) {\n build.onResolve({ filter: /^@\\// }, (args) => {\n const rest = args.path.slice('@/'.length)\n const bases = rest.startsWith('.mercato/')\n ? [path.join(appRoot, rest)]\n : [path.join(appRoot, 'src', rest), path.join(appRoot, rest)]\n for (const base of bases) {\n if (fs.existsSync(base) && fs.statSync(base).isFile()) {\n return { path: base }\n }\n for (const suffix of ['.ts', '.tsx', '/index.ts', '/index.tsx']) {\n if (fs.existsSync(base + suffix)) {\n return { path: base + suffix }\n }\n }\n }\n // Nothing matched \u2014 hand esbuild the literal mapping so it reports the\n // missing file against the path the app author actually wrote.\n return { path: path.join(appRoot, rest) }\n })\n },\n }\n\n // Plugin to mark non-JSON package imports as external\n const externalNonJsonPlugin: import('esbuild').Plugin = {\n name: 'external-non-json',\n setup(build) {\n // Mark all package imports as external EXCEPT JSON files\n // Filter matches paths that don't start with . or / (package imports like @open-mercato/shared)\n build.onResolve({ filter: /^[^./]/ }, (args) => {\n // Skip Windows absolute paths (e.g., C:\\...) - they're local files, not packages\n if (/^[a-zA-Z]:/.test(args.path)) {\n return null // Let esbuild handle it\n }\n // If it's a JSON file, let esbuild bundle it\n if (args.path.endsWith('.json')) {\n return null // Let esbuild handle it\n }\n // Otherwise mark as external\n return { path: args.path, external: true }\n })\n },\n }\n\n return [createClientOnlyStubPlugin(), aliasPlugin, externalNonJsonPlugin]\n}\n\nconst DYNAMIC_LOADER_CACHE_VERSION = 4\n\ntype DynamicLoaderCacheMetadata = {\n version: number\n inputHash: string\n outputHash: string\n dependencies: Record<string, string>\n}\n\nfunction cacheMetadataPath(jsPath: string): string {\n return `${jsPath}.cache.json`\n}\n\nfunction contentHash(content: Buffer | string): string {\n return crypto.createHash('sha256').update(content).digest('hex')\n}\n\nfunction parseJsonConfig(content: string): unknown {\n let normalized = ''\n let inString = false\n let escaped = false\n\n for (let index = 0; index < content.length; index += 1) {\n const character = content[index]\n const nextCharacter = content[index + 1]\n\n if (inString) {\n normalized += character\n if (escaped) {\n escaped = false\n } else if (character === '\\\\') {\n escaped = true\n } else if (character === '\"') {\n inString = false\n }\n continue\n }\n\n if (character === '\"') {\n inString = true\n normalized += character\n continue\n }\n\n if (character === '/' && nextCharacter === '/') {\n while (index < content.length && content[index] !== '\\n') index += 1\n normalized += '\\n'\n continue\n }\n\n if (character === '/' && nextCharacter === '*') {\n index += 2\n while (index < content.length && !(content[index] === '*' && content[index + 1] === '/')) {\n index += 1\n }\n index += 1\n continue\n }\n\n if (character === ',') {\n let lookahead = index + 1\n while (lookahead < content.length && /\\s/.test(content[lookahead])) lookahead += 1\n if (content[lookahead] === '}' || content[lookahead] === ']') continue\n }\n\n normalized += character\n }\n\n return JSON.parse(normalized)\n}\n\nfunction resolveExistingConfigPath(candidate: string): string | null {\n for (const configPath of [candidate, `${candidate}.json`, path.join(candidate, 'tsconfig.json')]) {\n if (fs.existsSync(configPath) && fs.statSync(configPath).isFile()) return configPath\n }\n return null\n}\n\nfunction resolvePackageConfig(configPath: string, reference: string): string | null {\n try {\n const resolved = createRequire(pathToFileURL(configPath)).resolve(reference)\n return path.extname(resolved) === '.json' ? resolved : null\n } catch {\n return null\n }\n}\n\nfunction resolveExtendedConfig(configPath: string, reference: string): string {\n if (path.isAbsolute(reference) || reference.startsWith('.')) {\n const resolved = resolveExistingConfigPath(path.resolve(path.dirname(configPath), reference))\n if (resolved) return resolved\n } else {\n for (const packageReference of [reference, `${reference}/tsconfig.json`]) {\n const resolved = resolvePackageConfig(configPath, packageReference)\n if (resolved) return resolved\n }\n }\n\n throw new Error(`[internal] TypeScript config extends target not found: ${reference}`)\n}\n\nfunction collectTsconfigPaths(entryPath: string, visited: Set<string> = new Set()): string[] {\n const configPath = path.resolve(entryPath)\n if (visited.has(configPath)) return []\n visited.add(configPath)\n\n const parsed = parseJsonConfig(fs.readFileSync(configPath, 'utf8'))\n if (typeof parsed !== 'object' || parsed === null || !('extends' in parsed)) return [configPath]\n\n const extendsValue = parsed.extends\n const references = typeof extendsValue === 'string'\n ? [extendsValue]\n : Array.isArray(extendsValue) && extendsValue.every((value) => typeof value === 'string')\n ? extendsValue\n : []\n\n return [\n ...references.flatMap((reference) => collectTsconfigPaths(\n resolveExtendedConfig(configPath, reference),\n visited,\n )),\n configPath,\n ]\n}\n\nfunction hashFilesRelativeTo(appRoot: string, filePaths: string[]): Record<string, string> {\n return Object.fromEntries(filePaths.map((filePath) => [\n path.relative(appRoot, filePath).split(path.sep).join('/'),\n contentHash(fs.readFileSync(filePath)),\n ]))\n}\n\nfunction cacheInputHash(tsPath: string, appRoot: string, tsconfigPaths: string[]): string {\n const hash = crypto.createHash('sha256')\n hash.update(JSON.stringify({\n version: DYNAMIC_LOADER_CACHE_VERSION,\n sourceHash: contentHash(fs.readFileSync(tsPath)),\n tsconfigHashes: hashFilesRelativeTo(appRoot, tsconfigPaths),\n }))\n return hash.digest('hex')\n}\n\nfunction dependenciesAreValid(appRoot: string, dependencies: Record<string, string>): boolean {\n return Object.entries(dependencies).every(([relativePath, expectedHash]) => {\n const dependencyPath = path.resolve(appRoot, relativePath)\n return fs.existsSync(dependencyPath)\n && contentHash(fs.readFileSync(dependencyPath)) === expectedHash\n })\n}\n\nfunction collectDependencyHashes(\n appRoot: string,\n inputs: Record<string, unknown>,\n): Record<string, string> {\n return Object.fromEntries(\n Object.keys(inputs)\n .filter((inputPath) => !inputPath.startsWith(`${CLIENT_ONLY_STUB_NAMESPACE}:`))\n .map((inputPath) => {\n const absolutePath = path.isAbsolute(inputPath)\n ? inputPath\n : path.resolve(appRoot, inputPath)\n const relativePath = path.relative(appRoot, absolutePath).split(path.sep).join('/')\n return [relativePath, contentHash(fs.readFileSync(absolutePath))]\n })\n .sort(([left], [right]) => left.localeCompare(right)),\n )\n}\n\nfunction readCacheMetadata(metadataPath: string): DynamicLoaderCacheMetadata | null {\n try {\n const parsed: unknown = JSON.parse(fs.readFileSync(metadataPath, 'utf8'))\n if (\n typeof parsed === 'object'\n && parsed !== null\n && 'version' in parsed\n && parsed.version === DYNAMIC_LOADER_CACHE_VERSION\n && 'inputHash' in parsed\n && typeof parsed.inputHash === 'string'\n && 'outputHash' in parsed\n && typeof parsed.outputHash === 'string'\n && 'dependencies' in parsed\n && typeof parsed.dependencies === 'object'\n && parsed.dependencies !== null\n && Object.values(parsed.dependencies).every((hash) => typeof hash === 'string')\n ) {\n return {\n version: parsed.version,\n inputHash: parsed.inputHash,\n outputHash: parsed.outputHash,\n dependencies: parsed.dependencies as Record<string, string>,\n }\n }\n } catch {\n return null\n }\n return null\n}\n\nfunction cacheIsValid(\n appRoot: string,\n jsPath: string,\n metadataPath: string,\n expectedInputHash: string,\n): boolean {\n if (!fs.existsSync(jsPath)) return false\n const metadata = readCacheMetadata(metadataPath)\n if (!metadata || metadata.inputHash !== expectedInputHash) return false\n return contentHash(fs.readFileSync(jsPath)) === metadata.outputHash\n && dependenciesAreValid(appRoot, metadata.dependencies)\n}\n\n/**\n * Options for `compileAndImport`.\n *\n * Both paths default to the generated-registry layout (`<appRoot>/.mercato/generated/<file>.ts`\n * compiled to a `.mjs` sibling). Sources that live elsewhere in the app \u2014 `src/di.ts` \u2014 MUST pass\n * both explicitly: the default app root is derived by walking three directories up from the source,\n * which only holds inside `.mercato/generated`.\n */\ntype CompileAndImportOptions = {\n appRoot?: string\n outFile?: string\n allowRecovery?: boolean\n}\n\n/**\n * Options for `compileAppSourceFile`.\n *\n * `appRoot` anchors the tsconfig, the `@/` alias resolution and the dependency\n * cache; `outFile` is the absolute path of the artifact to write. `format`\n * selects the module system of that artifact \u2014 `'cjs'` exists for the Jest\n * runtime, which cannot `import()` an ESM sibling.\n */\nexport type CompileAppSourceOptions = {\n appRoot: string\n outFile: string\n format?: 'esm' | 'cjs'\n}\n\n/**\n * Compile one app-owned TypeScript source and its relative import graph into a\n * single JavaScript artifact, leaving every package import external.\n *\n * This is the only supported way to load app source (`apps/<app>/src/**`,\n * `.mercato/generated/**`) from a plain Node process. Those files are never\n * compiled to `dist`, and Node's own type stripping cannot load them: it\n * requires explicit file extensions on relative specifiers and rejects the\n * decorator and enum syntax the entities and DI files use.\n *\n * The artifact is cached against the content of the entry, its whole bundled\n * dependency graph, and the tsconfig chain, so an edit anywhere in the graph\n * invalidates it.\n *\n * The build runs inside the shared esbuild lifecycle. Callers outside a\n * bootstrap load \u2014 the generated-registry loader compiling an `@app` module \u2014\n * would otherwise hold a build on a service another scope is entitled to\n * `stop()`, and would leave the helper process running afterwards. Nesting is\n * safe: the scope only releases the service when the last participant exits.\n */\nexport async function compileAppSourceFile(\n tsPath: string,\n options: CompileAppSourceOptions,\n): Promise<string> {\n return withEsbuildLifecycle(() => compileAppSourceFileWithActiveEsbuild(tsPath, options))\n}\n\nasync function compileAppSourceFileWithActiveEsbuild(\n tsPath: string,\n options: CompileAppSourceOptions,\n): Promise<string> {\n const { appRoot, outFile } = options\n const format = options.format ?? 'esm'\n const appTsconfig = path.join(appRoot, 'tsconfig.json')\n const metadataPath = cacheMetadataPath(outFile)\n\n const tsExists = fs.existsSync(tsPath)\n const tsconfigExists = fs.existsSync(appTsconfig)\n\n if (!tsExists) {\n throw new GeneratedFileNotFoundError(tsPath)\n }\n if (!tsconfigExists) {\n throw new Error(`App TypeScript config not found: ${appTsconfig}`)\n }\n\n const tsconfigPaths = collectTsconfigPaths(appTsconfig)\n const expectedInputHash = cacheInputHash(tsPath, appRoot, tsconfigPaths)\n\n if (cacheIsValid(appRoot, outFile, metadataPath, expectedInputHash)) {\n return outFile\n }\n\n fs.mkdirSync(path.dirname(outFile), { recursive: true })\n // Dynamically import esbuild only when needed\n const esbuild = await getEsbuildRuntime()\n\n // Use esbuild.build with bundling to handle JSON imports\n const result = await esbuild.build({\n entryPoints: [tsPath],\n outfile: outFile,\n absWorkingDir: appRoot,\n bundle: true,\n metafile: true,\n format,\n platform: 'node',\n target: 'node18',\n tsconfig: appTsconfig,\n plugins: createCliBundlePlugins(appRoot),\n // Allow JSON imports\n loader: { '.json': 'json' },\n })\n const metadata: DynamicLoaderCacheMetadata = {\n version: DYNAMIC_LOADER_CACHE_VERSION,\n inputHash: expectedInputHash,\n outputHash: contentHash(fs.readFileSync(outFile)),\n dependencies: {\n ...collectDependencyHashes(appRoot, result.metafile.inputs),\n ...hashFilesRelativeTo(appRoot, tsconfigPaths),\n },\n }\n fs.writeFileSync(metadataPath, JSON.stringify(metadata))\n\n return outFile\n}\n\n/**\n * Compile a TypeScript file to JavaScript using esbuild bundler.\n * This bundles the file and all its dependencies, handling JSON imports properly.\n * The compiled file is written next to the source file with a .mjs extension unless\n * `outFile` says otherwise.\n */\nasync function compileAndImport(\n tsPath: string,\n options: CompileAndImportOptions = {},\n): Promise<Record<string, unknown>> {\n const allowRecovery = options.allowRecovery ?? true\n const jsPath = options.outFile ?? tsPath.replace(/\\.ts$/, '.mjs')\n const appRoot = options.appRoot ?? path.dirname(path.dirname(path.dirname(tsPath)))\n\n await compileAppSourceFile(tsPath, { appRoot, outFile: jsPath })\n\n // Import the compiled JavaScript\n try {\n const outputHash = contentHash(fs.readFileSync(jsPath))\n const fileUrl = `${pathToFileURL(jsPath).href}?cache=${outputHash}`\n return await import(fileUrl)\n } catch (error) {\n if (!allowRecovery) {\n throw error\n }\n\n const recovered = recoverMikroOrmV7GeneratedCacheFromImportError(appRoot, error)\n if (!recovered.applied) {\n throw error\n }\n\n return compileAndImport(tsPath, { ...options, allowRecovery: false })\n }\n}\n\n\n/**\n * Load a generated registry that older apps may not have generated yet.\n *\n * An absent source file is the supported compatibility case and resolves to\n * `fallback` quietly. Any other failure \u2014 a compile error, a broken import, a\n * runtime throw at module scope \u2014 still resolves to `fallback` so bootstrap\n * keeps working, but is reported at error level: a registry that silently\n * degrades to nothing is exactly how command interceptors stopped applying in\n * worker/CLI processes (#4327, #4491).\n */\nasync function loadOptionalGeneratedModule(\n tsPath: string,\n fallback: Record<string, unknown>,\n): Promise<Record<string, unknown>> {\n try {\n return await compileAndImport(tsPath)\n } catch (error) {\n if (error instanceof GeneratedFileNotFoundError) {\n logger.debug('Optional generated registry not present, using empty fallback', {\n file: path.basename(tsPath),\n })\n return fallback\n }\n\n logger.error('Failed to load generated registry, continuing without its entries', {\n file: path.basename(tsPath),\n filePath: tsPath,\n err: error,\n })\n return fallback\n }\n}\n\nfunction resolveAppRootOrThrow(appRoot?: string): AppRoot {\n const resolved: AppRoot | null = appRoot\n ? {\n generatedDir: path.join(appRoot, '.mercato', 'generated'),\n appDir: appRoot,\n mercatoDir: path.join(appRoot, '.mercato'),\n }\n : findAppRoot()\n\n if (!resolved) {\n throw new Error(\n 'Could not find app root with .mercato/generated directory. ' +\n 'Make sure you run this command from within a Next.js app directory, ' +\n 'or run \"yarn mercato generate\" first to create the generated files.',\n )\n }\n\n return resolved\n}\n\n/**\n * Load the app-level DI registrar (`src/di.ts`) for the dynamic bootstrap path.\n *\n * The Next.js runtime imports `@/di` statically from its own `src/bootstrap.ts` and hands the\n * registrar to `createBootstrap`. Worker, scheduler and CLI processes bootstrap through\n * `bootstrapFromAppRoot` instead, where the `@/` alias does not exist \u2014 so without this the app's\n * DI registrations silently never ran there, and every request container paid a failed\n * `import('@/di')` resolution (the compatibility fallback in `lib/di/container.ts`).\n *\n * An absent `src/di.ts` is the supported case and resolves to `null` quietly. A file that exists\n * but cannot be compiled, imported, or does not export `register` is reported at error level and\n * still resolves to `null`, so a broken app DI module degrades the same way a broken generated\n * registry does (#4327, #4491) instead of taking the whole process down.\n */\nasync function loadAppDiRegistrar(appDir: string): Promise<AppDiRegistrar | null> {\n const tsPath = path.join(appDir, 'src', 'di.ts')\n if (!fs.existsSync(tsPath)) {\n logger.debug('App-level DI module not present, skipping its registrations', { filePath: tsPath })\n return null\n }\n\n try {\n const appDiModule = await compileAndImport(tsPath, {\n appRoot: appDir,\n outFile: path.join(appDir, '.mercato', 'generated', 'app-di.compiled.mjs'),\n })\n const register = appDiModule.register\n if (typeof register !== 'function') {\n logger.error('App-level DI module exports no register(); its registrations are skipped', {\n filePath: tsPath,\n })\n return null\n }\n return register as AppDiRegistrar\n } catch (error) {\n logger.error('Failed to load the app-level DI module; its registrations are skipped', {\n filePath: tsPath,\n err: error,\n })\n return null\n }\n}\n\n/**\n * Dynamically load bootstrap data from a resolved app directory.\n *\n * IMPORTANT: This only works in unbundled contexts (CLI, tsx).\n * Do NOT use this in Next.js bundled code - use static imports instead.\n *\n * For CLI context, we skip loading modules.generated.ts which has Next.js dependencies.\n * CLI commands are discovered separately via the CLI module system.\n *\n * @param appRoot - Optional explicit app root path. If not provided, will search from cwd.\n * @returns The loaded bootstrap data\n * @throws Error if app root cannot be found or generated files are missing\n */\nasync function loadBootstrapDataWithActiveEsbuild(appRoot?: string): Promise<BootstrapData> {\n const resolved = resolveAppRootOrThrow(appRoot)\n\n const { generatedDir } = resolved\n\n ensureMikroOrmV7GeneratedCacheCompatibility(resolved.appDir)\n\n // IMPORTANT: Load entity IDs FIRST and register them before loading modules.\n // This is because modules (e.g., ce.ts files) use E.xxx.xxx at module scope,\n // and they need entity IDs to be available when they're imported.\n const entityIdsModule = await compileAndImport(path.join(generatedDir, 'entities.ids.generated.ts'))\n registerEntityIds(entityIdsModule.E as BootstrapData['entityIds'])\n\n // Now load the rest of the generated files.\n // modules.cli.generated.ts excludes Next.js-dependent code (routes, APIs, widgets)\n const [\n modulesModule,\n entitiesModule,\n diModule,\n searchModule,\n commandLoadersModule,\n commandInterceptorsModule,\n workflowsModule,\n ] = await Promise.all([\n compileAndImport(path.join(generatedDir, 'modules.cli.generated.ts')),\n compileAndImport(path.join(generatedDir, 'entities.generated.ts')),\n compileAndImport(path.join(generatedDir, 'di.generated.ts')),\n loadOptionalGeneratedModule(path.join(generatedDir, 'search.generated.ts'), { searchModuleConfigs: [] }),\n loadOptionalGeneratedModule(path.join(generatedDir, 'command-loaders.generated.ts'), { commandLoaderEntries: [] }),\n loadOptionalGeneratedModule(path.join(generatedDir, 'command-interceptors.generated.ts'), {\n commandInterceptorEntries: [],\n }),\n loadOptionalGeneratedModule(path.join(generatedDir, 'workflows.generated.ts'), { allCodeWorkflows: [] }),\n ])\n\n return {\n modules: modulesModule.modules as BootstrapData['modules'],\n entities: entitiesModule.entities as BootstrapData['entities'],\n diRegistrars: diModule.diRegistrars as BootstrapData['diRegistrars'],\n entityIds: entityIdsModule.E as BootstrapData['entityIds'],\n // Search configs are needed by workers for indexing\n searchModuleConfigs: (searchModule.searchModuleConfigs ?? []) as BootstrapData['searchModuleConfigs'],\n commandLoaderEntries: (commandLoadersModule.commandLoaderEntries ?? []) as BootstrapData['commandLoaderEntries'],\n // Command interceptors must apply in worker/CLI processes too \u2014 the\n // interceptor registry is per-process, so relying on the Next.js runtime's\n // registration silently no-ops every interceptor for queued/CLI commands\n // (#4327).\n commandInterceptorEntries: (commandInterceptorsModule.commandInterceptorEntries ??\n []) as BootstrapData['commandInterceptorEntries'],\n // Code workflow definitions are needed by workers to resume code-defined instances\n codeWorkflows: (workflowsModule.allCodeWorkflows ?? []) as BootstrapData['codeWorkflows'],\n // Empty UI-related data - not needed for CLI\n dashboardWidgetEntries: [],\n injectionWidgetEntries: [],\n injectionTables: [],\n interceptorEntries: [],\n componentOverrideEntries: [],\n }\n}\n\nexport async function loadBootstrapData(appRoot?: string): Promise<BootstrapData> {\n return withEsbuildLifecycle(() => loadBootstrapDataWithActiveEsbuild(appRoot))\n}\n\n/**\n * Create and execute bootstrap in CLI context.\n *\n * This is a convenience function that finds the app root, loads the generated\n * data dynamically, and runs bootstrap. Use this in CLI entry points.\n *\n * Returns the loaded bootstrap data so the CLI can register modules directly\n * (avoids module resolution issues when importing @open-mercato/cli/mercato).\n *\n * @param appRoot - Optional explicit app root path\n * @returns The loaded bootstrap data (modules, entities, etc.)\n */\nexport async function bootstrapFromAppRoot(appRoot?: string): Promise<BootstrapData> {\n const { createBootstrap, waitForAsyncRegistration } = await import('./factory.js')\n const resolved = resolveAppRootOrThrow(appRoot)\n // Both loads compile through esbuild, so they share one lifecycle scope: without it\n // `loadBootstrapData` releases the esbuild helper process and `loadAppDiRegistrar`\n // silently starts a second one that nothing ever stops.\n const { data, appDiRegistrar } = await withEsbuildLifecycle(async () => ({\n data: await loadBootstrapData(resolved.appDir),\n appDiRegistrar: await loadAppDiRegistrar(resolved.appDir),\n }))\n const bootstrap = createBootstrap(data, appDiRegistrar ? { appDiRegistrar } : {})\n bootstrap()\n // In CLI context, wait for async registrations (UI widgets, search configs, etc.)\n await waitForAsyncRegistration()\n\n return data\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -148,14 +148,15 @@ function buildExportFromColumns(items, columnsConfig) {
148
148
  rows
149
149
  };
150
150
  }
151
- function buildExportFromCsv(items, csv) {
151
+ function buildExportFromCsv(items, csv, query, ctx) {
152
152
  const used = /* @__PURE__ */ new Set();
153
- const columns = csv.headers.map((header, idx) => ({
153
+ const resolvedHeaders = typeof csv.headers === "function" ? csv.headers(query, ctx) : csv.headers;
154
+ const columns = resolvedHeaders.map((header, idx) => ({
154
155
  field: sanitizeFieldName(header || `column_${idx + 1}`, used, idx),
155
156
  header: header || `Column ${idx + 1}`
156
157
  }));
157
158
  const rows = items.map((item) => {
158
- const values = csv.row(item) || [];
159
+ const values = csv.row(item, ctx) || [];
159
160
  const row = {};
160
161
  columns.forEach((column, idx) => {
161
162
  row[column.field] = values[idx];
@@ -176,12 +177,12 @@ function buildDefaultExport(items) {
176
177
  rows
177
178
  };
178
179
  }
179
- function prepareExportData(items, list) {
180
+ function prepareExportData(items, list, query, ctx) {
180
181
  if (list.export?.columns && list.export.columns.length > 0) {
181
182
  return buildExportFromColumns(items, list.export.columns);
182
183
  }
183
184
  if (list.csv) {
184
- return buildExportFromCsv(items, list.csv);
185
+ return buildExportFromCsv(items, list.csv, query, ctx);
185
186
  }
186
187
  const prepared = buildDefaultExport(items);
187
188
  return {
@@ -1323,7 +1324,7 @@ function makeCrudRoute(opts) {
1323
1324
  nextPage += 1;
1324
1325
  }
1325
1326
  }
1326
- const prepared = exportFullRequested ? { columns: ensureColumns(exportItems), rows: exportItems } : prepareExportData(exportItems, opts.list);
1327
+ const prepared = exportFullRequested ? { columns: ensureColumns(exportItems), rows: exportItems } : prepareExportData(exportItems, opts.list, validated, ctx);
1327
1328
  const fallbackBase = `${opts.events?.entity || resourceKind || "list"}${exportFullRequested ? "_full" : ""}`;
1328
1329
  const filename = finalizeExportFilename(opts.list, requestedExport, fallbackBase);
1329
1330
  const serialized = serializeExport(prepared, requestedExport);
@@ -1507,7 +1508,7 @@ function makeCrudRoute(opts) {
1507
1508
  profiler.mark("access_logged", accessLogResult);
1508
1509
  if (exportRequested && requestedExport) {
1509
1510
  const exportItems = exportFullRequested ? list.map(normalizeFullRecordForExport) : list;
1510
- const prepared = exportFullRequested ? { columns: ensureColumns(exportItems), rows: exportItems } : prepareExportData(exportItems, opts.list);
1511
+ const prepared = exportFullRequested ? { columns: ensureColumns(exportItems), rows: exportItems } : prepareExportData(exportItems, opts.list, validated, ctx);
1511
1512
  const fallbackBase = `${opts.events?.entity || resourceKind || "list"}${exportFullRequested ? "_full" : ""}`;
1512
1513
  const filename = finalizeExportFilename(opts.list, requestedExport, fallbackBase);
1513
1514
  const serialized = serializeExport(prepared, requestedExport);