@sonicjs-cms/core 3.0.0-beta.2 → 3.0.0-beta.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (170) hide show
  1. package/README.md +48 -49
  2. package/dist/admin-documents-form.template-DDSH6ROU.js +6 -0
  3. package/dist/{admin-documents-form.template-NLSI6Z42.js.map → admin-documents-form.template-DDSH6ROU.js.map} +1 -1
  4. package/dist/admin-documents-form.template-LSZKGA5J.cjs +19 -0
  5. package/dist/{admin-layout-catalyst.template-WHJGSWWD.js.map → admin-documents-form.template-LSZKGA5J.cjs.map} +1 -1
  6. package/dist/{filter-bar.template-DlVYMk-T.d.ts → admin-layout-catalyst.template-DrwDUfsE.d.cts} +25 -1
  7. package/dist/{filter-bar.template-DlVYMk-T.d.cts → admin-layout-catalyst.template-DrwDUfsE.d.ts} +25 -1
  8. package/dist/admin-layout-catalyst.template-KDHKVLXR.cjs +21 -0
  9. package/dist/{admin-layout-catalyst.template-ZK5HD545.cjs.map → admin-layout-catalyst.template-KDHKVLXR.cjs.map} +1 -1
  10. package/dist/admin-layout-catalyst.template-YQ4EMF2J.js +7 -0
  11. package/dist/{admin-documents-form.template-KN7JF66Q.cjs.map → admin-layout-catalyst.template-YQ4EMF2J.js.map} +1 -1
  12. package/dist/{app-Bo0X1OWX.d.ts → app-01M0dIwt.d.ts} +1 -1
  13. package/dist/{app-Do66yCcV.d.cts → app-aj39TGHB.d.cts} +1 -1
  14. package/dist/{chunk-ZEZ245PW.js → chunk-2XAQTPAE.js} +4 -236
  15. package/dist/chunk-2XAQTPAE.js.map +1 -0
  16. package/dist/{chunk-BDDABDAB.cjs → chunk-36Z3AKX3.cjs} +3 -239
  17. package/dist/chunk-36Z3AKX3.cjs.map +1 -0
  18. package/dist/{chunk-VXE42MYF.cjs → chunk-3E7IROND.cjs} +695 -428
  19. package/dist/chunk-3E7IROND.cjs.map +1 -0
  20. package/dist/{chunk-BLMTL57B.js → chunk-3TMTYJAJ.js} +26 -4
  21. package/dist/chunk-3TMTYJAJ.js.map +1 -0
  22. package/dist/{chunk-AAWNRBRB.cjs → chunk-4SHNHNRP.cjs} +95 -20
  23. package/dist/chunk-4SHNHNRP.cjs.map +1 -0
  24. package/dist/{chunk-QAYFOER6.cjs → chunk-5ARIHAGN.cjs} +285 -3
  25. package/dist/chunk-5ARIHAGN.cjs.map +1 -0
  26. package/dist/{chunk-XW56B23A.cjs → chunk-5RSB5SEK.cjs} +4 -4
  27. package/dist/{chunk-XW56B23A.cjs.map → chunk-5RSB5SEK.cjs.map} +1 -1
  28. package/dist/{chunk-VD2EA3WT.js → chunk-5UCMLBRQ.js} +328 -62
  29. package/dist/chunk-5UCMLBRQ.js.map +1 -0
  30. package/dist/{chunk-3TB6AT6X.js → chunk-5V62WT6M.js} +35 -4
  31. package/dist/chunk-5V62WT6M.js.map +1 -0
  32. package/dist/{chunk-LRZIAW7U.cjs → chunk-AQJEMVAY.cjs} +3 -3
  33. package/dist/chunk-AQJEMVAY.cjs.map +1 -0
  34. package/dist/{chunk-WULONYGB.cjs → chunk-CRGUD4KC.cjs} +9 -9
  35. package/dist/{chunk-WULONYGB.cjs.map → chunk-CRGUD4KC.cjs.map} +1 -1
  36. package/dist/{chunk-NLJVSER2.js → chunk-DSXEVMOM.js} +3 -2
  37. package/dist/chunk-DSXEVMOM.js.map +1 -0
  38. package/dist/{chunk-H2AXVCLS.cjs → chunk-DTGCXWWM.cjs} +141 -74
  39. package/dist/chunk-DTGCXWWM.cjs.map +1 -0
  40. package/dist/{chunk-NUKJ54GA.cjs → chunk-GMMCCIQO.cjs} +6 -6
  41. package/dist/{chunk-NUKJ54GA.cjs.map → chunk-GMMCCIQO.cjs.map} +1 -1
  42. package/dist/{chunk-6OUHGKFD.js → chunk-GMZ5TGYP.js} +3 -3
  43. package/dist/{chunk-6OUHGKFD.js.map → chunk-GMZ5TGYP.js.map} +1 -1
  44. package/dist/{chunk-6JQOUUOB.js → chunk-JQISFW6U.js} +3 -3
  45. package/dist/{chunk-6JQOUUOB.js.map → chunk-JQISFW6U.js.map} +1 -1
  46. package/dist/{chunk-NAVPFIG5.cjs → chunk-K623Q6WD.cjs} +35 -3
  47. package/dist/chunk-K623Q6WD.cjs.map +1 -0
  48. package/dist/{chunk-JEQ7FLOD.cjs → chunk-KIGVVO6N.cjs} +16 -10
  49. package/dist/chunk-KIGVVO6N.cjs.map +1 -0
  50. package/dist/{chunk-2CB4KY7I.cjs → chunk-LTZ5WYOK.cjs} +29 -7
  51. package/dist/chunk-LTZ5WYOK.cjs.map +1 -0
  52. package/dist/{chunk-YHSQVQXX.js → chunk-MYQ7KZUQ.js} +135 -68
  53. package/dist/chunk-MYQ7KZUQ.js.map +1 -0
  54. package/dist/{chunk-DNQCEKUK.cjs → chunk-N32OWET6.cjs} +5 -5
  55. package/dist/{chunk-DNQCEKUK.cjs.map → chunk-N32OWET6.cjs.map} +1 -1
  56. package/dist/{chunk-HDWE5FRJ.js → chunk-OBA2RYZN.js} +3 -3
  57. package/dist/{chunk-HDWE5FRJ.js.map → chunk-OBA2RYZN.js.map} +1 -1
  58. package/dist/{chunk-MVIZJOO5.cjs → chunk-PXNTCCPE.cjs} +8 -8
  59. package/dist/{chunk-MVIZJOO5.cjs.map → chunk-PXNTCCPE.cjs.map} +1 -1
  60. package/dist/{chunk-ZGGXCFR6.js → chunk-RDH6PUOP.js} +282 -4
  61. package/dist/chunk-RDH6PUOP.js.map +1 -0
  62. package/dist/{chunk-EF2NQUIQ.js → chunk-RMRJGMDE.js} +3 -3
  63. package/dist/{chunk-EF2NQUIQ.js.map → chunk-RMRJGMDE.js.map} +1 -1
  64. package/dist/{chunk-IVPRUGTY.js → chunk-SOZUG52O.js} +4 -4
  65. package/dist/{chunk-IVPRUGTY.js.map → chunk-SOZUG52O.js.map} +1 -1
  66. package/dist/{chunk-DSA4UX5B.cjs → chunk-TQG5FNNR.cjs} +3 -2
  67. package/dist/chunk-TQG5FNNR.cjs.map +1 -0
  68. package/dist/{chunk-GCDZZNIN.js → chunk-UWUP2VMT.js} +16 -10
  69. package/dist/chunk-UWUP2VMT.js.map +1 -0
  70. package/dist/{chunk-IESEVHXL.js → chunk-VVYVFCML.js} +12 -3
  71. package/dist/chunk-VVYVFCML.js.map +1 -0
  72. package/dist/{chunk-NMPEMSU4.js → chunk-W53J3BJ2.js} +3 -3
  73. package/dist/chunk-W53J3BJ2.js.map +1 -0
  74. package/dist/{chunk-RZ6H7OZK.js → chunk-WCA4VENG.js} +87 -12
  75. package/dist/chunk-WCA4VENG.js.map +1 -0
  76. package/dist/{chunk-HIKBY7MS.cjs → chunk-XWVDSM2L.cjs} +12 -3
  77. package/dist/chunk-XWVDSM2L.cjs.map +1 -0
  78. package/dist/{collection-config-JgHOpFCG.d.ts → collection-config-BTzAvKt2.d.cts} +25 -0
  79. package/dist/{collection-config-JgHOpFCG.d.cts → collection-config-BTzAvKt2.d.ts} +25 -0
  80. package/dist/config-6FB2BXMP.js +6 -0
  81. package/dist/{config-HFXANXCC.js.map → config-6FB2BXMP.js.map} +1 -1
  82. package/dist/config-OCH7S4WK.cjs +19 -0
  83. package/dist/{config-ON6FNMYX.cjs.map → config-OCH7S4WK.cjs.map} +1 -1
  84. package/dist/{define-plugin-BzNHc1ZI.d.ts → define-plugin-BYIey6sp.d.ts} +1 -1
  85. package/dist/{define-plugin-IWDKYaVm.d.cts → define-plugin-DsKiGu1q.d.cts} +1 -1
  86. package/dist/document-projection-4HG75S5S.js +4 -0
  87. package/dist/{document-projection-YYMC6I4U.js.map → document-projection-4HG75S5S.js.map} +1 -1
  88. package/dist/document-projection-JQHSTSFD.cjs +13 -0
  89. package/dist/{document-projection-TDWRJX3Z.cjs.map → document-projection-JQHSTSFD.cjs.map} +1 -1
  90. package/dist/index.cjs +928 -378
  91. package/dist/index.cjs.map +1 -1
  92. package/dist/index.d.cts +200 -12
  93. package/dist/index.d.ts +200 -12
  94. package/dist/index.js +612 -75
  95. package/dist/index.js.map +1 -1
  96. package/dist/middleware.cjs +37 -34
  97. package/dist/middleware.d.cts +2 -2
  98. package/dist/middleware.d.ts +2 -2
  99. package/dist/middleware.js +8 -5
  100. package/dist/migrations-HZJ6U6SX.js +4 -0
  101. package/dist/{migrations-WCAVBD7C.js.map → migrations-HZJ6U6SX.js.map} +1 -1
  102. package/dist/migrations-VQAFXMU7.cjs +13 -0
  103. package/dist/{migrations-NJJWQUKK.cjs.map → migrations-VQAFXMU7.cjs.map} +1 -1
  104. package/dist/{plugin-bootstrap-B8ThJU21.d.cts → plugin-bootstrap-BHWQ2df8.d.cts} +1 -1
  105. package/dist/{plugin-bootstrap-qu8hJgUt.d.ts → plugin-bootstrap-Bj4fxX1q.d.ts} +1 -1
  106. package/dist/plugins.cjs +40 -40
  107. package/dist/plugins.d.cts +2 -2
  108. package/dist/plugins.d.ts +2 -2
  109. package/dist/plugins.js +3 -3
  110. package/dist/rbac-7QZ4JZ2E.cjs +14 -0
  111. package/dist/{rbac-VONLJJKB.cjs.map → rbac-7QZ4JZ2E.cjs.map} +1 -1
  112. package/dist/rbac-Y43IEQOP.js +5 -0
  113. package/dist/{rbac-O73MFKDA.js.map → rbac-Y43IEQOP.js.map} +1 -1
  114. package/dist/routes.cjs +34 -34
  115. package/dist/routes.d.cts +2 -2
  116. package/dist/routes.d.ts +2 -2
  117. package/dist/routes.js +14 -14
  118. package/dist/services.cjs +42 -42
  119. package/dist/services.d.cts +16 -3
  120. package/dist/services.d.ts +16 -3
  121. package/dist/services.js +3 -3
  122. package/dist/{telemetry-B9vIV4wh.d.cts → telemetry-Cku1ax74.d.cts} +1 -1
  123. package/dist/{telemetry-B9vIV4wh.d.ts → telemetry-Cku1ax74.d.ts} +1 -1
  124. package/dist/templates.cjs +17 -17
  125. package/dist/templates.d.cts +2 -24
  126. package/dist/templates.d.ts +2 -24
  127. package/dist/templates.js +3 -3
  128. package/dist/{types-Dea1eNxU.d.ts → types-DT7XN5TX.d.cts} +1 -1
  129. package/dist/{types-Dea1eNxU.d.cts → types-DT7XN5TX.d.ts} +1 -1
  130. package/dist/types.d.cts +2 -2
  131. package/dist/types.d.ts +2 -2
  132. package/dist/utils.cjs +8 -8
  133. package/dist/utils.d.cts +2 -2
  134. package/dist/utils.d.ts +2 -2
  135. package/dist/utils.js +2 -2
  136. package/package.json +1 -1
  137. package/dist/admin-documents-form.template-KN7JF66Q.cjs +0 -19
  138. package/dist/admin-documents-form.template-NLSI6Z42.js +0 -6
  139. package/dist/admin-layout-catalyst.template-WHJGSWWD.js +0 -7
  140. package/dist/admin-layout-catalyst.template-ZK5HD545.cjs +0 -17
  141. package/dist/chunk-2CB4KY7I.cjs.map +0 -1
  142. package/dist/chunk-3TB6AT6X.js.map +0 -1
  143. package/dist/chunk-AAWNRBRB.cjs.map +0 -1
  144. package/dist/chunk-BDDABDAB.cjs.map +0 -1
  145. package/dist/chunk-BLMTL57B.js.map +0 -1
  146. package/dist/chunk-DSA4UX5B.cjs.map +0 -1
  147. package/dist/chunk-GCDZZNIN.js.map +0 -1
  148. package/dist/chunk-H2AXVCLS.cjs.map +0 -1
  149. package/dist/chunk-HIKBY7MS.cjs.map +0 -1
  150. package/dist/chunk-IESEVHXL.js.map +0 -1
  151. package/dist/chunk-JEQ7FLOD.cjs.map +0 -1
  152. package/dist/chunk-LRZIAW7U.cjs.map +0 -1
  153. package/dist/chunk-NAVPFIG5.cjs.map +0 -1
  154. package/dist/chunk-NLJVSER2.js.map +0 -1
  155. package/dist/chunk-NMPEMSU4.js.map +0 -1
  156. package/dist/chunk-QAYFOER6.cjs.map +0 -1
  157. package/dist/chunk-RZ6H7OZK.js.map +0 -1
  158. package/dist/chunk-VD2EA3WT.js.map +0 -1
  159. package/dist/chunk-VXE42MYF.cjs.map +0 -1
  160. package/dist/chunk-YHSQVQXX.js.map +0 -1
  161. package/dist/chunk-ZEZ245PW.js.map +0 -1
  162. package/dist/chunk-ZGGXCFR6.js.map +0 -1
  163. package/dist/config-HFXANXCC.js +0 -6
  164. package/dist/config-ON6FNMYX.cjs +0 -19
  165. package/dist/document-projection-TDWRJX3Z.cjs +0 -13
  166. package/dist/document-projection-YYMC6I4U.js +0 -4
  167. package/dist/migrations-NJJWQUKK.cjs +0 -13
  168. package/dist/migrations-WCAVBD7C.js +0 -4
  169. package/dist/rbac-O73MFKDA.js +0 -5
  170. package/dist/rbac-VONLJJKB.cjs +0 -14
