@sonicjs-cms/core 3.0.0-beta.17 → 3.0.0-beta.19

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.
Files changed (98) hide show
  1. package/dist/{chunk-C3KSTUEA.cjs → chunk-2DSRS3VA.cjs} +4 -2
  2. package/dist/chunk-2DSRS3VA.cjs.map +1 -0
  3. package/dist/{chunk-RQ6N3FTV.js → chunk-2XAQTPAE.js} +3 -2
  4. package/dist/chunk-2XAQTPAE.js.map +1 -0
  5. package/dist/{chunk-4BTBSXMR.cjs → chunk-36Z3AKX3.cjs} +3 -2
  6. package/dist/chunk-36Z3AKX3.cjs.map +1 -0
  7. package/dist/{chunk-PDC7DLOV.js → chunk-3TMTYJAJ.js} +7 -3
  8. package/dist/chunk-3TMTYJAJ.js.map +1 -0
  9. package/dist/{chunk-73KSHGOT.js → chunk-52DAVKDM.js} +3 -2
  10. package/dist/chunk-52DAVKDM.js.map +1 -0
  11. package/dist/{chunk-KXTGLSFY.js → chunk-64MTTVX2.js} +133 -67
  12. package/dist/chunk-64MTTVX2.js.map +1 -0
  13. package/dist/{chunk-3RNDJAZ5.cjs → chunk-EHTBXFTA.cjs} +4 -4
  14. package/dist/{chunk-3RNDJAZ5.cjs.map → chunk-EHTBXFTA.cjs.map} +1 -1
  15. package/dist/{chunk-KMCLNO4K.cjs → chunk-GMMCCIQO.cjs} +3 -3
  16. package/dist/{chunk-KMCLNO4K.cjs.map → chunk-GMMCCIQO.cjs.map} +1 -1
  17. package/dist/{chunk-OSMPF3PU.js → chunk-HUDG4GS6.js} +8 -7
  18. package/dist/chunk-HUDG4GS6.js.map +1 -0
  19. package/dist/{chunk-7YMMCIWY.cjs → chunk-IDMHRCZS.cjs} +3 -2
  20. package/dist/chunk-IDMHRCZS.cjs.map +1 -0
  21. package/dist/{chunk-NOBU34HS.cjs → chunk-JJ6HE4J4.cjs} +279 -273
  22. package/dist/chunk-JJ6HE4J4.cjs.map +1 -0
  23. package/dist/{chunk-JEQ7FLOD.cjs → chunk-KIGVVO6N.cjs} +16 -10
  24. package/dist/chunk-KIGVVO6N.cjs.map +1 -0
  25. package/dist/{chunk-YA4V4Y5U.js → chunk-L6IPQIWU.js} +4 -2
  26. package/dist/chunk-L6IPQIWU.js.map +1 -0
  27. package/dist/{chunk-CYDEM6SY.js → chunk-LGZHS6WW.js} +23 -17
  28. package/dist/chunk-LGZHS6WW.js.map +1 -0
  29. package/dist/{chunk-W36OZTJ5.cjs → chunk-LTZ5WYOK.cjs} +10 -6
  30. package/dist/chunk-LTZ5WYOK.cjs.map +1 -0
  31. package/dist/{chunk-KDRHGEUF.cjs → chunk-NZF3THNY.cjs} +3 -3
  32. package/dist/{chunk-KDRHGEUF.cjs.map → chunk-NZF3THNY.cjs.map} +1 -1
  33. package/dist/{chunk-RIFCRZYC.js → chunk-OJHJ4I34.js} +3 -3
  34. package/dist/{chunk-RIFCRZYC.js.map → chunk-OJHJ4I34.js.map} +1 -1
  35. package/dist/{chunk-Y34TG4TF.js → chunk-PMEV7CWP.js} +3 -3
  36. package/dist/{chunk-Y34TG4TF.js.map → chunk-PMEV7CWP.js.map} +1 -1
  37. package/dist/{chunk-IQZA2OY5.js → chunk-SOZUG52O.js} +3 -3
  38. package/dist/{chunk-IQZA2OY5.js.map → chunk-SOZUG52O.js.map} +1 -1
  39. package/dist/{chunk-ZHQP75SR.cjs → chunk-SYAUCKSD.cjs} +19 -18
  40. package/dist/chunk-SYAUCKSD.cjs.map +1 -0
  41. package/dist/{chunk-GCDZZNIN.js → chunk-UWUP2VMT.js} +16 -10
  42. package/dist/chunk-UWUP2VMT.js.map +1 -0
  43. package/dist/{chunk-MJZI3NHR.cjs → chunk-YS5S47VV.cjs} +139 -73
  44. package/dist/chunk-YS5S47VV.cjs.map +1 -0
  45. package/dist/config-6FB2BXMP.js +6 -0
  46. package/dist/{config-SM2UWSDN.js.map → config-6FB2BXMP.js.map} +1 -1
  47. package/dist/{config-YCRSU7ZP.cjs → config-OCH7S4WK.cjs} +5 -5
  48. package/dist/{config-YCRSU7ZP.cjs.map → config-OCH7S4WK.cjs.map} +1 -1
  49. package/dist/document-projection-4HG75S5S.js +4 -0
  50. package/dist/{document-projection-YYMC6I4U.js.map → document-projection-4HG75S5S.js.map} +1 -1
  51. package/dist/document-projection-JQHSTSFD.cjs +13 -0
  52. package/dist/{document-projection-TDWRJX3Z.cjs.map → document-projection-JQHSTSFD.cjs.map} +1 -1
  53. package/dist/index.cjs +327 -291
  54. package/dist/index.cjs.map +1 -1
  55. package/dist/index.js +56 -20
  56. package/dist/index.js.map +1 -1
  57. package/dist/middleware.cjs +35 -35
  58. package/dist/middleware.js +6 -6
  59. package/dist/migrations-HUR2YY4Q.js +4 -0
  60. package/dist/{migrations-7G6QBDSM.js.map → migrations-HUR2YY4Q.js.map} +1 -1
  61. package/dist/migrations-RYH2MGG4.cjs +13 -0
  62. package/dist/{migrations-QIRBSVJJ.cjs.map → migrations-RYH2MGG4.cjs.map} +1 -1
  63. package/dist/plugins.cjs +40 -40
  64. package/dist/plugins.js +3 -3
  65. package/dist/rbac-7QZ4JZ2E.cjs +14 -0
  66. package/dist/{rbac-ESTOCVT2.cjs.map → rbac-7QZ4JZ2E.cjs.map} +1 -1
  67. package/dist/rbac-Y43IEQOP.js +5 -0
  68. package/dist/{rbac-4QLDXIDF.js.map → rbac-Y43IEQOP.js.map} +1 -1
  69. package/dist/routes.cjs +29 -29
  70. package/dist/routes.js +9 -9
  71. package/dist/services.cjs +30 -30
  72. package/dist/services.js +3 -3
  73. package/dist/utils.cjs +3 -3
  74. package/dist/utils.js +1 -1
  75. package/package.json +1 -1
  76. package/dist/chunk-4BTBSXMR.cjs.map +0 -1
  77. package/dist/chunk-73KSHGOT.js.map +0 -1
  78. package/dist/chunk-7YMMCIWY.cjs.map +0 -1
  79. package/dist/chunk-C3KSTUEA.cjs.map +0 -1
  80. package/dist/chunk-CYDEM6SY.js.map +0 -1
  81. package/dist/chunk-GCDZZNIN.js.map +0 -1
  82. package/dist/chunk-JEQ7FLOD.cjs.map +0 -1
  83. package/dist/chunk-KXTGLSFY.js.map +0 -1
  84. package/dist/chunk-MJZI3NHR.cjs.map +0 -1
  85. package/dist/chunk-NOBU34HS.cjs.map +0 -1
  86. package/dist/chunk-OSMPF3PU.js.map +0 -1
  87. package/dist/chunk-PDC7DLOV.js.map +0 -1
  88. package/dist/chunk-RQ6N3FTV.js.map +0 -1
  89. package/dist/chunk-W36OZTJ5.cjs.map +0 -1
  90. package/dist/chunk-YA4V4Y5U.js.map +0 -1
  91. package/dist/chunk-ZHQP75SR.cjs.map +0 -1
  92. package/dist/config-SM2UWSDN.js +0 -6
  93. package/dist/document-projection-TDWRJX3Z.cjs +0 -13
  94. package/dist/document-projection-YYMC6I4U.js +0 -4
  95. package/dist/migrations-7G6QBDSM.js +0 -4
  96. package/dist/migrations-QIRBSVJJ.cjs +0 -13
  97. package/dist/rbac-4QLDXIDF.js +0 -5
  98. package/dist/rbac-ESTOCVT2.cjs +0 -14
