@sonicjs-cms/core 3.0.0-beta.2 → 3.0.0-beta.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +48 -49
- package/dist/admin-documents-form.template-DDSH6ROU.js +6 -0
- package/dist/{admin-documents-form.template-NLSI6Z42.js.map → admin-documents-form.template-DDSH6ROU.js.map} +1 -1
- package/dist/admin-documents-form.template-LSZKGA5J.cjs +19 -0
- package/dist/{admin-layout-catalyst.template-WHJGSWWD.js.map → admin-documents-form.template-LSZKGA5J.cjs.map} +1 -1
- package/dist/{filter-bar.template-DlVYMk-T.d.ts → admin-layout-catalyst.template-DrwDUfsE.d.cts} +25 -1
- package/dist/{filter-bar.template-DlVYMk-T.d.cts → admin-layout-catalyst.template-DrwDUfsE.d.ts} +25 -1
- package/dist/admin-layout-catalyst.template-KDHKVLXR.cjs +21 -0
- package/dist/{admin-layout-catalyst.template-ZK5HD545.cjs.map → admin-layout-catalyst.template-KDHKVLXR.cjs.map} +1 -1
- package/dist/admin-layout-catalyst.template-YQ4EMF2J.js +7 -0
- package/dist/{admin-documents-form.template-KN7JF66Q.cjs.map → admin-layout-catalyst.template-YQ4EMF2J.js.map} +1 -1
- package/dist/{app-Bo0X1OWX.d.ts → app-01M0dIwt.d.ts} +1 -1
- package/dist/{app-Do66yCcV.d.cts → app-aj39TGHB.d.cts} +1 -1
- package/dist/{chunk-ZEZ245PW.js → chunk-2XAQTPAE.js} +4 -236
- package/dist/chunk-2XAQTPAE.js.map +1 -0
- package/dist/{chunk-BDDABDAB.cjs → chunk-36Z3AKX3.cjs} +3 -239
- package/dist/chunk-36Z3AKX3.cjs.map +1 -0
- package/dist/{chunk-BLMTL57B.js → chunk-3TMTYJAJ.js} +26 -4
- package/dist/chunk-3TMTYJAJ.js.map +1 -0
- package/dist/{chunk-ZGGXCFR6.js → chunk-4LVVMVQI.js} +282 -4
- package/dist/chunk-4LVVMVQI.js.map +1 -0
- package/dist/{chunk-RZ6H7OZK.js → chunk-4UYJPHSV.js} +87 -12
- package/dist/chunk-4UYJPHSV.js.map +1 -0
- package/dist/{chunk-NLJVSER2.js → chunk-5U75XP74.js} +3 -2
- package/dist/chunk-5U75XP74.js.map +1 -0
- package/dist/{chunk-H2AXVCLS.cjs → chunk-5UXU3LP4.cjs} +141 -74
- package/dist/chunk-5UXU3LP4.cjs.map +1 -0
- package/dist/{chunk-3TB6AT6X.js → chunk-5V62WT6M.js} +35 -4
- package/dist/chunk-5V62WT6M.js.map +1 -0
- package/dist/{chunk-6OUHGKFD.js → chunk-7OTOXWEB.js} +3 -3
- package/dist/{chunk-6OUHGKFD.js.map → chunk-7OTOXWEB.js.map} +1 -1
- package/dist/{chunk-VXE42MYF.cjs → chunk-7RUW244J.cjs} +710 -434
- package/dist/chunk-7RUW244J.cjs.map +1 -0
- package/dist/{chunk-XW56B23A.cjs → chunk-A4KUJ3LD.cjs} +4 -4
- package/dist/{chunk-XW56B23A.cjs.map → chunk-A4KUJ3LD.cjs.map} +1 -1
- package/dist/{chunk-LRZIAW7U.cjs → chunk-AOUVUF32.cjs} +3 -3
- package/dist/chunk-AOUVUF32.cjs.map +1 -0
- package/dist/{chunk-WULONYGB.cjs → chunk-CRGUD4KC.cjs} +9 -9
- package/dist/{chunk-WULONYGB.cjs.map → chunk-CRGUD4KC.cjs.map} +1 -1
- package/dist/{chunk-AAWNRBRB.cjs → chunk-FCLKX2OS.cjs} +95 -20
- package/dist/chunk-FCLKX2OS.cjs.map +1 -0
- package/dist/{chunk-YHSQVQXX.js → chunk-GICS5AIO.js} +135 -68
- package/dist/chunk-GICS5AIO.js.map +1 -0
- package/dist/{chunk-NUKJ54GA.cjs → chunk-GMMCCIQO.cjs} +6 -6
- package/dist/{chunk-NUKJ54GA.cjs.map → chunk-GMMCCIQO.cjs.map} +1 -1
- package/dist/{chunk-NMPEMSU4.js → chunk-JEX3UPZL.js} +3 -3
- package/dist/chunk-JEX3UPZL.js.map +1 -0
- package/dist/{chunk-6JQOUUOB.js → chunk-JQISFW6U.js} +3 -3
- package/dist/{chunk-6JQOUUOB.js.map → chunk-JQISFW6U.js.map} +1 -1
- package/dist/{chunk-NAVPFIG5.cjs → chunk-K623Q6WD.cjs} +35 -3
- package/dist/chunk-K623Q6WD.cjs.map +1 -0
- package/dist/{chunk-JEQ7FLOD.cjs → chunk-KIGVVO6N.cjs} +16 -10
- package/dist/chunk-KIGVVO6N.cjs.map +1 -0
- package/dist/{chunk-QAYFOER6.cjs → chunk-KVBHB7QP.cjs} +285 -3
- package/dist/chunk-KVBHB7QP.cjs.map +1 -0
- package/dist/{chunk-2CB4KY7I.cjs → chunk-LTZ5WYOK.cjs} +29 -7
- package/dist/chunk-LTZ5WYOK.cjs.map +1 -0
- package/dist/{chunk-DNQCEKUK.cjs → chunk-N32OWET6.cjs} +5 -5
- package/dist/{chunk-DNQCEKUK.cjs.map → chunk-N32OWET6.cjs.map} +1 -1
- package/dist/{chunk-HDWE5FRJ.js → chunk-OBA2RYZN.js} +3 -3
- package/dist/{chunk-HDWE5FRJ.js.map → chunk-OBA2RYZN.js.map} +1 -1
- package/dist/{chunk-DSA4UX5B.cjs → chunk-OJC4G5JE.cjs} +3 -2
- package/dist/chunk-OJC4G5JE.cjs.map +1 -0
- package/dist/{chunk-MVIZJOO5.cjs → chunk-PXNTCCPE.cjs} +8 -8
- package/dist/{chunk-MVIZJOO5.cjs.map → chunk-PXNTCCPE.cjs.map} +1 -1
- package/dist/{chunk-EF2NQUIQ.js → chunk-RMRJGMDE.js} +3 -3
- package/dist/{chunk-EF2NQUIQ.js.map → chunk-RMRJGMDE.js.map} +1 -1
- package/dist/{chunk-IVPRUGTY.js → chunk-SOZUG52O.js} +4 -4
- package/dist/{chunk-IVPRUGTY.js.map → chunk-SOZUG52O.js.map} +1 -1
- package/dist/{chunk-GCDZZNIN.js → chunk-UWUP2VMT.js} +16 -10
- package/dist/chunk-UWUP2VMT.js.map +1 -0
- package/dist/{chunk-IESEVHXL.js → chunk-VVYVFCML.js} +12 -3
- package/dist/chunk-VVYVFCML.js.map +1 -0
- package/dist/{chunk-HIKBY7MS.cjs → chunk-XWVDSM2L.cjs} +12 -3
- package/dist/chunk-XWVDSM2L.cjs.map +1 -0
- package/dist/{chunk-VD2EA3WT.js → chunk-ZP77LTN4.js} +343 -68
- package/dist/chunk-ZP77LTN4.js.map +1 -0
- package/dist/{collection-config-JgHOpFCG.d.ts → collection-config-BTzAvKt2.d.cts} +25 -0
- package/dist/{collection-config-JgHOpFCG.d.cts → collection-config-BTzAvKt2.d.ts} +25 -0
- package/dist/config-6FB2BXMP.js +6 -0
- package/dist/{config-HFXANXCC.js.map → config-6FB2BXMP.js.map} +1 -1
- package/dist/config-OCH7S4WK.cjs +19 -0
- package/dist/{config-ON6FNMYX.cjs.map → config-OCH7S4WK.cjs.map} +1 -1
- package/dist/{define-plugin-BzNHc1ZI.d.ts → define-plugin-BYIey6sp.d.ts} +1 -1
- package/dist/{define-plugin-IWDKYaVm.d.cts → define-plugin-DsKiGu1q.d.cts} +1 -1
- package/dist/document-projection-4HG75S5S.js +4 -0
- package/dist/{document-projection-YYMC6I4U.js.map → document-projection-4HG75S5S.js.map} +1 -1
- package/dist/document-projection-JQHSTSFD.cjs +13 -0
- package/dist/{document-projection-TDWRJX3Z.cjs.map → document-projection-JQHSTSFD.cjs.map} +1 -1
- package/dist/index.cjs +1119 -440
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +200 -12
- package/dist/index.d.ts +200 -12
- package/dist/index.js +803 -137
- package/dist/index.js.map +1 -1
- package/dist/middleware.cjs +37 -34
- package/dist/middleware.d.cts +2 -2
- package/dist/middleware.d.ts +2 -2
- package/dist/middleware.js +8 -5
- package/dist/migrations-HMX5SPN2.js +4 -0
- package/dist/{migrations-WCAVBD7C.js.map → migrations-HMX5SPN2.js.map} +1 -1
- package/dist/migrations-V73ARYV5.cjs +13 -0
- package/dist/{migrations-NJJWQUKK.cjs.map → migrations-V73ARYV5.cjs.map} +1 -1
- package/dist/{plugin-bootstrap-B8ThJU21.d.cts → plugin-bootstrap-BHWQ2df8.d.cts} +1 -1
- package/dist/{plugin-bootstrap-qu8hJgUt.d.ts → plugin-bootstrap-Bj4fxX1q.d.ts} +1 -1
- package/dist/plugins.cjs +40 -40
- package/dist/plugins.d.cts +2 -2
- package/dist/plugins.d.ts +2 -2
- package/dist/plugins.js +3 -3
- package/dist/rbac-7QZ4JZ2E.cjs +14 -0
- package/dist/{rbac-VONLJJKB.cjs.map → rbac-7QZ4JZ2E.cjs.map} +1 -1
- package/dist/rbac-Y43IEQOP.js +5 -0
- package/dist/{rbac-O73MFKDA.js.map → rbac-Y43IEQOP.js.map} +1 -1
- package/dist/routes.cjs +34 -34
- package/dist/routes.d.cts +2 -2
- package/dist/routes.d.ts +2 -2
- package/dist/routes.js +14 -14
- package/dist/services.cjs +42 -42
- package/dist/services.d.cts +16 -3
- package/dist/services.d.ts +16 -3
- package/dist/services.js +3 -3
- package/dist/{telemetry-B9vIV4wh.d.cts → telemetry-Cku1ax74.d.cts} +1 -1
- package/dist/{telemetry-B9vIV4wh.d.ts → telemetry-Cku1ax74.d.ts} +1 -1
- package/dist/templates.cjs +17 -17
- package/dist/templates.d.cts +2 -24
- package/dist/templates.d.ts +2 -24
- package/dist/templates.js +3 -3
- package/dist/{types-Dea1eNxU.d.ts → types-DT7XN5TX.d.cts} +1 -1
- package/dist/{types-Dea1eNxU.d.cts → types-DT7XN5TX.d.ts} +1 -1
- package/dist/types.d.cts +2 -2
- package/dist/types.d.ts +2 -2
- package/dist/utils.cjs +8 -8
- package/dist/utils.d.cts +2 -2
- package/dist/utils.d.ts +2 -2
- package/dist/utils.js +2 -2
- package/package.json +1 -1
- package/dist/admin-documents-form.template-KN7JF66Q.cjs +0 -19
- package/dist/admin-documents-form.template-NLSI6Z42.js +0 -6
- package/dist/admin-layout-catalyst.template-WHJGSWWD.js +0 -7
- package/dist/admin-layout-catalyst.template-ZK5HD545.cjs +0 -17
- package/dist/chunk-2CB4KY7I.cjs.map +0 -1
- package/dist/chunk-3TB6AT6X.js.map +0 -1
- package/dist/chunk-AAWNRBRB.cjs.map +0 -1
- package/dist/chunk-BDDABDAB.cjs.map +0 -1
- package/dist/chunk-BLMTL57B.js.map +0 -1
- package/dist/chunk-DSA4UX5B.cjs.map +0 -1
- package/dist/chunk-GCDZZNIN.js.map +0 -1
- package/dist/chunk-H2AXVCLS.cjs.map +0 -1
- package/dist/chunk-HIKBY7MS.cjs.map +0 -1
- package/dist/chunk-IESEVHXL.js.map +0 -1
- package/dist/chunk-JEQ7FLOD.cjs.map +0 -1
- package/dist/chunk-LRZIAW7U.cjs.map +0 -1
- package/dist/chunk-NAVPFIG5.cjs.map +0 -1
- package/dist/chunk-NLJVSER2.js.map +0 -1
- package/dist/chunk-NMPEMSU4.js.map +0 -1
- package/dist/chunk-QAYFOER6.cjs.map +0 -1
- package/dist/chunk-RZ6H7OZK.js.map +0 -1
- package/dist/chunk-VD2EA3WT.js.map +0 -1
- package/dist/chunk-VXE42MYF.cjs.map +0 -1
- package/dist/chunk-YHSQVQXX.js.map +0 -1
- package/dist/chunk-ZEZ245PW.js.map +0 -1
- package/dist/chunk-ZGGXCFR6.js.map +0 -1
- package/dist/config-HFXANXCC.js +0 -6
- package/dist/config-ON6FNMYX.cjs +0 -19
- package/dist/document-projection-TDWRJX3Z.cjs +0 -13
- package/dist/document-projection-YYMC6I4U.js +0 -4
- package/dist/migrations-NJJWQUKK.cjs +0 -13
- package/dist/migrations-WCAVBD7C.js +0 -4
- package/dist/rbac-O73MFKDA.js +0 -5
- package/dist/rbac-VONLJJKB.cjs +0 -14
package/dist/index.js
CHANGED
|
@@ -1,41 +1,43 @@
|
|
|
1
|
-
import { createAuth } from './chunk-
|
|
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-
|
|
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-
|
|
4
|
-
import './chunk-
|
|
5
|
-
import './chunk-
|
|
6
|
-
import { SettingsService, setAppInstance } from './chunk-
|
|
7
|
-
export { Logger, getLogger, initLogger } from './chunk-
|
|
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-ZP77LTN4.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-ZP77LTN4.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-
|
|
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-
|
|
13
|
-
import { RbacService, DocumentsService } from './chunk-
|
|
14
|
-
export { RbacService } from './chunk-
|
|
15
|
-
import { nanoid } from './chunk-
|
|
16
|
-
import { PluginService, PLUGIN_REGISTRY, invalidateTenantCache, getCollectionRegistry, TENANT_COOKIE, MULTI_TENANT_PLUGIN_ID, collectionRecordToRow, tenantMiddleware } from './chunk-
|
|
17
|
-
export { PluginBootstrapService, PluginService as PluginServiceClass, getAvailableCollectionNames, loadCollectionConfig, loadCollectionConfigs, registerCollections, validateCollectionConfig } from './chunk-
|
|
18
|
-
export { MigrationService } from './chunk-
|
|
19
|
-
export { renderFilterBar } from './chunk-
|
|
20
|
-
import { renderAdminLayout } from './chunk-
|
|
21
|
-
export { getConfirmationDialogScript, renderAlert, renderConfirmationDialog, renderForm, renderFormField, renderPagination, renderTable } from './chunk-
|
|
22
|
-
import { init_admin_layout_catalyst_template, renderAdminLayoutCatalyst } from './chunk-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
11
|
+
import { requireAuth, DocumentTypeRegistry, requireRbac, requireRole, getJwtExpirySecondsFromDb, AuthManager, metricsMiddleware, bootstrapMiddleware, securityHeadersMiddleware, csrfProtection } from './chunk-4UYJPHSV.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-4UYJPHSV.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-4LVVMVQI.js';
|
|
17
|
+
export { PluginBootstrapService, PluginService as PluginServiceClass, getAvailableCollectionNames, loadCollectionConfig, loadCollectionConfigs, registerCollections, validateCollectionConfig } from './chunk-4LVVMVQI.js';
|
|
18
|
+
export { MigrationService } from './chunk-5U75XP74.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-GICS5AIO.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-GICS5AIO.js';
|
|
26
|
+
import { definePlugin, setPluginDefinitions } from './chunk-7OTOXWEB.js';
|
|
27
|
+
export { applySchemaDefaults, definePlugin, isDefinedPlugin, parseConfigSchema, parseFormDataToSettings, renderSchemaFields } from './chunk-7OTOXWEB.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
|
|
33
|
-
|
|
32
|
+
import './chunk-X7ZAEI5S.js';
|
|
33
|
+
import { getCoreVersion, package_default } from './chunk-JEX3UPZL.js';
|
|
34
|
+
export { SONICJS_VERSION, getCoreVersion } from './chunk-JEX3UPZL.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
|
*/
|
|
@@ -190,9 +193,9 @@ var DatabaseToolsService = class {
|
|
|
190
193
|
}
|
|
191
194
|
}
|
|
192
195
|
/**
|
|
193
|
-
* Get table data with optional pagination and
|
|
196
|
+
* Get table data with optional pagination, sorting, and search
|
|
194
197
|
*/
|
|
195
|
-
async getTableData(tableName, limit = 100, offset = 0, sortColumn, sortDirection = "asc") {
|
|
198
|
+
async getTableData(tableName, limit = 100, offset = 0, sortColumn, sortDirection = "asc", search) {
|
|
196
199
|
try {
|
|
197
200
|
const tables = await this.getTables();
|
|
198
201
|
if (!tables.includes(tableName)) {
|
|
@@ -203,14 +206,26 @@ var DatabaseToolsService = class {
|
|
|
203
206
|
if (sortColumn && !columns.includes(sortColumn)) {
|
|
204
207
|
sortColumn = void 0;
|
|
205
208
|
}
|
|
206
|
-
const
|
|
209
|
+
const searchTerm = search?.trim();
|
|
210
|
+
let whereClause = "";
|
|
211
|
+
let bindings = [];
|
|
212
|
+
if (searchTerm) {
|
|
213
|
+
const conditions = columns.map(() => `CAST(? AS TEXT) IS NOT NULL AND CAST(? AS TEXT) LIKE ?`).join(" OR ");
|
|
214
|
+
const colConditions = columns.map((col) => `CAST("${col}" AS TEXT) LIKE ?`).join(" OR ");
|
|
215
|
+
whereClause = ` WHERE (${colConditions})`;
|
|
216
|
+
bindings = columns.map(() => `%${searchTerm}%`);
|
|
217
|
+
}
|
|
218
|
+
const countQuery = `SELECT COUNT(*) as count FROM "${tableName}"${whereClause}`;
|
|
219
|
+
const countStmt = this.db.prepare(countQuery);
|
|
220
|
+
const countResult = bindings.length > 0 ? await countStmt.bind(...bindings).first() : await countStmt.first();
|
|
207
221
|
const totalRows = countResult?.count || 0;
|
|
208
|
-
let query = `SELECT * FROM ${tableName}`;
|
|
222
|
+
let query = `SELECT * FROM "${tableName}"${whereClause}`;
|
|
209
223
|
if (sortColumn) {
|
|
210
|
-
query += ` ORDER BY ${sortColumn} ${sortDirection.toUpperCase()}`;
|
|
224
|
+
query += ` ORDER BY "${sortColumn}" ${sortDirection.toUpperCase()}`;
|
|
211
225
|
}
|
|
212
226
|
query += ` LIMIT ${limit} OFFSET ${offset}`;
|
|
213
|
-
const
|
|
227
|
+
const dataStmt = this.db.prepare(query);
|
|
228
|
+
const dataResult = bindings.length > 0 ? await dataStmt.bind(...bindings).all() : await dataStmt.all();
|
|
214
229
|
return {
|
|
215
230
|
tableName,
|
|
216
231
|
columns,
|
|
@@ -314,6 +329,43 @@ function renderDatabaseTablePage(data) {
|
|
|
314
329
|
</div>
|
|
315
330
|
</div>
|
|
316
331
|
|
|
332
|
+
<!-- Search bar -->
|
|
333
|
+
<div class="flex items-center gap-3">
|
|
334
|
+
<div class="relative flex-1 max-w-xl">
|
|
335
|
+
<div class="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3">
|
|
336
|
+
<svg class="h-4 w-4 text-zinc-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
337
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0"/>
|
|
338
|
+
</svg>
|
|
339
|
+
</div>
|
|
340
|
+
<input
|
|
341
|
+
id="searchInput"
|
|
342
|
+
type="text"
|
|
343
|
+
placeholder="Search all columns including JSON data..."
|
|
344
|
+
value="${escapeHtml2(data.search || "")}"
|
|
345
|
+
class="block w-full rounded-lg border-0 py-2.5 pl-10 pr-10 text-sm text-zinc-900 dark:text-white bg-white dark:bg-zinc-800 ring-1 ring-inset ring-zinc-300 dark:ring-zinc-700 placeholder:text-zinc-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600"
|
|
346
|
+
onkeydown="if(event.key==='Enter') doSearch()"
|
|
347
|
+
/>
|
|
348
|
+
${data.search ? `
|
|
349
|
+
<button
|
|
350
|
+
onclick="clearSearch()"
|
|
351
|
+
class="absolute inset-y-0 right-0 flex items-center pr-3 text-zinc-400 hover:text-zinc-600 dark:hover:text-zinc-200"
|
|
352
|
+
title="Clear search"
|
|
353
|
+
>
|
|
354
|
+
<svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
355
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
|
|
356
|
+
</svg>
|
|
357
|
+
</button>
|
|
358
|
+
` : ""}
|
|
359
|
+
</div>
|
|
360
|
+
<button
|
|
361
|
+
onclick="doSearch()"
|
|
362
|
+
class="inline-flex items-center justify-center rounded-lg bg-indigo-600 px-4 py-2.5 text-sm font-semibold text-white hover:bg-indigo-500 transition-colors shadow-sm"
|
|
363
|
+
>
|
|
364
|
+
Search
|
|
365
|
+
</button>
|
|
366
|
+
${data.search ? `<span class="text-sm text-zinc-500 dark:text-zinc-400">Filtered: <strong class="text-zinc-900 dark:text-white">${escapeHtml2(data.search)}</strong></span>` : ""}
|
|
367
|
+
</div>
|
|
368
|
+
|
|
317
369
|
<!-- Table Card -->
|
|
318
370
|
<div class="rounded-xl bg-white dark:bg-zinc-900 shadow-sm ring-1 ring-zinc-950/5 dark:ring-white/10 overflow-hidden">
|
|
319
371
|
<!-- Table -->
|
|
@@ -348,7 +400,7 @@ function renderDatabaseTablePage(data) {
|
|
|
348
400
|
<tr class="${idx % 2 === 0 ? "bg-white dark:bg-zinc-900" : "bg-zinc-50 dark:bg-zinc-900/50"}">
|
|
349
401
|
${data.columns.map((col) => `
|
|
350
402
|
<td class="px-4 py-3 text-sm text-zinc-700 dark:text-zinc-300 whitespace-nowrap max-w-xs overflow-hidden text-ellipsis" title="${escapeHtml2(String(row[col] ?? ""))}">
|
|
351
|
-
${formatCellValue(row[col])}
|
|
403
|
+
${formatCellValue(row[col], col)}
|
|
352
404
|
</td>
|
|
353
405
|
`).join("")}
|
|
354
406
|
</tr>
|
|
@@ -424,79 +476,143 @@ function renderDatabaseTablePage(data) {
|
|
|
424
476
|
</div>
|
|
425
477
|
</div>
|
|
426
478
|
|
|
479
|
+
<!-- JSON Viewer Modal -->
|
|
480
|
+
<div id="jsonModal" class="fixed inset-0 z-50 hidden" role="dialog" aria-modal="true">
|
|
481
|
+
<div class="fixed inset-0 bg-black/60 backdrop-blur-sm" onclick="closeJsonModal()"></div>
|
|
482
|
+
<div class="fixed inset-0 flex items-center justify-center p-4 pointer-events-none">
|
|
483
|
+
<div class="pointer-events-auto relative w-full max-w-4xl max-h-[85vh] flex flex-col rounded-xl bg-white dark:bg-zinc-900 shadow-2xl ring-1 ring-zinc-950/10 dark:ring-white/10">
|
|
484
|
+
<div class="flex items-center justify-between px-6 py-4 border-b border-zinc-200 dark:border-zinc-700">
|
|
485
|
+
<div>
|
|
486
|
+
<h3 id="jsonModalTitle" class="text-base font-semibold text-zinc-900 dark:text-white">Field Value</h3>
|
|
487
|
+
<p id="jsonModalSubtitle" class="text-xs text-zinc-500 dark:text-zinc-400 mt-0.5"></p>
|
|
488
|
+
</div>
|
|
489
|
+
<div class="flex items-center gap-2">
|
|
490
|
+
<button onclick="copyJsonValue()" class="inline-flex items-center gap-1.5 rounded-lg bg-zinc-100 dark:bg-zinc-800 px-3 py-1.5 text-xs font-medium text-zinc-700 dark:text-zinc-300 hover:bg-zinc-200 dark:hover:bg-zinc-700 transition-colors">
|
|
491
|
+
<svg class="h-3.5 w-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
492
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"/>
|
|
493
|
+
</svg>
|
|
494
|
+
Copy
|
|
495
|
+
</button>
|
|
496
|
+
<button onclick="closeJsonModal()" class="rounded-lg p-1.5 text-zinc-400 hover:text-zinc-600 dark:hover:text-zinc-200 hover:bg-zinc-100 dark:hover:bg-zinc-800 transition-colors">
|
|
497
|
+
<svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
498
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
|
|
499
|
+
</svg>
|
|
500
|
+
</button>
|
|
501
|
+
</div>
|
|
502
|
+
</div>
|
|
503
|
+
<div class="flex-1 overflow-auto p-6">
|
|
504
|
+
<pre id="jsonModalContent" class="text-sm font-mono text-zinc-800 dark:text-zinc-200 whitespace-pre-wrap break-words leading-relaxed"></pre>
|
|
505
|
+
</div>
|
|
506
|
+
</div>
|
|
507
|
+
</div>
|
|
508
|
+
</div>
|
|
509
|
+
|
|
427
510
|
<script>
|
|
428
511
|
const currentTableName = '${data.tableName}';
|
|
429
512
|
let currentPage = ${data.currentPage};
|
|
430
513
|
let currentPageSize = ${data.pageSize};
|
|
431
514
|
let currentSort = '${data.sortColumn || ""}';
|
|
432
515
|
let currentSortDir = '${data.sortDirection || "asc"}';
|
|
516
|
+
let currentSearch = ${JSON.stringify(data.search || "")};
|
|
517
|
+
|
|
518
|
+
function buildParams(overrides = {}) {
|
|
519
|
+
const params = new URLSearchParams();
|
|
520
|
+
const p = { page: currentPage, pageSize: currentPageSize, sort: currentSort, dir: currentSortDir, search: currentSearch, ...overrides };
|
|
521
|
+
if (p.page) params.set('page', p.page);
|
|
522
|
+
if (p.pageSize) params.set('pageSize', p.pageSize);
|
|
523
|
+
if (p.sort) { params.set('sort', p.sort); params.set('dir', p.dir || 'asc'); }
|
|
524
|
+
if (p.search) params.set('search', p.search);
|
|
525
|
+
return params;
|
|
526
|
+
}
|
|
433
527
|
|
|
434
528
|
function goToPage(page) {
|
|
435
529
|
if (page < 1 || page > ${totalPages}) return;
|
|
436
|
-
|
|
437
|
-
params.set('page', page);
|
|
438
|
-
params.set('pageSize', currentPageSize);
|
|
439
|
-
if (currentSort) {
|
|
440
|
-
params.set('sort', currentSort);
|
|
441
|
-
params.set('dir', currentSortDir);
|
|
442
|
-
}
|
|
443
|
-
window.location.href = \`/admin/database-tools/tables/\${currentTableName}?\${params}\`;
|
|
530
|
+
window.location.href = \`/admin/database-tools/tables/\${currentTableName}?\${buildParams({ page })}\`;
|
|
444
531
|
}
|
|
445
532
|
|
|
446
533
|
function sortTable(column) {
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
newDir = 'desc';
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
const params = new URLSearchParams();
|
|
453
|
-
params.set('page', '1');
|
|
454
|
-
params.set('pageSize', currentPageSize);
|
|
455
|
-
params.set('sort', column);
|
|
456
|
-
params.set('dir', newDir);
|
|
457
|
-
window.location.href = \`/admin/database-tools/tables/\${currentTableName}?\${params}\`;
|
|
534
|
+
const newDir = (currentSort === column && currentSortDir === 'asc') ? 'desc' : 'asc';
|
|
535
|
+
window.location.href = \`/admin/database-tools/tables/\${currentTableName}?\${buildParams({ page: 1, sort: column, dir: newDir })}\`;
|
|
458
536
|
}
|
|
459
537
|
|
|
460
538
|
function changePageSize(newSize) {
|
|
461
|
-
|
|
462
|
-
params.set('page', '1');
|
|
463
|
-
params.set('pageSize', newSize);
|
|
464
|
-
if (currentSort) {
|
|
465
|
-
params.set('sort', currentSort);
|
|
466
|
-
params.set('dir', currentSortDir);
|
|
467
|
-
}
|
|
468
|
-
window.location.href = \`/admin/database-tools/tables/\${currentTableName}?\${params}\`;
|
|
539
|
+
window.location.href = \`/admin/database-tools/tables/\${currentTableName}?\${buildParams({ page: 1, pageSize: newSize })}\`;
|
|
469
540
|
}
|
|
470
541
|
|
|
471
542
|
function refreshTableData() {
|
|
472
543
|
window.location.reload();
|
|
473
544
|
}
|
|
474
545
|
|
|
475
|
-
function
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
546
|
+
function doSearch() {
|
|
547
|
+
const val = document.getElementById('searchInput').value.trim();
|
|
548
|
+
window.location.href = \`/admin/database-tools/tables/\${currentTableName}?\${buildParams({ page: 1, search: val })}\`;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
function clearSearch() {
|
|
552
|
+
window.location.href = \`/admin/database-tools/tables/\${currentTableName}?\${buildParams({ page: 1, search: '' })}\`;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
// JSON viewer modal
|
|
556
|
+
let _jsonModalValue = '';
|
|
557
|
+
|
|
558
|
+
function openJsonModal(rawValue, colName) {
|
|
559
|
+
// rawValue comes from dataset \u2014 browser already decoded HTML entities, so it's the original string
|
|
560
|
+
_jsonModalValue = rawValue;
|
|
561
|
+
document.getElementById('jsonModalTitle').textContent = colName;
|
|
562
|
+
const el = document.getElementById('jsonModalContent');
|
|
563
|
+
const subtitle = document.getElementById('jsonModalSubtitle');
|
|
564
|
+
try {
|
|
565
|
+
const parsed = JSON.parse(rawValue);
|
|
566
|
+
const pretty = JSON.stringify(parsed, null, 2);
|
|
567
|
+
subtitle.textContent = 'JSON \u2022 ' + rawValue.length + ' chars';
|
|
568
|
+
el.innerHTML = syntaxHighlight(pretty);
|
|
569
|
+
} catch {
|
|
570
|
+
el.textContent = rawValue;
|
|
571
|
+
subtitle.textContent = rawValue.length + ' chars';
|
|
488
572
|
}
|
|
489
|
-
|
|
573
|
+
document.getElementById('jsonModal').classList.remove('hidden');
|
|
574
|
+
document.body.style.overflow = 'hidden';
|
|
490
575
|
}
|
|
491
576
|
|
|
577
|
+
function closeJsonModal() {
|
|
578
|
+
document.getElementById('jsonModal').classList.add('hidden');
|
|
579
|
+
document.body.style.overflow = '';
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
function copyJsonValue() {
|
|
583
|
+
navigator.clipboard.writeText(_jsonModalValue).then(() => {
|
|
584
|
+
const btn = event.currentTarget;
|
|
585
|
+
const orig = btn.innerHTML;
|
|
586
|
+
btn.textContent = 'Copied!';
|
|
587
|
+
setTimeout(() => { btn.innerHTML = orig; }, 1500);
|
|
588
|
+
});
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
function syntaxHighlight(json) {
|
|
592
|
+
json = json.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
593
|
+
return json.replace(/("(\\\\u[a-zA-Z0-9]{4}|\\\\[^u]|[^\\\\"])*"(\\s*:)?|\\b(true|false|null)\\b|-?\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d+)?)/g, function(match) {
|
|
594
|
+
let cls = 'text-purple-600 dark:text-purple-400'; // number
|
|
595
|
+
if (/^"/.test(match)) {
|
|
596
|
+
if (/:$/.test(match)) {
|
|
597
|
+
cls = 'text-blue-600 dark:text-blue-400 font-medium'; // key
|
|
598
|
+
} else {
|
|
599
|
+
cls = 'text-green-700 dark:text-green-400'; // string value
|
|
600
|
+
}
|
|
601
|
+
} else if (/true|false/.test(match)) {
|
|
602
|
+
cls = 'text-orange-600 dark:text-orange-400';
|
|
603
|
+
} else if (/null/.test(match)) {
|
|
604
|
+
cls = 'text-zinc-400 italic';
|
|
605
|
+
}
|
|
606
|
+
return \`<span class="\${cls}">\${match}</span>\`;
|
|
607
|
+
});
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
document.addEventListener('keydown', (e) => {
|
|
611
|
+
if (e.key === 'Escape') closeJsonModal();
|
|
612
|
+
});
|
|
613
|
+
|
|
492
614
|
function escapeHtml(text) {
|
|
493
|
-
const map = {
|
|
494
|
-
'&': '&',
|
|
495
|
-
'<': '<',
|
|
496
|
-
'>': '>',
|
|
497
|
-
'"': '"',
|
|
498
|
-
"'": '''
|
|
499
|
-
};
|
|
615
|
+
const map = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' };
|
|
500
616
|
return String(text).replace(/[&<>"']/g, m => map[m]);
|
|
501
617
|
}
|
|
502
618
|
</script>
|
|
@@ -563,7 +679,16 @@ function escapeHtml2(text) {
|
|
|
563
679
|
};
|
|
564
680
|
return String(text).replace(/[&<>"']/g, (m) => map[m] || m);
|
|
565
681
|
}
|
|
566
|
-
function
|
|
682
|
+
function isJsonString(str2) {
|
|
683
|
+
const s = str2.trim();
|
|
684
|
+
return (s.startsWith("{") || s.startsWith("[")) && (s.endsWith("}") || s.endsWith("]"));
|
|
685
|
+
}
|
|
686
|
+
function jsonButton(raw, colName) {
|
|
687
|
+
const preview = raw.length > 60 ? escapeHtml2(raw.substring(0, 60)) + "\u2026" : escapeHtml2(raw);
|
|
688
|
+
return `<button data-json-val="${escapeHtml2(raw)}" data-col-name="${escapeHtml2(colName)}" onclick="openJsonModal(this.dataset.jsonVal, this.dataset.colName)" class="text-left text-xs font-mono text-indigo-600 dark:text-indigo-400 hover:underline">${preview}</button>`;
|
|
689
|
+
}
|
|
690
|
+
function formatCellValue(value, colName) {
|
|
691
|
+
const col = colName || "value";
|
|
567
692
|
if (value === null || value === void 0) {
|
|
568
693
|
return '<span class="text-zinc-400 dark:text-zinc-500 italic">null</span>';
|
|
569
694
|
}
|
|
@@ -571,11 +696,15 @@ function formatCellValue(value) {
|
|
|
571
696
|
return `<span class="px-2 py-0.5 rounded text-xs font-medium ${value ? "bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-400" : "bg-zinc-100 text-zinc-800 dark:bg-zinc-800 dark:text-zinc-400"}">${value}</span>`;
|
|
572
697
|
}
|
|
573
698
|
if (typeof value === "object") {
|
|
574
|
-
return
|
|
699
|
+
return jsonButton(JSON.stringify(value), col);
|
|
575
700
|
}
|
|
576
701
|
const str2 = String(value);
|
|
577
|
-
if (str2
|
|
578
|
-
return
|
|
702
|
+
if (isJsonString(str2)) {
|
|
703
|
+
return jsonButton(str2, col);
|
|
704
|
+
}
|
|
705
|
+
if (str2.length > 120) {
|
|
706
|
+
const preview = escapeHtml2(str2.substring(0, 120)) + "\u2026";
|
|
707
|
+
return `<button data-json-val="${escapeHtml2(str2)}" data-col-name="${escapeHtml2(col)}" onclick="openJsonModal(this.dataset.jsonVal, this.dataset.colName)" class="text-left text-sm text-zinc-700 dark:text-zinc-300 hover:underline">${preview}</button>`;
|
|
579
708
|
}
|
|
580
709
|
return escapeHtml2(str2);
|
|
581
710
|
}
|
|
@@ -710,9 +839,10 @@ function createDatabaseToolsAdminRoutes() {
|
|
|
710
839
|
const offset = parseInt(c.req.query("offset") || "0");
|
|
711
840
|
const sortColumn = c.req.query("sort");
|
|
712
841
|
const sortDirection = c.req.query("dir") || "asc";
|
|
842
|
+
const search = c.req.query("search");
|
|
713
843
|
const db = c.env.DB;
|
|
714
844
|
const service = new DatabaseToolsService(db);
|
|
715
|
-
const tableData = await service.getTableData(tableName, limit, offset, sortColumn, sortDirection);
|
|
845
|
+
const tableData = await service.getTableData(tableName, limit, offset, sortColumn, sortDirection, search);
|
|
716
846
|
return c.json({
|
|
717
847
|
success: true,
|
|
718
848
|
data: tableData
|
|
@@ -736,10 +866,11 @@ function createDatabaseToolsAdminRoutes() {
|
|
|
736
866
|
const pageSize = parseInt(c.req.query("pageSize") || "20");
|
|
737
867
|
const sortColumn = c.req.query("sort");
|
|
738
868
|
const sortDirection = c.req.query("dir") || "asc";
|
|
869
|
+
const search = c.req.query("search");
|
|
739
870
|
const offset = (page - 1) * pageSize;
|
|
740
871
|
const db = c.env.DB;
|
|
741
872
|
const service = new DatabaseToolsService(db);
|
|
742
|
-
const tableData = await service.getTableData(tableName, pageSize, offset, sortColumn, sortDirection);
|
|
873
|
+
const tableData = await service.getTableData(tableName, pageSize, offset, sortColumn, sortDirection, search);
|
|
743
874
|
const pageData = {
|
|
744
875
|
user: {
|
|
745
876
|
name: user.email.split("@")[0] || "Unknown",
|
|
@@ -753,7 +884,8 @@ function createDatabaseToolsAdminRoutes() {
|
|
|
753
884
|
currentPage: page,
|
|
754
885
|
pageSize,
|
|
755
886
|
sortColumn,
|
|
756
|
-
sortDirection
|
|
887
|
+
sortDirection,
|
|
888
|
+
search
|
|
757
889
|
};
|
|
758
890
|
return c.html(renderDatabaseTablePage(pageData));
|
|
759
891
|
} catch (error) {
|
|
@@ -907,6 +1039,7 @@ var EmailSettingsService = class {
|
|
|
907
1039
|
constructor(db) {
|
|
908
1040
|
this.db = db;
|
|
909
1041
|
}
|
|
1042
|
+
db;
|
|
910
1043
|
async load() {
|
|
911
1044
|
let row = null;
|
|
912
1045
|
try {
|
|
@@ -935,6 +1068,8 @@ var SiteConfigService = class {
|
|
|
935
1068
|
this.db = db;
|
|
936
1069
|
this.env = env;
|
|
937
1070
|
}
|
|
1071
|
+
db;
|
|
1072
|
+
env;
|
|
938
1073
|
async load() {
|
|
939
1074
|
const settings = new SettingsService(this.db);
|
|
940
1075
|
const general = await settings.getGeneralSettings();
|
|
@@ -1272,6 +1407,8 @@ var EmailValidationError = class extends Error {
|
|
|
1272
1407
|
this.reason = reason;
|
|
1273
1408
|
this.name = "EmailValidationError";
|
|
1274
1409
|
}
|
|
1410
|
+
field;
|
|
1411
|
+
reason;
|
|
1275
1412
|
code = "EMAIL_VALIDATION_FAILED";
|
|
1276
1413
|
};
|
|
1277
1414
|
|
|
@@ -1307,6 +1444,9 @@ var CfGraphqlClient = class {
|
|
|
1307
1444
|
throw new EmailValidationError("apiToken", "EMAIL_API_TOKEN is required for GraphQL queries");
|
|
1308
1445
|
}
|
|
1309
1446
|
}
|
|
1447
|
+
zoneId;
|
|
1448
|
+
apiToken;
|
|
1449
|
+
fetchImpl;
|
|
1310
1450
|
async queryEmailSends(input) {
|
|
1311
1451
|
const startIso = new Date(input.startSeconds * 1e3).toISOString();
|
|
1312
1452
|
const endIso = new Date(input.endSeconds * 1e3).toISOString();
|
|
@@ -1369,6 +1509,7 @@ var EmailLogService = class {
|
|
|
1369
1509
|
constructor(db) {
|
|
1370
1510
|
this.db = db;
|
|
1371
1511
|
}
|
|
1512
|
+
db;
|
|
1372
1513
|
/**
|
|
1373
1514
|
* Records a successful submission to CF Email Service. `status` =
|
|
1374
1515
|
* `'submitted'`, `delivery_state` remains NULL until reconciliation runs.
|
|
@@ -1542,6 +1683,8 @@ var ReconciliationService = class {
|
|
|
1542
1683
|
this.graphql = graphql;
|
|
1543
1684
|
this.emailLog = emailLog;
|
|
1544
1685
|
}
|
|
1686
|
+
graphql;
|
|
1687
|
+
emailLog;
|
|
1545
1688
|
async run(input = {}) {
|
|
1546
1689
|
const windowHours = input.windowHours ?? 24;
|
|
1547
1690
|
const nowMs = input.now ?? Date.now();
|
|
@@ -1950,6 +2093,7 @@ var CloudflareEmailProvider = class {
|
|
|
1950
2093
|
constructor(binding) {
|
|
1951
2094
|
this.binding = binding;
|
|
1952
2095
|
}
|
|
2096
|
+
binding;
|
|
1953
2097
|
name = "cloudflare";
|
|
1954
2098
|
isConfigured() {
|
|
1955
2099
|
return !!this.binding;
|
|
@@ -2132,6 +2276,7 @@ var OTPService = class {
|
|
|
2132
2276
|
constructor(db) {
|
|
2133
2277
|
this.db = db;
|
|
2134
2278
|
}
|
|
2279
|
+
db;
|
|
2135
2280
|
/**
|
|
2136
2281
|
* Generate a secure random OTP code
|
|
2137
2282
|
*/
|
|
@@ -2766,6 +2911,7 @@ var OAuthService = class {
|
|
|
2766
2911
|
constructor(db) {
|
|
2767
2912
|
this.db = db;
|
|
2768
2913
|
}
|
|
2914
|
+
db;
|
|
2769
2915
|
/**
|
|
2770
2916
|
* Build the authorization redirect URL for a provider.
|
|
2771
2917
|
*/
|
|
@@ -3282,6 +3428,7 @@ var EmbeddingService = class {
|
|
|
3282
3428
|
constructor(ai) {
|
|
3283
3429
|
this.ai = ai;
|
|
3284
3430
|
}
|
|
3431
|
+
ai;
|
|
3285
3432
|
/**
|
|
3286
3433
|
* Generate embedding for a single text
|
|
3287
3434
|
*/
|
|
@@ -3486,6 +3633,9 @@ var CustomRAGService = class {
|
|
|
3486
3633
|
this.embeddingService = new EmbeddingService(ai);
|
|
3487
3634
|
this.chunkingService = new ChunkingService();
|
|
3488
3635
|
}
|
|
3636
|
+
db;
|
|
3637
|
+
ai;
|
|
3638
|
+
vectorize;
|
|
3489
3639
|
embeddingService;
|
|
3490
3640
|
chunkingService;
|
|
3491
3641
|
/**
|
|
@@ -3776,6 +3926,9 @@ var AISearchService = class {
|
|
|
3776
3926
|
console.log("[AISearchService] Custom RAG not available, using keyword search only");
|
|
3777
3927
|
}
|
|
3778
3928
|
}
|
|
3929
|
+
db;
|
|
3930
|
+
ai;
|
|
3931
|
+
vectorize;
|
|
3779
3932
|
customRAG;
|
|
3780
3933
|
/**
|
|
3781
3934
|
* Get plugin settings
|
|
@@ -4216,6 +4369,9 @@ var IndexManager = class {
|
|
|
4216
4369
|
console.log("[IndexManager] Custom RAG initialized");
|
|
4217
4370
|
}
|
|
4218
4371
|
}
|
|
4372
|
+
db;
|
|
4373
|
+
ai;
|
|
4374
|
+
vectorize;
|
|
4219
4375
|
customRAG;
|
|
4220
4376
|
/**
|
|
4221
4377
|
* Index all content items within a collection using Custom RAG
|
|
@@ -5149,6 +5305,8 @@ var SecurityAuditService = class {
|
|
|
5149
5305
|
tenantId: TENANT
|
|
5150
5306
|
});
|
|
5151
5307
|
}
|
|
5308
|
+
db;
|
|
5309
|
+
settings;
|
|
5152
5310
|
docsService;
|
|
5153
5311
|
async logEvent(event) {
|
|
5154
5312
|
const doc = await this.docsService.create({
|
|
@@ -6092,6 +6250,7 @@ var BruteForceDetector = class {
|
|
|
6092
6250
|
this.kv = kv;
|
|
6093
6251
|
this.settings = settings || DEFAULT_SETTINGS2.bruteForce;
|
|
6094
6252
|
}
|
|
6253
|
+
kv;
|
|
6095
6254
|
settings;
|
|
6096
6255
|
async recordFailedAttempt(ip, email) {
|
|
6097
6256
|
if (!this.settings.enabled || !this.kv) {
|
|
@@ -6644,11 +6803,465 @@ var securityAuditPlugin = definePlugin({
|
|
|
6644
6803
|
deactivate: async () => console.log("[SecurityAudit] Plugin deactivated")
|
|
6645
6804
|
});
|
|
6646
6805
|
|
|
6806
|
+
// src/plugins/core-plugins/api-keys-plugin/services/api-key-service.ts
|
|
6807
|
+
var API_KEY_QUERYABLE = [
|
|
6808
|
+
{ name: "keyHash", kind: "scalar", type: "text", column: "q_apikey_hash" },
|
|
6809
|
+
{ name: "userId", kind: "scalar", type: "text", column: "q_apikey_user_id" },
|
|
6810
|
+
{ name: "revoked", kind: "scalar", type: "integer", column: "q_apikey_revoked" }
|
|
6811
|
+
];
|
|
6812
|
+
var KEY_PREFIX = "sk_";
|
|
6813
|
+
var KEY_BYTES = 24;
|
|
6814
|
+
var DISPLAY_PREFIX_LEN = KEY_PREFIX.length + 8;
|
|
6815
|
+
function generateApiKeySecret() {
|
|
6816
|
+
const bytes = new Uint8Array(KEY_BYTES);
|
|
6817
|
+
crypto.getRandomValues(bytes);
|
|
6818
|
+
let hex = "";
|
|
6819
|
+
for (const b of bytes) hex += b.toString(16).padStart(2, "0");
|
|
6820
|
+
return KEY_PREFIX + hex;
|
|
6821
|
+
}
|
|
6822
|
+
async function hashApiKey(secret) {
|
|
6823
|
+
const data = new TextEncoder().encode(secret);
|
|
6824
|
+
const digest = await crypto.subtle.digest("SHA-256", data);
|
|
6825
|
+
const view = new Uint8Array(digest);
|
|
6826
|
+
let hex = "";
|
|
6827
|
+
for (const b of view) hex += b.toString(16).padStart(2, "0");
|
|
6828
|
+
return hex;
|
|
6829
|
+
}
|
|
6830
|
+
var ApiKeyService = class {
|
|
6831
|
+
constructor(db, tenantId = "default") {
|
|
6832
|
+
this.db = db;
|
|
6833
|
+
this.tenantId = tenantId;
|
|
6834
|
+
}
|
|
6835
|
+
db;
|
|
6836
|
+
tenantId;
|
|
6837
|
+
docService() {
|
|
6838
|
+
return new DocumentsService(this.db, {
|
|
6839
|
+
queryableFields: API_KEY_QUERYABLE,
|
|
6840
|
+
tenantId: this.tenantId,
|
|
6841
|
+
maxVersionsPerRoot: 1
|
|
6842
|
+
});
|
|
6843
|
+
}
|
|
6844
|
+
/** Count a user's active (non-revoked) keys — used to enforce the per-user cap. */
|
|
6845
|
+
async countForUser(userId) {
|
|
6846
|
+
const row = await this.db.prepare(
|
|
6847
|
+
`SELECT COUNT(*) AS c FROM documents
|
|
6848
|
+
WHERE type_id = 'api_key' AND tenant_id = ? AND is_current_draft = 1
|
|
6849
|
+
AND deleted_at IS NULL AND q_apikey_user_id = ? AND q_apikey_revoked = 0`
|
|
6850
|
+
).bind(this.tenantId, userId).first();
|
|
6851
|
+
return row?.c ?? 0;
|
|
6852
|
+
}
|
|
6853
|
+
/**
|
|
6854
|
+
* Mint a new key for a user. The returned `key` is the only time the plaintext
|
|
6855
|
+
* exists outside the caller — it is hashed before storage.
|
|
6856
|
+
*/
|
|
6857
|
+
async create(input) {
|
|
6858
|
+
const name = input.name.trim() || "API Key";
|
|
6859
|
+
const secret = generateApiKeySecret();
|
|
6860
|
+
const keyHash = await hashApiKey(secret);
|
|
6861
|
+
const prefix = secret.slice(0, DISPLAY_PREFIX_LEN);
|
|
6862
|
+
const expiresAt = input.expiresAt ?? null;
|
|
6863
|
+
const doc = await this.docService().create(
|
|
6864
|
+
createDocumentSchema.parse({
|
|
6865
|
+
typeId: "api_key",
|
|
6866
|
+
tenantId: this.tenantId,
|
|
6867
|
+
title: name,
|
|
6868
|
+
ownerId: input.userId,
|
|
6869
|
+
publishOnCreate: true,
|
|
6870
|
+
data: {
|
|
6871
|
+
name,
|
|
6872
|
+
userId: input.userId,
|
|
6873
|
+
keyHash,
|
|
6874
|
+
keyPrefix: prefix,
|
|
6875
|
+
revoked: 0,
|
|
6876
|
+
lastUsedAt: null,
|
|
6877
|
+
expiresAt
|
|
6878
|
+
}
|
|
6879
|
+
}),
|
|
6880
|
+
input.userId
|
|
6881
|
+
);
|
|
6882
|
+
return { id: doc.rootId, key: secret, name, prefix, expiresAt };
|
|
6883
|
+
}
|
|
6884
|
+
/** List a user's non-revoked keys (metadata only — never the secret or hash). */
|
|
6885
|
+
async list(userId) {
|
|
6886
|
+
const res = await this.db.prepare(
|
|
6887
|
+
`SELECT root_id, data, created_at FROM documents
|
|
6888
|
+
WHERE type_id = 'api_key' AND tenant_id = ? AND is_current_draft = 1
|
|
6889
|
+
AND deleted_at IS NULL AND q_apikey_user_id = ? AND q_apikey_revoked = 0
|
|
6890
|
+
ORDER BY created_at DESC`
|
|
6891
|
+
).bind(this.tenantId, userId).all();
|
|
6892
|
+
return (res.results ?? []).map((row) => {
|
|
6893
|
+
const d = JSON.parse(row.data);
|
|
6894
|
+
return {
|
|
6895
|
+
id: row.root_id,
|
|
6896
|
+
name: d.name ?? "API Key",
|
|
6897
|
+
prefix: d.keyPrefix ?? "",
|
|
6898
|
+
createdAt: row.created_at,
|
|
6899
|
+
lastUsedAt: d.lastUsedAt ?? null,
|
|
6900
|
+
expiresAt: d.expiresAt ?? null
|
|
6901
|
+
};
|
|
6902
|
+
});
|
|
6903
|
+
}
|
|
6904
|
+
/**
|
|
6905
|
+
* Revoke (hard-delete) a key owned by `userId`. Credentials are erased, not
|
|
6906
|
+
* soft-flagged. Returns false if the key does not exist or is not owned by
|
|
6907
|
+
* the caller (no information leak about other users' keys).
|
|
6908
|
+
*/
|
|
6909
|
+
async revoke(rootId, userId) {
|
|
6910
|
+
const row = await this.db.prepare(
|
|
6911
|
+
`SELECT q_apikey_user_id AS owner FROM documents
|
|
6912
|
+
WHERE root_id = ? AND tenant_id = ? AND type_id = 'api_key' AND is_current_draft = 1 AND deleted_at IS NULL`
|
|
6913
|
+
).bind(rootId, this.tenantId).first();
|
|
6914
|
+
if (!row || row.owner !== userId) return false;
|
|
6915
|
+
await this.docService().erase(rootId, this.tenantId);
|
|
6916
|
+
return true;
|
|
6917
|
+
}
|
|
6918
|
+
/**
|
|
6919
|
+
* Resolve a presented secret to its owning user, or null. Rejects unknown,
|
|
6920
|
+
* revoked, expired keys and inactive users. Best-effort updates lastUsedAt.
|
|
6921
|
+
*/
|
|
6922
|
+
async resolve(secret) {
|
|
6923
|
+
if (!secret || !secret.startsWith(KEY_PREFIX)) return null;
|
|
6924
|
+
const keyHash = await hashApiKey(secret);
|
|
6925
|
+
const keyRow2 = await this.db.prepare(
|
|
6926
|
+
`SELECT root_id, data FROM documents
|
|
6927
|
+
WHERE type_id = 'api_key' AND tenant_id = ? AND is_current_draft = 1 AND deleted_at IS NULL
|
|
6928
|
+
AND q_apikey_hash = ? AND q_apikey_revoked = 0
|
|
6929
|
+
LIMIT 1`
|
|
6930
|
+
).bind(this.tenantId, keyHash).first();
|
|
6931
|
+
if (!keyRow2) return null;
|
|
6932
|
+
const d = JSON.parse(keyRow2.data);
|
|
6933
|
+
if (d.expiresAt != null && Date.now() > Number(d.expiresAt)) return null;
|
|
6934
|
+
const user = await this.db.prepare(`SELECT id, email, role, is_active, is_super_admin FROM auth_user WHERE id = ?`).bind(d.userId).first();
|
|
6935
|
+
if (!user || user.is_active !== 1) return null;
|
|
6936
|
+
try {
|
|
6937
|
+
await this.touchLastUsed(keyRow2.root_id, d);
|
|
6938
|
+
} catch {
|
|
6939
|
+
}
|
|
6940
|
+
return {
|
|
6941
|
+
userId: user.id,
|
|
6942
|
+
email: user.email,
|
|
6943
|
+
role: user.role ?? "viewer",
|
|
6944
|
+
isSuperAdmin: user.is_super_admin === 1
|
|
6945
|
+
};
|
|
6946
|
+
}
|
|
6947
|
+
/** Update lastUsedAt in-place (single-version type, no history churn). */
|
|
6948
|
+
async touchLastUsed(rootId, data) {
|
|
6949
|
+
const next = JSON.stringify({ ...data, lastUsedAt: Date.now() });
|
|
6950
|
+
await this.db.prepare(
|
|
6951
|
+
`UPDATE documents SET data = ? WHERE root_id = ? AND tenant_id = ? AND type_id = 'api_key' AND is_current_draft = 1`
|
|
6952
|
+
).bind(next, rootId, this.tenantId).run();
|
|
6953
|
+
}
|
|
6954
|
+
};
|
|
6955
|
+
|
|
6956
|
+
// src/plugins/core-plugins/api-keys-plugin/components/keys-page.ts
|
|
6957
|
+
init_admin_layout_catalyst_template();
|
|
6958
|
+
function fmtDate(ms) {
|
|
6959
|
+
if (!ms) return "\u2014";
|
|
6960
|
+
try {
|
|
6961
|
+
return new Date(ms).toISOString().slice(0, 10);
|
|
6962
|
+
} catch {
|
|
6963
|
+
return "\u2014";
|
|
6964
|
+
}
|
|
6965
|
+
}
|
|
6966
|
+
function keyRow(k) {
|
|
6967
|
+
const name = escapeHtml(k.name);
|
|
6968
|
+
const prefix = escapeHtml(k.prefix);
|
|
6969
|
+
const id = escapeHtml(k.id);
|
|
6970
|
+
return `
|
|
6971
|
+
<tr class="border-t border-zinc-950/5 dark:border-white/10" data-key-id="${id}">
|
|
6972
|
+
<td class="py-3 pr-4 text-sm font-medium text-zinc-950 dark:text-white">${name}</td>
|
|
6973
|
+
<td class="py-3 pr-4 text-sm font-mono text-zinc-500 dark:text-zinc-400">${prefix}\u2026</td>
|
|
6974
|
+
<td class="py-3 pr-4 text-sm text-zinc-500 dark:text-zinc-400">${fmtDate(k.createdAt ? k.createdAt * 1e3 : null)}</td>
|
|
6975
|
+
<td class="py-3 pr-4 text-sm text-zinc-500 dark:text-zinc-400">${k.lastUsedAt ? fmtDate(k.lastUsedAt) : "Never"}</td>
|
|
6976
|
+
<td class="py-3 pr-4 text-sm text-zinc-500 dark:text-zinc-400">${k.expiresAt ? fmtDate(k.expiresAt) : "Never"}</td>
|
|
6977
|
+
<td class="py-3 text-right">
|
|
6978
|
+
<button type="button" onclick="revokeApiKey('${id}', '${name.replace(/'/g, "\\'")}')"
|
|
6979
|
+
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">
|
|
6980
|
+
Revoke
|
|
6981
|
+
</button>
|
|
6982
|
+
</td>
|
|
6983
|
+
</tr>`;
|
|
6984
|
+
}
|
|
6985
|
+
function renderApiKeysPage(data) {
|
|
6986
|
+
const { keys, user, version, dynamicMenuItems } = data;
|
|
6987
|
+
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>`;
|
|
6988
|
+
const content2 = `
|
|
6989
|
+
<div>
|
|
6990
|
+
<div class="sm:flex sm:items-center sm:justify-between mb-6">
|
|
6991
|
+
<div class="sm:flex-auto">
|
|
6992
|
+
<h1 class="text-2xl/8 font-semibold text-zinc-950 dark:text-white sm:text-xl/8">API Keys</h1>
|
|
6993
|
+
<p class="mt-2 text-sm/6 text-zinc-500 dark:text-zinc-400">
|
|
6994
|
+
Long-lived secrets for headless / server-to-server REST access. Send a key as the
|
|
6995
|
+
<code class="font-mono">x-api-key</code> header or <code class="font-mono">Authorization: Bearer <key></code>.
|
|
6996
|
+
The secret is shown once at creation \u2014 store it now.
|
|
6997
|
+
</p>
|
|
6998
|
+
</div>
|
|
6999
|
+
<div class="mt-4 sm:mt-0 sm:ml-16">
|
|
7000
|
+
<button type="button" onclick="document.getElementById('create-key-modal').classList.remove('hidden')"
|
|
7001
|
+
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">
|
|
7002
|
+
Create API key
|
|
7003
|
+
</button>
|
|
7004
|
+
</div>
|
|
7005
|
+
</div>
|
|
7006
|
+
|
|
7007
|
+
<!-- Newly-created secret banner (populated by JS, shown once) -->
|
|
7008
|
+
<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">
|
|
7009
|
+
<p class="text-sm font-medium text-emerald-800 dark:text-emerald-300 mb-2">
|
|
7010
|
+
Copy your new key now \u2014 it will not be shown again.
|
|
7011
|
+
</p>
|
|
7012
|
+
<div class="flex items-center gap-2">
|
|
7013
|
+
<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>
|
|
7014
|
+
<button type="button" onclick="copyNewKey()"
|
|
7015
|
+
class="rounded-lg bg-emerald-600 px-3 py-2 text-sm font-semibold text-white hover:bg-emerald-500 transition-colors">
|
|
7016
|
+
Copy
|
|
7017
|
+
</button>
|
|
7018
|
+
</div>
|
|
7019
|
+
</div>
|
|
7020
|
+
|
|
7021
|
+
<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">
|
|
7022
|
+
<table class="w-full text-left">
|
|
7023
|
+
<thead>
|
|
7024
|
+
<tr class="text-xs font-semibold uppercase tracking-wide text-zinc-500 dark:text-zinc-400">
|
|
7025
|
+
<th class="pb-2 pr-4">Name</th>
|
|
7026
|
+
<th class="pb-2 pr-4">Prefix</th>
|
|
7027
|
+
<th class="pb-2 pr-4">Created</th>
|
|
7028
|
+
<th class="pb-2 pr-4">Last used</th>
|
|
7029
|
+
<th class="pb-2 pr-4">Expires</th>
|
|
7030
|
+
<th class="pb-2 text-right">Actions</th>
|
|
7031
|
+
</tr>
|
|
7032
|
+
</thead>
|
|
7033
|
+
<tbody id="keys-tbody">${rows}</tbody>
|
|
7034
|
+
</table>
|
|
7035
|
+
</div>
|
|
7036
|
+
</div>
|
|
7037
|
+
|
|
7038
|
+
<!-- Create modal -->
|
|
7039
|
+
<div id="create-key-modal" class="hidden fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4">
|
|
7040
|
+
<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">
|
|
7041
|
+
<h2 class="text-base font-semibold text-zinc-950 dark:text-white mb-4">Create API key</h2>
|
|
7042
|
+
<label class="block text-sm font-medium text-zinc-700 dark:text-zinc-300 mb-1">Name</label>
|
|
7043
|
+
<input id="new-key-name" type="text" placeholder="e.g. CI deploy token"
|
|
7044
|
+
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">
|
|
7045
|
+
<label class="block text-sm font-medium text-zinc-700 dark:text-zinc-300 mb-1">Expires in (days, optional)</label>
|
|
7046
|
+
<input id="new-key-expiry" type="number" min="1" max="3650" placeholder="Never"
|
|
7047
|
+
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">
|
|
7048
|
+
<div class="flex justify-end gap-2">
|
|
7049
|
+
<button type="button" onclick="document.getElementById('create-key-modal').classList.add('hidden')"
|
|
7050
|
+
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">
|
|
7051
|
+
Cancel
|
|
7052
|
+
</button>
|
|
7053
|
+
<button type="button" onclick="createApiKey()"
|
|
7054
|
+
class="rounded-lg bg-cyan-600 px-4 py-2 text-sm font-semibold text-white hover:bg-cyan-500 transition-colors">
|
|
7055
|
+
Create
|
|
7056
|
+
</button>
|
|
7057
|
+
</div>
|
|
7058
|
+
</div>
|
|
7059
|
+
</div>
|
|
7060
|
+
|
|
7061
|
+
<script>
|
|
7062
|
+
// CSRF: the csrf_token cookie is JS-readable (httpOnly:false); echo it back
|
|
7063
|
+
// as X-CSRF-Token on state-changing requests (signed double-submit).
|
|
7064
|
+
function csrfHeader() {
|
|
7065
|
+
const m = document.cookie.match(/(?:^|; )csrf_token=([^;]+)/)
|
|
7066
|
+
return m ? { 'X-CSRF-Token': decodeURIComponent(m[1]) } : {}
|
|
7067
|
+
}
|
|
7068
|
+
async function createApiKey() {
|
|
7069
|
+
const name = document.getElementById('new-key-name').value.trim()
|
|
7070
|
+
if (!name) { window.showNotification && window.showNotification('Name is required', 'error'); return }
|
|
7071
|
+
const expiry = parseInt(document.getElementById('new-key-expiry').value, 10)
|
|
7072
|
+
const body = { name }
|
|
7073
|
+
if (Number.isFinite(expiry) && expiry > 0) body.expiresInDays = expiry
|
|
7074
|
+
const res = await fetch('/admin/plugins/api-keys/api/keys', {
|
|
7075
|
+
method: 'POST',
|
|
7076
|
+
headers: { 'Content-Type': 'application/json', ...csrfHeader() },
|
|
7077
|
+
body: JSON.stringify(body),
|
|
7078
|
+
})
|
|
7079
|
+
if (!res.ok) {
|
|
7080
|
+
const e = await res.json().catch(() => ({}))
|
|
7081
|
+
window.showNotification && window.showNotification(e.error || 'Failed to create key', 'error')
|
|
7082
|
+
return
|
|
7083
|
+
}
|
|
7084
|
+
const { apiKey } = await res.json()
|
|
7085
|
+
document.getElementById('create-key-modal').classList.add('hidden')
|
|
7086
|
+
document.getElementById('new-key-value').textContent = apiKey.key
|
|
7087
|
+
document.getElementById('new-key-banner').classList.remove('hidden')
|
|
7088
|
+
setTimeout(() => location.reload(), 1500)
|
|
7089
|
+
}
|
|
7090
|
+
function copyNewKey() {
|
|
7091
|
+
const v = document.getElementById('new-key-value').textContent
|
|
7092
|
+
navigator.clipboard.writeText(v).then(() => window.showNotification && window.showNotification('Copied', 'success'))
|
|
7093
|
+
}
|
|
7094
|
+
async function revokeApiKey(id, name) {
|
|
7095
|
+
if (!confirm('Revoke "' + name + '"? This cannot be undone and will break any client using it.')) return
|
|
7096
|
+
const res = await fetch('/admin/plugins/api-keys/api/keys/' + id, { method: 'DELETE', headers: { ...csrfHeader() } })
|
|
7097
|
+
if (res.ok) {
|
|
7098
|
+
const row = document.querySelector('[data-key-id="' + id + '"]')
|
|
7099
|
+
if (row) row.remove()
|
|
7100
|
+
window.showNotification && window.showNotification('Key revoked', 'success')
|
|
7101
|
+
} else {
|
|
7102
|
+
window.showNotification && window.showNotification('Failed to revoke', 'error')
|
|
7103
|
+
}
|
|
7104
|
+
}
|
|
7105
|
+
</script>`;
|
|
7106
|
+
const layoutData = {
|
|
7107
|
+
title: "API Keys",
|
|
7108
|
+
pageTitle: "API Keys",
|
|
7109
|
+
currentPath: "/admin/plugins/api-keys",
|
|
7110
|
+
user,
|
|
7111
|
+
content: content2,
|
|
7112
|
+
version,
|
|
7113
|
+
dynamicMenuItems
|
|
7114
|
+
};
|
|
7115
|
+
return renderAdminLayoutCatalyst(layoutData);
|
|
7116
|
+
}
|
|
7117
|
+
|
|
7118
|
+
// src/plugins/core-plugins/api-keys-plugin/types.ts
|
|
7119
|
+
var DEFAULT_SETTINGS3 = {
|
|
7120
|
+
maxKeysPerUser: 50,
|
|
7121
|
+
defaultExpiryDays: 0
|
|
7122
|
+
};
|
|
7123
|
+
|
|
7124
|
+
// src/plugins/core-plugins/api-keys-plugin/routes/admin.ts
|
|
7125
|
+
var adminRoutes4 = new Hono();
|
|
7126
|
+
var DAY_MS = 24 * 60 * 60 * 1e3;
|
|
7127
|
+
var createSchema = z.object({
|
|
7128
|
+
name: z.string().min(1).max(100),
|
|
7129
|
+
// Optional lifetime in days; omitted/null → plugin default (which may be "never").
|
|
7130
|
+
expiresInDays: z.number().int().positive().max(3650).nullish()
|
|
7131
|
+
});
|
|
7132
|
+
async function getSettings3(db) {
|
|
7133
|
+
try {
|
|
7134
|
+
const plugin2 = await new PluginService(db).getPlugin("api-keys");
|
|
7135
|
+
if (plugin2?.settings) {
|
|
7136
|
+
const s = typeof plugin2.settings === "string" ? JSON.parse(plugin2.settings) : plugin2.settings;
|
|
7137
|
+
return { ...DEFAULT_SETTINGS3, ...s };
|
|
7138
|
+
}
|
|
7139
|
+
} catch {
|
|
7140
|
+
}
|
|
7141
|
+
return DEFAULT_SETTINGS3;
|
|
7142
|
+
}
|
|
7143
|
+
adminRoutes4.use("*", requireAuth());
|
|
7144
|
+
adminRoutes4.use("*", async (c, next) => {
|
|
7145
|
+
const user = c.get("user");
|
|
7146
|
+
if (user?.role !== "admin") {
|
|
7147
|
+
return c.json({ error: "Access denied" }, 403);
|
|
7148
|
+
}
|
|
7149
|
+
return next();
|
|
7150
|
+
});
|
|
7151
|
+
adminRoutes4.get("/", async (c) => {
|
|
7152
|
+
const user = c.get("user");
|
|
7153
|
+
const tenantId = c.get("tenantId") || "default";
|
|
7154
|
+
const keys = await new ApiKeyService(c.env.DB, tenantId).list(user.userId);
|
|
7155
|
+
return c.html(
|
|
7156
|
+
renderApiKeysPage({
|
|
7157
|
+
keys,
|
|
7158
|
+
user: { name: user.email, email: user.email, role: user.role },
|
|
7159
|
+
version: c.get("appVersion"),
|
|
7160
|
+
dynamicMenuItems: c.get("pluginMenuItems")
|
|
7161
|
+
})
|
|
7162
|
+
);
|
|
7163
|
+
});
|
|
7164
|
+
adminRoutes4.get("/api/keys", async (c) => {
|
|
7165
|
+
const user = c.get("user");
|
|
7166
|
+
const tenantId = c.get("tenantId") || "default";
|
|
7167
|
+
const keys = await new ApiKeyService(c.env.DB, tenantId).list(user.userId);
|
|
7168
|
+
return c.json({ keys });
|
|
7169
|
+
});
|
|
7170
|
+
adminRoutes4.post("/api/keys", async (c) => {
|
|
7171
|
+
const user = c.get("user");
|
|
7172
|
+
const tenantId = c.get("tenantId") || "default";
|
|
7173
|
+
const body = await c.req.json().catch(() => ({}));
|
|
7174
|
+
const parsed = createSchema.safeParse(body);
|
|
7175
|
+
if (!parsed.success) {
|
|
7176
|
+
return c.json({ error: "Invalid request", details: parsed.error.flatten() }, 400);
|
|
7177
|
+
}
|
|
7178
|
+
const settings = await getSettings3(c.env.DB);
|
|
7179
|
+
const svc = new ApiKeyService(c.env.DB, tenantId);
|
|
7180
|
+
if (await svc.countForUser(user.userId) >= settings.maxKeysPerUser) {
|
|
7181
|
+
return c.json({ error: `API key limit reached (max ${settings.maxKeysPerUser})` }, 409);
|
|
7182
|
+
}
|
|
7183
|
+
const days = parsed.data.expiresInDays ?? (settings.defaultExpiryDays > 0 ? settings.defaultExpiryDays : null);
|
|
7184
|
+
const expiresAt = days ? Date.now() + days * DAY_MS : null;
|
|
7185
|
+
const created = await svc.create({ userId: user.userId, name: parsed.data.name, expiresAt });
|
|
7186
|
+
return c.json({ apiKey: created }, 201);
|
|
7187
|
+
});
|
|
7188
|
+
adminRoutes4.delete("/api/keys/:id", async (c) => {
|
|
7189
|
+
const user = c.get("user");
|
|
7190
|
+
const tenantId = c.get("tenantId") || "default";
|
|
7191
|
+
const ok = await new ApiKeyService(c.env.DB, tenantId).revoke(c.req.param("id") ?? "", user.userId);
|
|
7192
|
+
if (!ok) return c.json({ error: "API key not found" }, 404);
|
|
7193
|
+
return c.json({ success: true });
|
|
7194
|
+
});
|
|
7195
|
+
|
|
7196
|
+
// src/plugins/core-plugins/api-keys-plugin/middleware/api-key-auth.ts
|
|
7197
|
+
function apiKeyAuthMiddleware() {
|
|
7198
|
+
return async (c, next) => {
|
|
7199
|
+
if (!c.get("user")) {
|
|
7200
|
+
const authz = c.req.header("authorization") || "";
|
|
7201
|
+
const bearer = authz.toLowerCase().startsWith("bearer ") ? authz.slice(7).trim() : "";
|
|
7202
|
+
const presented = c.req.header("x-api-key") || (bearer.startsWith("sk_") ? bearer : "");
|
|
7203
|
+
if (presented) {
|
|
7204
|
+
try {
|
|
7205
|
+
const tenantId = c.get("tenantId") || "default";
|
|
7206
|
+
const resolved = await new ApiKeyService(c.env.DB, tenantId).resolve(presented);
|
|
7207
|
+
if (resolved) {
|
|
7208
|
+
c.set("user", {
|
|
7209
|
+
userId: resolved.userId,
|
|
7210
|
+
email: resolved.email,
|
|
7211
|
+
role: resolved.role,
|
|
7212
|
+
isSuperAdmin: resolved.isSuperAdmin,
|
|
7213
|
+
// API keys are stateless bearer creds — no session window.
|
|
7214
|
+
exp: 0,
|
|
7215
|
+
iat: 0
|
|
7216
|
+
});
|
|
7217
|
+
}
|
|
7218
|
+
} catch {
|
|
7219
|
+
}
|
|
7220
|
+
}
|
|
7221
|
+
}
|
|
7222
|
+
await next();
|
|
7223
|
+
};
|
|
7224
|
+
}
|
|
7225
|
+
|
|
7226
|
+
// src/plugins/core-plugins/api-keys-plugin/index.ts
|
|
7227
|
+
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>`;
|
|
7228
|
+
var apiKeysPlugin = definePlugin({
|
|
7229
|
+
id: "api-keys",
|
|
7230
|
+
version: "1.0.0-beta.1",
|
|
7231
|
+
name: "API Keys",
|
|
7232
|
+
description: "Programmatic API access keys for headless / server-to-server REST access.",
|
|
7233
|
+
sonicjsVersionRange: "^3.0.0",
|
|
7234
|
+
author: { name: "SonicJS Team" },
|
|
7235
|
+
register(app2) {
|
|
7236
|
+
app2.route("/admin/plugins/api-keys", adminRoutes4);
|
|
7237
|
+
},
|
|
7238
|
+
menu: [
|
|
7239
|
+
{ label: "API Keys", path: "/admin/plugins/api-keys", icon: KEY_ICON, order: 86 }
|
|
7240
|
+
],
|
|
7241
|
+
configSchema: {
|
|
7242
|
+
maxKeysPerUser: {
|
|
7243
|
+
type: "number",
|
|
7244
|
+
label: "Max keys per user",
|
|
7245
|
+
description: "Hard cap on active keys a single user may hold.",
|
|
7246
|
+
default: 50
|
|
7247
|
+
},
|
|
7248
|
+
defaultExpiryDays: {
|
|
7249
|
+
type: "number",
|
|
7250
|
+
label: "Default expiry (days)",
|
|
7251
|
+
description: "Lifetime applied to new keys when no explicit expiry is given. 0 = never expires.",
|
|
7252
|
+
default: 0
|
|
7253
|
+
}
|
|
7254
|
+
},
|
|
7255
|
+
activate: async () => console.log("[ApiKeys] Plugin activated"),
|
|
7256
|
+
deactivate: async () => console.log("[ApiKeys] Plugin deactivated")
|
|
7257
|
+
});
|
|
7258
|
+
|
|
6647
7259
|
// src/plugins/core-plugins/stripe-plugin/services/subscription-service.ts
|
|
6648
7260
|
var SubscriptionService = class {
|
|
6649
7261
|
constructor(db) {
|
|
6650
7262
|
this.db = db;
|
|
6651
7263
|
}
|
|
7264
|
+
db;
|
|
6652
7265
|
/**
|
|
6653
7266
|
* Ensure the subscriptions table exists
|
|
6654
7267
|
*/
|
|
@@ -6887,6 +7500,7 @@ var StripeEventService = class {
|
|
|
6887
7500
|
constructor(db) {
|
|
6888
7501
|
this.db = db;
|
|
6889
7502
|
}
|
|
7503
|
+
db;
|
|
6890
7504
|
async ensureTable() {
|
|
6891
7505
|
await this.db.prepare(`
|
|
6892
7506
|
CREATE TABLE IF NOT EXISTS stripe_events (
|
|
@@ -7371,7 +7985,7 @@ function renderEventPagination(page, totalPages, type, status) {
|
|
|
7371
7985
|
}
|
|
7372
7986
|
|
|
7373
7987
|
// src/plugins/core-plugins/stripe-plugin/types.ts
|
|
7374
|
-
var
|
|
7988
|
+
var DEFAULT_SETTINGS4 = {
|
|
7375
7989
|
stripePublishableKey: "",
|
|
7376
7990
|
stripeSecretKey: "",
|
|
7377
7991
|
stripeWebhookSecret: "",
|
|
@@ -7381,28 +7995,28 @@ var DEFAULT_SETTINGS3 = {
|
|
|
7381
7995
|
};
|
|
7382
7996
|
|
|
7383
7997
|
// src/plugins/core-plugins/stripe-plugin/routes/admin.ts
|
|
7384
|
-
var
|
|
7385
|
-
|
|
7386
|
-
|
|
7998
|
+
var adminRoutes5 = new Hono();
|
|
7999
|
+
adminRoutes5.use("*", requireAuth());
|
|
8000
|
+
adminRoutes5.use("*", async (c, next) => {
|
|
7387
8001
|
const user = c.get("user");
|
|
7388
8002
|
if (user?.role !== "admin") {
|
|
7389
8003
|
return c.text("Access denied", 403);
|
|
7390
8004
|
}
|
|
7391
8005
|
return next();
|
|
7392
8006
|
});
|
|
7393
|
-
async function
|
|
8007
|
+
async function getSettings4(db) {
|
|
7394
8008
|
try {
|
|
7395
8009
|
const pluginService = new PluginService(db);
|
|
7396
8010
|
const plugin2 = await pluginService.getPlugin("stripe");
|
|
7397
8011
|
if (plugin2?.settings) {
|
|
7398
8012
|
const settings = typeof plugin2.settings === "string" ? JSON.parse(plugin2.settings) : plugin2.settings;
|
|
7399
|
-
return { ...
|
|
8013
|
+
return { ...DEFAULT_SETTINGS4, ...settings };
|
|
7400
8014
|
}
|
|
7401
8015
|
} catch {
|
|
7402
8016
|
}
|
|
7403
|
-
return
|
|
8017
|
+
return DEFAULT_SETTINGS4;
|
|
7404
8018
|
}
|
|
7405
|
-
|
|
8019
|
+
adminRoutes5.get("/", async (c) => {
|
|
7406
8020
|
const db = c.env.DB;
|
|
7407
8021
|
const user = c.get("user");
|
|
7408
8022
|
const subscriptionService = new SubscriptionService(db);
|
|
@@ -7425,7 +8039,7 @@ adminRoutes4.get("/", async (c) => {
|
|
|
7425
8039
|
});
|
|
7426
8040
|
return c.html(html4);
|
|
7427
8041
|
});
|
|
7428
|
-
|
|
8042
|
+
adminRoutes5.get("/events", async (c) => {
|
|
7429
8043
|
const db = c.env.DB;
|
|
7430
8044
|
const user = c.get("user");
|
|
7431
8045
|
const eventService = new StripeEventService(db);
|
|
@@ -7451,11 +8065,11 @@ adminRoutes4.get("/events", async (c) => {
|
|
|
7451
8065
|
});
|
|
7452
8066
|
return c.html(html4);
|
|
7453
8067
|
});
|
|
7454
|
-
|
|
8068
|
+
adminRoutes5.get("/settings", async (c) => {
|
|
7455
8069
|
const db = c.env.DB;
|
|
7456
8070
|
const user = c.get("user");
|
|
7457
|
-
const settings = await
|
|
7458
|
-
const { renderAdminLayoutCatalyst: renderAdminLayoutCatalyst2 } = await import('./admin-layout-catalyst.template-
|
|
8071
|
+
const settings = await getSettings4(db);
|
|
8072
|
+
const { renderAdminLayoutCatalyst: renderAdminLayoutCatalyst2 } = await import('./admin-layout-catalyst.template-YQ4EMF2J.js');
|
|
7459
8073
|
const content2 = `
|
|
7460
8074
|
<div>
|
|
7461
8075
|
<div class="mb-6">
|
|
@@ -7561,7 +8175,7 @@ adminRoutes4.get("/settings", async (c) => {
|
|
|
7561
8175
|
dynamicMenuItems: c.get("pluginMenuItems")
|
|
7562
8176
|
}));
|
|
7563
8177
|
});
|
|
7564
|
-
|
|
8178
|
+
adminRoutes5.post("/settings", async (c) => {
|
|
7565
8179
|
try {
|
|
7566
8180
|
const body = await c.req.json();
|
|
7567
8181
|
const db = c.env.DB;
|
|
@@ -7583,6 +8197,7 @@ var StripeAPI = class {
|
|
|
7583
8197
|
constructor(secretKey) {
|
|
7584
8198
|
this.secretKey = secretKey;
|
|
7585
8199
|
}
|
|
8200
|
+
secretKey;
|
|
7586
8201
|
baseUrl = "https://api.stripe.com/v1";
|
|
7587
8202
|
/**
|
|
7588
8203
|
* Verify a webhook signature
|
|
@@ -7712,17 +8327,17 @@ function timingSafeEqual(a, b) {
|
|
|
7712
8327
|
|
|
7713
8328
|
// src/plugins/core-plugins/stripe-plugin/routes/api.ts
|
|
7714
8329
|
var apiRoutes3 = new Hono();
|
|
7715
|
-
async function
|
|
8330
|
+
async function getSettings5(db) {
|
|
7716
8331
|
try {
|
|
7717
8332
|
const pluginService = new PluginService(db);
|
|
7718
8333
|
const plugin2 = await pluginService.getPlugin("stripe");
|
|
7719
8334
|
if (plugin2?.settings) {
|
|
7720
8335
|
const settings = typeof plugin2.settings === "string" ? JSON.parse(plugin2.settings) : plugin2.settings;
|
|
7721
|
-
return { ...
|
|
8336
|
+
return { ...DEFAULT_SETTINGS4, ...settings };
|
|
7722
8337
|
}
|
|
7723
8338
|
} catch {
|
|
7724
8339
|
}
|
|
7725
|
-
return
|
|
8340
|
+
return DEFAULT_SETTINGS4;
|
|
7726
8341
|
}
|
|
7727
8342
|
function mapStripeStatus(status) {
|
|
7728
8343
|
const map = {
|
|
@@ -7739,7 +8354,7 @@ function mapStripeStatus(status) {
|
|
|
7739
8354
|
}
|
|
7740
8355
|
apiRoutes3.post("/webhook", async (c) => {
|
|
7741
8356
|
const db = c.env.DB;
|
|
7742
|
-
const settings = await
|
|
8357
|
+
const settings = await getSettings5(db);
|
|
7743
8358
|
if (!settings.stripeWebhookSecret) {
|
|
7744
8359
|
return c.json({ error: "Webhook secret not configured" }, 500);
|
|
7745
8360
|
}
|
|
@@ -7869,7 +8484,7 @@ apiRoutes3.post("/create-checkout-session", requireAuth(), async (c) => {
|
|
|
7869
8484
|
const db = c.env.DB;
|
|
7870
8485
|
const user = c.get("user");
|
|
7871
8486
|
if (!user) return c.json({ error: "Unauthorized" }, 401);
|
|
7872
|
-
const settings = await
|
|
8487
|
+
const settings = await getSettings5(db);
|
|
7873
8488
|
if (!settings.stripeSecretKey) {
|
|
7874
8489
|
return c.json({ error: "Stripe not configured" }, 500);
|
|
7875
8490
|
}
|
|
@@ -7946,7 +8561,7 @@ apiRoutes3.post("/sync-subscriptions", requireAuth(), async (c) => {
|
|
|
7946
8561
|
const user = c.get("user");
|
|
7947
8562
|
if (user?.role !== "admin") return c.json({ error: "Access denied" }, 403);
|
|
7948
8563
|
const db = c.env.DB;
|
|
7949
|
-
const settings = await
|
|
8564
|
+
const settings = await getSettings5(db);
|
|
7950
8565
|
if (!settings.stripeSecretKey) {
|
|
7951
8566
|
return c.json({ error: "Stripe secret key not configured" }, 400);
|
|
7952
8567
|
}
|
|
@@ -8021,7 +8636,7 @@ var stripePlugin = definePlugin({
|
|
|
8021
8636
|
sonicjsVersionRange: "^3.0.0",
|
|
8022
8637
|
author: { name: "SonicJS Team" },
|
|
8023
8638
|
register(app2) {
|
|
8024
|
-
app2.route("/admin/plugins/stripe",
|
|
8639
|
+
app2.route("/admin/plugins/stripe", adminRoutes5);
|
|
8025
8640
|
app2.route("/api/stripe", apiRoutes3);
|
|
8026
8641
|
},
|
|
8027
8642
|
menu: [
|
|
@@ -9714,6 +10329,7 @@ function renderFormCreatePage(data) {
|
|
|
9714
10329
|
}
|
|
9715
10330
|
|
|
9716
10331
|
// src/routes/admin-forms.ts
|
|
10332
|
+
var isTableMissing = (err) => String(err?.message ?? err?.cause?.message ?? "").includes("no such table: forms");
|
|
9717
10333
|
var adminFormsRoutes = new Hono();
|
|
9718
10334
|
adminFormsRoutes.use("*", requireAuth());
|
|
9719
10335
|
adminFormsRoutes.get("/", async (c) => {
|
|
@@ -9755,6 +10371,14 @@ adminFormsRoutes.get("/", async (c) => {
|
|
|
9755
10371
|
};
|
|
9756
10372
|
return c.html(renderFormsListPage(pageData));
|
|
9757
10373
|
} catch (error) {
|
|
10374
|
+
if (isTableMissing(error)) {
|
|
10375
|
+
const user = c.get("user");
|
|
10376
|
+
return c.html(renderFormsListPage({
|
|
10377
|
+
forms: [],
|
|
10378
|
+
user: user ? { name: user.email, email: user.email, role: user.role } : void 0,
|
|
10379
|
+
version: c.get("appVersion")
|
|
10380
|
+
}));
|
|
10381
|
+
}
|
|
9758
10382
|
console.error("Error listing forms:", error);
|
|
9759
10383
|
return c.html("<p>Error loading forms</p>", 500);
|
|
9760
10384
|
}
|
|
@@ -9865,6 +10489,7 @@ adminFormsRoutes.post("/", async (c) => {
|
|
|
9865
10489
|
).run();
|
|
9866
10490
|
return c.redirect(`/admin/forms/${formId}/builder`);
|
|
9867
10491
|
} catch (error) {
|
|
10492
|
+
if (isTableMissing(error)) return c.json({ error: "Forms storage not configured \u2014 run database migrations" }, 503);
|
|
9868
10493
|
console.error("Error creating form:", error);
|
|
9869
10494
|
return c.json({ error: "Failed to create form" }, 500);
|
|
9870
10495
|
}
|
|
@@ -9902,6 +10527,7 @@ adminFormsRoutes.get("/:id/builder", async (c) => {
|
|
|
9902
10527
|
};
|
|
9903
10528
|
return c.html(renderFormBuilderPage(pageData));
|
|
9904
10529
|
} catch (error) {
|
|
10530
|
+
if (isTableMissing(error)) return c.html("<p>Forms storage not configured \u2014 run database migrations</p>", 503);
|
|
9905
10531
|
console.error("Error showing form builder:", error);
|
|
9906
10532
|
return c.html("<p>Error loading form builder</p>", 500);
|
|
9907
10533
|
}
|
|
@@ -9931,6 +10557,7 @@ adminFormsRoutes.put("/:id", async (c) => {
|
|
|
9931
10557
|
).run();
|
|
9932
10558
|
return c.json({ success: true, message: "Form saved successfully" });
|
|
9933
10559
|
} catch (error) {
|
|
10560
|
+
if (isTableMissing(error)) return c.json({ error: "Forms storage not configured \u2014 run database migrations" }, 503);
|
|
9934
10561
|
console.error("Error updating form:", error);
|
|
9935
10562
|
return c.json({ error: "Failed to save form" }, 500);
|
|
9936
10563
|
}
|
|
@@ -9952,6 +10579,7 @@ adminFormsRoutes.delete("/:id", async (c) => {
|
|
|
9952
10579
|
await db.prepare("DELETE FROM forms WHERE id = ?").bind(formId).run();
|
|
9953
10580
|
return c.json({ success: true, message: "Form deleted successfully" });
|
|
9954
10581
|
} catch (error) {
|
|
10582
|
+
if (isTableMissing(error)) return c.json({ error: "Forms storage not configured \u2014 run database migrations" }, 503);
|
|
9955
10583
|
console.error("Error deleting form:", error);
|
|
9956
10584
|
return c.json({ error: "Failed to delete form" }, 500);
|
|
9957
10585
|
}
|
|
@@ -10012,6 +10640,7 @@ adminFormsRoutes.get("/:id/submissions", async (c) => {
|
|
|
10012
10640
|
`;
|
|
10013
10641
|
return c.html(html4);
|
|
10014
10642
|
} catch (error) {
|
|
10643
|
+
if (isTableMissing(error)) return c.html("<p>Forms storage not configured \u2014 run database migrations</p>", 503);
|
|
10015
10644
|
console.error("Error loading submissions:", error);
|
|
10016
10645
|
return c.html("<p>Error loading submissions</p>", 500);
|
|
10017
10646
|
}
|
|
@@ -10032,6 +10661,7 @@ function sanitizeDeep(value) {
|
|
|
10032
10661
|
}
|
|
10033
10662
|
return value;
|
|
10034
10663
|
}
|
|
10664
|
+
var isTableMissing2 = (err) => String(err?.message ?? err?.cause?.message ?? "").includes("no such table: form");
|
|
10035
10665
|
var publicFormsRoutes = new Hono();
|
|
10036
10666
|
publicFormsRoutes.get("/:identifier/turnstile-config", async (c) => {
|
|
10037
10667
|
try {
|
|
@@ -10059,6 +10689,7 @@ publicFormsRoutes.get("/:identifier/turnstile-config", async (c) => {
|
|
|
10059
10689
|
appearance: formSettings.appearance || globalSettings.appearance || "always"
|
|
10060
10690
|
});
|
|
10061
10691
|
} catch (error) {
|
|
10692
|
+
if (isTableMissing2(error)) return c.json({ enabled: false });
|
|
10062
10693
|
console.error("Error fetching Turnstile config:", error);
|
|
10063
10694
|
return c.json({ error: "Failed to fetch config" }, 500);
|
|
10064
10695
|
}
|
|
@@ -10086,6 +10717,7 @@ publicFormsRoutes.get("/:identifier/schema", async (c) => {
|
|
|
10086
10717
|
submitUrl: `/api/forms/${form.id}/submit`
|
|
10087
10718
|
});
|
|
10088
10719
|
} catch (error) {
|
|
10720
|
+
if (isTableMissing2(error)) return c.json({ error: "Form not found" }, 404);
|
|
10089
10721
|
console.error("Error fetching form schema:", error);
|
|
10090
10722
|
return c.json({ error: "Failed to fetch form schema" }, 500);
|
|
10091
10723
|
}
|
|
@@ -10452,6 +11084,7 @@ publicFormsRoutes.get("/:name", async (c) => {
|
|
|
10452
11084
|
`;
|
|
10453
11085
|
return c.html(html4);
|
|
10454
11086
|
} catch (error) {
|
|
11087
|
+
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
11088
|
console.error("Error rendering form:", error);
|
|
10456
11089
|
return c.html("<p>Error loading form</p>", 500);
|
|
10457
11090
|
}
|
|
@@ -10525,6 +11158,7 @@ publicFormsRoutes.post("/:identifier/submit", async (c) => {
|
|
|
10525
11158
|
message: "Form submitted successfully"
|
|
10526
11159
|
});
|
|
10527
11160
|
} catch (error) {
|
|
11161
|
+
if (isTableMissing2(error)) return c.json({ error: "Form not found" }, 404);
|
|
10528
11162
|
console.error("Error submitting form:", error);
|
|
10529
11163
|
return c.json({ error: "Failed to submit form" }, 500);
|
|
10530
11164
|
}
|
|
@@ -10672,7 +11306,7 @@ adminRbacRoutes.get("/", async (c) => {
|
|
|
10672
11306
|
${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
11307
|
<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
11308
|
<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
|
-
|
|
11309
|
+
Admin Panel
|
|
10676
11310
|
</label>
|
|
10677
11311
|
<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
11312
|
${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 +11410,7 @@ adminRbacRoutes.get("/", async (c) => {
|
|
|
10776
11410
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-6">
|
|
10777
11411
|
<div class="${card}">
|
|
10778
11412
|
<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>
|
|
11413
|
+
<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
11414
|
${roleList}
|
|
10781
11415
|
</div>
|
|
10782
11416
|
<div class="${card}">
|
|
@@ -11074,14 +11708,24 @@ function pluginMenuMiddleware() {
|
|
|
11074
11708
|
}
|
|
11075
11709
|
} catch {
|
|
11076
11710
|
}
|
|
11077
|
-
|
|
11711
|
+
const user = c.get("user");
|
|
11712
|
+
const singletonItems = resolvePluginMenuItems(user ? { role: user.role } : void 0);
|
|
11713
|
+
const existingPaths = new Set(activeMenuItems.map((i) => i.path));
|
|
11714
|
+
for (const item of singletonItems) {
|
|
11715
|
+
if (!existingPaths.has(item.path)) {
|
|
11716
|
+
activeMenuItems.push({ label: item.label, path: item.path, icon: item.icon, order: item.order });
|
|
11717
|
+
}
|
|
11718
|
+
}
|
|
11719
|
+
activeMenuItems.sort((a, b) => a.order - b.order);
|
|
11720
|
+
c.set("pluginMenuItems", activeMenuItems.map((m) => ({ label: m.label, path: m.path, icon: resolveIcon(m.icon) || m.icon || "" })));
|
|
11078
11721
|
await next();
|
|
11079
|
-
|
|
11722
|
+
const finalItems = c.get("pluginMenuItems") ?? [];
|
|
11723
|
+
if (finalItems.length > 0 && c.res.headers.get("content-type")?.includes("text/html")) {
|
|
11080
11724
|
const status = c.res.status;
|
|
11081
11725
|
const headers = new Headers(c.res.headers);
|
|
11082
11726
|
const html4 = await c.res.text();
|
|
11083
11727
|
if (html4.includes(MARKER)) {
|
|
11084
|
-
const renderedItems =
|
|
11728
|
+
const renderedItems = finalItems.map((item) => renderMenuItem(item, path)).join("");
|
|
11085
11729
|
const newHtml = html4.split(MARKER).join(renderedItems);
|
|
11086
11730
|
c.res = new Response(newHtml, { status, headers });
|
|
11087
11731
|
} else {
|
|
@@ -11091,16 +11735,16 @@ function pluginMenuMiddleware() {
|
|
|
11091
11735
|
};
|
|
11092
11736
|
}
|
|
11093
11737
|
init_admin_layout_catalyst_template();
|
|
11094
|
-
var
|
|
11095
|
-
|
|
11096
|
-
|
|
11738
|
+
var adminRoutes6 = new Hono();
|
|
11739
|
+
adminRoutes6.use("*", requireAuth());
|
|
11740
|
+
adminRoutes6.use("*", async (c, next) => {
|
|
11097
11741
|
const user = c.get("user");
|
|
11098
11742
|
if (user?.role !== "admin") {
|
|
11099
11743
|
return c.text("Access denied", 403);
|
|
11100
11744
|
}
|
|
11101
11745
|
return next();
|
|
11102
11746
|
});
|
|
11103
|
-
|
|
11747
|
+
adminRoutes6.get("/", async (c) => {
|
|
11104
11748
|
const user = c.get("user");
|
|
11105
11749
|
const db = c.env.DB;
|
|
11106
11750
|
let totalRequests = 0;
|
|
@@ -11245,6 +11889,7 @@ var EventTrackingService = class {
|
|
|
11245
11889
|
tenantId: TENANT2
|
|
11246
11890
|
});
|
|
11247
11891
|
}
|
|
11892
|
+
db;
|
|
11248
11893
|
docsService;
|
|
11249
11894
|
async trackEvent(input) {
|
|
11250
11895
|
const doc = await this.docsService.create({
|
|
@@ -11456,7 +12101,7 @@ var analyticsPlugin = definePlugin({
|
|
|
11456
12101
|
author: { name: "SonicJS Team", email: "team@sonicjs.com" },
|
|
11457
12102
|
register(app2) {
|
|
11458
12103
|
app2.route("/api/events", apiRoutes4);
|
|
11459
|
-
app2.route("/admin/analytics",
|
|
12104
|
+
app2.route("/admin/analytics", adminRoutes6);
|
|
11460
12105
|
},
|
|
11461
12106
|
menu: [
|
|
11462
12107
|
{
|
|
@@ -11738,8 +12383,8 @@ apiRoutes5.delete("/:id", async (c) => {
|
|
|
11738
12383
|
return c.json({ success: false, error: "Failed to delete variable" }, 500);
|
|
11739
12384
|
}
|
|
11740
12385
|
});
|
|
11741
|
-
var
|
|
11742
|
-
|
|
12386
|
+
var adminRoutes7 = new Hono();
|
|
12387
|
+
adminRoutes7.use("*", async (c, next) => {
|
|
11743
12388
|
try {
|
|
11744
12389
|
const db = c.env?.DB;
|
|
11745
12390
|
if (db) {
|
|
@@ -11750,7 +12395,7 @@ adminRoutes6.use("*", async (c, next) => {
|
|
|
11750
12395
|
}
|
|
11751
12396
|
await next();
|
|
11752
12397
|
});
|
|
11753
|
-
|
|
12398
|
+
adminRoutes7.get("/", async (c) => {
|
|
11754
12399
|
const db = c.env.DB;
|
|
11755
12400
|
let variables = [];
|
|
11756
12401
|
try {
|
|
@@ -11780,7 +12425,7 @@ adminRoutes6.get("/", async (c) => {
|
|
|
11780
12425
|
}
|
|
11781
12426
|
return c.html(renderAdminPage(variables, { editorActive, activeEditorName, enableEditorIntegration }));
|
|
11782
12427
|
});
|
|
11783
|
-
|
|
12428
|
+
adminRoutes7.put("/:id", async (c) => {
|
|
11784
12429
|
const db = c.env.DB;
|
|
11785
12430
|
const id = c.req.param("id");
|
|
11786
12431
|
let body;
|
|
@@ -11796,7 +12441,7 @@ adminRoutes6.put("/:id", async (c) => {
|
|
|
11796
12441
|
}
|
|
11797
12442
|
return c.html('<span class="text-green-400 text-xs">Saved</span>');
|
|
11798
12443
|
});
|
|
11799
|
-
|
|
12444
|
+
adminRoutes7.post("/:id/toggle", async (c) => {
|
|
11800
12445
|
const db = c.env.DB;
|
|
11801
12446
|
const id = c.req.param("id");
|
|
11802
12447
|
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 +12449,7 @@ adminRoutes6.post("/:id/toggle", async (c) => {
|
|
|
11804
12449
|
c.header("HX-Redirect", "/admin/global-variables");
|
|
11805
12450
|
return c.body(null, 204);
|
|
11806
12451
|
});
|
|
11807
|
-
|
|
12452
|
+
adminRoutes7.post("/", async (c) => {
|
|
11808
12453
|
const db = c.env.DB;
|
|
11809
12454
|
const form = await c.req.parseBody();
|
|
11810
12455
|
const key = (form.key || "").trim();
|
|
@@ -11825,7 +12470,7 @@ adminRoutes6.post("/", async (c) => {
|
|
|
11825
12470
|
c.header("HX-Redirect", "/admin/global-variables");
|
|
11826
12471
|
return c.body(null, 204);
|
|
11827
12472
|
});
|
|
11828
|
-
|
|
12473
|
+
adminRoutes7.post("/settings/editor-integration", async (c) => {
|
|
11829
12474
|
const db = c.env.DB;
|
|
11830
12475
|
try {
|
|
11831
12476
|
const row = await db.prepare("SELECT settings FROM plugins WHERE id = 'global-variables'").first();
|
|
@@ -11837,7 +12482,7 @@ adminRoutes6.post("/settings/editor-integration", async (c) => {
|
|
|
11837
12482
|
return c.json({ success: false, error: "Failed to update setting" }, 500);
|
|
11838
12483
|
}
|
|
11839
12484
|
});
|
|
11840
|
-
|
|
12485
|
+
adminRoutes7.delete("/:id", async (c) => {
|
|
11841
12486
|
const db = c.env.DB;
|
|
11842
12487
|
await db.prepare("DELETE FROM global_variables WHERE id = ?").bind(c.req.param("id")).run();
|
|
11843
12488
|
invalidateVariablesCache();
|
|
@@ -12168,7 +12813,7 @@ var globalVariablesPlugin = definePlugin({
|
|
|
12168
12813
|
capabilities: ["hooks.content:subscribe"],
|
|
12169
12814
|
register(app2) {
|
|
12170
12815
|
app2.route("/api/global-variables", apiRoutes5);
|
|
12171
|
-
app2.route("/admin/global-variables",
|
|
12816
|
+
app2.route("/admin/global-variables", adminRoutes7);
|
|
12172
12817
|
},
|
|
12173
12818
|
menu: [
|
|
12174
12819
|
{ label: "Global Variables", path: "/admin/global-variables", icon: "bolt", order: 45, permissions: ["global-variables:view"] }
|
|
@@ -12489,8 +13134,8 @@ apiRoutes6.delete("/:id", async (c) => {
|
|
|
12489
13134
|
return c.json({ success: false, error: "Failed to delete shortcode" }, 500);
|
|
12490
13135
|
}
|
|
12491
13136
|
});
|
|
12492
|
-
var
|
|
12493
|
-
|
|
13137
|
+
var adminRoutes8 = new Hono();
|
|
13138
|
+
adminRoutes8.use("*", async (c, next) => {
|
|
12494
13139
|
try {
|
|
12495
13140
|
const db = c.env?.DB;
|
|
12496
13141
|
if (db) {
|
|
@@ -12501,7 +13146,7 @@ adminRoutes7.use("*", async (c, next) => {
|
|
|
12501
13146
|
}
|
|
12502
13147
|
await next();
|
|
12503
13148
|
});
|
|
12504
|
-
|
|
13149
|
+
adminRoutes8.get("/", async (c) => {
|
|
12505
13150
|
const db = c.env.DB;
|
|
12506
13151
|
let shortcodes = [];
|
|
12507
13152
|
try {
|
|
@@ -12531,7 +13176,7 @@ adminRoutes7.get("/", async (c) => {
|
|
|
12531
13176
|
}
|
|
12532
13177
|
return c.html(renderAdminPage2(shortcodes, { editorActive, activeEditorName, enableEditorIntegration }));
|
|
12533
13178
|
});
|
|
12534
|
-
|
|
13179
|
+
adminRoutes8.post("/", async (c) => {
|
|
12535
13180
|
const db = c.env.DB;
|
|
12536
13181
|
const form = await c.req.parseBody();
|
|
12537
13182
|
const name = (form.name || "").trim();
|
|
@@ -12552,7 +13197,7 @@ adminRoutes7.post("/", async (c) => {
|
|
|
12552
13197
|
c.header("HX-Redirect", "/admin/shortcodes");
|
|
12553
13198
|
return c.body(null, 204);
|
|
12554
13199
|
});
|
|
12555
|
-
|
|
13200
|
+
adminRoutes8.post("/settings/editor-integration", async (c) => {
|
|
12556
13201
|
const db = c.env.DB;
|
|
12557
13202
|
try {
|
|
12558
13203
|
const row = await db.prepare("SELECT settings FROM plugins WHERE id = 'shortcodes'").first();
|
|
@@ -12564,7 +13209,7 @@ adminRoutes7.post("/settings/editor-integration", async (c) => {
|
|
|
12564
13209
|
return c.json({ success: false, error: "Failed to update setting" }, 500);
|
|
12565
13210
|
}
|
|
12566
13211
|
});
|
|
12567
|
-
|
|
13212
|
+
adminRoutes8.delete("/:id", async (c) => {
|
|
12568
13213
|
await c.env.DB.prepare("DELETE FROM shortcodes WHERE id = ?").bind(c.req.param("id")).run();
|
|
12569
13214
|
return c.html("");
|
|
12570
13215
|
});
|
|
@@ -12775,7 +13420,7 @@ var shortcodesPlugin = definePlugin({
|
|
|
12775
13420
|
capabilities: ["hooks.content:subscribe"],
|
|
12776
13421
|
register(app2) {
|
|
12777
13422
|
app2.route("/api/shortcodes", apiRoutes6);
|
|
12778
|
-
app2.route("/admin/shortcodes",
|
|
13423
|
+
app2.route("/admin/shortcodes", adminRoutes8);
|
|
12779
13424
|
},
|
|
12780
13425
|
menu: [
|
|
12781
13426
|
{ label: "Shortcodes", path: "/admin/shortcodes", icon: "bolt", order: 46, permissions: ["shortcodes:view"] }
|
|
@@ -12884,6 +13529,9 @@ var helloWorldPlugin = definePlugin({
|
|
|
12884
13529
|
console.info("\u274C Hello World plugin deactivated");
|
|
12885
13530
|
}
|
|
12886
13531
|
});
|
|
13532
|
+
function createHelloWorldPlugin() {
|
|
13533
|
+
return helloWorldPlugin;
|
|
13534
|
+
}
|
|
12887
13535
|
|
|
12888
13536
|
// src/plugins/core-plugins/multi-tenant-plugin/manifest.json
|
|
12889
13537
|
var manifest_default2 = {
|
|
@@ -16057,6 +16705,7 @@ function createSonicJSApp(config = {}) {
|
|
|
16057
16705
|
const magicLinkPlugin = createMagicLinkAuthPlugin();
|
|
16058
16706
|
const corePluginsBeforeCatchAll = [
|
|
16059
16707
|
securityAuditPlugin,
|
|
16708
|
+
apiKeysPlugin,
|
|
16060
16709
|
aiSearchPlugin,
|
|
16061
16710
|
oauthProvidersPlugin,
|
|
16062
16711
|
userProfilesPlugin,
|
|
@@ -16154,6 +16803,17 @@ function createSonicJSApp(config = {}) {
|
|
|
16154
16803
|
app2.use("*", async (_c, next) => {
|
|
16155
16804
|
await next();
|
|
16156
16805
|
});
|
|
16806
|
+
app2.use("*", cors({
|
|
16807
|
+
origin: (origin, c) => {
|
|
16808
|
+
const allowed = c.env?.CORS_ORIGINS;
|
|
16809
|
+
if (!allowed) return null;
|
|
16810
|
+
const list = allowed.split(",").map((s) => s.trim());
|
|
16811
|
+
return list.includes(origin) ? origin : null;
|
|
16812
|
+
},
|
|
16813
|
+
allowMethods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
|
|
16814
|
+
allowHeaders: ["Content-Type", "Authorization", "X-API-Key"],
|
|
16815
|
+
credentials: true
|
|
16816
|
+
}));
|
|
16157
16817
|
app2.use("*", securityHeadersMiddleware());
|
|
16158
16818
|
app2.use("*", csrfProtection());
|
|
16159
16819
|
app2.use("*", async (c, next) => {
|
|
@@ -16187,6 +16847,7 @@ function createSonicJSApp(config = {}) {
|
|
|
16187
16847
|
}
|
|
16188
16848
|
await next();
|
|
16189
16849
|
});
|
|
16850
|
+
app2.use("*", apiKeyAuthMiddleware());
|
|
16190
16851
|
if (config.middleware?.afterAuth) {
|
|
16191
16852
|
for (const middleware of config.middleware.afterAuth) {
|
|
16192
16853
|
app2.use("*", middleware);
|
|
@@ -16211,7 +16872,7 @@ function createSonicJSApp(config = {}) {
|
|
|
16211
16872
|
if (!user?.userId) return next();
|
|
16212
16873
|
let perms = [];
|
|
16213
16874
|
try {
|
|
16214
|
-
const { RbacService: RbacService2 } = await import('./rbac-
|
|
16875
|
+
const { RbacService: RbacService2 } = await import('./rbac-Y43IEQOP.js');
|
|
16215
16876
|
perms = await new RbacService2(c.env.DB, c.env.CACHE_KV).permissionsForUser(user.userId);
|
|
16216
16877
|
} catch {
|
|
16217
16878
|
return next();
|
|
@@ -16285,7 +16946,10 @@ function createSonicJSApp(config = {}) {
|
|
|
16285
16946
|
...corePluginsAfterCatchAll,
|
|
16286
16947
|
...config.plugins?.register ?? []
|
|
16287
16948
|
];
|
|
16288
|
-
|
|
16949
|
+
const userPlugins = (config.plugins?.register ?? []).filter(
|
|
16950
|
+
(p) => !PLUGIN_REGISTRY[p.id]
|
|
16951
|
+
);
|
|
16952
|
+
setPluginMenu(userPlugins.flatMap((p) => p.menu ?? []));
|
|
16289
16953
|
setPluginDefinitions(allMountedPlugins);
|
|
16290
16954
|
}
|
|
16291
16955
|
app2.get("/favicon.svg", (c) => {
|
|
@@ -17150,6 +17814,8 @@ var RedirectService = class {
|
|
|
17150
17814
|
this.cloudflareService = new CloudflareBulkService(env);
|
|
17151
17815
|
}
|
|
17152
17816
|
}
|
|
17817
|
+
db;
|
|
17818
|
+
env;
|
|
17153
17819
|
cloudflareService = null;
|
|
17154
17820
|
getDocService() {
|
|
17155
17821
|
return new DocumentsService(this.db, {
|
|
@@ -19914,6 +20580,6 @@ function createDb(d1) {
|
|
|
19914
20580
|
// src/index.ts
|
|
19915
20581
|
var VERSION = package_default.version;
|
|
19916
20582
|
|
|
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 };
|
|
20583
|
+
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
20584
|
//# sourceMappingURL=index.js.map
|
|
19919
20585
|
//# sourceMappingURL=index.js.map
|