package/dist/index.js CHANGED
@@ -1,41 +1,43 @@
1
- import { createAuth } from './chunk-IVPRUGTY.js';
2
- import { getEmailService, hasEmailService, setEmailService, invalidateVariablesCache, resolveVariablesInObject, resolveDocScope, denyIfNotAllowed, DocumentRepository, dispatchHookEvent, getCustomData, renderTable, getVariablesCached, setVariablesCache, TenantService, isValidMemberRole, renderConfirmationDialog, getConfirmationDialogScript, VALID_MEMBER_ROLES, userProfilesPlugin, lexicalEditorPlugin, api_media_default, api_system_default, apiDocumentsRoutes, api_default, adminDocumentsRoutes, admin_api_default, adminCollectionsRoutes, adminSettingsRoutes, router2, admin_content_default, adminMediaRoutes, router, adminPluginRoutes, adminLogsRoutes, userRoutes, auth_default, test_cleanup_default } from './chunk-VD2EA3WT.js';
3
- export { ROUTES_INFO, admin_api_default as adminApiRoutes, adminCheckboxRoutes, adminCollectionsRoutes, admin_content_default as adminContentRoutes, router as adminDashboardRoutes, adminLogsRoutes, adminMediaRoutes, adminPluginRoutes, adminSettingsRoutes, userRoutes as adminUsersRoutes, api_content_crud_default as apiContentCrudRoutes, api_media_default as apiMediaRoutes, api_default as apiRoutes, api_system_default as apiSystemRoutes, auth_default as authRoutes, createUserProfilesPlugin, defineUserProfile, getUserProfileConfig, userProfilesPlugin } from './chunk-VD2EA3WT.js';
4
- import './chunk-IESEVHXL.js';
5
- import './chunk-EF2NQUIQ.js';
6
- import { SettingsService, setAppInstance } from './chunk-ZEZ245PW.js';
7
- export { Logger, getLogger, initLogger } from './chunk-ZEZ245PW.js';
1
+ import { createAuth } from './chunk-SOZUG52O.js';
2
+ import { getEmailService, hasEmailService, setEmailService, invalidateVariablesCache, resolveVariablesInObject, resolveDocScope, denyIfNotAllowed, DocumentRepository, dispatchHookEvent, getCustomData, createDocumentSchema, renderTable, getVariablesCached, setVariablesCache, TenantService, isValidMemberRole, renderConfirmationDialog, getConfirmationDialogScript, VALID_MEMBER_ROLES, userProfilesPlugin, lexicalEditorPlugin, api_media_default, api_system_default, apiDocumentsRoutes, api_default, adminDocumentsRoutes, admin_api_default, adminCollectionsRoutes, adminSettingsRoutes, router2, admin_content_default, adminMediaRoutes, router, adminPluginRoutes, adminLogsRoutes, userRoutes, auth_default, test_cleanup_default } from './chunk-5UCMLBRQ.js';
3
+ export { DocumentRepository, ROUTES_INFO, admin_api_default as adminApiRoutes, adminCheckboxRoutes, adminCollectionsRoutes, admin_content_default as adminContentRoutes, router as adminDashboardRoutes, adminLogsRoutes, adminMediaRoutes, adminPluginRoutes, adminSettingsRoutes, userRoutes as adminUsersRoutes, api_content_crud_default as apiContentCrudRoutes, api_media_default as apiMediaRoutes, api_default as apiRoutes, api_system_default as apiSystemRoutes, auth_default as authRoutes, createUserProfilesPlugin, defineUserProfile, getUserProfileConfig, userProfilesPlugin } from './chunk-5UCMLBRQ.js';
4
+ import './chunk-VVYVFCML.js';
5
+ import './chunk-RMRJGMDE.js';
6
+ import { SettingsService, setAppInstance } from './chunk-2XAQTPAE.js';
7
+ export { Logger, getLogger, initLogger } from './chunk-2XAQTPAE.js';
8
8
  import { getAllCacheStats, CACHE_CONFIGS, getCacheService, clearAllCaches, parseCacheKey } from './chunk-K25XHMM3.js';
9
9
  import { schema_exports } from './chunk-AI663NBO.js';
10
10
  export { apiTokens, content, contentVersions, insertContentSchema, insertLogConfigSchema, insertMediaSchema, insertPluginActivityLogSchema, insertPluginAssetSchema, insertPluginHookSchema, insertPluginRouteSchema, insertPluginSchema, insertSystemLogSchema, insertUserSchema, insertWorkflowHistorySchema, logConfig, media, pluginActivityLog, pluginAssets, pluginHooks, pluginRoutes, plugins, selectContentSchema, selectLogConfigSchema, selectMediaSchema, selectPluginActivityLogSchema, selectPluginAssetSchema, selectPluginHookSchema, selectPluginRouteSchema, selectPluginSchema, selectSystemLogSchema, selectUserSchema, selectWorkflowHistorySchema, systemLogs, users, workflowHistory } from './chunk-AI663NBO.js';
