@murumets-ee/create 0.1.18 → 0.1.20

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/cli.mjs CHANGED
@@ -15,9 +15,8 @@ export const allEntities = [
15
15
  Ticket, TicketMessage, TicketAttachment, Department, TicketTag,
16
16
  ]
17
17
 
18
- /** Taxonomy entities keyed by name */
18
+ /** Taxonomy entities keyed by name (only defineTaxonomy entities) */
19
19
  export const taxonomyVocabularies = {
20
- category: Category,
21
20
  department: Department,
22
21
  ticket_tag: TicketTag,
23
22
  }
@@ -241,7 +240,7 @@ import { cookies, headers } from 'next/headers'
241
240
  import { redirect } from 'next/navigation'
242
241
  import { Suspense } from 'react'
243
242
  import { allEntities } from '@/lib/admin-config'
244
- import { auth } from '@/lib/auth'
243
+ import { getAuthInstance } from '@/lib/auth'
245
244
  import { AdminLayout } from '../../admin-layout'
246
245
  import { ThemeToggle } from '../../theme-toggle'
247
246
 
@@ -252,6 +251,7 @@ async function DynamicShell({
252
251
  children: React.ReactNode
253
252
  interfaceLocale: string
254
253
  }) {
254
+ const auth = await getAuthInstance()
255
255
  const h = await headers()
256
256
  const session = await auth.api.getSession({ headers: h })
257
257
  if (!session?.user) {
@@ -294,7 +294,7 @@ export default async function ShellLayout({
294
294
  }
295
295
  `),await h(r(e,`app/[locale]/(shell)/admin/layout.tsx`),`import { headers } from 'next/headers'
296
296
  import { redirect } from 'next/navigation'
297
- import { auth } from '@/lib/auth'
297
+ import { getAuthInstance } from '@/lib/auth'
298
298
 
299
299
  const ALLOWED_ROLES = new Set(['admin', 'editor'])
300
300
 
@@ -306,6 +306,7 @@ export default async function AdminGuardLayout({
306
306
  params: Promise<{ locale: string }>
307
307
  }) {
308
308
  const { locale } = await params
309
+ const auth = await getAuthInstance()
309
310
  const h = await headers()
310
311
  const session = await auth.api.getSession({ headers: h })
311
312
 
@@ -438,7 +439,7 @@ import { setRequestLocale } from 'next-intl/server'
438
439
  import { GenericBlockEditor } from '@murumets-ee/admin-ui/content-editor'
439
440
  import { GenericEntityForm } from '@murumets-ee/admin-ui/entity-form'
440
441
  import { allEntities } from '@/lib/admin-config'
441
- import { auth } from '@/lib/auth'
442
+ import { getAuthInstance } from '@/lib/auth'
442
443
  import { loadRoles } from '@/lib/load-roles'
443
444
  import { withAdminContext } from '@/lib/with-admin-context'
444
445
 
@@ -485,6 +486,7 @@ export default async function EditEntityPage({ params }: EditEntityPageProps) {
485
486
  }
486
487
  }
487
488
 
489
+ const auth = await getAuthInstance()
488
490
  const session = await auth.api.getSession({ headers: await headers() })
489
491
  if (session?.user) {
490
492
  const role = (session.user as Record<string, unknown>).role as string | undefined
@@ -884,18 +886,16 @@ export default async function ImageStylesPage({ params }: { params: Promise<{ lo
884
886
  )
885
887
  }
886
888
  `),await h(r(e,`app/[locale]/(shell)/admin/users/page.tsx`),`import type { UsersInitialData } from '@murumets-ee/admin-ui/users'
887
- import { getAuth } from '@murumets-ee/auth'
888
889
  import { headers } from 'next/headers'
889
890
  import { setRequestLocale } from 'next-intl/server'
890
- import { getToolkitApp } from '@/lib/app'
891
+ import { getAuthInstance } from '@/lib/auth'
891
892
  import { UsersPage } from './users-page'
892
893
 
893
894
  export default async function UsersAdminPage({ params }: { params: Promise<{ locale: string }> }) {
894
895
  const { locale } = await params
895
896
  setRequestLocale(locale)
896
897
 
897
- await getToolkitApp()
898
- const auth = getAuth()
898
+ const auth = await getAuthInstance()
899
899
 
900
900
  const result = await auth.api.listUsers({
901
901
  headers: await headers(),
@@ -1053,7 +1053,7 @@ export default async function ActivityPage({ params }: { params: Promise<{ local
1053
1053
  import { headers } from 'next/headers'
1054
1054
  import { setRequestLocale } from 'next-intl/server'
1055
1055
  import { withAdminContext } from '@/lib/with-admin-context'
1056
- import { auth } from '@/lib/auth'
1056
+ import { getAuthInstance } from '@/lib/auth'
1057
1057
  import { TicketsInboxClient } from './tickets-inbox-client'
1058
1058
  import { fetchEntityList } from '@murumets-ee/admin-ui/server'
1059
1059
  import type {
@@ -1070,6 +1070,7 @@ export default async function TicketsPage({ params }: TicketsPageProps) {
1070
1070
  const { locale } = await params
1071
1071
  setRequestLocale(locale)
1072
1072
 
1073
+ const auth = await getAuthInstance()
1073
1074
  const h = await headers()
1074
1075
  const session = await auth.api.getSession({ headers: h })
1075
1076
  const currentUserId = session?.user?.id ?? ''
@@ -1238,9 +1239,8 @@ export function TicketBoardClient({
1238
1239
 
1239
1240
  import { getToolkitApp } from '@/lib/app'
1240
1241
 
1241
- await getToolkitApp()
1242
-
1243
1242
  export async function POST(req: Request): Promise<Response> {
1243
+ await getToolkitApp()
1244
1244
  const { handleInboundWebhook } = await import('@murumets-ee/ticketing')
1245
1245
  const { QueueClient } = await import('@murumets-ee/queue/client')
1246
1246
  const { getApp } = await import('@murumets-ee/core')
@@ -1258,9 +1258,10 @@ import { Ticket, TicketMessage, Department, TicketTag } from '@murumets-ee/ticke
1258
1258
  import { headers } from 'next/headers'
1259
1259
  import { Article, Category } from '@/entities'
1260
1260
  import { getToolkitApp } from '@/lib/app'
1261
- import { auth } from '@/lib/auth'
1261
+ import { getAuthInstance } from '@/lib/auth'
1262
1262
 
1263
1263
  async function requireAdmin() {
1264
+ const auth = await getAuthInstance()
1264
1265
  const session = await auth.api.getSession({ headers: await headers() })
1265
1266
  if (!session?.user) throw new Error('Unauthorized')
1266
1267
  const role = (session.user as Record<string, unknown>).role as string | undefined
@@ -1274,15 +1275,19 @@ export async function seedContent() {
1274
1275
 
1275
1276
  await requireAdmin()
1276
1277
  const app = await getToolkitApp()
1277
- const categories = createTaxonomyClient(Category)
1278
+ const categoryAdmin = new AdminClient({
1279
+ entity: Category,
1280
+ db: app.db.readWrite,
1281
+ logger: app.logger.child({ entity: 'category' }),
1282
+ })
1278
1283
  const articles = new AdminClient({
1279
1284
  entity: Article,
1280
1285
  db: app.db.readWrite,
1281
1286
  logger: app.logger.child({ entity: 'article' }),
1282
1287
  })
1283
1288
 
1284
- const techCat = await categories.create({ name: 'Technology', slug: 'technology', color: '#3B82F6' })
1285
- const newsCat = await categories.create({ name: 'News', slug: 'news', color: '#EF4444' })
1289
+ const techCat = await categoryAdmin.create({ name: 'Technology', slug: 'technology' })
1290
+ const newsCat = await categoryAdmin.create({ name: 'News', slug: 'news' })
1286
1291
 
1287
1292
  await articles.create({
1288
1293
  title: 'Getting Started with Lumi CMS',
@@ -1502,86 +1507,115 @@ import {
1502
1507
  taxonomyVocabularies,
1503
1508
  } from '@/lib/admin-config'
1504
1509
  import { getToolkitApp } from '@/lib/app'
1505
- import { auth } from '@/lib/auth'
1510
+ import { getAuthInstance } from '@/lib/auth'
1506
1511
  import { loadRoles } from '@/lib/load-roles'
1507
1512
  import { permissionSettings } from '@/settings/permissions'
1508
1513
  import { siteSettings } from '@/settings/site'
1509
1514
 
1510
- await getToolkitApp()
1511
-
1515
+ // Lazy init — no DB connection at import time (safe for next build)
1516
+ let _handler: ReturnType<typeof createAdminApiHandler> | null = null
1512
1517
  let _auditLogger: ReturnType<typeof createAuditLogger> | null = null
1513
1518
  let _checker: PermissionChecker | null = null
1514
1519
 
1515
- const routes = [
1516
- mediaRoutes(),
1517
- storageRoutes(),
1518
- settingsRoutes(siteSettings),
1519
- taxonomyRoutes(taxonomyVocabularies),
1520
- ticketingRoutes(),
1521
- logRoutes(() => new AuditLogClient(getApp().db.readWrite)),
1522
- permissionRoutes({
1523
- getStatements: () => buildResourceCatalog(allEntities, pluginResources),
1524
- loadRoles: async () => loadRoles(getApp()),
1525
- saveRoles: async (roles) => {
1526
- const app = getApp()
1527
- const client = createSettingsClient(permissionSettings, { app })
1528
- await client.set('roles', roles)
1529
- },
1530
- onSave: () => {
1531
- _checker = null
1532
- },
1533
- }),
1534
- ]
1520
+ async function getHandler() {
1521
+ if (_handler) return _handler
1535
1522
 
1536
- const handler = createAdminApiHandler({
1537
- authenticate: async (req) => {
1538
- const session = await auth.api.getSession({ headers: req.headers })
1539
- if (!session?.user) return null
1540
- const role = (session.user as Record<string, unknown>).role as string | undefined
1541
- return { id: session.user.id, role, name: session.user.name, email: session.user.email }
1542
- },
1543
- defaultLocale: 'en',
1544
- entities: crudEntities,
1545
- routes,
1546
- loadPermissions: async () => {
1547
- if (_checker) return _checker
1548
- const roles = await loadRoles(getApp())
1549
- _checker = buildPermissionChecker(roles)
1550
- return _checker
1551
- },
1552
- auditLogger: {
1553
- log: async (entry) => {
1554
- if (!_auditLogger) {
1523
+ await getToolkitApp()
1524
+
1525
+ const routes = [
1526
+ mediaRoutes(),
1527
+ storageRoutes(),
1528
+ settingsRoutes(siteSettings),
1529
+ taxonomyRoutes(taxonomyVocabularies),
1530
+ ticketingRoutes(),
1531
+ logRoutes(() => new AuditLogClient(getApp().db.readWrite)),
1532
+ permissionRoutes({
1533
+ getStatements: () => buildResourceCatalog(allEntities, pluginResources),
1534
+ loadRoles: async () => loadRoles(getApp()),
1535
+ saveRoles: async (roles) => {
1555
1536
  const app = getApp()
1556
- _auditLogger = createAuditLogger({
1557
- logger: createLogger({ name: 'audit' }),
1558
- dbWriter: createAuditDbWriter(app.db.readWrite),
1559
- })
1560
- }
1561
- return _auditLogger.log(entry)
1537
+ const client = createSettingsClient(permissionSettings, { app })
1538
+ await client.set('roles', roles)
1539
+ },
1540
+ onSave: () => {
1541
+ _checker = null
1542
+ },
1543
+ }),
1544
+ ]
1545
+
1546
+ _handler = createAdminApiHandler({
1547
+ authenticate: async (req) => {
1548
+ const auth = await getAuthInstance()
1549
+ const session = await auth.api.getSession({ headers: req.headers })
1550
+ if (!session?.user) return null
1551
+ const role = (session.user as Record<string, unknown>).role as string | undefined
1552
+ return { id: session.user.id, role, name: session.user.name, email: session.user.email }
1562
1553
  },
1563
- },
1564
- contentClientFactory: (entity) =>
1565
- new ContentClient({ entity, db: getApp().db.readWrite }),
1566
- lockServiceFactory: () =>
1567
- new LockService({ db: getApp().db.readWrite }),
1568
- })
1554
+ defaultLocale: 'en',
1555
+ entities: crudEntities,
1556
+ routes,
1557
+ loadPermissions: async () => {
1558
+ if (_checker) return _checker
1559
+ const roles = await loadRoles(getApp())
1560
+ _checker = buildPermissionChecker(roles)
1561
+ return _checker
1562
+ },
1563
+ auditLogger: {
1564
+ log: async (entry) => {
1565
+ if (!_auditLogger) {
1566
+ const app = getApp()
1567
+ _auditLogger = createAuditLogger({
1568
+ logger: createLogger({ name: 'audit' }),
1569
+ dbWriter: createAuditDbWriter(app.db.readWrite),
1570
+ })
1571
+ }
1572
+ return _auditLogger.log(entry)
1573
+ },
1574
+ },
1575
+ contentClientFactory: (entity) =>
1576
+ new ContentClient({ entity, db: getApp().db.readWrite }),
1577
+ lockServiceFactory: () =>
1578
+ new LockService({ db: getApp().db.readWrite }),
1579
+ })
1569
1580
 
1570
- export const { GET, POST, PATCH, DELETE } = handler
1581
+ return _handler
1582
+ }
1583
+
1584
+ export async function GET(req: Request) { return (await getHandler()).GET(req) }
1585
+ export async function POST(req: Request) { return (await getHandler()).POST(req) }
1586
+ export async function PATCH(req: Request) { return (await getHandler()).PATCH(req) }
1587
+ export async function DELETE(req: Request) { return (await getHandler()).DELETE(req) }
1571
1588
  `)}async function x(e,t){await h(r(e,`lib/auth.ts`),`import { getAuth } from '@murumets-ee/auth'
1572
1589
  import { getToolkitApp } from './app'
1573
1590
 
1574
- await getToolkitApp()
1575
-
1576
- export const auth = getAuth()
1591
+ /** Lazily initialize and return the auth instance. Safe for Docker builds. */
1592
+ export async function getAuthInstance() {
1593
+ await getToolkitApp()
1594
+ return getAuth()
1595
+ }
1577
1596
  `),await h(r(e,`lib/auth-client.ts`),`import { createClient } from '@murumets-ee/auth/client'
1578
1597
 
1579
1598
  export const authClient = createClient()
1580
1599
  `),await h(r(e,`app/api/auth/[...all]/route.ts`),`import { toNextJsHandler } from 'better-auth/next-js'
1581
- import { auth } from '@/lib/auth'
1600
+ import { getAuthInstance } from '@/lib/auth'
1582
1601
 
1583
- const { GET, POST } = toNextJsHandler(auth)
1584
- export { GET, POST }
1602
+ let _handler: ReturnType<typeof toNextJsHandler> | null = null
1603
+
1604
+ async function handler() {
1605
+ if (!_handler) {
1606
+ const auth = await getAuthInstance()
1607
+ _handler = toNextJsHandler(auth)
1608
+ }
1609
+ return _handler
1610
+ }
1611
+
1612
+ export async function GET(req: Request) {
1613
+ return (await handler()).GET(req)
1614
+ }
1615
+
1616
+ export async function POST(req: Request) {
1617
+ return (await handler()).POST(req)
1618
+ }
1585
1619
  `),await h(r(e,`app/[locale]/auth/layout.tsx`),`import { AuthProviders } from './providers'
1586
1620
  import type { ReactNode } from 'react'
1587
1621
 
package/dist/index.mjs CHANGED
@@ -14,9 +14,8 @@ export const allEntities = [
14
14
  Ticket, TicketMessage, TicketAttachment, Department, TicketTag,
15
15
  ]
16
16
 
17
- /** Taxonomy entities keyed by name */
17
+ /** Taxonomy entities keyed by name (only defineTaxonomy entities) */
18
18
  export const taxonomyVocabularies = {
19
- category: Category,
20
19
  department: Department,
21
20
  ticket_tag: TicketTag,
22
21
  }
@@ -240,7 +239,7 @@ import { cookies, headers } from 'next/headers'
240
239
  import { redirect } from 'next/navigation'
241
240
  import { Suspense } from 'react'
242
241
  import { allEntities } from '@/lib/admin-config'
243
- import { auth } from '@/lib/auth'
242
+ import { getAuthInstance } from '@/lib/auth'
244
243
  import { AdminLayout } from '../../admin-layout'
245
244
  import { ThemeToggle } from '../../theme-toggle'
246
245
 
@@ -251,6 +250,7 @@ async function DynamicShell({
251
250
  children: React.ReactNode
252
251
  interfaceLocale: string
253
252
  }) {
253
+ const auth = await getAuthInstance()
254
254
  const h = await headers()
255
255
  const session = await auth.api.getSession({ headers: h })
256
256
  if (!session?.user) {
@@ -293,7 +293,7 @@ export default async function ShellLayout({
293
293
  }
294
294
  `),await n(a(e,`app/[locale]/(shell)/admin/layout.tsx`),`import { headers } from 'next/headers'
295
295
  import { redirect } from 'next/navigation'
296
- import { auth } from '@/lib/auth'
296
+ import { getAuthInstance } from '@/lib/auth'
297
297
 
298
298
  const ALLOWED_ROLES = new Set(['admin', 'editor'])
299
299
 
@@ -305,6 +305,7 @@ export default async function AdminGuardLayout({
305
305
  params: Promise<{ locale: string }>
306
306
  }) {
307
307
  const { locale } = await params
308
+ const auth = await getAuthInstance()
308
309
  const h = await headers()
309
310
  const session = await auth.api.getSession({ headers: h })
310
311
 
@@ -437,7 +438,7 @@ import { setRequestLocale } from 'next-intl/server'
437
438
  import { GenericBlockEditor } from '@murumets-ee/admin-ui/content-editor'
438
439
  import { GenericEntityForm } from '@murumets-ee/admin-ui/entity-form'
439
440
  import { allEntities } from '@/lib/admin-config'
440
- import { auth } from '@/lib/auth'
441
+ import { getAuthInstance } from '@/lib/auth'
441
442
  import { loadRoles } from '@/lib/load-roles'
442
443
  import { withAdminContext } from '@/lib/with-admin-context'
443
444
 
@@ -484,6 +485,7 @@ export default async function EditEntityPage({ params }: EditEntityPageProps) {
484
485
  }
485
486
  }
486
487
 
488
+ const auth = await getAuthInstance()
487
489
  const session = await auth.api.getSession({ headers: await headers() })
488
490
  if (session?.user) {
489
491
  const role = (session.user as Record<string, unknown>).role as string | undefined
@@ -883,18 +885,16 @@ export default async function ImageStylesPage({ params }: { params: Promise<{ lo
883
885
  )
884
886
  }
885
887
  `),await n(a(e,`app/[locale]/(shell)/admin/users/page.tsx`),`import type { UsersInitialData } from '@murumets-ee/admin-ui/users'
886
- import { getAuth } from '@murumets-ee/auth'
887
888
  import { headers } from 'next/headers'
888
889
  import { setRequestLocale } from 'next-intl/server'
889
- import { getToolkitApp } from '@/lib/app'
890
+ import { getAuthInstance } from '@/lib/auth'
890
891
  import { UsersPage } from './users-page'
891
892
 
892
893
  export default async function UsersAdminPage({ params }: { params: Promise<{ locale: string }> }) {
893
894
  const { locale } = await params
894
895
  setRequestLocale(locale)
895
896
 
896
- await getToolkitApp()
897
- const auth = getAuth()
897
+ const auth = await getAuthInstance()
898
898
 
899
899
  const result = await auth.api.listUsers({
900
900
  headers: await headers(),
@@ -1052,7 +1052,7 @@ export default async function ActivityPage({ params }: { params: Promise<{ local
1052
1052
  import { headers } from 'next/headers'
1053
1053
  import { setRequestLocale } from 'next-intl/server'
1054
1054
  import { withAdminContext } from '@/lib/with-admin-context'
1055
- import { auth } from '@/lib/auth'
1055
+ import { getAuthInstance } from '@/lib/auth'
1056
1056
  import { TicketsInboxClient } from './tickets-inbox-client'
1057
1057
  import { fetchEntityList } from '@murumets-ee/admin-ui/server'
1058
1058
  import type {
@@ -1069,6 +1069,7 @@ export default async function TicketsPage({ params }: TicketsPageProps) {
1069
1069
  const { locale } = await params
1070
1070
  setRequestLocale(locale)
1071
1071
 
1072
+ const auth = await getAuthInstance()
1072
1073
  const h = await headers()
1073
1074
  const session = await auth.api.getSession({ headers: h })
1074
1075
  const currentUserId = session?.user?.id ?? ''
@@ -1237,9 +1238,8 @@ export function TicketBoardClient({
1237
1238
 
1238
1239
  import { getToolkitApp } from '@/lib/app'
1239
1240
 
1240
- await getToolkitApp()
1241
-
1242
1241
  export async function POST(req: Request): Promise<Response> {
1242
+ await getToolkitApp()
1243
1243
  const { handleInboundWebhook } = await import('@murumets-ee/ticketing')
1244
1244
  const { QueueClient } = await import('@murumets-ee/queue/client')
1245
1245
  const { getApp } = await import('@murumets-ee/core')
@@ -1257,9 +1257,10 @@ import { Ticket, TicketMessage, Department, TicketTag } from '@murumets-ee/ticke
1257
1257
  import { headers } from 'next/headers'
1258
1258
  import { Article, Category } from '@/entities'
1259
1259
  import { getToolkitApp } from '@/lib/app'
1260
- import { auth } from '@/lib/auth'
1260
+ import { getAuthInstance } from '@/lib/auth'
1261
1261
 
1262
1262
  async function requireAdmin() {
1263
+ const auth = await getAuthInstance()
1263
1264
  const session = await auth.api.getSession({ headers: await headers() })
1264
1265
  if (!session?.user) throw new Error('Unauthorized')
1265
1266
  const role = (session.user as Record<string, unknown>).role as string | undefined
@@ -1273,15 +1274,19 @@ export async function seedContent() {
1273
1274
 
1274
1275
  await requireAdmin()
1275
1276
  const app = await getToolkitApp()
1276
- const categories = createTaxonomyClient(Category)
1277
+ const categoryAdmin = new AdminClient({
1278
+ entity: Category,
1279
+ db: app.db.readWrite,
1280
+ logger: app.logger.child({ entity: 'category' }),
1281
+ })
1277
1282
  const articles = new AdminClient({
1278
1283
  entity: Article,
1279
1284
  db: app.db.readWrite,
1280
1285
  logger: app.logger.child({ entity: 'article' }),
1281
1286
  })
1282
1287
 
1283
- const techCat = await categories.create({ name: 'Technology', slug: 'technology', color: '#3B82F6' })
1284
- const newsCat = await categories.create({ name: 'News', slug: 'news', color: '#EF4444' })
1288
+ const techCat = await categoryAdmin.create({ name: 'Technology', slug: 'technology' })
1289
+ const newsCat = await categoryAdmin.create({ name: 'News', slug: 'news' })
1285
1290
 
1286
1291
  await articles.create({
1287
1292
  title: 'Getting Started with Lumi CMS',
@@ -1501,86 +1506,115 @@ import {
1501
1506
  taxonomyVocabularies,
1502
1507
  } from '@/lib/admin-config'
1503
1508
  import { getToolkitApp } from '@/lib/app'
1504
- import { auth } from '@/lib/auth'
1509
+ import { getAuthInstance } from '@/lib/auth'
1505
1510
  import { loadRoles } from '@/lib/load-roles'
1506
1511
  import { permissionSettings } from '@/settings/permissions'
1507
1512
  import { siteSettings } from '@/settings/site'
1508
1513
 
1509
- await getToolkitApp()
1510
-
1514
+ // Lazy init — no DB connection at import time (safe for next build)
1515
+ let _handler: ReturnType<typeof createAdminApiHandler> | null = null
1511
1516
  let _auditLogger: ReturnType<typeof createAuditLogger> | null = null
1512
1517
  let _checker: PermissionChecker | null = null
1513
1518
 
1514
- const routes = [
1515
- mediaRoutes(),
1516
- storageRoutes(),
1517
- settingsRoutes(siteSettings),
1518
- taxonomyRoutes(taxonomyVocabularies),
1519
- ticketingRoutes(),
1520
- logRoutes(() => new AuditLogClient(getApp().db.readWrite)),
1521
- permissionRoutes({
1522
- getStatements: () => buildResourceCatalog(allEntities, pluginResources),
1523
- loadRoles: async () => loadRoles(getApp()),
1524
- saveRoles: async (roles) => {
1525
- const app = getApp()
1526
- const client = createSettingsClient(permissionSettings, { app })
1527
- await client.set('roles', roles)
1528
- },
1529
- onSave: () => {
1530
- _checker = null
1531
- },
1532
- }),
1533
- ]
1519
+ async function getHandler() {
1520
+ if (_handler) return _handler
1534
1521
 
1535
- const handler = createAdminApiHandler({
1536
- authenticate: async (req) => {
1537
- const session = await auth.api.getSession({ headers: req.headers })
1538
- if (!session?.user) return null
1539
- const role = (session.user as Record<string, unknown>).role as string | undefined
1540
- return { id: session.user.id, role, name: session.user.name, email: session.user.email }
1541
- },
1542
- defaultLocale: 'en',
1543
- entities: crudEntities,
1544
- routes,
1545
- loadPermissions: async () => {
1546
- if (_checker) return _checker
1547
- const roles = await loadRoles(getApp())
1548
- _checker = buildPermissionChecker(roles)
1549
- return _checker
1550
- },
1551
- auditLogger: {
1552
- log: async (entry) => {
1553
- if (!_auditLogger) {
1522
+ await getToolkitApp()
1523
+
1524
+ const routes = [
1525
+ mediaRoutes(),
1526
+ storageRoutes(),
1527
+ settingsRoutes(siteSettings),
1528
+ taxonomyRoutes(taxonomyVocabularies),
1529
+ ticketingRoutes(),
1530
+ logRoutes(() => new AuditLogClient(getApp().db.readWrite)),
1531
+ permissionRoutes({
1532
+ getStatements: () => buildResourceCatalog(allEntities, pluginResources),
1533
+ loadRoles: async () => loadRoles(getApp()),
1534
+ saveRoles: async (roles) => {
1554
1535
  const app = getApp()
1555
- _auditLogger = createAuditLogger({
1556
- logger: createLogger({ name: 'audit' }),
1557
- dbWriter: createAuditDbWriter(app.db.readWrite),
1558
- })
1559
- }
1560
- return _auditLogger.log(entry)
1536
+ const client = createSettingsClient(permissionSettings, { app })
1537
+ await client.set('roles', roles)
1538
+ },
1539
+ onSave: () => {
1540
+ _checker = null
1541
+ },
1542
+ }),
1543
+ ]
1544
+
1545
+ _handler = createAdminApiHandler({
1546
+ authenticate: async (req) => {
1547
+ const auth = await getAuthInstance()
1548
+ const session = await auth.api.getSession({ headers: req.headers })
1549
+ if (!session?.user) return null
1550
+ const role = (session.user as Record<string, unknown>).role as string | undefined
1551
+ return { id: session.user.id, role, name: session.user.name, email: session.user.email }
1561
1552
  },
1562
- },
1563
- contentClientFactory: (entity) =>
1564
- new ContentClient({ entity, db: getApp().db.readWrite }),
1565
- lockServiceFactory: () =>
1566
- new LockService({ db: getApp().db.readWrite }),
1567
- })
1553
+ defaultLocale: 'en',
1554
+ entities: crudEntities,
1555
+ routes,
1556
+ loadPermissions: async () => {
1557
+ if (_checker) return _checker
1558
+ const roles = await loadRoles(getApp())
1559
+ _checker = buildPermissionChecker(roles)
1560
+ return _checker
1561
+ },
1562
+ auditLogger: {
1563
+ log: async (entry) => {
1564
+ if (!_auditLogger) {
1565
+ const app = getApp()
1566
+ _auditLogger = createAuditLogger({
1567
+ logger: createLogger({ name: 'audit' }),
1568
+ dbWriter: createAuditDbWriter(app.db.readWrite),
1569
+ })
1570
+ }
1571
+ return _auditLogger.log(entry)
1572
+ },
1573
+ },
1574
+ contentClientFactory: (entity) =>
1575
+ new ContentClient({ entity, db: getApp().db.readWrite }),
1576
+ lockServiceFactory: () =>
1577
+ new LockService({ db: getApp().db.readWrite }),
1578
+ })
1568
1579
 
1569
- export const { GET, POST, PATCH, DELETE } = handler
1580
+ return _handler
1581
+ }
1582
+
1583
+ export async function GET(req: Request) { return (await getHandler()).GET(req) }
1584
+ export async function POST(req: Request) { return (await getHandler()).POST(req) }
1585
+ export async function PATCH(req: Request) { return (await getHandler()).PATCH(req) }
1586
+ export async function DELETE(req: Request) { return (await getHandler()).DELETE(req) }
1570
1587
  `)}async function c(e,t){await n(a(e,`lib/auth.ts`),`import { getAuth } from '@murumets-ee/auth'
1571
1588
  import { getToolkitApp } from './app'
1572
1589
 
1573
- await getToolkitApp()
1574
-
1575
- export const auth = getAuth()
1590
+ /** Lazily initialize and return the auth instance. Safe for Docker builds. */
1591
+ export async function getAuthInstance() {
1592
+ await getToolkitApp()
1593
+ return getAuth()
1594
+ }
1576
1595
  `),await n(a(e,`lib/auth-client.ts`),`import { createClient } from '@murumets-ee/auth/client'
1577
1596
 
1578
1597
  export const authClient = createClient()
1579
1598
  `),await n(a(e,`app/api/auth/[...all]/route.ts`),`import { toNextJsHandler } from 'better-auth/next-js'
1580
- import { auth } from '@/lib/auth'
1599
+ import { getAuthInstance } from '@/lib/auth'
1581
1600
 
1582
- const { GET, POST } = toNextJsHandler(auth)
1583
- export { GET, POST }
1601
+ let _handler: ReturnType<typeof toNextJsHandler> | null = null
1602
+
1603
+ async function handler() {
1604
+ if (!_handler) {
1605
+ const auth = await getAuthInstance()
1606
+ _handler = toNextJsHandler(auth)
1607
+ }
1608
+ return _handler
1609
+ }
1610
+
1611
+ export async function GET(req: Request) {
1612
+ return (await handler()).GET(req)
1613
+ }
1614
+
1615
+ export async function POST(req: Request) {
1616
+ return (await handler()).POST(req)
1617
+ }
1584
1618
  `),await n(a(e,`app/[locale]/auth/layout.tsx`),`import { AuthProviders } from './providers'
1585
1619
  import type { ReactNode } from 'react'
1586
1620