@@ -429,6 +429,7 @@ var SettingsService = class {
429
429
  constructor(db) {
430
430
  this.db = db;
431
431
  }
432
+ db;
432
433
  /**
433
434
  * Get settings document for a category (general or security)
434
435
  */
@@ -908,5 +909,5 @@ exports.getCacheService = getCacheService2;
908
909
  exports.getLogger = getLogger;
909
910
  exports.initLogger = initLogger;
910
911
  exports.setAppInstance = setAppInstance;
911
- //# sourceMappingURL=chunk-4BTBSXMR.cjs.map
912
- //# sourceMappingURL=chunk-4BTBSXMR.cjs.map
912
+ //# sourceMappingURL=chunk-36Z3AKX3.cjs.map
913
+ //# sourceMappingURL=chunk-36Z3AKX3.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/services/logger.ts","../src/services/cache.ts","../src/services/settings.ts","../src/services/route-metadata.ts"],"names":["drizzle","systemLogs","inArray","eq","like","gte","lte","and","count","asc","desc","logConfig","getCacheService","inspectRoutes"],"mappings":"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","file":"chunk-36Z3AKX3.cjs","sourcesContent":["import type { D1Database } from '@cloudflare/workers-types'\nimport { systemLogs, logConfig, type NewSystemLog, type LogConfig } from '../db/schema'\nimport { drizzle } from 'drizzle-orm/d1'\nimport { eq, and, gte, lte, desc, asc, count, like, inArray } from 'drizzle-orm'\n\nexport type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'fatal'\nexport type LogCategory = 'auth' | 'api' | 'workflow' | 'plugin' | 'media' | 'system' | 'security' | 'error'\n\nexport interface LogEntry {\n level: LogLevel\n category: LogCategory\n message: string\n data?: any\n userId?: string\n sessionId?: string\n requestId?: string\n ipAddress?: string\n userAgent?: string\n method?: string\n url?: string\n statusCode?: number\n duration?: number\n stackTrace?: string\n tags?: string[]\n source?: string\n}\n\nexport interface LogFilter {\n level?: LogLevel[]\n category?: LogCategory[]\n userId?: string\n source?: string\n search?: string\n startDate?: Date\n endDate?: Date\n tags?: string[]\n limit?: number\n offset?: number\n sortBy?: 'created_at' | 'level' | 'category'\n sortOrder?: 'asc' | 'desc'\n}\n\nexport class Logger {\n private db: ReturnType<typeof drizzle>\n private enabled: boolean = true\n private configCache: Map<string, LogConfig> = new Map()\n private lastConfigRefresh: number = 0\n private configRefreshInterval: number = 60000 // 1 minute\n\n constructor(database: D1Database) {\n this.db = drizzle(database)\n }\n\n /**\n * Log a debug message\n */\n async debug(category: LogCategory, message: string, data?: any, context?: Partial<LogEntry>): Promise<void> {\n return this.log('debug', category, message, data, context)\n }\n\n /**\n * Log an info message\n */\n async info(category: LogCategory, message: string, data?: any, context?: Partial<LogEntry>): Promise<void> {\n return this.log('info', category, message, data, context)\n }\n\n /**\n * Log a warning message\n */\n async warn(category: LogCategory, message: string, data?: any, context?: Partial<LogEntry>): Promise<void> {\n return this.log('warn', category, message, data, context)\n }\n\n /**\n * Log an error message\n */\n async error(category: LogCategory, message: string, error?: Error | any, context?: Partial<LogEntry>): Promise<void> {\n const errorData = error instanceof Error ? {\n name: error.name,\n message: error.message,\n stack: error.stack\n } : error\n\n return this.log('error', category, message, errorData, {\n ...context,\n stackTrace: error instanceof Error ? error.stack : undefined\n })\n }\n\n /**\n * Log a fatal message\n */\n async fatal(category: LogCategory, message: string, error?: Error | any, context?: Partial<LogEntry>): Promise<void> {\n const errorData = error instanceof Error ? {\n name: error.name,\n message: error.message,\n stack: error.stack\n } : error\n\n return this.log('fatal', category, message, errorData, {\n ...context,\n stackTrace: error instanceof Error ? error.stack : undefined\n })\n }\n\n /**\n * Log an API request\n */\n async logRequest(\n method: string,\n url: string,\n statusCode: number,\n duration: number,\n context?: Partial<LogEntry>\n ): Promise<void> {\n const level: LogLevel = statusCode >= 500 ? 'error' : statusCode >= 400 ? 'warn' : 'info'\n \n return this.log(level, 'api', `${method} ${url} - ${statusCode}`, {\n method,\n url,\n statusCode,\n duration\n }, {\n ...context,\n method,\n url,\n statusCode,\n duration\n })\n }\n\n /**\n * Log an authentication event\n */\n async logAuth(action: string, userId?: string, success: boolean = true, context?: Partial<LogEntry>): Promise<void> {\n const level: LogLevel = success ? 'info' : 'warn'\n \n return this.log(level, 'auth', `Authentication ${action}: ${success ? 'success' : 'failed'}`, {\n action,\n success,\n userId\n }, {\n ...context,\n userId,\n tags: ['authentication', action]\n })\n }\n\n /**\n * Log a security event\n */\n async logSecurity(event: string, severity: 'low' | 'medium' | 'high' | 'critical', context?: Partial<LogEntry>): Promise<void> {\n const level: LogLevel = severity === 'critical' ? 'fatal' : severity === 'high' ? 'error' : 'warn'\n \n return this.log(level, 'security', `Security event: ${event}`, {\n event,\n severity\n }, {\n ...context,\n tags: ['security', severity]\n })\n }\n\n /**\n * Core logging method\n */\n private async log(\n level: LogLevel,\n category: LogCategory,\n message: string,\n data?: any,\n context?: Partial<LogEntry>\n ): Promise<void> {\n if (!this.enabled) return\n\n try {\n // Check if logging is enabled for this category and level\n const config = await this.getConfig(category)\n if (!config || !config.enabled || !this.shouldLog(level, config.level)) {\n return\n }\n\n const logEntry: NewSystemLog = {\n id: crypto.randomUUID(),\n level,\n category,\n message,\n data: data ? JSON.stringify(data) : null,\n userId: context?.userId || null,\n sessionId: context?.sessionId || null,\n requestId: context?.requestId || null,\n ipAddress: context?.ipAddress || null,\n userAgent: context?.userAgent || null,\n method: context?.method || null,\n url: context?.url || null,\n statusCode: context?.statusCode || null,\n duration: context?.duration || null,\n stackTrace: context?.stackTrace || null,\n tags: context?.tags ? JSON.stringify(context.tags) : null,\n source: context?.source || null,\n createdAt: new Date()\n }\n\n await this.db.insert(systemLogs).values(logEntry)\n\n // Check if we need to clean up old logs\n if (config.maxSize) {\n await this.cleanupCategory(category, config.maxSize)\n }\n\n } catch (error) {\n // Don't log errors in the logger to avoid infinite loops\n console.error('Logger error:', error)\n }\n }\n\n /**\n * Get logs with filtering and pagination\n */\n async getLogs(filter: LogFilter = {}): Promise<{ logs: any[], total: number }> {\n try {\n const conditions = []\n \n if (filter.level && filter.level.length > 0) {\n conditions.push(inArray(systemLogs.level, filter.level))\n }\n \n if (filter.category && filter.category.length > 0) {\n conditions.push(inArray(systemLogs.category, filter.category))\n }\n \n if (filter.userId) {\n conditions.push(eq(systemLogs.userId, filter.userId))\n }\n \n if (filter.source) {\n conditions.push(eq(systemLogs.source, filter.source))\n }\n \n if (filter.search) {\n conditions.push(\n like(systemLogs.message, `%${filter.search}%`)\n )\n }\n \n if (filter.startDate) {\n conditions.push(gte(systemLogs.createdAt, filter.startDate))\n }\n \n if (filter.endDate) {\n conditions.push(lte(systemLogs.createdAt, filter.endDate))\n }\n\n const whereClause = conditions.length > 0 ? and(...conditions) : undefined\n\n // Get total count\n const totalResult = await this.db\n .select({ count: count() })\n .from(systemLogs)\n .where(whereClause)\n\n const total = totalResult[0]?.count || 0\n\n // Get logs with pagination and sorting\n const sortColumn = filter.sortBy === 'level' ? systemLogs.level :\n filter.sortBy === 'category' ? systemLogs.category :\n systemLogs.createdAt\n\n const sortFn = filter.sortOrder === 'asc' ? asc : desc\n\n const logs = await this.db\n .select()\n .from(systemLogs)\n .where(whereClause)\n .orderBy(sortFn(sortColumn))\n .limit(filter.limit || 50)\n .offset(filter.offset || 0)\n\n return { logs, total }\n } catch (error) {\n console.error('Error getting logs:', error)\n return { logs: [], total: 0 }\n }\n }\n\n /**\n * Get log configuration for a category\n */\n private async getConfig(category: LogCategory): Promise<LogConfig | null> {\n try {\n // Check cache first\n const now = Date.now()\n if (this.configCache.has(category) && (now - this.lastConfigRefresh) < this.configRefreshInterval) {\n return this.configCache.get(category) || null\n }\n\n // Refresh config from database\n const configs = await this.db\n .select()\n .from(logConfig)\n .where(eq(logConfig.category, category))\n\n const config = configs[0] || null\n \n if (config) {\n this.configCache.set(category, config)\n this.lastConfigRefresh = now\n }\n\n return config\n } catch (error) {\n console.error('Error getting log config:', error)\n return null\n }\n }\n\n /**\n * Update log configuration\n */\n async updateConfig(category: LogCategory, updates: Partial<LogConfig>): Promise<void> {\n try {\n await this.db\n .update(logConfig)\n .set({\n ...updates,\n updatedAt: new Date()\n })\n .where(eq(logConfig.category, category))\n\n // Clear cache for this category\n this.configCache.delete(category)\n } catch (error) {\n console.error('Error updating log config:', error)\n }\n }\n\n /**\n * Get all log configurations\n */\n async getAllConfigs(): Promise<LogConfig[]> {\n try {\n return await this.db.select().from(logConfig)\n } catch (error) {\n console.error('Error getting log configs:', error)\n return []\n }\n }\n\n /**\n * Clean up old logs for a category\n */\n private async cleanupCategory(category: LogCategory, maxSize: number): Promise<void> {\n try {\n // Count current logs for this category\n const countResult = await this.db\n .select({ count: count() })\n .from(systemLogs)\n .where(eq(systemLogs.category, category))\n\n const currentCount = countResult[0]?.count || 0\n\n if (currentCount > maxSize) {\n // Get the cutoff date (keep newest maxSize logs)\n const cutoffLogs = await this.db\n .select({ createdAt: systemLogs.createdAt })\n .from(systemLogs)\n .where(eq(systemLogs.category, category))\n .orderBy(desc(systemLogs.createdAt))\n .limit(1)\n .offset(maxSize - 1)\n\n if (cutoffLogs[0]) {\n // Delete older logs\n await this.db\n .delete(systemLogs)\n .where(\n and(\n eq(systemLogs.category, category),\n lte(systemLogs.createdAt, cutoffLogs[0].createdAt)\n )\n )\n }\n }\n } catch (error) {\n console.error('Error cleaning up logs:', error)\n }\n }\n\n /**\n * Clean up logs based on retention policy\n */\n async cleanupByRetention(): Promise<void> {\n try {\n const configs = await this.getAllConfigs()\n \n for (const config of configs) {\n if (config.retention > 0) {\n const cutoffDate = new Date()\n cutoffDate.setDate(cutoffDate.getDate() - config.retention)\n\n await this.db\n .delete(systemLogs)\n .where(\n and(\n eq(systemLogs.category, config.category),\n lte(systemLogs.createdAt, cutoffDate)\n )\n )\n }\n }\n } catch (error) {\n console.error('Error cleaning up logs by retention:', error)\n }\n }\n\n /**\n * Check if a log level should be recorded based on configuration\n */\n private shouldLog(level: LogLevel, configLevel: string): boolean {\n const levels = ['debug', 'info', 'warn', 'error', 'fatal']\n const levelIndex = levels.indexOf(level)\n const configLevelIndex = levels.indexOf(configLevel)\n \n return levelIndex >= configLevelIndex\n }\n\n /**\n * Enable or disable logging\n */\n setEnabled(enabled: boolean): void {\n this.enabled = enabled\n }\n\n /**\n * Check if logging is enabled\n */\n isEnabled(): boolean {\n return this.enabled\n }\n}\n\n// Singleton logger instance\nlet loggerInstance: Logger | null = null\n\n/**\n * Get the logger instance\n */\nexport function getLogger(database?: D1Database): Logger {\n if (!loggerInstance && database) {\n loggerInstance = new Logger(database)\n }\n \n if (!loggerInstance) {\n throw new Error('Logger not initialized. Call getLogger with a database instance first.')\n }\n \n return loggerInstance\n}\n\n/**\n * Initialize the logger with a database\n */\nexport function initLogger(database: D1Database): Logger {\n loggerInstance = new Logger(database)\n return loggerInstance\n}","/**\n * Cache Service Adapter\n *\n * Thin facade over the cache plugin's `CacheService` so route code can keep its\n * legacy `{ ttl, keyPrefix }` contract while writes land in the plugin's\n * singleton — that's the same registry the admin dashboard at /admin/cache reads\n * via `getAllCacheStats()`. Without this adapter the two caches would be split:\n * routes would write to one, the dashboard would read from another, and the UI\n * would always show zero entries.\n */\n\nimport {\n getCacheService as getPluginCacheService,\n type CacheService as PluginCacheService,\n} from '../plugins/cache/services/cache'\nimport type { CacheConfig as PluginCacheConfig } from '../plugins/cache/services/cache-config'\n\nexport interface CacheConfig {\n ttl: number // Time to live in seconds\n keyPrefix: string\n}\n\nfunction toPluginConfig(config: CacheConfig): PluginCacheConfig {\n return {\n ttl: config.ttl,\n namespace: config.keyPrefix,\n // KV survives isolate evictions — required for the dashboard to show non-zero\n // counts across requests in production. Falls back to memory-only when the\n // CACHE_KV binding is missing (cache plugin handles the null case).\n kvEnabled: true,\n memoryEnabled: true,\n invalidateOn: [],\n version: 'v1',\n }\n}\n\nexport class CacheService {\n private config: CacheConfig\n private inner: PluginCacheService\n // Tracks expiry times so getWithSource can distinguish 'none' vs 'expired'.\n // The plugin returns source:'miss' for both cases; we differentiate here.\n private keyExpiry = new Map<string, number>()\n\n constructor(config: CacheConfig) {\n this.config = config\n this.inner = getPluginCacheService(toPluginConfig(config))\n }\n\n generateKey(type: string, identifier?: string): string {\n const parts = [this.config.keyPrefix, type]\n if (identifier !== undefined && identifier !== '') parts.push(identifier)\n return parts.join(':')\n }\n\n async get<T>(key: string): Promise<T | null> {\n return this.inner.get<T>(key)\n }\n\n async getWithSource<T>(key: string): Promise<{\n hit: boolean\n data: T | null\n source: string\n ttl?: number\n }> {\n const result = await this.inner.getWithSource<T>(key)\n if (result.hit) {\n const out: { hit: boolean; data: T | null; source: string; ttl?: number } = {\n hit: true,\n data: result.data,\n source: result.source,\n }\n if (result.ttl !== undefined) out.ttl = result.ttl\n return out\n }\n // Plugin returns source:'miss' for both \"never set\" and \"expired\". Distinguish\n // by checking if we ever recorded an expiry for this key.\n const expiry = this.keyExpiry.get(key)\n if (expiry !== undefined) {\n this.keyExpiry.delete(key)\n return { hit: false, data: null, source: 'expired' }\n }\n return { hit: false, data: null, source: 'none' }\n }\n\n async set(key: string, value: any, ttl?: number): Promise<void> {\n const effectiveTtl = ttl ?? this.config.ttl\n this.keyExpiry.set(key, Date.now() + effectiveTtl * 1000)\n await this.inner.set(key, value, ttl !== undefined ? { ttl } : undefined)\n }\n\n async delete(key: string): Promise<void> {\n this.keyExpiry.delete(key)\n await this.inner.delete(key)\n }\n\n async invalidate(pattern: string): Promise<void> {\n // Clear expiry tracking for invalidated keys\n if (pattern.includes('*') || pattern.includes('?')) {\n const regex = new RegExp('^' + pattern.replace(/\\*/g, '.*').replace(/\\?/g, '.') + '$')\n for (const k of this.keyExpiry.keys()) {\n if (regex.test(k)) this.keyExpiry.delete(k)\n }\n } else {\n this.keyExpiry.delete(pattern)\n }\n await this.inner.invalidate(pattern)\n }\n\n async clear(): Promise<void> {\n this.keyExpiry.clear()\n await this.inner.clear()\n }\n\n async getOrSet<T>(key: string, callback: () => Promise<T>, ttl?: number): Promise<T> {\n const cached = await this.get<T>(key)\n if (cached !== null) return cached\n const value = await callback()\n await this.set(key, value, ttl)\n return value\n }\n}\n\n/**\n * Default cache configurations for different data types.\n */\nexport const CACHE_CONFIGS = {\n api: {\n ttl: 300, // 5 minutes\n keyPrefix: 'api',\n },\n user: {\n ttl: 600, // 10 minutes\n keyPrefix: 'user',\n },\n content: {\n ttl: 300, // 5 minutes\n keyPrefix: 'content',\n },\n collection: {\n ttl: 600, // 10 minutes\n keyPrefix: 'collection',\n },\n}\n\n/**\n * Resolve a cache service for a config. Wraps the plugin's singleton so admin\n * dashboard stats and route-side writes share the same store.\n */\nexport function getCacheService(config: CacheConfig): CacheService {\n return new CacheService(config)\n}\n\n/** Clear every cached value across all plugin singletons. Test/admin use only. */\nexport async function clearAllCacheInstances(): Promise<void> {\n const { clearAllCaches } = await import('../plugins/cache/services/cache')\n await clearAllCaches()\n}\n","export interface GeneralSettings {\n siteName: string\n siteDescription: string\n adminEmail: string\n timezone: string\n language: string\n maintenanceMode: boolean\n}\n\nexport interface SecuritySettings {\n jwtExpiresIn: string\n jwtRefreshGraceSeconds: number\n}\n\nconst TYPE_ID = 'site_settings'\nconst TENANT = 'default'\n\nexport class SettingsService {\n constructor(private db: D1Database) {}\n\n /**\n * Get settings document for a category (general or security)\n */\n private async getSettingsDocument(category: string): Promise<any | null> {\n try {\n const row = await this.db.prepare(`\n SELECT data FROM documents\n WHERE type_id = ? AND slug = ? AND tenant_id = ? AND is_current_draft = 1 AND deleted_at IS NULL\n `).bind(TYPE_ID, category, TENANT).first()\n\n if (!row) {\n return null\n }\n\n return JSON.parse((row as any).data)\n } catch (error) {\n console.error(`Error getting settings document for ${category}:`, error)\n return null\n }\n }\n\n /**\n * Save settings document for a category (general or security)\n */\n private async saveSettingsDocument(category: string, data: Record<string, any>): Promise<boolean> {\n try {\n const now = Math.floor(Date.now() / 1000)\n const jsonData = JSON.stringify(data)\n\n // Ensure document_types row exists (FK constraint on documents.type_id)\n await this.db.prepare(`\n INSERT OR IGNORE INTO document_types (id, name, display_name, description, schema, source, is_system, is_active, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `).bind(\n TYPE_ID, TYPE_ID, 'Site Settings',\n 'Global site configuration settings',\n '{}', 'system', 1, 1, now, now\n ).run()\n\n // Check if document already exists\n const existing = await this.db.prepare(`\n SELECT id FROM documents\n WHERE type_id = ? AND slug = ? AND tenant_id = ? AND is_current_draft = 1 AND deleted_at IS NULL\n `).bind(TYPE_ID, category, TENANT).first() as any\n\n if (existing) {\n // Update existing document\n await this.db.prepare(`\n UPDATE documents\n SET data = ?, updated_at = ?\n WHERE id = ? AND is_current_draft = 1\n `).bind(jsonData, now, existing.id).run()\n } else {\n // Create new document\n const docId = crypto.randomUUID()\n const rootId = docId\n const title = category === 'general' ? 'General Settings' : 'Security Settings'\n\n await this.db.prepare(`\n INSERT INTO documents (\n id, root_id, type_id, version_number, is_current_draft, is_published, status,\n parent_root_id, slug, title, tenant_id, locale, translation_group_id,\n data, metadata, created_at, updated_at\n ) VALUES (\n ?, ?, ?, 1, 1, 1, 'published',\n '', ?, ?, ?, 'default', '',\n ?, '{}', ?, ?\n )\n `).bind(\n docId, rootId, TYPE_ID,\n category, title, TENANT,\n jsonData, now, now\n ).run()\n }\n\n return true\n } catch (error) {\n console.error(`Error saving settings document for ${category}:`, error)\n return false\n }\n }\n\n /**\n * Get general settings with defaults\n */\n async getGeneralSettings(userEmail?: string): Promise<GeneralSettings> {\n const settings = await this.getSettingsDocument('general')\n\n return {\n siteName: settings?.siteName || 'SonicJS AI',\n siteDescription: settings?.siteDescription || 'A modern headless CMS powered by AI',\n adminEmail: settings?.adminEmail || userEmail || 'admin@example.com',\n timezone: settings?.timezone || 'UTC',\n language: settings?.language || 'en',\n maintenanceMode: settings?.maintenanceMode || false\n }\n }\n\n /**\n * Save general settings\n */\n async saveGeneralSettings(settings: Partial<GeneralSettings>): Promise<boolean> {\n const existing = await this.getSettingsDocument('general')\n const merged = { ...existing, ...settings }\n return await this.saveSettingsDocument('general', merged)\n }\n\n /**\n * Get security settings with defaults\n */\n async getSecuritySettings(): Promise<SecuritySettings> {\n const settings = await this.getSettingsDocument('security')\n\n return {\n jwtExpiresIn: settings?.jwtExpiresIn || '30d',\n jwtRefreshGraceSeconds:\n typeof settings?.jwtRefreshGraceSeconds === 'number'\n ? settings.jwtRefreshGraceSeconds\n : 60 * 60 * 24 * 7\n }\n }\n\n /**\n * Save security settings\n */\n async saveSecuritySettings(settings: Partial<SecuritySettings>): Promise<boolean> {\n const existing = await this.getSettingsDocument('security')\n const merged = { ...existing, ...settings }\n return await this.saveSettingsDocument('security', merged)\n }\n}\n","/**\n * Route Metadata Service\n *\n * Auto-discovers API routes using Hono's inspectRoutes() and enriches them\n * with metadata from a static registry. Routes without metadata still appear\n * as \"auto-discovered\" — nothing is ever invisible.\n */\n\nimport { inspectRoutes } from 'hono/dev'\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface RouteMetadata {\n method: string\n path: string\n description: string\n authentication: boolean | 'unknown'\n category: string\n documented: boolean\n}\n\ninterface RouteMeta {\n description: string\n authentication: boolean\n category: string\n}\n\nexport interface CategoryInfo {\n title: string\n description: string\n icon: string\n}\n\n// ============================================================================\n// App Instance Storage\n// ============================================================================\n\nlet appInstance: any = null\n\nexport function setAppInstance(app: any): void {\n appInstance = app\n}\n\nexport function getAppInstance(): any {\n return appInstance\n}\n\n// ============================================================================\n// Category Information\n// ============================================================================\n\nexport const CATEGORY_INFO: Record<string, CategoryInfo> = {\n 'Auth': {\n title: 'Authentication',\n description: 'User authentication and authorization endpoints',\n icon: '&#x1f510;'\n },\n 'Content': {\n title: 'Content Management',\n description: 'Content creation, retrieval, and management',\n icon: '&#x1f4dd;'\n },\n 'Media': {\n title: 'Media Management',\n description: 'File upload, storage, and media operations',\n icon: '&#x1f5bc;&#xfe0f;'\n },\n 'Admin': {\n title: 'Admin Interface',\n description: 'Administrative panel and management features',\n icon: '&#x2699;&#xfe0f;'\n },\n 'System': {\n title: 'System',\n description: 'Health checks and system information',\n icon: '&#x1f527;'\n },\n 'Search': {\n title: 'Search',\n description: 'AI-powered search, full-text search, and analytics',\n icon: '&#x1f50d;'\n },\n 'API Keys': {\n title: 'API Keys',\n description: 'API key management and authentication',\n icon: '&#x1f511;'\n },\n 'Workflow': {\n title: 'Workflow',\n description: 'Content workflow and approval processes',\n icon: '&#x1f504;'\n },\n 'Cache': {\n title: 'Cache',\n description: 'Cache management and invalidation',\n icon: '&#x26a1;'\n },\n 'Forms': {\n title: 'Forms',\n description: 'Form submissions and management',\n icon: '&#x1f4cb;'\n },\n 'Files': {\n title: 'Files',\n description: 'File serving from R2 storage',\n icon: '&#x1f4c1;'\n },\n 'Collections': {\n title: 'Collections',\n description: 'Per-collection REST endpoints (auto-generated from registered collections)',\n icon: '&#x1f4da;'\n }\n}\n\n// ============================================================================\n// Route Metadata Registry\n// ============================================================================\n\nconst ROUTE_METADATA: Record<string, RouteMeta> = {\n // Auth endpoints\n 'POST /auth/login': { description: 'Authenticate user with email and password (returns JWT)', category: 'Auth', authentication: false },\n 'POST /auth/login/form': { description: 'Form-based login (sets session cookie)', category: 'Auth', authentication: false },\n 'POST /auth/register': { description: 'Register a new user account', category: 'Auth', authentication: false },\n 'POST /auth/logout': { description: 'Log out the current user and invalidate session', category: 'Auth', authentication: true },\n 'GET /auth/me': { description: 'Get current authenticated user information', category: 'Auth', authentication: true },\n 'POST /auth/refresh': { description: 'Refresh authentication token', category: 'Auth', authentication: true },\n 'POST /auth/seed-admin': { description: 'Create or reset the admin user account', category: 'Auth', authentication: false },\n 'POST /auth/magic-link/request': { description: 'Request a magic link login email', category: 'Auth', authentication: false },\n 'GET /auth/magic-link/verify': { description: 'Verify magic link token and authenticate', category: 'Auth', authentication: false },\n 'POST /auth/otp/request': { description: 'Request a one-time password via email', category: 'Auth', authentication: false },\n 'POST /auth/otp/verify': { description: 'Verify OTP code and authenticate', category: 'Auth', authentication: false },\n\n // Content endpoints\n 'GET /api/collections': { description: 'List all available collections', category: 'Content', authentication: false },\n 'GET /api/collections/:collection/content': { description: 'Get all content items from a specific collection', category: 'Content', authentication: false },\n 'GET /api/content/:id': { description: 'Get a specific content item by ID', category: 'Content', authentication: false },\n 'POST /api/content': { description: 'Create a new content item', category: 'Content', authentication: true },\n 'PUT /api/content/:id': { description: 'Update an existing content item', category: 'Content', authentication: true },\n 'DELETE /api/content/:id': { description: 'Delete a content item', category: 'Content', authentication: true },\n 'GET /api/content/:id/versions': { description: 'Get version history for a content item', category: 'Content', authentication: true },\n 'POST /api/content/:id/restore/:versionId': { description: 'Restore a content item to a previous version', category: 'Content', authentication: true },\n\n // Media endpoints\n 'GET /api/media': { description: 'List all media files with pagination', category: 'Media', authentication: false },\n 'GET /api/media/:id': { description: 'Get a specific media file by ID', category: 'Media', authentication: false },\n 'POST /api/media/upload': { description: 'Upload a new media file to R2 storage', category: 'Media', authentication: true },\n 'DELETE /api/media/:id': { description: 'Delete a media file from storage', category: 'Media', authentication: true },\n\n // Admin API endpoints\n 'GET /admin/api/stats': { description: 'Get dashboard statistics (collections, content, media, users)', category: 'Admin', authentication: true },\n 'GET /admin/api/storage': { description: 'Get storage usage information', category: 'Admin', authentication: true },\n 'GET /admin/api/activity': { description: 'Get recent activity logs', category: 'Admin', authentication: true },\n 'GET /admin/api/collections': { description: 'List all collections with field counts', category: 'Admin', authentication: true },\n 'POST /admin/api/collections': { description: 'Create a new collection', category: 'Admin', authentication: true },\n 'GET /admin/api/collections/:id': { description: 'Get a specific collection with its fields', category: 'Admin', authentication: true },\n 'PATCH /admin/api/collections/:id': { description: 'Update an existing collection', category: 'Admin', authentication: true },\n 'DELETE /admin/api/collections/:id': { description: 'Delete a collection (must be empty)', category: 'Admin', authentication: true },\n 'GET /admin/api/collections/:id/fields': { description: 'Get fields for a specific collection', category: 'Admin', authentication: true },\n 'POST /admin/api/collections/:id/fields': { description: 'Add a field to a collection', category: 'Admin', authentication: true },\n 'PATCH /admin/api/collections/:id/fields/:fieldId': { description: 'Update a collection field', category: 'Admin', authentication: true },\n 'DELETE /admin/api/collections/:id/fields/:fieldId': { description: 'Remove a field from a collection', category: 'Admin', authentication: true },\n 'POST /admin/api/collections/:id/fields/reorder': { description: 'Reorder fields in a collection', category: 'Admin', authentication: true },\n 'GET /admin/api/migrations/status': { description: 'Get database migration status', category: 'Admin', authentication: true },\n 'POST /admin/api/migrations/run': { description: 'Explain how to run D1 migrations with Wrangler', category: 'Admin', authentication: true },\n 'GET /admin/api/content': { description: 'List content items with filtering and pagination', category: 'Admin', authentication: true },\n 'GET /admin/api/content/:id': { description: 'Get a content item for admin editing', category: 'Admin', authentication: true },\n 'POST /admin/api/content': { description: 'Create content via admin API', category: 'Admin', authentication: true },\n 'PUT /admin/api/content/:id': { description: 'Update content via admin API', category: 'Admin', authentication: true },\n 'DELETE /admin/api/content/:id': { description: 'Delete content via admin API', category: 'Admin', authentication: true },\n 'GET /admin/api/media': { description: 'List media files for admin management', category: 'Admin', authentication: true },\n 'POST /admin/api/media/upload': { description: 'Upload media via admin interface', category: 'Admin', authentication: true },\n 'DELETE /admin/api/media/:id': { description: 'Delete media via admin interface', category: 'Admin', authentication: true },\n 'GET /admin/api/users': { description: 'List all users', category: 'Admin', authentication: true },\n 'POST /admin/api/users': { description: 'Create a new user', category: 'Admin', authentication: true },\n 'PUT /admin/api/users/:id': { description: 'Update a user', category: 'Admin', authentication: true },\n 'DELETE /admin/api/users/:id': { description: 'Delete a user', category: 'Admin', authentication: true },\n 'GET /admin/api/logs': { description: 'Get application logs with filtering', category: 'Admin', authentication: true },\n 'GET /admin/api/plugins': { description: 'List all registered plugins', category: 'Admin', authentication: true },\n 'POST /admin/api/plugins/:id/toggle': { description: 'Enable or disable a plugin', category: 'Admin', authentication: true },\n 'GET /admin/api/settings': { description: 'Get application settings', category: 'Admin', authentication: true },\n 'PUT /admin/api/settings': { description: 'Update application settings', category: 'Admin', authentication: true },\n 'GET /admin/api/forms': { description: 'List all forms', category: 'Admin', authentication: true },\n 'GET /admin/api/forms/:id': { description: 'Get form details and submissions', category: 'Admin', authentication: true },\n 'POST /admin/api/forms': { description: 'Create a new form', category: 'Admin', authentication: true },\n 'PUT /admin/api/forms/:id': { description: 'Update a form', category: 'Admin', authentication: true },\n 'DELETE /admin/api/forms/:id': { description: 'Delete a form', category: 'Admin', authentication: true },\n 'GET /admin/api/forms/:id/submissions': { description: 'Get form submissions', category: 'Admin', authentication: true },\n 'DELETE /admin/api/forms/:id/submissions/:submissionId': { description: 'Delete a form submission', category: 'Admin', authentication: true },\n\n // Search endpoints\n 'GET /api/search': { description: 'Search content using AI, FTS5, keyword, or hybrid mode', category: 'Search', authentication: false },\n 'POST /api/search/click': { description: 'Track a search result click for analytics', category: 'Search', authentication: false },\n 'GET /admin/plugins/ai-search/api/status': { description: 'Get search plugin status and configuration', category: 'Search', authentication: true },\n 'POST /admin/plugins/ai-search/api/index': { description: 'Trigger content indexing for search', category: 'Search', authentication: true },\n 'POST /admin/plugins/ai-search/api/index/reset': { description: 'Reset the search index', category: 'Search', authentication: true },\n 'GET /admin/plugins/ai-search/api/analytics': { description: 'Get search analytics and metrics', category: 'Search', authentication: true },\n 'GET /admin/plugins/ai-search/api/analytics/queries': { description: 'Get top search queries', category: 'Search', authentication: true },\n 'GET /admin/plugins/ai-search/api/analytics/clicks': { description: 'Get click-through analytics', category: 'Search', authentication: true },\n 'GET /admin/plugins/ai-search/api/fts5/status': { description: 'Get FTS5 full-text search status', category: 'Search', authentication: true },\n 'POST /admin/plugins/ai-search/api/fts5/rebuild': { description: 'Rebuild the FTS5 search index', category: 'Search', authentication: true },\n 'GET /admin/plugins/ai-search/api/facets': { description: 'Get available search facets', category: 'Search', authentication: true },\n 'GET /admin/plugins/ai-search/api/experiments': { description: 'List search A/B test experiments', category: 'Search', authentication: true },\n 'POST /admin/plugins/ai-search/api/experiments': { description: 'Create a search A/B test experiment', category: 'Search', authentication: true },\n 'GET /admin/plugins/ai-search/api/experiments/:id': { description: 'Get experiment details', category: 'Search', authentication: true },\n 'PUT /admin/plugins/ai-search/api/experiments/:id': { description: 'Update an experiment', category: 'Search', authentication: true },\n 'DELETE /admin/plugins/ai-search/api/experiments/:id': { description: 'Delete an experiment', category: 'Search', authentication: true },\n 'POST /admin/plugins/ai-search/api/experiments/:id/start': { description: 'Start an experiment', category: 'Search', authentication: true },\n 'POST /admin/plugins/ai-search/api/experiments/:id/stop': { description: 'Stop a running experiment', category: 'Search', authentication: true },\n 'GET /admin/plugins/ai-search/api/experiments/:id/results': { description: 'Get experiment results and statistics', category: 'Search', authentication: true },\n 'GET /admin/plugins/ai-search/api/quality': { description: 'Get search quality agent analysis', category: 'Search', authentication: true },\n 'POST /admin/plugins/ai-search/api/quality/run': { description: 'Run search quality analysis', category: 'Search', authentication: true },\n 'GET /admin/plugins/ai-search/api/quality/recommendations': { description: 'Get quality improvement recommendations', category: 'Search', authentication: true },\n 'POST /admin/plugins/ai-search/api/quality/recommendations/:id/apply': { description: 'Apply a quality recommendation', category: 'Search', authentication: true },\n 'POST /admin/plugins/ai-search/api/quality/recommendations/:id/dismiss': { description: 'Dismiss a quality recommendation', category: 'Search', authentication: true },\n 'GET /admin/plugins/ai-search/api/synonyms': { description: 'List search synonyms', category: 'Search', authentication: true },\n 'POST /admin/plugins/ai-search/api/synonyms': { description: 'Add a search synonym', category: 'Search', authentication: true },\n 'DELETE /admin/plugins/ai-search/api/synonyms/:id': { description: 'Delete a search synonym', category: 'Search', authentication: true },\n 'GET /admin/plugins/ai-search/api/query-rules': { description: 'List search query rules', category: 'Search', authentication: true },\n 'POST /admin/plugins/ai-search/api/query-rules': { description: 'Create a query rule', category: 'Search', authentication: true },\n 'PUT /admin/plugins/ai-search/api/query-rules/:id': { description: 'Update a query rule', category: 'Search', authentication: true },\n 'DELETE /admin/plugins/ai-search/api/query-rules/:id': { description: 'Delete a query rule', category: 'Search', authentication: true },\n 'GET /admin/plugins/ai-search/api/settings': { description: 'Get search plugin settings', category: 'Search', authentication: true },\n 'PUT /admin/plugins/ai-search/api/settings': { description: 'Update search plugin settings', category: 'Search', authentication: true },\n\n // API Key endpoints\n 'GET /admin/api-keys/api/keys': { description: 'List all API keys', category: 'API Keys', authentication: true },\n 'POST /admin/api-keys/api/keys': { description: 'Create a new API key', category: 'API Keys', authentication: true },\n 'DELETE /admin/api-keys/api/keys/:id': { description: 'Revoke an API key', category: 'API Keys', authentication: true },\n 'PUT /admin/api-keys/api/keys/:id': { description: 'Update an API key', category: 'API Keys', authentication: true },\n\n // Cache endpoints\n 'GET /admin/cache/api/stats': { description: 'Get cache statistics', category: 'Cache', authentication: true },\n 'POST /admin/cache/api/purge': { description: 'Purge cache entries', category: 'Cache', authentication: true },\n 'GET /admin/cache/api/entries': { description: 'List cache entries', category: 'Cache', authentication: true },\n 'DELETE /admin/cache/api/entries/:key': { description: 'Delete a specific cache entry', category: 'Cache', authentication: true },\n\n // Workflow endpoints\n 'GET /workflow/status/:id': { description: 'Get workflow status for a content item', category: 'Workflow', authentication: true },\n 'POST /workflow/submit/:id': { description: 'Submit content for review', category: 'Workflow', authentication: true },\n 'POST /workflow/approve/:id': { description: 'Approve content in review', category: 'Workflow', authentication: true },\n 'POST /workflow/reject/:id': { description: 'Reject content in review', category: 'Workflow', authentication: true },\n 'POST /workflow/publish/:id': { description: 'Publish approved content', category: 'Workflow', authentication: true },\n 'POST /workflow/unpublish/:id': { description: 'Unpublish content', category: 'Workflow', authentication: true },\n 'GET /workflow/history/:id': { description: 'Get workflow history for a content item', category: 'Workflow', authentication: true },\n\n // Form endpoints (public)\n 'POST /forms/:formId/submit': { description: 'Submit a form (public endpoint)', category: 'Forms', authentication: false },\n 'GET /forms/:formId': { description: 'Get form definition for rendering', category: 'Forms', authentication: false },\n 'POST /api/forms/:formId/submit': { description: 'Submit a form via API', category: 'Forms', authentication: false },\n 'GET /api/forms/:formId': { description: 'Get form definition via API', category: 'Forms', authentication: false },\n\n // System endpoints\n 'GET /health': { description: 'Health check endpoint for monitoring', category: 'System', authentication: false },\n 'GET /api/health': { description: 'API health check with schema information', category: 'System', authentication: false },\n 'GET /api': { description: 'API root - returns API information and available endpoints', category: 'System', authentication: false },\n 'GET /api/system/info': { description: 'Get system information and version', category: 'System', authentication: false },\n 'GET /api/system/schema': { description: 'Get database schema information', category: 'System', authentication: false },\n\n // Collection shorthand routes\n 'GET /api/:collection': { description: 'List items from a collection (shorthand route)', category: 'Collections', authentication: false },\n 'GET /api/:collection/:id': { description: 'Get a single item by ID from a collection', category: 'Collections', authentication: false },\n 'POST /api/:collection': { description: 'Create an item in a collection', category: 'Collections', authentication: true },\n 'PUT /api/:collection/:id': { description: 'Update an item in a collection', category: 'Collections', authentication: true },\n 'DELETE /api/:collection/:id': { description: 'Delete an item from a collection', category: 'Collections', authentication: true },\n\n // File serving\n 'GET /files/*': { description: 'Serve files from R2 storage (public access)', category: 'Files', authentication: false },\n\n // Database tools\n 'POST /admin/database-tools/api/query': { description: 'Execute a database query', category: 'Admin', authentication: true },\n 'GET /admin/database-tools/api/tables': { description: 'List database tables', category: 'Admin', authentication: true },\n 'GET /admin/database-tools/api/tables/:name': { description: 'Get table schema and sample data', category: 'Admin', authentication: true },\n\n // Seed data\n 'POST /admin/seed-data/api/generate': { description: 'Generate seed data for development', category: 'Admin', authentication: true },\n 'GET /admin/seed-data/api/status': { description: 'Get seed data generation status', category: 'Admin', authentication: true },\n\n // Email plugin\n 'POST /admin/plugins/email/api/send': { description: 'Send an email', category: 'Admin', authentication: true },\n 'GET /admin/plugins/email/api/templates': { description: 'List email templates', category: 'Admin', authentication: true },\n 'POST /admin/plugins/email/api/test': { description: 'Send a test email', category: 'Admin', authentication: true },\n}\n\n// ============================================================================\n// Whitelist Patterns for API routes\n// ============================================================================\n\nconst INCLUDED_ROUTE_PATTERNS: RegExp[] = [\n /^\\/api\\//, // All /api/* routes\n /^\\/api$/, // API root\n /^\\/auth\\/(?!login$|register$)/, // Auth routes except GET login/register HTML pages\n /^\\/auth\\/login$/, // POST /auth/login (method filtered later)\n /^\\/auth\\/register$/, // POST /auth/register (method filtered later)\n /^\\/admin\\/api\\//, // Admin API endpoints\n /^\\/admin\\/api-keys\\/api\\//, // API key management\n /^\\/admin\\/cache\\/api\\//, // Cache management API\n /^\\/admin\\/plugins\\/.*\\/api\\//, // Plugin API endpoints\n /^\\/admin\\/database-tools\\/api\\//, // Database tools API\n /^\\/admin\\/seed-data\\/api\\//, // Seed data API\n /^\\/workflow\\//, // Workflow endpoints\n /^\\/health$/, // Health check\n /^\\/files\\//, // File serving\n /^\\/forms\\//, // Public form endpoints\n]\n\n// Routes to always exclude (even if they match an include pattern)\nconst EXCLUDED_ROUTES = new Set([\n 'GET /auth/login',\n 'GET /auth/register',\n 'GET /auth/login/form',\n])\n\n// ============================================================================\n// Route Discovery\n// ============================================================================\n\nlet cachedRouteList: RouteMetadata[] | null = null\n\nfunction isIncludedRoute(method: string, path: string): boolean {\n // Check exclusions first\n const key = `${method} ${path}`\n if (EXCLUDED_ROUTES.has(key)) {\n return false\n }\n\n // Check if the path matches any include pattern\n return INCLUDED_ROUTE_PATTERNS.some(pattern => pattern.test(path))\n}\n\nfunction inferCategory(path: string): string {\n if (path.startsWith('/auth/')) return 'Auth'\n if (path.startsWith('/api/search')) return 'Search'\n if (path.startsWith('/api/media')) return 'Media'\n if (path.startsWith('/api/system')) return 'System'\n if (path.startsWith('/api/content') || path.startsWith('/api/collections')) return 'Content'\n if (path.startsWith('/api/forms')) return 'Forms'\n if (path.startsWith('/admin/api-keys')) return 'API Keys'\n if (path.startsWith('/admin/cache')) return 'Cache'\n if (path.startsWith('/admin/plugins/ai-search')) return 'Search'\n if (path.startsWith('/admin/api')) return 'Admin'\n if (path.startsWith('/admin/database-tools')) return 'Admin'\n if (path.startsWith('/admin/seed-data')) return 'Admin'\n if (path.startsWith('/admin/plugins/email')) return 'Admin'\n if (path.startsWith('/workflow/')) return 'Workflow'\n if (path.startsWith('/forms/')) return 'Forms'\n if (path.startsWith('/files/')) return 'Files'\n if (path === '/health' || path.startsWith('/api')) return 'System'\n if (path.match(/^\\/api\\/[^/]+(\\/:id)?$/) && !path.startsWith('/api/content') && !path.startsWith('/api/collections') && !path.startsWith('/api/media') && !path.startsWith('/api/search') && !path.startsWith('/api/system') && !path.startsWith('/api/health') && !path.startsWith('/api/documents') && !path.startsWith('/api/forms')) return 'Collections'\n return 'Other'\n}\n\nfunction inferAuth(path: string): boolean | 'unknown' {\n // Known public routes\n if (path === '/health' || path === '/api' || path === '/api/health') return false\n if (path === '/api/system/info' || path === '/api/system/schema') return false\n if (path.startsWith('/files/')) return false\n if (path.startsWith('/forms/') || path.startsWith('/api/forms/')) return false\n\n // Admin routes require auth\n if (path.startsWith('/admin/')) return true\n if (path.startsWith('/workflow/')) return true\n\n return 'unknown'\n}\n\nexport function buildRouteList(app: any): RouteMetadata[] {\n if (cachedRouteList) return cachedRouteList\n\n if (!app) return []\n\n try {\n const routes = inspectRoutes(app as any)\n\n // Deduplicate and filter\n const seen = new Set<string>()\n const result: RouteMetadata[] = []\n\n for (const route of routes) {\n // Skip middleware entries\n if (route.isMiddleware) continue\n // Skip ALL method (middleware-like catch-all)\n if (route.method === 'ALL') continue\n\n const key = `${route.method} ${route.path}`\n\n // Skip duplicates\n if (seen.has(key)) continue\n seen.add(key)\n\n // Apply whitelist filter\n if (!isIncludedRoute(route.method, route.path)) continue\n\n // Look up metadata\n const meta = ROUTE_METADATA[key]\n\n if (meta) {\n result.push({\n method: route.method,\n path: route.path,\n description: meta.description,\n authentication: meta.authentication,\n category: meta.category,\n documented: true\n })\n } else {\n // Auto-discovered: infer category and auth\n result.push({\n method: route.method,\n path: route.path,\n description: '',\n authentication: inferAuth(route.path),\n category: inferCategory(route.path),\n documented: false\n })\n }\n }\n\n // Sort: by category, then method order, then path\n const methodOrder: Record<string, number> = { GET: 0, POST: 1, PUT: 2, PATCH: 3, DELETE: 4 }\n result.sort((a, b) => {\n const catCmp = a.category.localeCompare(b.category)\n if (catCmp !== 0) return catCmp\n const methCmp = (methodOrder[a.method] ?? 5) - (methodOrder[b.method] ?? 5)\n if (methCmp !== 0) return methCmp\n return a.path.localeCompare(b.path)\n })\n\n cachedRouteList = result\n return result\n } catch (error) {\n console.error('Failed to inspect routes:', error)\n return []\n }\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { DocumentProjection, nanoid } from './chunk-GCDZZNIN.js';
1
+ import { DocumentProjection, nanoid } from './chunk-UWUP2VMT.js';
2
2
 
3
3
  // src/services/documents.ts
4
4
  var DEFAULT_MAX_VERSIONS = 50;
@@ -47,6 +47,8 @@ var DocumentsService = class {
47
47
  this.tenantId = opts.tenantId ?? "default";
48
48
  this.versioning = opts.versioning ?? false;
49
49
  }
50
+ db;
51
+ opts;
50
52
  projection;
51
53
  tenantId;
52
54
  versioning;
@@ -385,6 +387,8 @@ var RbacService = class _RbacService {
385
387
  this.db = db;
386
388
  this.kv = kv;
387
389
  }
390
+ db;
391
+ kv;
388
392
  // Precedence for projecting the user's RBAC roles back onto the legacy
389
393
  // users.role compat column (highest privilege first). Only `admin` is
390
394
  // hardcoded as a seeded role — `editor` is listed here purely so that if an
@@ -781,5 +785,5 @@ var RbacService = class _RbacService {
781
785
  };
782
786
 
783
787
  export { DocumentsService, RbacService, documentSecondsToMs };
784
- //# sourceMappingURL=chunk-PDC7DLOV.js.map
785
- //# sourceMappingURL=chunk-PDC7DLOV.js.map
788
+ //# sourceMappingURL=chunk-3TMTYJAJ.js.map
789
+ //# sourceMappingURL=chunk-3TMTYJAJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/services/documents.ts","../src/services/rbac.ts"],"names":[],"mappings":"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","file":"chunk-3TMTYJAJ.js","sourcesContent":["import { D1Database } from '@cloudflare/workers-types'\nimport { nanoid } from 'nanoid'\nimport type {\n Document,\n DocumentRow,\n CreateDocumentInput,\n UpdateDocumentInput,\n QueryableField,\n} from '../schemas/document'\nimport { DocumentProjection } from './document-projection'\n\nconst DEFAULT_MAX_VERSIONS = 50\n\n/**\n * D29: documents store `created_at`/`updated_at` in SECONDS (see `create`/`saveDraft`), but the legacy\n * `content` table — and therefore the public/CRUD `/api/content` contract — used MILLISECONDS. Any code\n * that shapes a document row into the content response must convert so `new Date(item.created_at)` keeps\n * working for API consumers. Null/undefined pass through unchanged.\n */\nexport function documentSecondsToMs(ts: number | null | undefined): number | null {\n return ts == null ? null : ts * 1000\n}\n\nfunction rowToDocument(row: DocumentRow): Document {\n return {\n id: row.id,\n rootId: row.root_id,\n typeId: row.type_id,\n typeVersion: row.type_version,\n versionOfId: row.version_of_id,\n versionNumber: row.version_number,\n isCurrentDraft: row.is_current_draft === 1,\n isPublished: row.is_published === 1,\n status: row.status,\n parentRootId: row.parent_root_id,\n slug: row.slug,\n path: row.path,\n title: row.title,\n zone: row.zone,\n sortOrder: row.sort_order,\n visible: row.visible === 1,\n publishedAt: row.published_at,\n scheduledAt: row.scheduled_at,\n expiresAt: row.expires_at,\n deletedAt: row.deleted_at,\n tenantId: row.tenant_id,\n locale: row.locale,\n translationGroupId: row.translation_group_id,\n data: JSON.parse(row.data),\n metadata: JSON.parse(row.metadata),\n ownerId: row.owner_id,\n createdBy: row.created_by,\n updatedBy: row.updated_by,\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n }\n}\n\nexport interface DocumentsServiceOptions {\n queryableFields?: QueryableField[]\n typeSchemaVersion?: number\n maxVersionsPerRoot?: number\n /** Tenant this service operates within. Every root-keyed lookup is scoped to it (R3). POC default: 'default'. */\n tenantId?: string\n /** Retain version history (new row per saveDraft, supersede-as-history). Default false (in-place). */\n versioning?: boolean\n}\n\nexport class DocumentsService {\n private projection: DocumentProjection\n private tenantId: string\n private versioning: boolean\n\n constructor(\n private db: D1Database,\n private opts: DocumentsServiceOptions = {},\n ) {\n this.projection = new DocumentProjection(db)\n this.tenantId = opts.tenantId ?? 'default'\n this.versioning = opts.versioning ?? false\n }\n\n // ─── Create ───────────────────────────────────────────────────────────────\n\n async create(input: CreateDocumentInput, createdBy?: string): Promise<Document> {\n // D23: document timestamps are stored in SECONDS (legacy `content` rows use milliseconds). Any\n // Date() rendering of a document timestamp must multiply by 1000.\n const now = Math.floor(Date.now() / 1000)\n const id = nanoid()\n const publish = input.publishOnCreate ?? false\n // D34: backfill may carry the source row's original timestamps; normal creates default to now.\n const createdAt = input.createdAt ?? now\n const updatedAt = input.updatedAt ?? now\n\n const doc: Document = {\n id,\n rootId: id,\n typeId: input.typeId,\n typeVersion: this.opts.typeSchemaVersion ?? 1,\n versionOfId: null,\n versionNumber: 1,\n isCurrentDraft: true,\n isPublished: publish,\n status: publish ? 'published' : 'draft',\n parentRootId: input.parentRootId ?? '',\n slug: input.slug ?? null,\n path: null,\n title: input.title ?? null,\n zone: input.zone ?? null,\n sortOrder: input.sortOrder ?? 0,\n visible: input.visible ?? true,\n publishedAt: publish ? createdAt : null,\n scheduledAt: input.scheduledAt ?? null,\n expiresAt: input.expiresAt ?? null,\n deletedAt: null,\n // Tenant comes from the service scope unless the caller passes one explicitly. Never trust a\n // request-body tenant: route handlers must override with the resolved request-context tenant.\n tenantId: input.tenantId ?? this.tenantId,\n locale: input.locale ?? 'default',\n translationGroupId: '',\n data: input.data ?? {},\n metadata: input.metadata ?? {},\n ownerId: input.ownerId ?? null,\n createdBy: createdBy ?? null,\n updatedBy: createdBy ?? null,\n createdAt,\n updatedAt,\n }\n\n const insertDoc = this.db.prepare(\n `INSERT INTO documents (id, root_id, type_id, type_version, version_of_id, version_number,\n is_current_draft, is_published, status, parent_root_id, slug, path, title, zone,\n sort_order, visible, published_at, scheduled_at, expires_at, deleted_at,\n tenant_id, locale, translation_group_id, data, metadata,\n owner_id, created_by, updated_by, created_at, updated_at)\n VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`,\n ).bind(\n doc.id, doc.rootId, doc.typeId, doc.typeVersion, null, 1,\n 1, publish ? 1 : 0, doc.status, doc.parentRootId, doc.slug, null, doc.title, doc.zone,\n doc.sortOrder, doc.visible ? 1 : 0, doc.publishedAt, doc.scheduledAt, doc.expiresAt, null,\n doc.tenantId, doc.locale, '', JSON.stringify(doc.data), JSON.stringify(doc.metadata),\n doc.ownerId, doc.createdBy, doc.updatedBy, createdAt, updatedAt,\n )\n\n const derivedInserts = this.projection.buildDerivedInsertStatements(doc, this.opts.queryableFields ?? [], now)\n\n await this.db.batch([insertDoc, ...derivedInserts])\n return doc\n }\n\n // ─── Save new draft ───────────────────────────────────────────────────────\n // Atomically: demote previous draft → delete its derived rows (if not published) →\n // insert new draft → materialize derived rows → prune excess versions.\n\n async saveDraft(rootId: string, input: UpdateDocumentInput, updatedBy?: string): Promise<Document> {\n const now = Math.floor(Date.now() / 1000)\n const newId = nanoid()\n\n // Fetch current state synchronously before starting the batch. Tenant-scoped (R3): a service\n // for tenant B must not find or mutate tenant A's root.\n const prevDraftRow = await this.db\n .prepare('SELECT * FROM documents WHERE root_id = ? AND tenant_id = ? AND is_current_draft = 1')\n .bind(rootId, this.tenantId)\n .first<DocumentRow>()\n\n if (!prevDraftRow) throw new Error(`No current draft found for root ${rootId}`)\n\n const prevDraft = rowToDocument(prevDraftRow)\n\n const mergedData = { ...prevDraft.data, ...(input.data ?? {}) }\n const mergedMeta = { ...prevDraft.metadata, ...(input.metadata ?? {}) }\n\n const newDoc: Document = {\n ...prevDraft,\n id: newId,\n rootId,\n typeVersion: this.opts.typeSchemaVersion ?? prevDraft.typeVersion,\n versionOfId: prevDraft.id,\n versionNumber: 0, // computed by SQL below\n isCurrentDraft: true,\n isPublished: false,\n status: 'draft',\n slug: input.slug !== undefined ? input.slug ?? null : prevDraft.slug,\n title: input.title !== undefined ? input.title ?? null : prevDraft.title,\n zone: input.zone !== undefined ? input.zone ?? null : prevDraft.zone,\n sortOrder: input.sortOrder ?? prevDraft.sortOrder,\n visible: input.visible ?? prevDraft.visible,\n scheduledAt: input.scheduledAt !== undefined ? input.scheduledAt : prevDraft.scheduledAt,\n expiresAt: input.expiresAt !== undefined ? input.expiresAt : prevDraft.expiresAt,\n data: mergedData,\n metadata: mergedMeta,\n updatedBy: updatedBy ?? prevDraft.updatedBy,\n updatedAt: now,\n createdAt: now,\n }\n\n const prevIsPublished = prevDraftRow.is_published === 1\n\n // Versioning off + the working draft is a pure draft (not the live published row):\n // update it in place. No new row, no history accumulation. (R7: rebuild derived rows.)\n if (!this.versioning && !prevIsPublished) {\n return this.updateInPlace(prevDraft, input, now, updatedBy)\n }\n\n const statements: D1PreparedStatement[] = [\n // 1. Demote previous current draft FIRST (unique index: never two current drafts mid-batch).\n this.db.prepare('UPDATE documents SET is_current_draft = 0, updated_at = ? WHERE id = ? AND tenant_id = ?')\n .bind(now, prevDraft.id, this.tenantId),\n\n // 2. If the previous draft was not also the published row, delete its derived rows.\n ...(!prevIsPublished ? this.projection.buildDerivedDeleteStatements(prevDraft.id) : []),\n\n // 3. Insert new draft. version_number derived in SQL (COALESCE(MAX)+1 from existing rows).\n // R5 arithmetic — keep balanced: 30 columns = 5 leading '?' + 1 version_number subquery\n // + 3 literals (1,0,'draft') + 21 trailing '?'. Total placeholders: 5 + 1 (subquery\n // root_id) + 21 = 27, which MUST equal the 27 .bind() args below. Do not change one side\n // without recounting the other.\n this.db.prepare(\n `INSERT INTO documents (id, root_id, type_id, type_version, version_of_id, version_number,\n is_current_draft, is_published, status, parent_root_id, slug, path, title, zone,\n sort_order, visible, published_at, scheduled_at, expires_at, deleted_at,\n tenant_id, locale, translation_group_id, data, metadata,\n owner_id, created_by, updated_by, created_at, updated_at)\n SELECT ?,?,?,?,?,\n (SELECT COALESCE(MAX(version_number), 0) + 1 FROM documents WHERE root_id = ?),\n 1,0,'draft',?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?\n WHERE 1=1`,\n ).bind(\n newId, rootId, newDoc.typeId, newDoc.typeVersion, prevDraft.id,\n rootId,\n newDoc.parentRootId, newDoc.slug, null, newDoc.title, newDoc.zone,\n newDoc.sortOrder, newDoc.visible ? 1 : 0, null, newDoc.scheduledAt, newDoc.expiresAt, null,\n newDoc.tenantId, newDoc.locale, newDoc.translationGroupId,\n JSON.stringify(newDoc.data), JSON.stringify(newDoc.metadata),\n newDoc.ownerId, newDoc.createdBy, newDoc.updatedBy, now, now,\n ),\n\n // 4. Materialize derived rows for new draft.\n ...this.projection.buildDerivedInsertStatements(newDoc, this.opts.queryableFields ?? [], now),\n ]\n\n // 5. Prune excess versions (beyond maxVersionsPerRoot), never the published or current-draft row,\n // and never a version still referenced as version_of_id by another row (FK RESTRICT).\n const maxVersions = this.opts.maxVersionsPerRoot ?? DEFAULT_MAX_VERSIONS\n statements.push(\n this.db.prepare(\n `DELETE FROM documents WHERE root_id = ? AND tenant_id = ? AND is_current_draft = 0 AND is_published = 0\n AND id NOT IN (\n SELECT id FROM documents WHERE root_id = ? AND tenant_id = ? AND is_current_draft = 0 AND is_published = 0\n ORDER BY version_number DESC LIMIT ?\n )\n AND id NOT IN (SELECT version_of_id FROM documents WHERE version_of_id IS NOT NULL AND root_id = ? AND tenant_id = ?)`,\n ).bind(rootId, this.tenantId, rootId, this.tenantId, maxVersions, rootId, this.tenantId),\n )\n\n await this.db.batch(statements)\n\n // Fetch the saved row to get the SQL-computed version_number.\n const saved = await this.db\n .prepare('SELECT * FROM documents WHERE id = ?')\n .bind(newId)\n .first<DocumentRow>()\n return rowToDocument(saved!)\n }\n\n // In-place draft update (versioning off). Mutates the existing draft row; preserves id/root_id/\n // version_number/version_of_id and the is_current_draft/is_published flags. Rebuilds derived rows.\n private async updateInPlace(\n prevDraft: Document,\n input: UpdateDocumentInput,\n now: number,\n updatedBy?: string,\n ): Promise<Document> {\n const mergedData = { ...prevDraft.data, ...(input.data ?? {}) }\n const mergedMeta = { ...prevDraft.metadata, ...(input.metadata ?? {}) }\n\n const updated: Document = {\n ...prevDraft,\n slug: input.slug !== undefined ? input.slug ?? null : prevDraft.slug,\n title: input.title !== undefined ? input.title ?? null : prevDraft.title,\n zone: input.zone !== undefined ? input.zone ?? null : prevDraft.zone,\n sortOrder: input.sortOrder ?? prevDraft.sortOrder,\n visible: input.visible ?? prevDraft.visible,\n scheduledAt: input.scheduledAt !== undefined ? input.scheduledAt : prevDraft.scheduledAt,\n expiresAt: input.expiresAt !== undefined ? input.expiresAt : prevDraft.expiresAt,\n data: mergedData,\n metadata: mergedMeta,\n updatedBy: updatedBy ?? prevDraft.updatedBy,\n updatedAt: now,\n }\n\n const statements: D1PreparedStatement[] = [\n // R5: 11 SET '?' + 2 WHERE '?' (id, tenant_id) = 13 binds, matching .bind() below.\n this.db.prepare(\n `UPDATE documents SET\n slug = ?, title = ?, zone = ?, sort_order = ?, visible = ?,\n scheduled_at = ?, expires_at = ?, data = ?, metadata = ?, updated_by = ?, updated_at = ?\n WHERE id = ? AND tenant_id = ?`,\n ).bind(\n updated.slug, updated.title, updated.zone, updated.sortOrder, updated.visible ? 1 : 0,\n updated.scheduledAt, updated.expiresAt, JSON.stringify(updated.data), JSON.stringify(updated.metadata),\n updated.updatedBy, now,\n updated.id, this.tenantId,\n ),\n // R7: derived rows track the new data — delete then reinsert for this row.\n ...this.projection.buildDerivedDeleteStatements(updated.id),\n ...this.projection.buildDerivedInsertStatements(updated, this.opts.queryableFields ?? [], now),\n ]\n\n await this.db.batch(statements)\n\n const saved = await this.db.prepare('SELECT * FROM documents WHERE id = ?').bind(updated.id).first<DocumentRow>()\n return rowToDocument(saved!)\n }\n\n // ─── Publish ──────────────────────────────────────────────────────────────\n\n async publish(documentId: string, publishedBy?: string): Promise<Document> {\n const now = Math.floor(Date.now() / 1000)\n\n const targetRow = await this.db\n .prepare('SELECT * FROM documents WHERE id = ? AND tenant_id = ?')\n .bind(documentId, this.tenantId)\n .first<DocumentRow>()\n\n if (!targetRow) throw new Error(`Document ${documentId} not found`)\n\n const prevPublishedRow = await this.db\n .prepare('SELECT * FROM documents WHERE root_id = ? AND tenant_id = ? AND is_published = 1 AND id != ?')\n .bind(targetRow.root_id, this.tenantId, documentId)\n .first<DocumentRow>()\n\n const statements: D1PreparedStatement[] = []\n\n if (prevPublishedRow) {\n if (!this.versioning && prevPublishedRow.is_current_draft !== 1) {\n // Versioning off: old published row is pure history — remove it + its derived rows.\n // First null any version_of_id pointing at it (the target draft may chain off it) so the\n // delete can't trip the FK RESTRICT on documents.version_of_id (plan risk #1; the chain is\n // unused when versioning is off). Tenant-scoped (R3).\n statements.push(this.db.prepare('UPDATE documents SET version_of_id = NULL WHERE version_of_id = ? AND tenant_id = ?')\n .bind(prevPublishedRow.id, this.tenantId))\n statements.push(...this.projection.buildDerivedDeleteStatements(prevPublishedRow.id))\n statements.push(this.db.prepare('DELETE FROM documents WHERE id = ? AND tenant_id = ?')\n .bind(prevPublishedRow.id, this.tenantId))\n } else {\n // existing behavior: clear is_published, drop derived rows if not the current draft\n statements.push(\n this.db.prepare('UPDATE documents SET is_published = 0, updated_at = ? WHERE id = ?')\n .bind(now, prevPublishedRow.id),\n )\n if (prevPublishedRow.is_current_draft !== 1) {\n statements.push(...this.projection.buildDerivedDeleteStatements(prevPublishedRow.id))\n }\n }\n }\n\n // Set published on target row.\n statements.push(\n this.db.prepare(\n `UPDATE documents SET is_published = 1, status = 'published', published_at = ?, updated_at = ?, updated_by = ? WHERE id = ?`,\n ).bind(now, now, publishedBy ?? null, documentId),\n )\n\n // Ensure derived rows exist for the target (they do if it was current draft; materialize if not).\n if (targetRow.is_current_draft !== 1) {\n const targetDoc = rowToDocument(targetRow)\n statements.push(...this.projection.buildDerivedInsertStatements(targetDoc, this.opts.queryableFields ?? [], now))\n }\n\n await this.db.batch(statements)\n\n const saved = await this.db.prepare('SELECT * FROM documents WHERE id = ?').bind(documentId).first<DocumentRow>()\n return rowToDocument(saved!)\n }\n\n // ─── Unpublish ────────────────────────────────────────────────────────────\n\n async unpublish(documentId: string): Promise<Document> {\n const now = Math.floor(Date.now() / 1000)\n\n const row = await this.db\n .prepare('SELECT * FROM documents WHERE id = ? AND tenant_id = ?')\n .bind(documentId, this.tenantId)\n .first<DocumentRow>()\n\n if (!row) throw new Error(`Document ${documentId} not found`)\n if (!row.is_published) throw new Error(`Document ${documentId} is not published`)\n\n const statements: D1PreparedStatement[] = [\n this.db.prepare(`UPDATE documents SET is_published = 0, status = 'draft', updated_at = ? WHERE id = ?`)\n .bind(now, documentId),\n ]\n\n // If the unpublished row is not the current draft, remove its derived rows.\n if (row.is_current_draft !== 1) {\n statements.push(...this.projection.buildDerivedDeleteStatements(documentId))\n }\n\n await this.db.batch(statements)\n\n const saved = await this.db.prepare('SELECT * FROM documents WHERE id = ?').bind(documentId).first<DocumentRow>()\n return rowToDocument(saved!)\n }\n\n // ─── Soft delete ──────────────────────────────────────────────────────────\n\n async softDelete(documentId: string): Promise<void> {\n const now = Math.floor(Date.now() / 1000)\n await this.db\n .prepare('UPDATE documents SET deleted_at = ?, updated_at = ? WHERE id = ? AND tenant_id = ?')\n .bind(now, now, documentId, this.tenantId)\n .run()\n }\n\n // ─── Hard erase (PII types) ───────────────────────────────────────────────\n // Deletes every version row for a root plus all derived data, in dependency order.\n\n async erase(rootId: string, tenantId: string): Promise<void> {\n // Get all document IDs for this root.\n const result = await this.db\n .prepare('SELECT id FROM documents WHERE root_id = ? AND tenant_id = ?')\n .bind(rootId, tenantId)\n .all<{ id: string }>()\n\n const docIds = (result.results ?? []).map(r => r.id)\n if (docIds.length === 0) return\n\n const statements: D1PreparedStatement[] = []\n\n // Delete derived tables first (explicit; don't rely on FK cascade).\n for (const id of docIds) {\n statements.push(this.db.prepare('DELETE FROM document_facets WHERE document_id = ?').bind(id))\n statements.push(this.db.prepare('DELETE FROM document_references WHERE from_document_id = ?').bind(id))\n }\n\n statements.push(this.db.prepare('DELETE FROM document_permissions WHERE root_id = ? AND tenant_id = ?').bind(rootId, tenantId))\n\n // Delete all version rows.\n for (const id of docIds) {\n statements.push(this.db.prepare('DELETE FROM documents WHERE id = ?').bind(id))\n }\n\n await this.db.batch(statements)\n }\n}\n","/**\n * Dynamic RBAC service — document-backed.\n *\n * Roles, verbs, and user-role assignments are stored as `is_auth` documents\n * (slug-addressed) instead of relational tables:\n * rbac_role slug = roleId, data = { name, displayName, description, isSystem, grants:[{resource,verb,scope}] }\n * rbac_verb slug = verbId, data = { name, description, isSystem, sortOrder }\n * rbac_user_roles slug = userId, data = { roleIds:[] }\n * Grants are embedded in the role document (no separate join type); user-role\n * assignments are embedded in a per-user document. Resources are still computed:\n * a fixed set of system resources plus one `document_type:<name>` per type.\n *\n * Wildcards: resource '*' / 'document_type:*', verb '*' / 'manage' (implies all).\n * Scope: 'any' beats 'own' beats 'none'.\n *\n * The public API is unchanged from the relational implementation, so callers\n * (admin-rbac routes, permission checks) need no changes.\n */\nimport { DocumentsService } from './documents'\n\nexport interface RbacRole {\n id: string\n name: string\n display_name: string\n description: string | null\n is_system: number\n}\nexport interface RbacVerb {\n id: string\n name: string\n description: string | null\n is_system: number\n sort_order: number\n}\nexport interface RbacResource {\n key: string // e.g. 'content' or 'collection:blog_posts'\n label: string\n group: 'system' | 'document_type'\n}\nexport type PermissionScope = 'none' | 'own' | 'any'\nexport interface Grant {\n role_id: string\n resource: string\n verb: string\n scope: Exclude<PermissionScope, 'none'>\n}\n\ninterface GrantData { resource: string; verb: string; scope?: PermissionScope }\ninterface RoleData { name: string; displayName: string; description?: string | null; isSystem?: boolean; grants?: GrantData[] }\ninterface VerbData { name: string; description?: string | null; isSystem?: boolean; sortOrder?: number }\ninterface UserRolesData { roleIds?: string[] }\ninterface DocRow { id: string; root_id: string; slug: string | null; data: string }\n\nconst TENANT = 'default'\nconst T_ROLE = 'rbac_role'\nconst T_VERB = 'rbac_verb'\nconst T_USER_ROLES = 'rbac_user_roles'\n\nconst SYSTEM_RESOURCES: RbacResource[] = [\n { key: '*', label: 'All resources', group: 'system' },\n { key: 'portal', label: 'Admin Panel', group: 'system' },\n { key: 'dashboard', label: 'Dashboard', group: 'system' },\n { key: 'rbac', label: 'Roles & Permissions', group: 'system' },\n { key: 'documents', label: 'Documents', group: 'system' as const },\n { key: 'document_types', label: 'Document Types', group: 'system' as const },\n { key: 'email', label: 'Email Management', group: 'system' },\n { key: 'users', label: 'Users', group: 'system' },\n { key: 'settings', label: 'Settings', group: 'system' },\n { key: 'logs', label: 'Logs', group: 'system' },\n]\n\nexport class RbacService {\n // Precedence for projecting the user's RBAC roles back onto the legacy\n // users.role compat column (highest privilege first). Only `admin` is\n // hardcoded as a seeded role — `editor` is listed here purely so that if an\n // administrator chooses to recreate a role named `editor`, legacy code that\n // still gates on the `editor` label keeps working.\n private static readonly LEGACY_ROLE_PRECEDENCE = ['admin', 'editor']\n\n private _docs?: DocumentsService\n\n constructor(private db: D1Database, private kv?: KVNamespace) {}\n\n // ── Document access helpers ──────────────────────────────────────────────────\n\n private docs(): DocumentsService {\n if (!this._docs) {\n this._docs = new DocumentsService(this.db, { tenantId: TENANT, maxVersionsPerRoot: 1, queryableFields: [] })\n }\n return this._docs\n }\n\n private parse<T>(row: DocRow): { id: string; rootId: string; slug: string; data: T } {\n let data: T\n try { data = JSON.parse(row.data) as T } catch { data = {} as T }\n return { id: row.id, rootId: row.root_id, slug: row.slug ?? '', data }\n }\n\n private async listDocs<T>(typeId: string): Promise<Array<{ id: string; rootId: string; slug: string; data: T }>> {\n const res = await this.db\n .prepare(\n `SELECT id, root_id, slug, data FROM documents\n WHERE type_id = ? AND tenant_id = ? AND is_current_draft = 1 AND deleted_at IS NULL`,\n )\n .bind(typeId, TENANT)\n .all<DocRow>()\n return (res.results ?? []).map((r) => this.parse<T>(r))\n }\n\n private async getDoc<T>(typeId: string, slug: string): Promise<{ id: string; rootId: string; data: T } | null> {\n const row = await this.db\n .prepare(\n `SELECT id, root_id, slug, data FROM documents\n WHERE type_id = ? AND tenant_id = ? AND slug = ? AND is_current_draft = 1 AND deleted_at IS NULL`,\n )\n .bind(typeId, TENANT, slug)\n .first<DocRow>()\n return row ? this.parse<T>(row) : null\n }\n\n private async upsertDoc(typeId: string, slug: string, data: unknown, title: string | null): Promise<void> {\n const existing = await this.db\n .prepare(\n `SELECT root_id FROM documents\n WHERE type_id = ? AND tenant_id = ? AND slug = ? AND is_current_draft = 1 AND deleted_at IS NULL`,\n )\n .bind(typeId, TENANT, slug)\n .first<{ root_id: string }>()\n const payload = data as Record<string, unknown>\n if (existing?.root_id) {\n await this.docs().saveDraft(existing.root_id, { data: payload, title })\n } else {\n await this.docs().create({\n typeId,\n tenantId: TENANT,\n locale: 'default',\n parentRootId: '',\n slug,\n title,\n sortOrder: 0,\n visible: true,\n data: payload,\n metadata: {},\n ownerId: null,\n publishOnCreate: false,\n })\n }\n }\n\n private async deleteDoc(typeId: string, slug: string): Promise<void> {\n const doc = await this.getDoc(typeId, slug)\n if (doc) await this.docs().softDelete(doc.id)\n }\n\n private roleToRow(d: { slug: string; data: RoleData }): RbacRole {\n return {\n id: d.slug,\n name: d.data.name,\n display_name: d.data.displayName,\n description: d.data.description ?? null,\n is_system: d.data.isSystem ? 1 : 0,\n }\n }\n\n // ── Reads ────────────────────────────────────────────────────────────────────\n\n async getRoles(): Promise<RbacRole[]> {\n const docs = await this.listDocs<RoleData>(T_ROLE)\n return docs\n .map((d) => this.roleToRow(d))\n .sort((a, b) => b.is_system - a.is_system || a.name.localeCompare(b.name))\n }\n\n async getVerbs(): Promise<RbacVerb[]> {\n const docs = await this.listDocs<VerbData>(T_VERB)\n return docs\n .map((d) => ({\n id: d.slug,\n name: d.data.name,\n description: d.data.description ?? null,\n is_system: d.data.isSystem ? 1 : 0,\n sort_order: d.data.sortOrder ?? 100,\n }))\n .sort((a, b) => a.sort_order - b.sort_order || a.name.localeCompare(b.name))\n }\n\n /** System resources + one `document_type:<name>` per active document type. */\n async getResources(): Promise<RbacResource[]> {\n const types = (\n await this.db\n .prepare('SELECT name, display_name FROM document_types WHERE is_active = 1 ORDER BY name')\n .all<{ name: string; display_name: string }>()\n ).results as Array<{ name: string; display_name: string }>\n const documentTypeResources: RbacResource[] = [\n { key: 'document_type:*', label: 'All document types', group: 'document_type' },\n ...types.map((t) => ({\n key: `document_type:${t.name}`,\n label: t.display_name || t.name,\n group: 'document_type' as const,\n })),\n ]\n return [...SYSTEM_RESOURCES, ...documentTypeResources]\n }\n\n async getGrants(): Promise<Grant[]> {\n const roles = await this.listDocs<RoleData>(T_ROLE)\n const out: Grant[] = []\n for (const r of roles) {\n for (const g of r.data.grants ?? []) {\n out.push({ role_id: r.slug, resource: g.resource, verb: g.verb, scope: g.scope === 'own' ? 'own' : 'any' })\n }\n }\n return out\n }\n\n async getRolesForUser(userId: string): Promise<RbacRole[]> {\n const ur = await this.getDoc<UserRolesData>(T_USER_ROLES, userId)\n const roleIds = new Set(ur?.data.roleIds ?? [])\n if (roleIds.size === 0) return []\n const roles = await this.listDocs<RoleData>(T_ROLE)\n return roles.filter((r) => roleIds.has(r.slug)).map((d) => this.roleToRow(d))\n }\n\n /** Grants attached to a set of role ids (from the embedded role grants). */\n private async grantsForRoleIds(roleIds: string[]): Promise<Array<{ resource: string; verb: string; scope: PermissionScope }>> {\n if (roleIds.length === 0) return []\n const want = new Set(roleIds)\n const roles = await this.listDocs<RoleData>(T_ROLE)\n const out: Array<{ resource: string; verb: string; scope: PermissionScope }> = []\n for (const r of roles) {\n if (!want.has(r.slug)) continue\n for (const g of r.data.grants ?? []) {\n out.push({ resource: g.resource, verb: g.verb, scope: g.scope === 'own' ? 'own' : 'any' })\n }\n }\n return out\n }\n\n /** Does a single grant row satisfy the requested (resource, verb)? */\n private grantMatches(g: { resource: string; verb: string }, resource: string, verb: string): boolean {\n const resourceOk =\n g.resource === '*' ||\n g.resource === resource ||\n (g.resource === 'document_type:*' && resource.startsWith('document_type:'))\n if (!resourceOk) return false\n return g.verb === '*' || g.verb === verb || g.verb === 'manage'\n }\n\n private strongestScope(scopes: PermissionScope[]): PermissionScope {\n if (scopes.includes('any')) return 'any'\n if (scopes.includes('own')) return 'own'\n return 'none'\n }\n\n /** Can the user perform `verb` on `resource`? Reads the live grant matrix. */\n async can(userId: string, resource: string, verb: string): Promise<boolean> {\n return (await this.getPermissionScope(userId, resource, verb)) !== 'none'\n }\n\n /** Highest scope granted to the user for `resource:verb`. */\n async getPermissionScope(userId: string, resource: string, verb: string): Promise<PermissionScope> {\n const ur = await this.getDoc<UserRolesData>(T_USER_ROLES, userId)\n const grants = await this.grantsForRoleIds(ur?.data.roleIds ?? [])\n return this.strongestScope(\n grants.filter((g) => this.grantMatches(g, resource, verb)).map((g) => (g.scope === 'own' ? 'own' : 'any')),\n )\n }\n\n /** Flattened, human-readable permission list for a user. Cached in KV for 60 s. */\n async permissionsForUser(userId: string): Promise<string[]> {\n if (this.kv) {\n const cached = await this.kv.get(`rbac:perms:${userId}`)\n if (cached !== null) return JSON.parse(cached) as string[]\n }\n const ur = await this.getDoc<UserRolesData>(T_USER_ROLES, userId)\n const roleIds = ur?.data.roleIds ?? []\n if (roleIds.length === 0) return []\n const grants = await this.grantsForRoleIds(roleIds)\n const resources = await this.getResources()\n const verbs = await this.getVerbs()\n const out = new Set<string>()\n for (const r of resources) {\n for (const v of verbs) {\n if (grants.some((g) => this.grantMatches(g, r.key, v.name))) out.add(`${r.key}:${v.name}`)\n }\n }\n const result = [...out].sort()\n if (this.kv) {\n await this.kv.put(`rbac:perms:${userId}`, JSON.stringify(result), { expirationTtl: 60 })\n }\n return result\n }\n\n // ── Mutations ──────────────────────────────────────────────────────────────\n\n async createRole(name: string, displayName: string, description = ''): Promise<void> {\n const slug = name.toLowerCase().replace(/[^a-z0-9]+/g, '-')\n const id = `role-${slug}`\n await this.upsertDoc(\n T_ROLE,\n id,\n { name: name.toLowerCase(), displayName, description, isSystem: false, grants: [] } satisfies RoleData,\n displayName,\n )\n }\n\n async deleteRole(roleId: string): Promise<void> {\n const role = await this.getDoc<RoleData>(T_ROLE, roleId)\n if (!role || role.data.isSystem) return // System roles cannot be deleted.\n await this.deleteDoc(T_ROLE, roleId)\n }\n\n /**\n * Update a role's display name and description. The `name` (slug) can only be\n * changed for custom roles — system role names are referenced by the legacy\n * mapping, so they stay fixed.\n */\n async updateRole(roleId: string, displayName: string, description = '', name?: string): Promise<void> {\n const role = await this.getDoc<RoleData>(T_ROLE, roleId)\n if (!role) return\n const next: RoleData = { ...role.data, displayName, description }\n if (!role.data.isSystem && name) {\n next.name = name.toLowerCase().replace(/[^a-z0-9]+/g, '-')\n }\n await this.upsertDoc(T_ROLE, roleId, next, displayName)\n }\n\n /** Update displayName + portal access in a single write to avoid double-saveDraft FK issues. */\n async updateRoleAndPortalAccess(\n roleId: string,\n displayName: string,\n name: string | undefined,\n portalEnabled: boolean,\n description?: string,\n ): Promise<void> {\n const role = await this.getDoc<RoleData>(T_ROLE, roleId)\n if (!role) return\n const next: RoleData = { ...role.data, displayName, description: description ?? role.data.description ?? '' }\n if (!role.data.isSystem && name) {\n next.name = name.toLowerCase().replace(/[^a-z0-9]+/g, '-')\n }\n const grants = (next.grants ?? []).filter((g) => !(g.resource === 'portal' && g.verb === 'access'))\n if (portalEnabled) grants.push({ resource: 'portal', verb: 'access', scope: 'any' })\n next.grants = grants\n await this.upsertDoc(T_ROLE, roleId, next, displayName)\n }\n\n async createVerb(name: string, description = ''): Promise<void> {\n const slug = name.toLowerCase().replace(/[^a-z0-9]+/g, '-')\n const id = `verb-${slug}`\n await this.upsertDoc(\n T_VERB,\n id,\n { name: name.toLowerCase(), description, isSystem: false, sortOrder: 100 } satisfies VerbData,\n name,\n )\n }\n\n async deleteVerb(verbId: string): Promise<void> {\n const verb = await this.getDoc<VerbData>(T_VERB, verbId)\n if (!verb || verb.data.isSystem) return\n await this.deleteDoc(T_VERB, verbId)\n }\n\n /** Replace all grants for one role with the supplied (resource, verb, scope) rows. */\n async setRoleGrants(\n roleId: string,\n pairs: Array<{ resource: string; verb: string; scope?: Exclude<PermissionScope, 'none'> }>,\n ): Promise<void> {\n const role = await this.getDoc<RoleData>(T_ROLE, roleId)\n if (!role) return\n const grants: GrantData[] = pairs.map((p) => ({ resource: p.resource, verb: p.verb, scope: p.scope === 'own' ? 'own' : 'any' }))\n await this.upsertDoc(T_ROLE, roleId, { ...role.data, grants } satisfies RoleData, role.data.displayName)\n }\n\n /**\n * Count active users (optionally excluding one) who hold BOTH an effective\n * portal:access grant and an effective rbac:manage grant — the users who could\n * recover from a permission lockout. Powers the self-lockout guard.\n */\n async countPortalAdmins(excludeUserId?: string): Promise<number> {\n const active = (\n await this.db.prepare('SELECT id FROM auth_user WHERE is_active = 1').all<{ id: string }>()\n ).results as Array<{ id: string }>\n const activeIds = new Set(active.map((u) => u.id))\n\n // role id -> its grants\n const roles = await this.listDocs<RoleData>(T_ROLE)\n const grantsByRole = new Map<string, GrantData[]>(roles.map((r) => [r.slug, r.data.grants ?? []]))\n\n const userRoles = await this.listDocs<UserRolesData>(T_USER_ROLES)\n let count = 0\n for (const ur of userRoles) {\n const userId = ur.slug\n if (!activeIds.has(userId)) continue\n if (excludeUserId && userId === excludeUserId) continue\n let portal = false\n let rbac = false\n for (const rid of ur.data.roleIds ?? []) {\n for (const g of grantsByRole.get(rid) ?? []) {\n if (this.grantMatches(g, 'portal', 'access')) portal = true\n if (this.grantMatches(g, 'rbac', 'manage')) rbac = true\n }\n }\n if (portal && rbac) count++\n }\n return count\n }\n\n /**\n * Replace a user's RBAC role assignments. The `rbac_user_roles` document is the\n * single source of truth for authorization; the legacy `auth_user.role` column\n * is kept as a derived projection (highest-precedence system role, else\n * 'viewer') so the two never diverge.\n */\n async setUserRoles(userId: string, roleIds: string[]): Promise<void> {\n const allRoles = await this.listDocs<RoleData>(T_ROLE)\n const byId = new Map(allRoles.map((r) => [r.slug, r.data]))\n const names = roleIds.map((id) => byId.get(id)?.name).filter((n): n is string => !!n)\n const primaryRole = RbacService.LEGACY_ROLE_PRECEDENCE.find((r) => names.includes(r)) || 'viewer'\n\n // Self-lockout guard: never leave zero active users who can BOTH enter the\n // portal and manage RBAC (the minimum needed to recover).\n const newGrants: GrantData[] = []\n for (const id of roleIds) for (const g of byId.get(id)?.grants ?? []) newGrants.push(g)\n const userWillBeAdmin =\n newGrants.some((g) => this.grantMatches(g, 'portal', 'access')) &&\n newGrants.some((g) => this.grantMatches(g, 'rbac', 'manage'))\n if (!userWillBeAdmin && (await this.countPortalAdmins(userId)) === 0) {\n throw new Error(\n 'Refusing to update roles: this would leave no user able to manage Roles & Permissions and access the portal. Grant another user portal access + Roles & Permissions first.',\n )\n }\n\n await this.upsertDoc(T_USER_ROLES, userId, { roleIds } satisfies UserRolesData, null)\n // Keep the legacy auth_user.role column in lockstep as a projection of RBAC.\n await this.db.prepare('UPDATE auth_user SET role = ?, updated_at = ? WHERE id = ?').bind(primaryRole, Date.now(), userId).run()\n if (this.kv) await this.kv.delete(`rbac:perms:${userId}`)\n }\n\n async setRolePortalAccess(roleId: string, enabled: boolean): Promise<void> {\n const role = await this.getDoc<RoleData>(T_ROLE, roleId)\n if (!role) return\n const grants = (role.data.grants ?? []).filter((g) => !(g.resource === 'portal' && g.verb === 'access'))\n if (enabled) grants.push({ resource: 'portal', verb: 'access', scope: 'any' })\n await this.upsertDoc(T_ROLE, roleId, { ...role.data, grants } satisfies RoleData, role.data.displayName)\n }\n\n // ── Bootstrap helpers ────────────────────────────────────────────────────────\n\n /**\n * Seed the system roles, verbs, and their grants as documents. Idempotent —\n * existing roles/verbs (by slug) are left untouched. Replaces the INSERT OR\n * IGNORE seeds that lived in migration 0001. Call at bootstrap, after the rbac\n * document types are registered.\n */\n async ensureSystemRbacSeed(): Promise<void> {\n // `admin` is the only hardcoded SYSTEM role (locked, undeletable). `editor`\n // is seeded as a non-system example so a fresh install has a usable second\n // role out of the box, but an administrator can edit, rename, or delete it.\n const roles: Array<RoleData & { id: string }> = [\n { id: 'role-admin', name: 'admin', displayName: 'Administrator', description: 'Full access to everything', isSystem: true,\n grants: [\n { resource: '*', verb: 'manage' }, { resource: 'portal', verb: 'access' }, { resource: 'rbac', verb: 'manage' },\n { resource: 'document_types', verb: 'manage' }, { resource: 'email', verb: 'manage' }, { resource: 'users', verb: 'manage' },\n ] },\n { id: 'role-editor', name: 'editor', displayName: 'Editor', description: 'Manage documents across all types', isSystem: false,\n grants: [\n { resource: 'portal', verb: 'access' },\n { resource: 'documents', verb: 'manage' },\n { resource: 'document_type:*', verb: 'read' },\n { resource: 'document_type:*', verb: 'create' },\n { resource: 'document_type:*', verb: 'update' },\n { resource: 'document_type:*', verb: 'delete' },\n { resource: 'settings', verb: 'read' },\n ] },\n { id: 'role-authenticated', name: 'authenticated', displayName: 'Authenticated', description: 'Signed-in users with no Admin Panel access', isSystem: false,\n grants: [\n { resource: 'document_type:*', verb: 'read' },\n ] },\n { id: 'role-public', name: 'public', displayName: 'Public', description: 'Unauthenticated visitors — read-only public content', isSystem: false,\n grants: [] },\n ]\n const verbs: Array<VerbData & { id: string }> = [\n { id: 'verb-access', name: 'access', description: 'Enter or use a portal/resource', isSystem: true, sortOrder: 5 },\n { id: 'verb-read', name: 'read', description: 'View a resource', isSystem: true, sortOrder: 10 },\n { id: 'verb-create', name: 'create', description: 'Create a resource', isSystem: true, sortOrder: 20 },\n { id: 'verb-update', name: 'update', description: 'Edit a resource', isSystem: true, sortOrder: 30 },\n { id: 'verb-delete', name: 'delete', description: 'Remove a resource', isSystem: true, sortOrder: 40 },\n { id: 'verb-manage', name: 'manage', description: 'Full control (implies all verbs)', isSystem: true, sortOrder: 50 },\n ]\n\n for (const r of roles) {\n if (await this.getDoc(T_ROLE, r.id)) continue\n const { id, ...data } = r\n await this.upsertDoc(T_ROLE, id, data, r.displayName)\n }\n for (const v of verbs) {\n if (await this.getDoc(T_VERB, v.id)) continue\n const { id, ...data } = v\n await this.upsertDoc(T_VERB, id, data, v.name)\n }\n }\n\n /** Assign a role to a user by role name (e.g. 'admin'), preserving existing roles. */\n async addUserRoleByName(userId: string, roleName: string): Promise<void> {\n const roles = await this.listDocs<RoleData>(T_ROLE)\n const role = roles.find((r) => r.data.name === roleName.toLowerCase())\n if (!role) return\n const ur = await this.getDoc<UserRolesData>(T_USER_ROLES, userId)\n const roleIds = new Set(ur?.data.roleIds ?? [])\n if (roleIds.has(role.slug)) return\n roleIds.add(role.slug)\n await this.setUserRoles(userId, [...roleIds])\n }\n}\n"]}
@@ -80,6 +80,7 @@ var MigrationService = class {
80
80
  constructor(db) {
81
81
  this.db = db;
82
82
  }
83
+ db;
83
84
  /**
84
85
  * Cloudflare D1 owns migration bookkeeping through `d1_migrations`.
85
86
  * SonicJS intentionally does not create its own tracking table.
@@ -269,5 +270,5 @@ var MigrationService = class {
269
270
  };
270
271
 
271
272
  export { MigrationService, ensureScalarSchema };
272
- //# sourceMappingURL=chunk-73KSHGOT.js.map
273
- //# sourceMappingURL=chunk-73KSHGOT.js.map
273
+ //# sourceMappingURL=chunk-52DAVKDM.js.map
274
+ //# sourceMappingURL=chunk-52DAVKDM.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/db/migrations-bundle.ts","../src/services/document-scalar-schema.ts","../src/services/migrations.ts"],"names":[],"mappings":"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","file":"chunk-52DAVKDM.js","sourcesContent":["/**\n * AUTO-GENERATED FILE - DO NOT EDIT\n * Generated by: scripts/generate-migrations.ts\n * Generated at: 2026-06-30T01:07:09.452Z\n *\n * This file contains all migration SQL bundled for use in Cloudflare Workers\n * where filesystem access is not available at runtime.\n */\n\nexport interface BundledMigration {\n id: string\n name: string\n filename: string\n description: string\n sql: string\n}\n\nexport const bundledMigrations: BundledMigration[] = [\n {\n id: '0001',\n name: 'Core',\n filename: '0001_core.sql',\n description: 'Migration 0001: Core',\n sql: \"-- Migration 0001: Auth tables\\n-- auth_user, auth_session, auth_account, auth_verification + BA plugin tables + RBAC + auth support.\\n-- Only auth_* prefixed tables live here. All content lives in document_* tables (0002_documents.sql).\\n\\n-- ── auth_user ────────────────────────────────────────────────────────────────\\n-- BA user model + SonicJS domain columns as BA additionalFields.\\nCREATE TABLE IF NOT EXISTS auth_user (\\n id TEXT PRIMARY KEY,\\n name TEXT,\\n email TEXT NOT NULL UNIQUE,\\n email_verified INTEGER NOT NULL DEFAULT 0,\\n image TEXT,\\n created_at INTEGER NOT NULL,\\n updated_at INTEGER NOT NULL,\\n -- SonicJS additionalFields\\n first_name TEXT NOT NULL,\\n last_name TEXT NOT NULL,\\n role TEXT NOT NULL DEFAULT 'viewer',\\n -- Platform super-admin: bypasses the multi-tenant membership gate, uses global roles in every\\n -- tenant. Opt-in (default 0); intentionally NOT derived from the 'admin' role.\\n is_super_admin INTEGER NOT NULL DEFAULT 0,\\n avatar TEXT,\\n password_hash TEXT,\\n is_active INTEGER NOT NULL DEFAULT 1,\\n last_login_at INTEGER,\\n phone TEXT,\\n bio TEXT,\\n timezone TEXT DEFAULT 'UTC',\\n language TEXT DEFAULT 'en',\\n email_notifications INTEGER DEFAULT 1,\\n theme TEXT DEFAULT 'dark',\\n invitation_token TEXT,\\n invited_by TEXT,\\n invited_at INTEGER,\\n accepted_invitation_at INTEGER,\\n failed_login_count INTEGER NOT NULL DEFAULT 0,\\n locked_until INTEGER\\n);\\n\\nCREATE INDEX IF NOT EXISTS idx_auth_user_email ON auth_user(email);\\nCREATE INDEX IF NOT EXISTS idx_auth_user_role ON auth_user(role);\\nCREATE INDEX IF NOT EXISTS idx_auth_user_invitation_token ON auth_user(invitation_token);\\nCREATE INDEX IF NOT EXISTS idx_auth_user_locked_until ON auth_user(locked_until) WHERE locked_until IS NOT NULL;\\n\\n-- ── auth_session ─────────────────────────────────────────────────────────────\\nCREATE TABLE IF NOT EXISTS auth_session (\\n id TEXT PRIMARY KEY,\\n user_id TEXT NOT NULL REFERENCES auth_user(id) ON DELETE CASCADE,\\n token TEXT NOT NULL UNIQUE,\\n expires_at INTEGER NOT NULL,\\n ip_address TEXT,\\n user_agent TEXT,\\n created_at INTEGER NOT NULL,\\n updated_at INTEGER NOT NULL\\n);\\nCREATE INDEX IF NOT EXISTS idx_auth_session_user_id ON auth_session(user_id);\\nCREATE INDEX IF NOT EXISTS idx_auth_session_token ON auth_session(token);\\nCREATE INDEX IF NOT EXISTS idx_auth_session_expires_at ON auth_session(expires_at);\\n\\n-- ── auth_account ─────────────────────────────────────────────────────────────\\nCREATE TABLE IF NOT EXISTS auth_account (\\n id TEXT PRIMARY KEY,\\n user_id TEXT NOT NULL REFERENCES auth_user(id) ON DELETE CASCADE,\\n account_id TEXT NOT NULL,\\n provider_id TEXT NOT NULL,\\n access_token TEXT,\\n refresh_token TEXT,\\n access_token_expires_at INTEGER,\\n refresh_token_expires_at INTEGER,\\n scope TEXT,\\n id_token TEXT,\\n password TEXT,\\n created_at INTEGER NOT NULL,\\n updated_at INTEGER NOT NULL\\n);\\nCREATE INDEX IF NOT EXISTS idx_auth_account_user_id ON auth_account(user_id);\\nCREATE INDEX IF NOT EXISTS idx_auth_account_provider ON auth_account(provider_id, account_id);\\n\\n-- ── auth_verification ────────────────────────────────────────────────────────\\n-- Covers email verification, password reset, magic-link tokens, OTP codes.\\nCREATE TABLE IF NOT EXISTS auth_verification (\\n id TEXT PRIMARY KEY,\\n identifier TEXT NOT NULL,\\n value TEXT NOT NULL,\\n expires_at INTEGER NOT NULL,\\n created_at INTEGER NOT NULL,\\n updated_at INTEGER NOT NULL\\n);\\nCREATE INDEX IF NOT EXISTS idx_auth_verification_identifier ON auth_verification(identifier);\\n\\n-- ── BA plugin tables ──────────────────────────────────────────────────────────\\n\\nCREATE TABLE IF NOT EXISTS auth_two_factor (\\n id TEXT PRIMARY KEY,\\n secret TEXT NOT NULL,\\n backup_codes TEXT NOT NULL,\\n user_id TEXT NOT NULL REFERENCES auth_user(id) ON DELETE CASCADE,\\n verified INTEGER NOT NULL DEFAULT 1,\\n created_at INTEGER NOT NULL,\\n updated_at INTEGER NOT NULL\\n);\\nCREATE INDEX IF NOT EXISTS idx_auth_two_factor_user_id ON auth_two_factor(user_id);\\n\\nCREATE TABLE IF NOT EXISTS auth_tenant (\\n id TEXT PRIMARY KEY,\\n name TEXT NOT NULL,\\n slug TEXT NOT NULL UNIQUE,\\n logo TEXT,\\n metadata TEXT,\\n -- SonicJS tenant-resolution fields (BA organization additionalFields):\\n status TEXT NOT NULL DEFAULT 'active',\\n domain TEXT,\\n notes TEXT NOT NULL DEFAULT '',\\n created_at INTEGER NOT NULL,\\n updated_at INTEGER NOT NULL\\n);\\nCREATE INDEX IF NOT EXISTS idx_auth_tenant_domain ON auth_tenant(domain);\\n\\nCREATE TABLE IF NOT EXISTS auth_tenant_member (\\n id TEXT PRIMARY KEY,\\n tenant_id TEXT NOT NULL REFERENCES auth_tenant(id) ON DELETE CASCADE,\\n user_id TEXT NOT NULL REFERENCES auth_user(id) ON DELETE CASCADE,\\n role TEXT NOT NULL DEFAULT 'member',\\n email TEXT,\\n created_at INTEGER NOT NULL,\\n updated_at INTEGER NOT NULL,\\n UNIQUE(tenant_id, user_id)\\n);\\nCREATE INDEX IF NOT EXISTS idx_auth_tenant_member_tenant ON auth_tenant_member(tenant_id);\\nCREATE INDEX IF NOT EXISTS idx_auth_tenant_member_user ON auth_tenant_member(user_id);\\n\\nCREATE TABLE IF NOT EXISTS auth_tenant_invitation (\\n id TEXT PRIMARY KEY,\\n tenant_id TEXT NOT NULL REFERENCES auth_tenant(id) ON DELETE CASCADE,\\n email TEXT NOT NULL,\\n role TEXT NOT NULL DEFAULT 'member',\\n status TEXT NOT NULL DEFAULT 'pending',\\n expires_at INTEGER NOT NULL,\\n inviter_id TEXT REFERENCES auth_user(id) ON DELETE SET NULL,\\n created_at INTEGER NOT NULL,\\n updated_at INTEGER NOT NULL\\n);\\nCREATE INDEX IF NOT EXISTS idx_auth_tenant_invitation_tenant ON auth_tenant_invitation(tenant_id);\\nCREATE INDEX IF NOT EXISTS idx_auth_tenant_invitation_email ON auth_tenant_invitation(email);\\n\\nCREATE TABLE IF NOT EXISTS auth_tenant_team (\\n id TEXT PRIMARY KEY,\\n name TEXT NOT NULL,\\n tenant_id TEXT NOT NULL REFERENCES auth_tenant(id) ON DELETE CASCADE,\\n created_at INTEGER NOT NULL,\\n updated_at INTEGER NOT NULL\\n);\\n\\n-- ── RBAC ─────────────────────────────────────────────────────────────────────\\n-- RBAC roles, verbs, and user-role assignments are document-backed (is_auth doc\\n-- types rbac_role / rbac_verb / rbac_user_roles — see services/rbac.ts). The\\n-- system roles/verbs/grants are seeded at bootstrap by RbacService.ensureSystemRbacSeed().\\n-- No auth_rbac_* tables.\\n\\n-- ── Auth support tables ───────────────────────────────────────────────────────\\nCREATE TABLE IF NOT EXISTS auth_password_history (\\n id TEXT PRIMARY KEY,\\n user_id TEXT NOT NULL REFERENCES auth_user(id) ON DELETE CASCADE,\\n password_hash TEXT NOT NULL,\\n created_at INTEGER NOT NULL\\n);\\nCREATE INDEX IF NOT EXISTS idx_auth_password_history_user_id ON auth_password_history(user_id);\\n\\nCREATE TABLE IF NOT EXISTS auth_api_tokens (\\n id TEXT PRIMARY KEY,\\n name TEXT NOT NULL,\\n token TEXT NOT NULL UNIQUE,\\n user_id TEXT NOT NULL REFERENCES auth_user(id),\\n permissions TEXT NOT NULL,\\n expires_at INTEGER,\\n last_used_at INTEGER,\\n created_at INTEGER NOT NULL\\n);\\nCREATE INDEX IF NOT EXISTS idx_auth_api_tokens_user ON auth_api_tokens(user_id);\\nCREATE INDEX IF NOT EXISTS idx_auth_api_tokens_token ON auth_api_tokens(token);\\n\\n-- User profiles moved to the document model: a `user_profile` document (is_auth type),\\n-- one per user, addressed by slug = userId. See services/document-types-seed.ts and\\n-- plugins/core-plugins/user-profiles/user-profile-document.ts. No auth_user_profiles table.\\n\"\n },\n {\n id: '0002',\n name: 'Documents',\n filename: '0002_documents.sql',\n description: 'Migration 0002: Documents',\n sql: \"-- Migration 0002: Document Schema (v3 greenfield)\\n-- Contains only the new document data model tables, generated columns, and indexes.\\n\\n-- Document type registry\\nCREATE TABLE IF NOT EXISTS document_types (\\n id TEXT PRIMARY KEY,\\n name TEXT NOT NULL UNIQUE,\\n display_name TEXT NOT NULL,\\n description TEXT,\\n schema TEXT NOT NULL DEFAULT '{}',\\n queryable_fields TEXT NOT NULL DEFAULT '[]',\\n settings TEXT NOT NULL DEFAULT '{}',\\n plugin_id TEXT,\\n source TEXT NOT NULL DEFAULT 'code' CHECK (source IN ('code', 'plugin', 'system')),\\n schema_version INTEGER NOT NULL DEFAULT 1,\\n is_system INTEGER NOT NULL DEFAULT 0,\\n is_active INTEGER NOT NULL DEFAULT 1,\\n is_auth INTEGER NOT NULL DEFAULT 0,\\n created_at INTEGER NOT NULL DEFAULT (unixepoch()),\\n updated_at INTEGER NOT NULL DEFAULT (unixepoch())\\n);\\n\\nCREATE INDEX IF NOT EXISTS idx_document_types_plugin ON document_types(plugin_id);\\nCREATE INDEX IF NOT EXISTS idx_document_types_active ON document_types(is_active);\\n\\n-- Documents: canonical document rows and historical versions.\\nCREATE TABLE IF NOT EXISTS documents (\\n id TEXT PRIMARY KEY,\\n root_id TEXT NOT NULL,\\n type_id TEXT NOT NULL REFERENCES document_types(id),\\n type_version INTEGER NOT NULL DEFAULT 1,\\n\\n version_of_id TEXT REFERENCES documents(id),\\n version_number INTEGER NOT NULL DEFAULT 1,\\n\\n is_current_draft INTEGER NOT NULL DEFAULT 1,\\n is_published INTEGER NOT NULL DEFAULT 0,\\n status TEXT NOT NULL DEFAULT 'draft' CHECK (status IN ('draft', 'published', 'archived')),\\n\\n parent_root_id TEXT NOT NULL DEFAULT '',\\n slug TEXT,\\n path TEXT,\\n title TEXT,\\n zone TEXT,\\n sort_order INTEGER NOT NULL DEFAULT 0,\\n visible INTEGER NOT NULL DEFAULT 1,\\n\\n published_at INTEGER,\\n scheduled_at INTEGER,\\n expires_at INTEGER,\\n deleted_at INTEGER,\\n\\n tenant_id TEXT NOT NULL DEFAULT 'default',\\n locale TEXT NOT NULL DEFAULT 'default',\\n translation_group_id TEXT NOT NULL DEFAULT '',\\n\\n data TEXT NOT NULL DEFAULT '{}',\\n metadata TEXT NOT NULL DEFAULT '{}',\\n\\n owner_id TEXT,\\n created_by TEXT,\\n updated_by TEXT,\\n created_at INTEGER NOT NULL DEFAULT (unixepoch()),\\n updated_at INTEGER NOT NULL DEFAULT (unixepoch())\\n);\\n\\n-- Queryable scalar fields (VIRTUAL generated columns) and their q_* filter indexes\\n-- are AUTO-GENERATED at runtime from each document type's queryableFields config —\\n-- see DocumentTypeRegistry.register() -> ensureScalarSchema() (document-scalar-schema.ts).\\n-- Do not hand-add q_* columns/indexes here; declare the field in the type instead.\\n\\n-- Revision chain\\nCREATE INDEX IF NOT EXISTS idx_documents_root ON documents(root_id, version_number DESC);\\n\\n-- List / lifecycle\\nCREATE INDEX IF NOT EXISTS idx_documents_published ON documents(tenant_id, type_id, locale, is_published)\\n WHERE is_published = 1 AND deleted_at IS NULL;\\nCREATE INDEX IF NOT EXISTS idx_documents_drafts ON documents(tenant_id, type_id, status, is_current_draft)\\n WHERE is_current_draft = 1;\\nCREATE INDEX IF NOT EXISTS idx_documents_parent ON documents(tenant_id, parent_root_id, sort_order, is_published);\\nCREATE INDEX IF NOT EXISTS idx_documents_path ON documents(tenant_id, path);\\nCREATE INDEX IF NOT EXISTS idx_documents_translation ON documents(translation_group_id, locale);\\nCREATE INDEX IF NOT EXISTS idx_documents_deleted ON documents(deleted_at);\\nCREATE INDEX IF NOT EXISTS idx_documents_scheduled ON documents(scheduled_at) WHERE scheduled_at IS NOT NULL;\\nCREATE INDEX IF NOT EXISTS idx_documents_expires ON documents(expires_at) WHERE expires_at IS NOT NULL;\\n\\n-- Stable keyset/cursor pagination for published lists\\nCREATE INDEX IF NOT EXISTS idx_documents_published_cursor\\n ON documents(tenant_id, type_id, updated_at DESC, id DESC)\\n WHERE is_published = 1 AND deleted_at IS NULL;\\n\\n-- (q_* generated-column filter indexes are auto-created at runtime — see note above.)\\n\\n-- Partial unique indexes: the hard concurrency guarantees for draft/publish invariants.\\nCREATE UNIQUE INDEX IF NOT EXISTS idx_documents_one_current_draft\\n ON documents(root_id) WHERE is_current_draft = 1;\\nCREATE UNIQUE INDEX IF NOT EXISTS idx_documents_one_published\\n ON documents(root_id) WHERE is_published = 1;\\nCREATE UNIQUE INDEX IF NOT EXISTS idx_documents_unique_version\\n ON documents(root_id, version_number);\\nCREATE UNIQUE INDEX IF NOT EXISTS idx_documents_unique_slug\\n ON documents(tenant_id, locale, type_id, parent_root_id, slug)\\n WHERE is_current_draft = 1 AND deleted_at IS NULL AND slug IS NOT NULL;\\nCREATE UNIQUE INDEX IF NOT EXISTS idx_documents_one_translation_per_locale\\n ON documents(tenant_id, translation_group_id, locale)\\n WHERE is_current_draft = 1 AND translation_group_id <> '';\\n\\n-- Document references: typed document-to-document edges.\\nCREATE TABLE IF NOT EXISTS document_references (\\n id TEXT PRIMARY KEY,\\n tenant_id TEXT NOT NULL,\\n from_root_id TEXT NOT NULL,\\n from_document_id TEXT NOT NULL REFERENCES documents(id) ON DELETE CASCADE,\\n field_name TEXT NOT NULL,\\n ordinal INTEGER NOT NULL DEFAULT 0,\\n to_root_id TEXT NOT NULL,\\n ref_strength TEXT NOT NULL DEFAULT 'weak' CHECK (ref_strength IN ('strong', 'weak')),\\n created_at INTEGER NOT NULL DEFAULT (unixepoch())\\n);\\n\\nCREATE INDEX IF NOT EXISTS idx_docref_to ON document_references(tenant_id, to_root_id);\\nCREATE INDEX IF NOT EXISTS idx_docref_from ON document_references(from_document_id);\\nCREATE UNIQUE INDEX IF NOT EXISTS idx_docref_unique\\n ON document_references(from_document_id, field_name, ordinal);\\n\\n-- Document facets: indexed rows for multi-valued scalar fields (e.g. tags arrays).\\nCREATE TABLE IF NOT EXISTS document_facets (\\n id TEXT PRIMARY KEY,\\n tenant_id TEXT NOT NULL,\\n document_id TEXT NOT NULL REFERENCES documents(id) ON DELETE CASCADE,\\n root_id TEXT NOT NULL,\\n type_id TEXT NOT NULL,\\n field_name TEXT NOT NULL,\\n ordinal INTEGER NOT NULL DEFAULT 0,\\n value_text TEXT,\\n value_number REAL,\\n created_at INTEGER NOT NULL DEFAULT (unixepoch())\\n);\\n\\nCREATE INDEX IF NOT EXISTS idx_facets_lookup ON document_facets(tenant_id, type_id, field_name, value_text);\\nCREATE INDEX IF NOT EXISTS idx_facets_doc ON document_facets(document_id);\\nCREATE UNIQUE INDEX IF NOT EXISTS idx_facets_unique\\n ON document_facets(document_id, field_name, ordinal);\\n\\n-- Document permissions: per-document ACL overrides.\\nCREATE TABLE IF NOT EXISTS document_permissions (\\n id TEXT PRIMARY KEY,\\n tenant_id TEXT NOT NULL,\\n root_id TEXT NOT NULL,\\n principal_type TEXT NOT NULL CHECK (principal_type IN ('user', 'role', 'group', 'public', 'token')),\\n principal_id TEXT NOT NULL,\\n permission TEXT NOT NULL CHECK (permission IN ('read', 'create', 'update', 'delete', 'publish', 'manage')),\\n effect TEXT NOT NULL DEFAULT 'allow' CHECK (effect IN ('allow', 'deny')),\\n inherited INTEGER NOT NULL DEFAULT 0,\\n created_at INTEGER NOT NULL DEFAULT (unixepoch()),\\n created_by TEXT\\n);\\n\\nCREATE INDEX IF NOT EXISTS idx_document_permissions_root ON document_permissions(tenant_id, root_id);\\nCREATE INDEX IF NOT EXISTS idx_document_permissions_principal\\n ON document_permissions(tenant_id, principal_type, principal_id, permission);\\nCREATE UNIQUE INDEX IF NOT EXISTS idx_document_permissions_unique\\n ON document_permissions(root_id, principal_type, principal_id, permission);\\n\"\n }\n]\n\n// Map for quick lookup by ID\nexport const migrationsByIdMap = new Map<string, BundledMigration>(\n bundledMigrations.map(m => [m.id, m])\n)\n\n// Get migration SQL by ID\nexport function getMigrationSQLById(id: string): string | null {\n return migrationsByIdMap.get(id)?.sql ?? null\n}\n\n// Get all migration info (without SQL for lighter payloads)\nexport function getMigrationList(): Array<Omit<BundledMigration, 'sql'>> {\n return bundledMigrations.map(({ sql, ...rest }) => rest)\n}\n","import { D1Database } from '@cloudflare/workers-types'\nimport type { QueryableField } from '../schemas/document'\n\n// Identifiers and JSON paths are interpolated into DDL (they cannot be bound), so\n// they are format-guarded here. Source is trusted code config, not user input —\n// this is defense-in-depth, mirroring document-repository.ts.\nconst SAFE_IDENTIFIER = /^[a-z_][a-z0-9_]*$/\n\n/** Map a queryable field's logical type to a SQLite column affinity. */\nfunction affinity(type?: QueryableField['type']): 'TEXT' | 'INTEGER' | 'REAL' {\n if (type === 'number') return 'REAL'\n if (type === 'integer' || type === 'boolean' || type === 'date') return 'INTEGER'\n return 'TEXT'\n}\n\nconst slug = (s: string) => s.toLowerCase().replace(/[^a-z0-9]+/g, '_').replace(/^_+|_+$/g, '')\n\n/**\n * Authoritative generated-column name for a scalar field. An explicit `column`\n * always wins (back-compat with every existing type definition); otherwise it is\n * derived deterministically from the type id + field name. The repository reads\n * the same `column`/derivation when building filter SQL, so the two never drift.\n */\nexport function resolveColumn(typeId: string, f: QueryableField): string {\n if (f.column) return f.column\n const name = `q_${slug(typeId)}_${slug(f.name)}`\n return name.length <= 60 ? name : `q_${slug(typeId).slice(0, 20)}_${slug(f.name).slice(0, 20)}`\n}\n\n/**\n * Idempotently ensure the `documents` table has a VIRTUAL generated column and a\n * filter/sort index for each of a type's scalar queryable fields. Safe to call on\n * every registration and every bootstrap: existing columns/indexes are skipped,\n * and a concurrent add surfaces as a swallowed \"duplicate column name\".\n *\n * Facet and reference fields need no DDL (generic document_facets /\n * document_references tables), so they are ignored here.\n *\n * Returns the columns it actually created (empty when all already existed).\n */\nexport async function ensureScalarSchema(\n db: D1Database,\n typeId: string,\n fields: QueryableField[],\n): Promise<string[]> {\n const scalars = fields.filter((f) => f.kind === 'scalar')\n if (scalars.length === 0) return []\n\n // pragma_table_info does NOT list VIRTUAL generated columns — use table_xinfo, which does.\n let existing = new Set<string>()\n try {\n const info = await db.prepare(\"SELECT name FROM pragma_table_xinfo('documents')\").all()\n existing = new Set((info?.results ?? []).map((r: any) => r.name))\n } catch {\n // table_xinfo unavailable — fall back to attempting every ALTER (duplicate errors swallowed).\n }\n\n const added: string[] = []\n for (const f of scalars) {\n const col = resolveColumn(typeId, f)\n if (!SAFE_IDENTIFIER.test(col)) {\n console.error(`[scalar-schema] unsafe column name '${col}' for ${typeId}.${f.name} — skipped`)\n continue\n }\n const path = f.path ?? `$.${f.name}`\n if (path.includes(\"'\")) {\n console.error(`[scalar-schema] unsafe json path for ${col} (${typeId}.${f.name}) — skipped`)\n continue\n }\n\n if (!existing.has(col)) {\n try {\n await db\n .prepare(`ALTER TABLE documents ADD COLUMN ${col} ${affinity(f.type)} AS (json_extract(data, '${path}')) VIRTUAL`)\n .run()\n added.push(col)\n console.log(`[scalar-schema] added documents.${col} for type '${typeId}'`)\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error)\n if (!msg.includes('duplicate column name')) {\n console.error(`[scalar-schema] failed to add documents.${col}:`, msg)\n continue\n }\n }\n }\n\n // One general index per column: the leading (tenant_id, type_id, col) prefix\n // serves every equality filter the repository builds; the trailing\n // (updated_at DESC, id DESC) matches the default keyset sort/cursor. Non-partial\n // so a single index covers both draft and published lists.\n try {\n await db\n .prepare(`CREATE INDEX IF NOT EXISTS idx_${col} ON documents(tenant_id, type_id, ${col}, updated_at DESC, id DESC)`)\n .run()\n } catch (error) {\n console.error(`[scalar-schema] failed to create idx_${col}:`, error instanceof Error ? error.message : String(error))\n }\n }\n return added\n}\n","import { D1Database } from '@cloudflare/workers-types'\nimport { bundledMigrations } from '../db/migrations-bundle'\nimport { ensureScalarSchema } from './document-scalar-schema'\nimport type { QueryableField } from '../schemas/document'\n\nexport interface Migration {\n id: string\n name: string\n filename: string\n description?: string\n applied: boolean\n appliedAt?: string\n size?: number\n}\n\nexport interface MigrationStatus {\n totalMigrations: number\n appliedMigrations: number\n pendingMigrations: number\n lastApplied?: string\n migrations: Migration[]\n}\n\nexport class MigrationService {\n constructor(private db: D1Database) {}\n\n /**\n * Cloudflare D1 owns migration bookkeeping through `d1_migrations`.\n * SonicJS intentionally does not create its own tracking table.\n */\n async initializeMigrationsTable(): Promise<void> {\n // Kept as a no-op for compatibility with older callers.\n }\n\n /**\n * Get all available migrations from the bundled migrations\n */\n async getAvailableMigrations(): Promise<Migration[]> {\n const migrations: Migration[] = []\n const appliedMigrations = await this.getD1AppliedMigrations()\n await this.ensureSchemaCompatibility()\n\n // Use bundled migrations as the source of truth\n for (const bundled of bundledMigrations) {\n const applied = appliedMigrations.has(bundled.id)\n const appliedData = appliedMigrations.get(bundled.id)\n\n migrations.push({\n id: bundled.id,\n name: bundled.name,\n filename: bundled.filename,\n description: bundled.description,\n applied,\n appliedAt: applied ? appliedData?.applied_at : undefined,\n size: bundled.sql.length\n })\n }\n\n return migrations\n }\n\n /**\n * Read Wrangler/D1's canonical migration table. If the table is absent, no\n * migrations have been applied by the supported migration runner yet.\n */\n private async getD1AppliedMigrations(): Promise<Map<string, any>> {\n try {\n const appliedResult = await this.db.prepare(\n 'SELECT name, applied_at FROM d1_migrations ORDER BY applied_at ASC'\n ).all()\n\n return new Map(\n (appliedResult.results ?? [])\n .map((row: any) => {\n const filename = String(row.name ?? '')\n const id = filename.match(/^(\\d+)/)?.[1]\n if (!id) return null\n return [id, {\n id,\n name: filename,\n filename,\n applied_at: row.applied_at\n }]\n })\n .filter((entry): entry is [string, any] => entry !== null)\n )\n } catch (error) {\n return new Map()\n }\n }\n\n /**\n * Run idempotent compatibility repairs that are safe outside migration state.\n */\n async ensureSchemaCompatibility(): Promise<void> {\n if (await this.checkTablesExist(['documents'])) {\n await this.ensureDocumentGeneratedColumns()\n }\n }\n\n /**\n * Ensure the `documents` table exposes every queryable VIRTUAL generated column + index (D45).\n * Data-driven repair: reconciles from each active type's `queryable_fields` rather than a hardcoded\n * list, so it stays in sync with whatever types are registered. Generation of these columns is owned\n * by DocumentTypeRegistry.register() (via ensureScalarSchema); this pass is a bootstrap safety net for\n * a DB that has document_types rows but lost columns (e.g. table rebuilt). Idempotent.\n */\n private async ensureDocumentGeneratedColumns(): Promise<void> {\n if (!(await this.checkTablesExist(['document_types']))) return\n const rows = await this.db\n .prepare('SELECT id, queryable_fields FROM document_types WHERE is_active = 1')\n .all<{ id: string; queryable_fields: string }>()\n for (const row of rows.results ?? []) {\n let fields: QueryableField[]\n try {\n fields = JSON.parse(row.queryable_fields)\n } catch {\n continue\n }\n await ensureScalarSchema(this.db, row.id, fields)\n }\n }\n\n /**\n * Check if specific tables exist in the database\n */\n private async checkTablesExist(tableNames: string[]): Promise<boolean> {\n try {\n for (const tableName of tableNames) {\n const result = await this.db.prepare(\n `SELECT name FROM sqlite_master WHERE type='table' AND name=?`\n ).bind(tableName).first()\n\n if (!result) {\n return false\n }\n }\n return true\n } catch (error) {\n return false\n }\n }\n\n /**\n * Check if a specific column exists in a table\n */\n private async checkColumnExists(tableName: string, columnName: string): Promise<boolean> {\n try {\n const result = await this.db.prepare(\n `SELECT * FROM pragma_table_info(?) WHERE name = ?`\n ).bind(tableName, columnName).first()\n\n return !!result\n } catch (error) {\n return false\n }\n }\n\n /**\n * Get migration status summary\n */\n async getMigrationStatus(): Promise<MigrationStatus> {\n const migrations = await this.getAvailableMigrations()\n const appliedMigrations = migrations.filter(m => m.applied)\n const pendingMigrations = migrations.filter(m => !m.applied)\n\n const lastApplied = appliedMigrations.length > 0\n ? appliedMigrations[appliedMigrations.length - 1]?.appliedAt\n : undefined\n\n return {\n totalMigrations: migrations.length,\n appliedMigrations: appliedMigrations.length,\n pendingMigrations: pendingMigrations.length,\n lastApplied,\n migrations\n }\n }\n\n /**\n * D1 migration state is managed by Wrangler.\n */\n async markMigrationApplied(migrationId: string, name: string, filename: string): Promise<void> {\n void migrationId\n void name\n void filename\n }\n\n /**\n * D1 migration state is managed by Wrangler.\n */\n async removeMigrationApplied(migrationId: string): Promise<void> {\n void migrationId\n }\n\n /**\n * Check if a specific migration has been applied\n */\n async isMigrationApplied(migrationId: string): Promise<boolean> {\n const appliedMigrations = await this.getD1AppliedMigrations()\n return appliedMigrations.has(migrationId)\n }\n\n /**\n * Get the last applied migration\n */\n async getLastAppliedMigration(): Promise<Migration | null> {\n const migrations = await this.getAvailableMigrations()\n return migrations.filter(m => m.applied).at(-1) ?? null\n }\n\n /**\n * Run pending migrations\n */\n async runPendingMigrations(): Promise<{ success: boolean; message: string; applied: string[]; errors: string[] }> {\n return {\n success: false,\n message: 'Migrations are managed by Cloudflare D1. Run `wrangler d1 migrations apply DB --local` or `wrangler d1 migrations apply DB --remote`.',\n applied: [],\n errors: []\n }\n }\n\n /**\n * Validate database schema\n */\n async validateSchema(): Promise<{ valid: boolean; issues: string[] }> {\n const issues: string[] = []\n\n // Basic table existence checks\n const requiredTables = [\n 'users', 'documents', 'document_types'\n ]\n\n for (const table of requiredTables) {\n try {\n await this.db.prepare(`SELECT COUNT(*) FROM ${table} LIMIT 1`).first()\n } catch (error) {\n issues.push(`Missing table: ${table}`)\n }\n }\n\n return {\n valid: issues.length === 0,\n issues\n }\n }\n}\n"]}