11
- import { requireAuth, DocumentTypeRegistry, requireRbac, requireRole, getJwtExpirySecondsFromDb, AuthManager, metricsMiddleware, bootstrapMiddleware, securityHeadersMiddleware, csrfProtection } from './chunk-RZ6H7OZK.js';
12
- export { AuthManager, PermissionManager, bootstrapDocumentTypes, bootstrapMiddleware, cacheHeaders, compressionMiddleware, detailedLoggingMiddleware, getActivePlugins, isPluginActive, logActivity, loggingMiddleware, optionalAuth, performanceLoggingMiddleware, requireActivePlugin, requireActivePlugins, requireAnyPermission, requireAuth, requirePermission, requireRole, securityHeadersMiddleware as securityHeaders, securityLoggingMiddleware } from './chunk-RZ6H7OZK.js';
13
- import { RbacService, DocumentsService } from './chunk-BLMTL57B.js';
14
- export { RbacService } from './chunk-BLMTL57B.js';
15
- import { nanoid } from './chunk-GCDZZNIN.js';
16
- import { PluginService, PLUGIN_REGISTRY, invalidateTenantCache, getCollectionRegistry, TENANT_COOKIE, MULTI_TENANT_PLUGIN_ID, collectionRecordToRow, tenantMiddleware } from './chunk-ZGGXCFR6.js';
17
- export { PluginBootstrapService, PluginService as PluginServiceClass, getAvailableCollectionNames, loadCollectionConfig, loadCollectionConfigs, registerCollections, validateCollectionConfig } from './chunk-ZGGXCFR6.js';
18
- export { MigrationService } from './chunk-NLJVSER2.js';
19
- export { renderFilterBar } from './chunk-6JQOUUOB.js';
20
- import { renderAdminLayout } from './chunk-HDWE5FRJ.js';
21
- export { getConfirmationDialogScript, renderAlert, renderConfirmationDialog, renderForm, renderFormField, renderPagination, renderTable } from './chunk-HDWE5FRJ.js';
22
- import { init_admin_layout_catalyst_template, renderAdminLayoutCatalyst } from './chunk-3TB6AT6X.js';
23
- import { TurnstileService, HookSystemImpl, createPluginWirer, registerPluginRoutes, setPluginMenu } from './chunk-YHSQVQXX.js';
24
- export { HookSystemImpl, HookUtils, PluginDependencyCycleError, PluginManager as PluginManagerClass, PluginRegistryImpl, PluginValidator as PluginValidatorClass, RegisterPluginsError, ScopedHookSystem as ScopedHookSystemClass, collectCronSchedules, collectCrons, createScheduledHandler, dispatchCronTick, getPluginMenu, registerPlugins, resetPluginMenu, resolvePluginMenuItems, setPluginMenu, topoSort } from './chunk-YHSQVQXX.js';
25
- import { definePlugin, setPluginDefinitions } from './chunk-6OUHGKFD.js';
26
- export { applySchemaDefaults, definePlugin, isDefinedPlugin, parseConfigSchema, parseFormDataToSettings, renderSchemaFields } from './chunk-6OUHGKFD.js';
11
+ import { requireAuth, DocumentTypeRegistry, requireRbac, requireRole, getJwtExpirySecondsFromDb, AuthManager, metricsMiddleware, bootstrapMiddleware, securityHeadersMiddleware, csrfProtection } from './chunk-WCA4VENG.js';
12
+ export { AuthManager, PermissionManager, bootstrapDocumentTypes, bootstrapMiddleware, cacheHeaders, compressionMiddleware, detailedLoggingMiddleware, getActivePlugins, isPluginActive, logActivity, loggingMiddleware, optionalAuth, performanceLoggingMiddleware, requireActivePlugin, requireActivePlugins, requireAnyPermission, requireAuth, requirePermission, requireRole, securityHeadersMiddleware as securityHeaders, securityLoggingMiddleware } from './chunk-WCA4VENG.js';
13
+ import { RbacService, DocumentsService } from './chunk-3TMTYJAJ.js';
14
+ export { DocumentsService, RbacService } from './chunk-3TMTYJAJ.js';
15
+ import { nanoid } from './chunk-UWUP2VMT.js';
16
+ import { PluginService, PLUGIN_REGISTRY, invalidateTenantCache, getCollectionRegistry, TENANT_COOKIE, MULTI_TENANT_PLUGIN_ID, collectionRecordToRow, tenantMiddleware } from './chunk-RDH6PUOP.js';
17
+ export { PluginBootstrapService, PluginService as PluginServiceClass, getAvailableCollectionNames, loadCollectionConfig, loadCollectionConfigs, registerCollections, validateCollectionConfig } from './chunk-RDH6PUOP.js';
18
+ export { MigrationService } from './chunk-DSXEVMOM.js';
19
+ export { renderFilterBar } from './chunk-JQISFW6U.js';
20
+ import { renderAdminLayout } from './chunk-OBA2RYZN.js';
21
+ export { getConfirmationDialogScript, renderAlert, renderConfirmationDialog, renderForm, renderFormField, renderPagination, renderTable } from './chunk-OBA2RYZN.js';
22
+ import { init_admin_layout_catalyst_template, renderAdminLayoutCatalyst } from './chunk-5V62WT6M.js';
23
+ export { renderAdminLayoutCatalyst } from './chunk-5V62WT6M.js';
24
+ import { TurnstileService, HookSystemImpl, createPluginWirer, registerPluginRoutes, setPluginMenu, resolvePluginMenuItems } from './chunk-MYQ7KZUQ.js';
25
+ export { HookSystemImpl, HookUtils, PluginDependencyCycleError, PluginManager as PluginManagerClass, PluginRegistryImpl, PluginValidator as PluginValidatorClass, RegisterPluginsError, ScopedHookSystem as ScopedHookSystemClass, collectCronSchedules, collectCrons, createScheduledHandler, dispatchCronTick, getPluginMenu, registerPlugins, resetPluginMenu, resolvePluginMenuItems, setPluginMenu, topoSort } from './chunk-MYQ7KZUQ.js';
26
+ import { definePlugin, setPluginDefinitions } from './chunk-GMZ5TGYP.js';
27
+ export { applySchemaDefaults, definePlugin, isDefinedPlugin, parseConfigSchema, parseFormDataToSettings, renderSchemaFields } from './chunk-GMZ5TGYP.js';
27
28
  import { setHookSystem } from './chunk-RNZFGN4R.js';
28
29
  export { getHookSystem, getTypedHooks, hasHookSystem, resetHookSystem, setHookSystem } from './chunk-RNZFGN4R.js';
29
30
  export { QueryFilterBuilder, TemplateRenderer, buildQuery, renderTemplate, templateRenderer } from './chunk-QZGABF2M.js';
30
- import './chunk-X7ZAEI5S.js';
31
31
  export { metricsTracker } from './chunk-FICTAGD4.js';
32
- import { getCoreVersion, package_default } from './chunk-NMPEMSU4.js';
33
- export { SONICJS_VERSION, getCoreVersion } from './chunk-NMPEMSU4.js';
32
+ import './chunk-X7ZAEI5S.js';
33
+ import { getCoreVersion, package_default } from './chunk-W53J3BJ2.js';
34
+ export { SONICJS_VERSION, getCoreVersion } from './chunk-W53J3BJ2.js';
34
35
  import { escapeHtml, sanitizeInput } from './chunk-TQABQWOP.js';
35
36
  export { escapeHtml, sanitizeInput, sanitizeObject } from './chunk-TQABQWOP.js';
36
37
  export { HOOKS } from './chunk-QXOZI5Q2.js';
37
38
  import './chunk-V4OQ3NZ2.js';
38
39
  import { Hono } from 'hono';
40
+ import { cors } from 'hono/cors';
39
41
  import { z } from 'zod';
40
42
  import { setCookie, getCookie } from 'hono/cookie';
41
43
  import { html } from 'hono/html';
@@ -49,6 +51,7 @@ var DatabaseToolsService = class {
49
51
  constructor(db) {
50
52
  this.db = db;
51
53
  }
54
+ db;
52
55
  /**
53
56
  * Get database statistics
54
57
  */
@@ -907,6 +910,7 @@ var EmailSettingsService = class {
907
910
  constructor(db) {
908
911
  this.db = db;
909
912
  }
913
+ db;
910
914
  async load() {
911
915
  let row = null;
912
916
  try {
@@ -935,6 +939,8 @@ var SiteConfigService = class {
935
939
  this.db = db;
936
940
  this.env = env;
937
941
  }
942
+ db;
943
+ env;
938
944
  async load() {
939
945
  const settings = new SettingsService(this.db);
940
946
  const general = await settings.getGeneralSettings();
@@ -1272,6 +1278,8 @@ var EmailValidationError = class extends Error {
1272
1278
  this.reason = reason;
1273
1279
  this.name = "EmailValidationError";
1274
1280
  }
1281
+ field;
1282
+ reason;
1275
1283
  code = "EMAIL_VALIDATION_FAILED";
1276
1284
  };
1277
1285
 
@@ -1307,6 +1315,9 @@ var CfGraphqlClient = class {
1307
1315
  throw new EmailValidationError("apiToken", "EMAIL_API_TOKEN is required for GraphQL queries");
1308
1316
  }
1309
1317
  }
1318
+ zoneId;
1319
+ apiToken;
1320
+ fetchImpl;
1310
1321
  async queryEmailSends(input) {
1311
1322
  const startIso = new Date(input.startSeconds * 1e3).toISOString();
1312
1323
  const endIso = new Date(input.endSeconds * 1e3).toISOString();
@@ -1369,6 +1380,7 @@ var EmailLogService = class {
1369
1380
  constructor(db) {
1370
1381
  this.db = db;
1371
1382
  }
1383
+ db;
1372
1384
  /**
1373
1385
  * Records a successful submission to CF Email Service. `status` =
1374
1386
  * `'submitted'`, `delivery_state` remains NULL until reconciliation runs.
@@ -1542,6 +1554,8 @@ var ReconciliationService = class {
1542
1554
  this.graphql = graphql;
1543
1555
  this.emailLog = emailLog;
1544
1556
  }
1557
+ graphql;
1558
+ emailLog;
1545
1559
  async run(input = {}) {
1546
1560
  const windowHours = input.windowHours ?? 24;
1547
1561
  const nowMs = input.now ?? Date.now();
@@ -1950,6 +1964,7 @@ var CloudflareEmailProvider = class {
1950
1964
  constructor(binding) {
1951
1965
  this.binding = binding;
1952
1966
  }
1967
+ binding;
1953
1968
  name = "cloudflare";
1954
1969
  isConfigured() {
1955
1970
  return !!this.binding;
@@ -2132,6 +2147,7 @@ var OTPService = class {
2132
2147
  constructor(db) {
2133
2148
  this.db = db;
2134
2149
  }
2150
+ db;
2135
2151
  /**
2136
2152
  * Generate a secure random OTP code
2137
2153
  */
@@ -2766,6 +2782,7 @@ var OAuthService = class {
2766
2782
  constructor(db) {
2767
2783
  this.db = db;
2768
2784
  }
2785
+ db;
2769
2786
  /**
2770
2787
  * Build the authorization redirect URL for a provider.
2771
2788
  */
@@ -3282,6 +3299,7 @@ var EmbeddingService = class {
3282
3299
  constructor(ai) {
3283
3300
  this.ai = ai;
3284
3301
  }
3302
+ ai;
3285
3303
  /**
3286
3304
  * Generate embedding for a single text
3287
3305
  */
@@ -3486,6 +3504,9 @@ var CustomRAGService = class {
3486
3504
  this.embeddingService = new EmbeddingService(ai);
3487
3505
  this.chunkingService = new ChunkingService();
3488
3506
  }
3507
+ db;
3508
+ ai;
3509
+ vectorize;
3489
3510
  embeddingService;
3490
3511
  chunkingService;
3491
3512
  /**
@@ -3776,6 +3797,9 @@ var AISearchService = class {
3776
3797
  console.log("[AISearchService] Custom RAG not available, using keyword search only");
3777
3798
  }
3778
3799
  }
3800
+ db;
3801
+ ai;
3802
+ vectorize;
3779
3803
  customRAG;
3780
3804
  /**
3781
3805
  * Get plugin settings
@@ -4216,6 +4240,9 @@ var IndexManager = class {
4216
4240
  console.log("[IndexManager] Custom RAG initialized");
4217
4241
  }
4218
4242
  }
4243
+ db;
4244
+ ai;
4245
+ vectorize;
4219
4246
  customRAG;
4220
4247
  /**
4221
4248
  * Index all content items within a collection using Custom RAG
@@ -5149,6 +5176,8 @@ var SecurityAuditService = class {
5149
5176
  tenantId: TENANT
5150
5177
  });
5151
5178
  }
5179
+ db;
5180
+ settings;
5152
5181
  docsService;
5153
5182
  async logEvent(event) {
5154
5183
  const doc = await this.docsService.create({
@@ -6092,6 +6121,7 @@ var BruteForceDetector = class {
6092
6121
  this.kv = kv;
6093
6122
  this.settings = settings || DEFAULT_SETTINGS2.bruteForce;
6094
6123
  }
6124
+ kv;
6095
6125
  settings;
6096
6126
  async recordFailedAttempt(ip, email) {
6097
6127
  if (!this.settings.enabled || !this.kv) {
@@ -6644,11 +6674,465 @@ var securityAuditPlugin = definePlugin({
6644
6674
  deactivate: async () => console.log("[SecurityAudit] Plugin deactivated")
6645
6675
  });
6646
6676
 
6677
+ // src/plugins/core-plugins/api-keys-plugin/services/api-key-service.ts
6678
+ var API_KEY_QUERYABLE = [
6679
+ { name: "keyHash", kind: "scalar", type: "text", column: "q_apikey_hash" },
6680
+ { name: "userId", kind: "scalar", type: "text", column: "q_apikey_user_id" },
6681
+ { name: "revoked", kind: "scalar", type: "integer", column: "q_apikey_revoked" }
6682
+ ];
6683
+ var KEY_PREFIX = "sk_";
6684
+ var KEY_BYTES = 24;
6685
+ var DISPLAY_PREFIX_LEN = KEY_PREFIX.length + 8;
6686
+ function generateApiKeySecret() {
6687
+ const bytes = new Uint8Array(KEY_BYTES);
6688
+ crypto.getRandomValues(bytes);
6689
+ let hex = "";
6690
+ for (const b of bytes) hex += b.toString(16).padStart(2, "0");
6691
+ return KEY_PREFIX + hex;
6692
+ }
6693
+ async function hashApiKey(secret) {
6694
+ const data = new TextEncoder().encode(secret);
6695
+ const digest = await crypto.subtle.digest("SHA-256", data);
6696
+ const view = new Uint8Array(digest);
6697
+ let hex = "";
6698
+ for (const b of view) hex += b.toString(16).padStart(2, "0");
6699
+ return hex;
6700
+ }
6701
+ var ApiKeyService = class {
6702
+ constructor(db, tenantId = "default") {
6703
+ this.db = db;
6704
+ this.tenantId = tenantId;
6705
+ }
6706
+ db;
6707
+ tenantId;
6708
+ docService() {
6709
+ return new DocumentsService(this.db, {
6710
+ queryableFields: API_KEY_QUERYABLE,
6711
+ tenantId: this.tenantId,
6712
+ maxVersionsPerRoot: 1
6713
+ });
6714
+ }
6715
+ /** Count a user's active (non-revoked) keys — used to enforce the per-user cap. */
6716
+ async countForUser(userId) {
6717
+ const row = await this.db.prepare(
6718
+ `SELECT COUNT(*) AS c FROM documents
6719
+ WHERE type_id = 'api_key' AND tenant_id = ? AND is_current_draft = 1
6720
+ AND deleted_at IS NULL AND q_apikey_user_id = ? AND q_apikey_revoked = 0`
6721
+ ).bind(this.tenantId, userId).first();
6722
+ return row?.c ?? 0;
6723
+ }
6724
+ /**
6725
+ * Mint a new key for a user. The returned `key` is the only time the plaintext
6726
+ * exists outside the caller — it is hashed before storage.
6727
+ */
6728
+ async create(input) {
6729
+ const name = input.name.trim() || "API Key";
6730
+ const secret = generateApiKeySecret();
6731
+ const keyHash = await hashApiKey(secret);
6732
+ const prefix = secret.slice(0, DISPLAY_PREFIX_LEN);
6733
+ const expiresAt = input.expiresAt ?? null;
6734
+ const doc = await this.docService().create(
6735
+ createDocumentSchema.parse({
6736
+ typeId: "api_key",
6737
+ tenantId: this.tenantId,
6738
+ title: name,
6739
+ ownerId: input.userId,
6740
+ publishOnCreate: true,
6741
+ data: {
6742
+ name,
6743
+ userId: input.userId,
6744
+ keyHash,
6745
+ keyPrefix: prefix,
6746
+ revoked: 0,
6747
+ lastUsedAt: null,
6748
+ expiresAt
6749
+ }
6750
+ }),
6751
+ input.userId
6752
+ );
6753
+ return { id: doc.rootId, key: secret, name, prefix, expiresAt };
6754
+ }
6755
+ /** List a user's non-revoked keys (metadata only — never the secret or hash). */
6756
+ async list(userId) {
6757
+ const res = await this.db.prepare(
6758
+ `SELECT root_id, data, created_at FROM documents
6759
+ WHERE type_id = 'api_key' AND tenant_id = ? AND is_current_draft = 1
6760
+ AND deleted_at IS NULL AND q_apikey_user_id = ? AND q_apikey_revoked = 0
6761
+ ORDER BY created_at DESC`
6762
+ ).bind(this.tenantId, userId).all();
6763
+ return (res.results ?? []).map((row) => {
6764
+ const d = JSON.parse(row.data);
6765
+ return {
6766
+ id: row.root_id,
6767
+ name: d.name ?? "API Key",
6768
+ prefix: d.keyPrefix ?? "",
6769
+ createdAt: row.created_at,
6770
+ lastUsedAt: d.lastUsedAt ?? null,
6771
+ expiresAt: d.expiresAt ?? null
6772
+ };
6773
+ });
6774
+ }
6775
+ /**
6776
+ * Revoke (hard-delete) a key owned by `userId`. Credentials are erased, not
6777
+ * soft-flagged. Returns false if the key does not exist or is not owned by
6778
+ * the caller (no information leak about other users' keys).
6779
+ */
6780
+ async revoke(rootId, userId) {
6781
+ const row = await this.db.prepare(
6782
+ `SELECT q_apikey_user_id AS owner FROM documents
6783
+ WHERE root_id = ? AND tenant_id = ? AND type_id = 'api_key' AND is_current_draft = 1 AND deleted_at IS NULL`
6784
+ ).bind(rootId, this.tenantId).first();
6785
+ if (!row || row.owner !== userId) return false;
6786
+ await this.docService().erase(rootId, this.tenantId);
6787
+ return true;
6788
+ }
6789
+ /**
6790
+ * Resolve a presented secret to its owning user, or null. Rejects unknown,
6791
+ * revoked, expired keys and inactive users. Best-effort updates lastUsedAt.
6792
+ */
6793
+ async resolve(secret) {
6794
+ if (!secret || !secret.startsWith(KEY_PREFIX)) return null;
6795
+ const keyHash = await hashApiKey(secret);
6796
+ const keyRow2 = await this.db.prepare(
6797
+ `SELECT root_id, data FROM documents
6798
+ WHERE type_id = 'api_key' AND tenant_id = ? AND is_current_draft = 1 AND deleted_at IS NULL
6799
+ AND q_apikey_hash = ? AND q_apikey_revoked = 0
6800
+ LIMIT 1`
6801
+ ).bind(this.tenantId, keyHash).first();
6802
+ if (!keyRow2) return null;
6803
+ const d = JSON.parse(keyRow2.data);
6804
+ if (d.expiresAt != null && Date.now() > Number(d.expiresAt)) return null;
6805
+ const user = await this.db.prepare(`SELECT id, email, role, is_active, is_super_admin FROM auth_user WHERE id = ?`).bind(d.userId).first();
6806
+ if (!user || user.is_active !== 1) return null;
6807
+ try {
6808
+ await this.touchLastUsed(keyRow2.root_id, d);
6809
+ } catch {
6810
+ }
6811
+ return {
6812
+ userId: user.id,
6813
+ email: user.email,
6814
+ role: user.role ?? "viewer",
6815
+ isSuperAdmin: user.is_super_admin === 1
6816
+ };
6817
+ }
6818
+ /** Update lastUsedAt in-place (single-version type, no history churn). */
6819
+ async touchLastUsed(rootId, data) {
6820
+ const next = JSON.stringify({ ...data, lastUsedAt: Date.now() });
6821
+ await this.db.prepare(
6822
+ `UPDATE documents SET data = ? WHERE root_id = ? AND tenant_id = ? AND type_id = 'api_key' AND is_current_draft = 1`
6823
+ ).bind(next, rootId, this.tenantId).run();
6824
+ }
6825
+ };
6826
+
6827
+ // src/plugins/core-plugins/api-keys-plugin/components/keys-page.ts
6828
+ init_admin_layout_catalyst_template();
6829
+ function fmtDate(ms) {
6830
+ if (!ms) return "\u2014";
6831
+ try {
6832
+ return new Date(ms).toISOString().slice(0, 10);
6833
+ } catch {
6834
+ return "\u2014";
6835
+ }
6836
+ }
6837
+ function keyRow(k) {
6838
+ const name = escapeHtml(k.name);
6839
+ const prefix = escapeHtml(k.prefix);
6840
+ const id = escapeHtml(k.id);
6841
+ return `
6842
+ <tr class="border-t border-zinc-950/5 dark:border-white/10" data-key-id="${id}">
6843
+ <td class="py-3 pr-4 text-sm font-medium text-zinc-950 dark:text-white">${name}</td>
6844
+ <td class="py-3 pr-4 text-sm font-mono text-zinc-500 dark:text-zinc-400">${prefix}\u2026</td>
6845
+ <td class="py-3 pr-4 text-sm text-zinc-500 dark:text-zinc-400">${fmtDate(k.createdAt ? k.createdAt * 1e3 : null)}</td>
6846
+ <td class="py-3 pr-4 text-sm text-zinc-500 dark:text-zinc-400">${k.lastUsedAt ? fmtDate(k.lastUsedAt) : "Never"}</td>
6847
+ <td class="py-3 pr-4 text-sm text-zinc-500 dark:text-zinc-400">${k.expiresAt ? fmtDate(k.expiresAt) : "Never"}</td>
6848
+ <td class="py-3 text-right">
6849
+ <button type="button" onclick="revokeApiKey('${id}', '${name.replace(/'/g, "\\'")}')"
6850
+ class="rounded-lg bg-red-50 dark:bg-red-900/20 px-3 py-1.5 text-sm font-medium text-red-700 dark:text-red-400 hover:bg-red-100 dark:hover:bg-red-900/40 ring-1 ring-red-200 dark:ring-red-800 transition-colors">
6851
+ Revoke
6852
+ </button>
6853
+ </td>
6854
+ </tr>`;
6855
+ }
6856
+ function renderApiKeysPage(data) {
6857
+ const { keys, user, version, dynamicMenuItems } = data;
6858
+ const rows = keys.length ? keys.map(keyRow).join("") : `<tr><td colspan="6" class="py-8 text-center text-sm text-zinc-500 dark:text-zinc-400">No API keys yet. Create one to enable programmatic access.</td></tr>`;
6859
+ const content2 = `
6860
+ <div>
6861
+ <div class="sm:flex sm:items-center sm:justify-between mb-6">
6862
+ <div class="sm:flex-auto">
6863
+ <h1 class="text-2xl/8 font-semibold text-zinc-950 dark:text-white sm:text-xl/8">API Keys</h1>
6864
+ <p class="mt-2 text-sm/6 text-zinc-500 dark:text-zinc-400">
6865
+ Long-lived secrets for headless / server-to-server REST access. Send a key as the
6866
+ <code class="font-mono">x-api-key</code> header or <code class="font-mono">Authorization: Bearer &lt;key&gt;</code>.
6867
+ The secret is shown once at creation \u2014 store it now.
6868
+ </p>
6869
+ </div>
6870
+ <div class="mt-4 sm:mt-0 sm:ml-16">
6871
+ <button type="button" onclick="document.getElementById('create-key-modal').classList.remove('hidden')"
6872
+ class="inline-flex items-center justify-center rounded-lg bg-cyan-600 px-4 py-2.5 text-sm font-semibold text-white hover:bg-cyan-500 transition-colors shadow-sm">
6873
+ Create API key
6874
+ </button>
6875
+ </div>
6876
+ </div>
6877
+
6878
+ <!-- Newly-created secret banner (populated by JS, shown once) -->
6879
+ <div id="new-key-banner" class="hidden mb-6 rounded-xl bg-emerald-50 dark:bg-emerald-900/20 p-4 ring-1 ring-emerald-200 dark:ring-emerald-800">
6880
+ <p class="text-sm font-medium text-emerald-800 dark:text-emerald-300 mb-2">
6881
+ Copy your new key now \u2014 it will not be shown again.
6882
+ </p>
6883
+ <div class="flex items-center gap-2">
6884
+ <code id="new-key-value" class="flex-1 rounded-lg bg-white dark:bg-zinc-900 px-3 py-2 text-sm font-mono text-zinc-950 dark:text-white ring-1 ring-zinc-950/10 dark:ring-white/10 break-all"></code>
6885
+ <button type="button" onclick="copyNewKey()"
6886
+ class="rounded-lg bg-emerald-600 px-3 py-2 text-sm font-semibold text-white hover:bg-emerald-500 transition-colors">
6887
+ Copy
6888
+ </button>
6889
+ </div>
6890
+ </div>
6891
+
6892
+ <div class="rounded-xl bg-white/80 dark:bg-zinc-900/80 backdrop-blur-xl p-6 ring-1 ring-zinc-950/5 dark:ring-white/10 shadow-sm overflow-x-auto">
6893
+ <table class="w-full text-left">
6894
+ <thead>
6895
+ <tr class="text-xs font-semibold uppercase tracking-wide text-zinc-500 dark:text-zinc-400">
6896
+ <th class="pb-2 pr-4">Name</th>
6897
+ <th class="pb-2 pr-4">Prefix</th>
6898
+ <th class="pb-2 pr-4">Created</th>
6899
+ <th class="pb-2 pr-4">Last used</th>
6900
+ <th class="pb-2 pr-4">Expires</th>
6901
+ <th class="pb-2 text-right">Actions</th>
6902
+ </tr>
6903
+ </thead>
6904
+ <tbody id="keys-tbody">${rows}</tbody>
6905
+ </table>
6906
+ </div>
6907
+ </div>
6908
+
6909
+ <!-- Create modal -->
6910
+ <div id="create-key-modal" class="hidden fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4">
6911
+ <div class="w-full max-w-md rounded-xl bg-white dark:bg-zinc-900 p-6 ring-1 ring-zinc-950/10 dark:ring-white/10 shadow-xl">
6912
+ <h2 class="text-base font-semibold text-zinc-950 dark:text-white mb-4">Create API key</h2>
6913
+ <label class="block text-sm font-medium text-zinc-700 dark:text-zinc-300 mb-1">Name</label>
6914
+ <input id="new-key-name" type="text" placeholder="e.g. CI deploy token"
6915
+ class="w-full rounded-lg border-zinc-300 dark:border-zinc-700 bg-white dark:bg-zinc-800 px-3 py-2 text-sm text-zinc-950 dark:text-white mb-4 ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10">
6916
+ <label class="block text-sm font-medium text-zinc-700 dark:text-zinc-300 mb-1">Expires in (days, optional)</label>
6917
+ <input id="new-key-expiry" type="number" min="1" max="3650" placeholder="Never"
6918
+ class="w-full rounded-lg border-zinc-300 dark:border-zinc-700 bg-white dark:bg-zinc-800 px-3 py-2 text-sm text-zinc-950 dark:text-white mb-4 ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10">
6919
+ <div class="flex justify-end gap-2">
6920
+ <button type="button" onclick="document.getElementById('create-key-modal').classList.add('hidden')"
6921
+ class="rounded-lg bg-white dark:bg-zinc-800 px-4 py-2 text-sm font-semibold text-zinc-950 dark:text-white ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10">
6922
+ Cancel
6923
+ </button>
6924
+ <button type="button" onclick="createApiKey()"
6925
+ class="rounded-lg bg-cyan-600 px-4 py-2 text-sm font-semibold text-white hover:bg-cyan-500 transition-colors">
6926
+ Create
6927
+ </button>
6928
+ </div>
6929
+ </div>
6930
+ </div>
6931
+
6932
+ <script>
6933
+ // CSRF: the csrf_token cookie is JS-readable (httpOnly:false); echo it back
6934
+ // as X-CSRF-Token on state-changing requests (signed double-submit).
6935
+ function csrfHeader() {
6936
+ const m = document.cookie.match(/(?:^|; )csrf_token=([^;]+)/)
6937
+ return m ? { 'X-CSRF-Token': decodeURIComponent(m[1]) } : {}
6938
+ }
6939
+ async function createApiKey() {
6940
+ const name = document.getElementById('new-key-name').value.trim()
6941
+ if (!name) { window.showNotification && window.showNotification('Name is required', 'error'); return }
6942
+ const expiry = parseInt(document.getElementById('new-key-expiry').value, 10)
6943
+ const body = { name }
6944
+ if (Number.isFinite(expiry) && expiry > 0) body.expiresInDays = expiry
6945
+ const res = await fetch('/admin/plugins/api-keys/api/keys', {
6946
+ method: 'POST',
6947
+ headers: { 'Content-Type': 'application/json', ...csrfHeader() },
6948
+ body: JSON.stringify(body),
6949
+ })
6950
+ if (!res.ok) {
6951
+ const e = await res.json().catch(() => ({}))
6952
+ window.showNotification && window.showNotification(e.error || 'Failed to create key', 'error')
6953
+ return
6954
+ }
6955
+ const { apiKey } = await res.json()
6956
+ document.getElementById('create-key-modal').classList.add('hidden')
6957
+ document.getElementById('new-key-value').textContent = apiKey.key
6958
+ document.getElementById('new-key-banner').classList.remove('hidden')
6959
+ setTimeout(() => location.reload(), 1500)
6960
+ }
6961
+ function copyNewKey() {
6962
+ const v = document.getElementById('new-key-value').textContent
6963
+ navigator.clipboard.writeText(v).then(() => window.showNotification && window.showNotification('Copied', 'success'))
6964
+ }
6965
+ async function revokeApiKey(id, name) {
6966
+ if (!confirm('Revoke "' + name + '"? This cannot be undone and will break any client using it.')) return
6967
+ const res = await fetch('/admin/plugins/api-keys/api/keys/' + id, { method: 'DELETE', headers: { ...csrfHeader() } })
6968
+ if (res.ok) {
6969
+ const row = document.querySelector('[data-key-id="' + id + '"]')
6970
+ if (row) row.remove()
6971
+ window.showNotification && window.showNotification('Key revoked', 'success')
6972
+ } else {
6973
+ window.showNotification && window.showNotification('Failed to revoke', 'error')
6974
+ }
6975
+ }
6976
+ </script>`;
6977
+ const layoutData = {
6978
+ title: "API Keys",
6979
+ pageTitle: "API Keys",
6980
+ currentPath: "/admin/plugins/api-keys",
6981
+ user,
6982
+ content: content2,
6983
+ version,
6984
+ dynamicMenuItems
6985
+ };
6986
+ return renderAdminLayoutCatalyst(layoutData);
6987
+ }
6988
+
6989
+ // src/plugins/core-plugins/api-keys-plugin/types.ts
6990
+ var DEFAULT_SETTINGS3 = {
6991
+ maxKeysPerUser: 50,
6992
+ defaultExpiryDays: 0
6993
+ };
6994
+
6995
+ // src/plugins/core-plugins/api-keys-plugin/routes/admin.ts
6996
+ var adminRoutes4 = new Hono();
6997
+ var DAY_MS = 24 * 60 * 60 * 1e3;
6998
+ var createSchema = z.object({
6999
+ name: z.string().min(1).max(100),
7000
+ // Optional lifetime in days; omitted/null → plugin default (which may be "never").
7001
+ expiresInDays: z.number().int().positive().max(3650).nullish()
7002
+ });
7003
+ async function getSettings3(db) {
7004
+ try {
7005
+ const plugin2 = await new PluginService(db).getPlugin("api-keys");
7006
+ if (plugin2?.settings) {
7007
+ const s = typeof plugin2.settings === "string" ? JSON.parse(plugin2.settings) : plugin2.settings;
7008
+ return { ...DEFAULT_SETTINGS3, ...s };
7009
+ }
7010
+ } catch {
7011
+ }
7012
+ return DEFAULT_SETTINGS3;
7013
+ }
7014
+ adminRoutes4.use("*", requireAuth());
7015
+ adminRoutes4.use("*", async (c, next) => {
7016
+ const user = c.get("user");
7017
+ if (user?.role !== "admin") {
7018
+ return c.json({ error: "Access denied" }, 403);
7019
+ }
7020
+ return next();
7021
+ });
7022
+ adminRoutes4.get("/", async (c) => {
7023
+ const user = c.get("user");
7024
+ const tenantId = c.get("tenantId") || "default";
7025
+ const keys = await new ApiKeyService(c.env.DB, tenantId).list(user.userId);
7026
+ return c.html(
7027
+ renderApiKeysPage({
7028
+ keys,
7029
+ user: { name: user.email, email: user.email, role: user.role },
7030
+ version: c.get("appVersion"),
7031
+ dynamicMenuItems: c.get("pluginMenuItems")
7032
+ })
7033
+ );
7034
+ });
7035
+ adminRoutes4.get("/api/keys", async (c) => {
7036
+ const user = c.get("user");
7037
+ const tenantId = c.get("tenantId") || "default";
7038
+ const keys = await new ApiKeyService(c.env.DB, tenantId).list(user.userId);
7039
+ return c.json({ keys });
7040
+ });
7041
+ adminRoutes4.post("/api/keys", async (c) => {
7042
+ const user = c.get("user");
7043
+ const tenantId = c.get("tenantId") || "default";
7044
+ const body = await c.req.json().catch(() => ({}));
7045
+ const parsed = createSchema.safeParse(body);
7046
+ if (!parsed.success) {
7047
+ return c.json({ error: "Invalid request", details: parsed.error.flatten() }, 400);
7048
+ }
7049
+ const settings = await getSettings3(c.env.DB);
7050
+ const svc = new ApiKeyService(c.env.DB, tenantId);
7051
+ if (await svc.countForUser(user.userId) >= settings.maxKeysPerUser) {
7052
+ return c.json({ error: `API key limit reached (max ${settings.maxKeysPerUser})` }, 409);
7053
+ }
7054
+ const days = parsed.data.expiresInDays ?? (settings.defaultExpiryDays > 0 ? settings.defaultExpiryDays : null);
7055
+ const expiresAt = days ? Date.now() + days * DAY_MS : null;
7056
+ const created = await svc.create({ userId: user.userId, name: parsed.data.name, expiresAt });
7057
+ return c.json({ apiKey: created }, 201);
7058
+ });
7059
+ adminRoutes4.delete("/api/keys/:id", async (c) => {
7060
+ const user = c.get("user");
7061
+ const tenantId = c.get("tenantId") || "default";
7062
+ const ok = await new ApiKeyService(c.env.DB, tenantId).revoke(c.req.param("id") ?? "", user.userId);
7063
+ if (!ok) return c.json({ error: "API key not found" }, 404);
7064
+ return c.json({ success: true });
7065
+ });
7066
+
7067
+ // src/plugins/core-plugins/api-keys-plugin/middleware/api-key-auth.ts
7068
+ function apiKeyAuthMiddleware() {
7069
+ return async (c, next) => {
7070
+ if (!c.get("user")) {
7071
+ const authz = c.req.header("authorization") || "";
7072
+ const bearer = authz.toLowerCase().startsWith("bearer ") ? authz.slice(7).trim() : "";
7073
+ const presented = c.req.header("x-api-key") || (bearer.startsWith("sk_") ? bearer : "");
7074
+ if (presented) {
7075
+ try {
7076
+ const tenantId = c.get("tenantId") || "default";
7077
+ const resolved = await new ApiKeyService(c.env.DB, tenantId).resolve(presented);
7078
+ if (resolved) {
7079
+ c.set("user", {
7080
+ userId: resolved.userId,
7081
+ email: resolved.email,
7082
+ role: resolved.role,
7083
+ isSuperAdmin: resolved.isSuperAdmin,
7084
+ // API keys are stateless bearer creds — no session window.
7085
+ exp: 0,
7086
+ iat: 0
7087
+ });
7088
+ }
7089
+ } catch {
7090
+ }
7091
+ }
7092
+ }
7093
+ await next();
7094
+ };
7095
+ }
7096
+
7097
+ // src/plugins/core-plugins/api-keys-plugin/index.ts
7098
+ var KEY_ICON = `<svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11 17H9v2H7v2H4a1 1 0 01-1-1v-2.586a1 1 0 01.293-.707l5.964-5.964A6 6 0 1121 9z"/></svg>`;
7099
+ var apiKeysPlugin = definePlugin({
7100
+ id: "api-keys",
7101
+ version: "1.0.0-beta.1",
7102
+ name: "API Keys",
7103
+ description: "Programmatic API access keys for headless / server-to-server REST access.",
7104
+ sonicjsVersionRange: "^3.0.0",
7105
+ author: { name: "SonicJS Team" },
7106
+ register(app2) {
7107
+ app2.route("/admin/plugins/api-keys", adminRoutes4);
7108
+ },
7109
+ menu: [
7110
+ { label: "API Keys", path: "/admin/plugins/api-keys", icon: KEY_ICON, order: 86 }
7111
+ ],
7112
+ configSchema: {
7113
+ maxKeysPerUser: {
7114
+ type: "number",
7115
+ label: "Max keys per user",
7116
+ description: "Hard cap on active keys a single user may hold.",
7117
+ default: 50
7118
+ },
7119
+ defaultExpiryDays: {
7120
+ type: "number",
7121
+ label: "Default expiry (days)",
7122
+ description: "Lifetime applied to new keys when no explicit expiry is given. 0 = never expires.",
7123
+ default: 0
7124
+ }
7125
+ },
7126
+ activate: async () => console.log("[ApiKeys] Plugin activated"),
7127
+ deactivate: async () => console.log("[ApiKeys] Plugin deactivated")
7128
+ });
7129
+
6647
7130
  // src/plugins/core-plugins/stripe-plugin/services/subscription-service.ts
6648
7131
  var SubscriptionService = class {
6649
7132
  constructor(db) {
6650
7133
  this.db = db;
6651
7134
  }
7135
+ db;
6652
7136
  /**
6653
7137
  * Ensure the subscriptions table exists
6654
7138
  */
@@ -6887,6 +7371,7 @@ var StripeEventService = class {
6887
7371
  constructor(db) {
6888
7372
  this.db = db;
6889
7373
  }
7374
+ db;
6890
7375
  async ensureTable() {
6891
7376
  await this.db.prepare(`
6892
7377
  CREATE TABLE IF NOT EXISTS stripe_events (
@@ -7371,7 +7856,7 @@ function renderEventPagination(page, totalPages, type, status) {
7371
7856
  }
7372
7857
 
7373
7858
  // src/plugins/core-plugins/stripe-plugin/types.ts
7374
- var DEFAULT_SETTINGS3 = {
7859
+ var DEFAULT_SETTINGS4 = {
7375
7860
  stripePublishableKey: "",
7376
7861
  stripeSecretKey: "",
7377
7862
  stripeWebhookSecret: "",
@@ -7381,28 +7866,28 @@ var DEFAULT_SETTINGS3 = {
7381
7866
  };
7382
7867
 
7383
7868
  // src/plugins/core-plugins/stripe-plugin/routes/admin.ts
7384
- var adminRoutes4 = new Hono();
7385
- adminRoutes4.use("*", requireAuth());
7386
- adminRoutes4.use("*", async (c, next) => {
7869
+ var adminRoutes5 = new Hono();
7870
+ adminRoutes5.use("*", requireAuth());
7871
+ adminRoutes5.use("*", async (c, next) => {
7387
7872
  const user = c.get("user");
7388
7873
  if (user?.role !== "admin") {
7389
7874
  return c.text("Access denied", 403);
7390
7875
  }
7391
7876
  return next();
7392
7877
  });
7393
- async function getSettings3(db) {
7878
+ async function getSettings4(db) {
7394
7879
  try {
7395
7880
  const pluginService = new PluginService(db);
7396
7881
  const plugin2 = await pluginService.getPlugin("stripe");
7397
7882
  if (plugin2?.settings) {
7398
7883
  const settings = typeof plugin2.settings === "string" ? JSON.parse(plugin2.settings) : plugin2.settings;
7399
- return { ...DEFAULT_SETTINGS3, ...settings };
7884
+ return { ...DEFAULT_SETTINGS4, ...settings };
7400
7885
  }
7401
7886
  } catch {
7402
7887
  }
7403
- return DEFAULT_SETTINGS3;
7888
+ return DEFAULT_SETTINGS4;
7404
7889
  }
7405
- adminRoutes4.get("/", async (c) => {
7890
+ adminRoutes5.get("/", async (c) => {
7406
7891
  const db = c.env.DB;
7407
7892
  const user = c.get("user");
7408
7893
  const subscriptionService = new SubscriptionService(db);
@@ -7425,7 +7910,7 @@ adminRoutes4.get("/", async (c) => {
7425
7910
  });
7426
7911
  return c.html(html4);
7427
7912
  });
7428
- adminRoutes4.get("/events", async (c) => {
7913
+ adminRoutes5.get("/events", async (c) => {
7429
7914
  const db = c.env.DB;
7430
7915
  const user = c.get("user");
7431
7916
  const eventService = new StripeEventService(db);
@@ -7451,11 +7936,11 @@ adminRoutes4.get("/events", async (c) => {
7451
7936
  });
7452
7937
  return c.html(html4);
7453
7938
  });
7454
- adminRoutes4.get("/settings", async (c) => {
7939
+ adminRoutes5.get("/settings", async (c) => {
7455
7940
  const db = c.env.DB;
7456
7941
  const user = c.get("user");
7457
- const settings = await getSettings3(db);
7458
- const { renderAdminLayoutCatalyst: renderAdminLayoutCatalyst2 } = await import('./admin-layout-catalyst.template-WHJGSWWD.js');
7942
+ const settings = await getSettings4(db);
7943
+ const { renderAdminLayoutCatalyst: renderAdminLayoutCatalyst2 } = await import('./admin-layout-catalyst.template-YQ4EMF2J.js');
7459
7944
  const content2 = `
7460
7945
  <div>
7461
7946
  <div class="mb-6">
@@ -7561,7 +8046,7 @@ adminRoutes4.get("/settings", async (c) => {
7561
8046
  dynamicMenuItems: c.get("pluginMenuItems")
7562
8047
  }));
7563
8048
  });
7564
- adminRoutes4.post("/settings", async (c) => {
8049
+ adminRoutes5.post("/settings", async (c) => {
7565
8050
  try {
7566
8051
  const body = await c.req.json();
7567
8052
  const db = c.env.DB;
@@ -7583,6 +8068,7 @@ var StripeAPI = class {
7583
8068
  constructor(secretKey) {
7584
8069
  this.secretKey = secretKey;
7585
8070
  }
8071
+ secretKey;
7586
8072
  baseUrl = "https://api.stripe.com/v1";
7587
8073
  /**
7588
8074
  * Verify a webhook signature
@@ -7712,17 +8198,17 @@ function timingSafeEqual(a, b) {
7712
8198
 
7713
8199
  // src/plugins/core-plugins/stripe-plugin/routes/api.ts
7714
8200
  var apiRoutes3 = new Hono();
7715
- async function getSettings4(db) {
8201
+ async function getSettings5(db) {
7716
8202
  try {
7717
8203
  const pluginService = new PluginService(db);
7718
8204
  const plugin2 = await pluginService.getPlugin("stripe");
7719
8205
  if (plugin2?.settings) {
7720
8206
  const settings = typeof plugin2.settings === "string" ? JSON.parse(plugin2.settings) : plugin2.settings;
7721
- return { ...DEFAULT_SETTINGS3, ...settings };
8207
+ return { ...DEFAULT_SETTINGS4, ...settings };
7722
8208
  }
7723
8209
  } catch {
7724
8210
  }
7725
- return DEFAULT_SETTINGS3;
8211
+ return DEFAULT_SETTINGS4;
7726
8212
  }
7727
8213
  function mapStripeStatus(status) {
7728
8214
  const map = {
@@ -7739,7 +8225,7 @@ function mapStripeStatus(status) {
7739
8225
  }
7740
8226
  apiRoutes3.post("/webhook", async (c) => {
7741
8227
  const db = c.env.DB;
7742
- const settings = await getSettings4(db);
8228
+ const settings = await getSettings5(db);
7743
8229
  if (!settings.stripeWebhookSecret) {
7744
8230
  return c.json({ error: "Webhook secret not configured" }, 500);
7745
8231
  }
@@ -7869,7 +8355,7 @@ apiRoutes3.post("/create-checkout-session", requireAuth(), async (c) => {
7869
8355
  const db = c.env.DB;
7870
8356
  const user = c.get("user");
7871
8357
  if (!user) return c.json({ error: "Unauthorized" }, 401);
7872
- const settings = await getSettings4(db);
8358
+ const settings = await getSettings5(db);
7873
8359
  if (!settings.stripeSecretKey) {
7874
8360
  return c.json({ error: "Stripe not configured" }, 500);
7875
8361
  }
@@ -7946,7 +8432,7 @@ apiRoutes3.post("/sync-subscriptions", requireAuth(), async (c) => {
7946
8432
  const user = c.get("user");
7947
8433
  if (user?.role !== "admin") return c.json({ error: "Access denied" }, 403);
7948
8434
  const db = c.env.DB;
7949
- const settings = await getSettings4(db);
8435
+ const settings = await getSettings5(db);
7950
8436
  if (!settings.stripeSecretKey) {
7951
8437
  return c.json({ error: "Stripe secret key not configured" }, 400);
7952
8438
  }
@@ -8021,7 +8507,7 @@ var stripePlugin = definePlugin({
8021
8507
  sonicjsVersionRange: "^3.0.0",
8022
8508
  author: { name: "SonicJS Team" },
8023
8509
  register(app2) {
8024
- app2.route("/admin/plugins/stripe", adminRoutes4);
8510
+ app2.route("/admin/plugins/stripe", adminRoutes5);
8025
8511
  app2.route("/api/stripe", apiRoutes3);
8026
8512
  },
8027
8513
  menu: [
@@ -9714,6 +10200,7 @@ function renderFormCreatePage(data) {
9714
10200
  }
9715
10201
 
9716
10202
  // src/routes/admin-forms.ts
10203
+ var isTableMissing = (err) => String(err?.message ?? err?.cause?.message ?? "").includes("no such table: forms");
9717
10204
  var adminFormsRoutes = new Hono();
9718
10205
  adminFormsRoutes.use("*", requireAuth());
9719
10206
  adminFormsRoutes.get("/", async (c) => {
@@ -9755,6 +10242,14 @@ adminFormsRoutes.get("/", async (c) => {
9755
10242
  };
9756
10243
  return c.html(renderFormsListPage(pageData));
9757
10244
  } catch (error) {
10245
+ if (isTableMissing(error)) {
10246
+ const user = c.get("user");
10247
+ return c.html(renderFormsListPage({
10248
+ forms: [],
10249
+ user: user ? { name: user.email, email: user.email, role: user.role } : void 0,
10250
+ version: c.get("appVersion")
10251
+ }));
10252
+ }
9758
10253
  console.error("Error listing forms:", error);
9759
10254
  return c.html("<p>Error loading forms</p>", 500);
9760
10255
  }
@@ -9865,6 +10360,7 @@ adminFormsRoutes.post("/", async (c) => {
9865
10360
  ).run();
9866
10361
  return c.redirect(`/admin/forms/${formId}/builder`);
9867
10362
  } catch (error) {
10363
+ if (isTableMissing(error)) return c.json({ error: "Forms storage not configured \u2014 run database migrations" }, 503);
9868
10364
  console.error("Error creating form:", error);
9869
10365
  return c.json({ error: "Failed to create form" }, 500);
9870
10366
  }
@@ -9902,6 +10398,7 @@ adminFormsRoutes.get("/:id/builder", async (c) => {
9902
10398
  };
9903
10399
  return c.html(renderFormBuilderPage(pageData));
9904
10400
  } catch (error) {
10401
+ if (isTableMissing(error)) return c.html("<p>Forms storage not configured \u2014 run database migrations</p>", 503);
9905
10402
  console.error("Error showing form builder:", error);
9906
10403
  return c.html("<p>Error loading form builder</p>", 500);
9907
10404
  }
@@ -9931,6 +10428,7 @@ adminFormsRoutes.put("/:id", async (c) => {
9931
10428
  ).run();
9932
10429
  return c.json({ success: true, message: "Form saved successfully" });
9933
10430
  } catch (error) {
10431
+ if (isTableMissing(error)) return c.json({ error: "Forms storage not configured \u2014 run database migrations" }, 503);
9934
10432
  console.error("Error updating form:", error);
9935
10433
  return c.json({ error: "Failed to save form" }, 500);
9936
10434
  }
@@ -9952,6 +10450,7 @@ adminFormsRoutes.delete("/:id", async (c) => {
9952
10450
  await db.prepare("DELETE FROM forms WHERE id = ?").bind(formId).run();
9953
10451
  return c.json({ success: true, message: "Form deleted successfully" });
9954
10452
  } catch (error) {
10453
+ if (isTableMissing(error)) return c.json({ error: "Forms storage not configured \u2014 run database migrations" }, 503);
9955
10454
  console.error("Error deleting form:", error);
9956
10455
  return c.json({ error: "Failed to delete form" }, 500);
9957
10456
  }
@@ -10012,6 +10511,7 @@ adminFormsRoutes.get("/:id/submissions", async (c) => {
10012
10511
  `;
10013
10512
  return c.html(html4);
10014
10513
  } catch (error) {
10514
+ if (isTableMissing(error)) return c.html("<p>Forms storage not configured \u2014 run database migrations</p>", 503);
10015
10515
  console.error("Error loading submissions:", error);
10016
10516
  return c.html("<p>Error loading submissions</p>", 500);
10017
10517
  }
@@ -10032,6 +10532,7 @@ function sanitizeDeep(value) {
10032
10532
  }
10033
10533
  return value;
10034
10534
  }
10535
+ var isTableMissing2 = (err) => String(err?.message ?? err?.cause?.message ?? "").includes("no such table: form");
10035
10536
  var publicFormsRoutes = new Hono();
10036
10537
  publicFormsRoutes.get("/:identifier/turnstile-config", async (c) => {
10037
10538
  try {
@@ -10059,6 +10560,7 @@ publicFormsRoutes.get("/:identifier/turnstile-config", async (c) => {
10059
10560
  appearance: formSettings.appearance || globalSettings.appearance || "always"
10060
10561
  });
10061
10562
  } catch (error) {
10563
+ if (isTableMissing2(error)) return c.json({ enabled: false });
10062
10564
  console.error("Error fetching Turnstile config:", error);
10063
10565
  return c.json({ error: "Failed to fetch config" }, 500);
10064
10566
  }
@@ -10086,6 +10588,7 @@ publicFormsRoutes.get("/:identifier/schema", async (c) => {
10086
10588
  submitUrl: `/api/forms/${form.id}/submit`
10087
10589
  });
10088
10590
  } catch (error) {
10591
+ if (isTableMissing2(error)) return c.json({ error: "Form not found" }, 404);
10089
10592
  console.error("Error fetching form schema:", error);
10090
10593
  return c.json({ error: "Failed to fetch form schema" }, 500);
10091
10594
  }
@@ -10452,6 +10955,7 @@ publicFormsRoutes.get("/:name", async (c) => {
10452
10955
  `;
10453
10956
  return c.html(html4);
10454
10957
  } catch (error) {
10958
+ if (isTableMissing2(error)) return c.html("<h1>Form not found</h1><p>This form does not exist or is not publicly available.</p>", 404);
10455
10959
  console.error("Error rendering form:", error);
10456
10960
  return c.html("<p>Error loading form</p>", 500);
10457
10961
  }
@@ -10525,6 +11029,7 @@ publicFormsRoutes.post("/:identifier/submit", async (c) => {
10525
11029
  message: "Form submitted successfully"
10526
11030
  });
10527
11031
  } catch (error) {
11032
+ if (isTableMissing2(error)) return c.json({ error: "Form not found" }, 404);
10528
11033
  console.error("Error submitting form:", error);
10529
11034
  return c.json({ error: "Failed to submit form" }, 500);
10530
11035
  }
@@ -10672,7 +11177,7 @@ adminRbacRoutes.get("/", async (c) => {
10672
11177
  ${r.is_system ? `<code class="text-xs text-zinc-500 dark:text-zinc-400">${esc(r.name)}</code><span class="rounded-full bg-zinc-100 dark:bg-white/10 px-2 py-0.5 text-[11px] text-zinc-500 dark:text-zinc-400">system</span>` : `<input form="roles-bulk-form" class="${inpSm} w-28" name="name_${esc(r.id)}" value="${esc(r.name)}" required>`}
10673
11178
  <label class="ml-auto inline-flex items-center gap-2 rounded-md bg-white/5 px-2.5 py-1 text-xs font-medium text-zinc-700 dark:text-zinc-300 ring-1 ring-inset ring-zinc-500/20">
10674
11179
  <input form="roles-bulk-form" type="checkbox" name="portal_${esc(r.id)}" value="1" ${portalChecked ? "checked" : ""} ${portalDisabled ? "disabled" : ""} class="h-3.5 w-3.5 rounded border-zinc-400 text-cyan-600 focus:ring-cyan-500">
10675
- Access portal
11180
+ Admin Panel
10676
11181
  </label>
10677
11182
  <a href="/admin/tenants/roles/${esc(r.name)}" data-role-tenants="${esc(r.name)}" class="text-xs text-cyan-600 dark:text-cyan-400 hover:underline" title="Per-tenant assignments of this role">tenants</a>
10678
11183
  ${r.is_system ? "" : `<button form="delete-role-${esc(r.id)}" type="submit" onclick="return confirm('Delete role ${esc(r.name)}?')" class="text-xs text-red-600 dark:text-red-400 hover:underline">delete</button>`}
@@ -10776,7 +11281,7 @@ adminRbacRoutes.get("/", async (c) => {
10776
11281
  <div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-6">
10777
11282
  <div class="${card}">
10778
11283
  <h3 class="text-base font-semibold text-zinc-950 dark:text-white mb-3">Roles</h3>
10779
- <p class="mb-3 text-xs text-zinc-500 dark:text-zinc-400">Use <strong>Access portal</strong> to allow a role into the admin backend. Resource permissions are configured in the <strong>Matrix</strong> tab.</p>
11284
+ <p class="mb-3 text-xs text-zinc-500 dark:text-zinc-400">Use <strong>Admin Panel</strong> to allow a role into the admin backend. Resource permissions are configured in the <strong>Matrix</strong> tab.</p>
10780
11285
  ${roleList}
10781
11286
  </div>
10782
11287
  <div class="${card}">
@@ -11074,14 +11579,24 @@ function pluginMenuMiddleware() {
11074
11579
  }
11075
11580
  } catch {
11076
11581
  }
11077
- c.set("pluginMenuItems", activeMenuItems.map((m) => ({ label: m.label, path: m.path, icon: resolveIcon(m.icon) || "" })));
11582
+ const user = c.get("user");
11583
+ const singletonItems = resolvePluginMenuItems(user ? { role: user.role } : void 0);
11584
+ const existingPaths = new Set(activeMenuItems.map((i) => i.path));
11585
+ for (const item of singletonItems) {
11586
+ if (!existingPaths.has(item.path)) {
11587
+ activeMenuItems.push({ label: item.label, path: item.path, icon: item.icon, order: item.order });
11588
+ }
11589
+ }
11590
+ activeMenuItems.sort((a, b) => a.order - b.order);
11591
+ c.set("pluginMenuItems", activeMenuItems.map((m) => ({ label: m.label, path: m.path, icon: resolveIcon(m.icon) || m.icon || "" })));
11078
11592
  await next();
11079
- if (activeMenuItems.length > 0 && c.res.headers.get("content-type")?.includes("text/html")) {
11593
+ const finalItems = c.get("pluginMenuItems") ?? [];
11594
+ if (finalItems.length > 0 && c.res.headers.get("content-type")?.includes("text/html")) {
11080
11595
  const status = c.res.status;
11081
11596
  const headers = new Headers(c.res.headers);
11082
11597
  const html4 = await c.res.text();
11083
11598
  if (html4.includes(MARKER)) {
11084
- const renderedItems = activeMenuItems.map((item) => renderMenuItem(item, path)).join("");
11599
+ const renderedItems = finalItems.map((item) => renderMenuItem(item, path)).join("");
11085
11600
  const newHtml = html4.split(MARKER).join(renderedItems);
11086
11601
  c.res = new Response(newHtml, { status, headers });
11087
11602
  } else {
@@ -11091,16 +11606,16 @@ function pluginMenuMiddleware() {
11091
11606
  };
11092
11607
  }
11093
11608
  init_admin_layout_catalyst_template();
11094
- var adminRoutes5 = new Hono();
11095
- adminRoutes5.use("*", requireAuth());
11096
- adminRoutes5.use("*", async (c, next) => {
11609
+ var adminRoutes6 = new Hono();
11610
+ adminRoutes6.use("*", requireAuth());
11611
+ adminRoutes6.use("*", async (c, next) => {
11097
11612
  const user = c.get("user");
11098
11613
  if (user?.role !== "admin") {
11099
11614
  return c.text("Access denied", 403);
11100
11615
  }
11101
11616
  return next();
11102
11617
  });
11103
- adminRoutes5.get("/", async (c) => {
11618
+ adminRoutes6.get("/", async (c) => {
11104
11619
  const user = c.get("user");
11105
11620
  const db = c.env.DB;
11106
11621
  let totalRequests = 0;
@@ -11245,6 +11760,7 @@ var EventTrackingService = class {
11245
11760
  tenantId: TENANT2
11246
11761
  });
11247
11762
  }
11763
+ db;
11248
11764
  docsService;
11249
11765
  async trackEvent(input) {
11250
11766
  const doc = await this.docsService.create({
@@ -11456,7 +11972,7 @@ var analyticsPlugin = definePlugin({
11456
11972
  author: { name: "SonicJS Team", email: "team@sonicjs.com" },
11457
11973
  register(app2) {
11458
11974
  app2.route("/api/events", apiRoutes4);
11459
- app2.route("/admin/analytics", adminRoutes5);
11975
+ app2.route("/admin/analytics", adminRoutes6);
11460
11976
  },
11461
11977
  menu: [
11462
11978
  {
@@ -11738,8 +12254,8 @@ apiRoutes5.delete("/:id", async (c) => {
11738
12254
  return c.json({ success: false, error: "Failed to delete variable" }, 500);
11739
12255
  }
11740
12256
  });
11741
- var adminRoutes6 = new Hono();
11742
- adminRoutes6.use("*", async (c, next) => {
12257
+ var adminRoutes7 = new Hono();
12258
+ adminRoutes7.use("*", async (c, next) => {
11743
12259
  try {
11744
12260
  const db = c.env?.DB;
11745
12261
  if (db) {
@@ -11750,7 +12266,7 @@ adminRoutes6.use("*", async (c, next) => {
11750
12266
  }
11751
12267
  await next();
11752
12268
  });
11753
- adminRoutes6.get("/", async (c) => {
12269
+ adminRoutes7.get("/", async (c) => {
11754
12270
  const db = c.env.DB;
11755
12271
  let variables = [];
11756
12272
  try {
@@ -11780,7 +12296,7 @@ adminRoutes6.get("/", async (c) => {
11780
12296
  }
11781
12297
  return c.html(renderAdminPage(variables, { editorActive, activeEditorName, enableEditorIntegration }));
11782
12298
  });
11783
- adminRoutes6.put("/:id", async (c) => {
12299
+ adminRoutes7.put("/:id", async (c) => {
11784
12300
  const db = c.env.DB;
11785
12301
  const id = c.req.param("id");
11786
12302
  let body;
@@ -11796,7 +12312,7 @@ adminRoutes6.put("/:id", async (c) => {
11796
12312
  }
11797
12313
  return c.html('<span class="text-green-400 text-xs">Saved</span>');
11798
12314
  });
11799
- adminRoutes6.post("/:id/toggle", async (c) => {
12315
+ adminRoutes7.post("/:id/toggle", async (c) => {
11800
12316
  const db = c.env.DB;
11801
12317
  const id = c.req.param("id");
11802
12318
  await db.prepare("UPDATE global_variables SET is_active = CASE WHEN is_active = 1 THEN 0 ELSE 1 END, updated_at = strftime('%s', 'now') WHERE id = ?").bind(id).run();
@@ -11804,7 +12320,7 @@ adminRoutes6.post("/:id/toggle", async (c) => {
11804
12320
  c.header("HX-Redirect", "/admin/global-variables");
11805
12321
  return c.body(null, 204);
11806
12322
  });
11807
- adminRoutes6.post("/", async (c) => {
12323
+ adminRoutes7.post("/", async (c) => {
11808
12324
  const db = c.env.DB;
11809
12325
  const form = await c.req.parseBody();
11810
12326
  const key = (form.key || "").trim();
@@ -11825,7 +12341,7 @@ adminRoutes6.post("/", async (c) => {
11825
12341
  c.header("HX-Redirect", "/admin/global-variables");
11826
12342
  return c.body(null, 204);
11827
12343
  });
11828
- adminRoutes6.post("/settings/editor-integration", async (c) => {
12344
+ adminRoutes7.post("/settings/editor-integration", async (c) => {
11829
12345
  const db = c.env.DB;
11830
12346
  try {
11831
12347
  const row = await db.prepare("SELECT settings FROM plugins WHERE id = 'global-variables'").first();
@@ -11837,7 +12353,7 @@ adminRoutes6.post("/settings/editor-integration", async (c) => {
11837
12353
  return c.json({ success: false, error: "Failed to update setting" }, 500);
11838
12354
  }
11839
12355
  });
11840
- adminRoutes6.delete("/:id", async (c) => {
12356
+ adminRoutes7.delete("/:id", async (c) => {
11841
12357
  const db = c.env.DB;
11842
12358
  await db.prepare("DELETE FROM global_variables WHERE id = ?").bind(c.req.param("id")).run();
11843
12359
  invalidateVariablesCache();
@@ -12168,7 +12684,7 @@ var globalVariablesPlugin = definePlugin({
12168
12684
  capabilities: ["hooks.content:subscribe"],
12169
12685
  register(app2) {
12170
12686
  app2.route("/api/global-variables", apiRoutes5);
12171
- app2.route("/admin/global-variables", adminRoutes6);
12687
+ app2.route("/admin/global-variables", adminRoutes7);
12172
12688
  },
12173
12689
  menu: [
12174
12690
  { label: "Global Variables", path: "/admin/global-variables", icon: "bolt", order: 45, permissions: ["global-variables:view"] }
@@ -12489,8 +13005,8 @@ apiRoutes6.delete("/:id", async (c) => {
12489
13005
  return c.json({ success: false, error: "Failed to delete shortcode" }, 500);
12490
13006
  }
12491
13007
  });
12492
- var adminRoutes7 = new Hono();
12493
- adminRoutes7.use("*", async (c, next) => {
13008
+ var adminRoutes8 = new Hono();
13009
+ adminRoutes8.use("*", async (c, next) => {
12494
13010
  try {
12495
13011
  const db = c.env?.DB;
12496
13012
  if (db) {
@@ -12501,7 +13017,7 @@ adminRoutes7.use("*", async (c, next) => {
12501
13017
  }
12502
13018
  await next();
12503
13019
  });
12504
- adminRoutes7.get("/", async (c) => {
13020
+ adminRoutes8.get("/", async (c) => {
12505
13021
  const db = c.env.DB;
12506
13022
  let shortcodes = [];
12507
13023
  try {
@@ -12531,7 +13047,7 @@ adminRoutes7.get("/", async (c) => {
12531
13047
  }
12532
13048
  return c.html(renderAdminPage2(shortcodes, { editorActive, activeEditorName, enableEditorIntegration }));
12533
13049
  });
12534
- adminRoutes7.post("/", async (c) => {
13050
+ adminRoutes8.post("/", async (c) => {
12535
13051
  const db = c.env.DB;
12536
13052
  const form = await c.req.parseBody();
12537
13053
  const name = (form.name || "").trim();
@@ -12552,7 +13068,7 @@ adminRoutes7.post("/", async (c) => {
12552
13068
  c.header("HX-Redirect", "/admin/shortcodes");
12553
13069
  return c.body(null, 204);
12554
13070
  });
12555
- adminRoutes7.post("/settings/editor-integration", async (c) => {
13071
+ adminRoutes8.post("/settings/editor-integration", async (c) => {
12556
13072
  const db = c.env.DB;
12557
13073
  try {
12558
13074
  const row = await db.prepare("SELECT settings FROM plugins WHERE id = 'shortcodes'").first();
@@ -12564,7 +13080,7 @@ adminRoutes7.post("/settings/editor-integration", async (c) => {
12564
13080
  return c.json({ success: false, error: "Failed to update setting" }, 500);
12565
13081
  }
12566
13082
  });
12567
- adminRoutes7.delete("/:id", async (c) => {
13083
+ adminRoutes8.delete("/:id", async (c) => {
12568
13084
  await c.env.DB.prepare("DELETE FROM shortcodes WHERE id = ?").bind(c.req.param("id")).run();
12569
13085
  return c.html("");
12570
13086
  });
@@ -12775,7 +13291,7 @@ var shortcodesPlugin = definePlugin({
12775
13291
  capabilities: ["hooks.content:subscribe"],
12776
13292
  register(app2) {
12777
13293
  app2.route("/api/shortcodes", apiRoutes6);
12778
- app2.route("/admin/shortcodes", adminRoutes7);
13294
+ app2.route("/admin/shortcodes", adminRoutes8);
12779
13295
  },
12780
13296
  menu: [
12781
13297
  { label: "Shortcodes", path: "/admin/shortcodes", icon: "bolt", order: 46, permissions: ["shortcodes:view"] }
@@ -12884,6 +13400,9 @@ var helloWorldPlugin = definePlugin({
12884
13400
  console.info("\u274C Hello World plugin deactivated");
12885
13401
  }
12886
13402
  });
13403
+ function createHelloWorldPlugin() {
13404
+ return helloWorldPlugin;
13405
+ }
12887
13406
 
12888
13407
  // src/plugins/core-plugins/multi-tenant-plugin/manifest.json
12889
13408
  var manifest_default2 = {
@@ -16057,6 +16576,7 @@ function createSonicJSApp(config = {}) {
16057
16576
  const magicLinkPlugin = createMagicLinkAuthPlugin();
16058
16577
  const corePluginsBeforeCatchAll = [
16059
16578
  securityAuditPlugin,
16579
+ apiKeysPlugin,
16060
16580
  aiSearchPlugin,
16061
16581
  oauthProvidersPlugin,
16062
16582
  userProfilesPlugin,
@@ -16154,6 +16674,17 @@ function createSonicJSApp(config = {}) {
16154
16674
  app2.use("*", async (_c, next) => {
16155
16675
  await next();
16156
16676
  });
16677
+ app2.use("*", cors({
16678
+ origin: (origin, c) => {
16679
+ const allowed = c.env?.CORS_ORIGINS;
16680
+ if (!allowed) return null;
16681
+ const list = allowed.split(",").map((s) => s.trim());
16682
+ return list.includes(origin) ? origin : null;
16683
+ },
16684
+ allowMethods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
16685
+ allowHeaders: ["Content-Type", "Authorization", "X-API-Key"],
16686
+ credentials: true
16687
+ }));
16157
16688
  app2.use("*", securityHeadersMiddleware());
16158
16689
  app2.use("*", csrfProtection());
16159
16690
  app2.use("*", async (c, next) => {
@@ -16187,6 +16718,7 @@ function createSonicJSApp(config = {}) {
16187
16718
  }
16188
16719
  await next();
16189
16720
  });
16721
+ app2.use("*", apiKeyAuthMiddleware());
16190
16722
  if (config.middleware?.afterAuth) {
16191
16723
  for (const middleware of config.middleware.afterAuth) {
16192
16724
  app2.use("*", middleware);
@@ -16211,7 +16743,7 @@ function createSonicJSApp(config = {}) {
16211
16743
  if (!user?.userId) return next();
16212
16744
  let perms = [];
16213
16745
  try {
16214
- const { RbacService: RbacService2 } = await import('./rbac-O73MFKDA.js');
16746
+ const { RbacService: RbacService2 } = await import('./rbac-Y43IEQOP.js');
16215
16747
  perms = await new RbacService2(c.env.DB, c.env.CACHE_KV).permissionsForUser(user.userId);
16216
16748
  } catch {
16217
16749
  return next();
@@ -16285,7 +16817,10 @@ function createSonicJSApp(config = {}) {
16285
16817
  ...corePluginsAfterCatchAll,
16286
16818
  ...config.plugins?.register ?? []
16287
16819
  ];
16288
- setPluginMenu(allMountedPlugins.flatMap((p) => p.menu ?? []));
16820
+ const userPlugins = (config.plugins?.register ?? []).filter(
16821
+ (p) => !PLUGIN_REGISTRY[p.id]
16822
+ );
16823
+ setPluginMenu(userPlugins.flatMap((p) => p.menu ?? []));
16289
16824
  setPluginDefinitions(allMountedPlugins);
16290
16825
  }
16291
16826
  app2.get("/favicon.svg", (c) => {
@@ -17150,6 +17685,8 @@ var RedirectService = class {
17150
17685
  this.cloudflareService = new CloudflareBulkService(env);
17151
17686
  }
17152
17687
  }
17688
+ db;
17689
+ env;
17153
17690
  cloudflareService = null;
17154
17691
  getDocService() {
17155
17692
  return new DocumentsService(this.db, {
@@ -19914,6 +20451,6 @@ function createDb(d1) {
19914
20451
  // src/index.ts
19915
20452
  var VERSION = package_default.version;
19916
20453
 
19917
- export { BUILT_IN_PROVIDERS, CloudflareEmailProvider2 as CloudflareEmailProvider, OAuthService, VERSION, createDb, createOAuthProvidersPlugin, createRedirectPlugin, createSonicJSApp, emailReconciliationPlugin, generateTriggersComment, oauthProvidersPlugin, parseCronTriggers, redirectPlugin, setupCoreMiddleware, setupCoreRoutes, site_settings_collection_default as siteSettingsCollection, updateWranglerTriggers };
20454
+ export { BUILT_IN_PROVIDERS, CloudflareEmailProvider2 as CloudflareEmailProvider, OAuthService, VERSION, createDb, createHelloWorldPlugin, createOAuthProvidersPlugin, createRedirectPlugin, createSonicJSApp, emailReconciliationPlugin, generateTriggersComment, helloWorldPlugin, oauthProvidersPlugin, parseCronTriggers, redirectPlugin, setupCoreMiddleware, setupCoreRoutes, site_settings_collection_default as siteSettingsCollection, updateWranglerTriggers };
19918
20455
  //# sourceMappingURL=index.js.map
19919
20456
  //# sourceMappingURL=index.js.map