@sonicjs-cms/core 3.0.0-beta.14 → 3.0.0-beta.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{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-SIPBHWMG.cjs → chunk-3XFA3E2F.cjs} +4 -4
- package/dist/{chunk-SIPBHWMG.cjs.map → chunk-3XFA3E2F.cjs.map} +1 -1
- package/dist/{chunk-QNPT6BQP.js → chunk-7P2IJM4K.js} +3 -3
- package/dist/{chunk-QNPT6BQP.js.map → chunk-7P2IJM4K.js.map} +1 -1
- package/dist/{chunk-32SDMKZ7.js → chunk-HYO2MSFI.js} +2 -2
- package/dist/{chunk-32SDMKZ7.js.map → chunk-HYO2MSFI.js.map} +1 -1
- package/dist/{chunk-H5FB6GKR.cjs → chunk-IA24HACT.cjs} +2 -2
- package/dist/{chunk-H5FB6GKR.cjs.map → chunk-IA24HACT.cjs.map} +1 -1
- package/dist/{chunk-75JKPNUZ.js → chunk-IQZA2OY5.js} +3 -3
- package/dist/{chunk-75JKPNUZ.js.map → chunk-IQZA2OY5.js.map} +1 -1
- package/dist/{chunk-5L6EMI7A.js → chunk-IXUNNFZZ.js} +6 -5
- package/dist/chunk-IXUNNFZZ.js.map +1 -0
- package/dist/{chunk-U7T5EOHJ.js → chunk-JRMBHDGM.js} +4 -4
- package/dist/{chunk-U7T5EOHJ.js.map → chunk-JRMBHDGM.js.map} +1 -1
- package/dist/{chunk-INE5E3SL.js → chunk-KIB7K5LV.js} +27 -2
- package/dist/chunk-KIB7K5LV.js.map +1 -0
- package/dist/{chunk-ZTEJHSYS.cjs → chunk-KMCLNO4K.cjs} +5 -5
- package/dist/{chunk-ZTEJHSYS.cjs.map → chunk-KMCLNO4K.cjs.map} +1 -1
- package/dist/{chunk-L3KHLEHL.cjs → chunk-KMM45BTY.cjs} +53 -15
- package/dist/chunk-KMM45BTY.cjs.map +1 -0
- package/dist/{chunk-4YRYGDCQ.cjs → chunk-KOXFYFOF.cjs} +4 -4
- package/dist/{chunk-4YRYGDCQ.cjs.map → chunk-KOXFYFOF.cjs.map} +1 -1
- package/dist/{chunk-WIV3R2MJ.cjs → chunk-KZIBF2EV.cjs} +27 -2
- package/dist/chunk-KZIBF2EV.cjs.map +1 -0
- package/dist/{chunk-G5LC7MYH.cjs → chunk-LXYDJU6U.cjs} +12 -11
- package/dist/chunk-LXYDJU6U.cjs.map +1 -0
- package/dist/{chunk-O32IZ6JS.js → chunk-PA2UIFB7.js} +43 -5
- package/dist/chunk-PA2UIFB7.js.map +1 -0
- package/dist/{chunk-SSOP7G4R.cjs → chunk-SC2WZFNQ.cjs} +309 -243
- package/dist/chunk-SC2WZFNQ.cjs.map +1 -0
- package/dist/{chunk-HNUGMALL.js → chunk-UOFRE5PY.js} +104 -39
- package/dist/chunk-UOFRE5PY.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/config-SM2UWSDN.js +6 -0
- package/dist/{config-PLJTDINX.js.map → config-SM2UWSDN.js.map} +1 -1
- package/dist/config-YCRSU7ZP.cjs +19 -0
- package/dist/{config-FLOUCYHH.cjs.map → config-YCRSU7ZP.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/index.cjs +775 -297
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +194 -7
- package/dist/index.d.ts +194 -7
- package/dist/index.js +527 -59
- package/dist/index.js.map +1 -1
- package/dist/middleware.cjs +33 -33
- package/dist/middleware.d.cts +2 -2
- package/dist/middleware.d.ts +2 -2
- package/dist/middleware.js +4 -4
- package/dist/migrations-F4LBAHQN.js +4 -0
- package/dist/{migrations-DOPZXFK3.js.map → migrations-F4LBAHQN.js.map} +1 -1
- package/dist/migrations-KMCULV6H.cjs +13 -0
- package/dist/{migrations-TYYC66P4.cjs.map → migrations-KMCULV6H.cjs.map} +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/routes.cjs +27 -27
- package/dist/routes.d.cts +2 -2
- package/dist/routes.d.ts +2 -2
- package/dist/routes.js +7 -7
- package/dist/services.cjs +18 -18
- package/dist/services.js +2 -2
- package/dist/{types-Dea1eNxU.d.cts → types-DT7XN5TX.d.cts} +1 -1
- package/dist/{types-Dea1eNxU.d.ts → types-DT7XN5TX.d.ts} +1 -1
- package/dist/utils.cjs +3 -3
- package/dist/utils.js +1 -1
- package/package.json +2 -2
- package/dist/chunk-5L6EMI7A.js.map +0 -1
- package/dist/chunk-G5LC7MYH.cjs.map +0 -1
- package/dist/chunk-HIKBY7MS.cjs.map +0 -1
- package/dist/chunk-HNUGMALL.js.map +0 -1
- package/dist/chunk-IESEVHXL.js.map +0 -1
- package/dist/chunk-INE5E3SL.js.map +0 -1
- package/dist/chunk-L3KHLEHL.cjs.map +0 -1
- package/dist/chunk-O32IZ6JS.js.map +0 -1
- package/dist/chunk-SSOP7G4R.cjs.map +0 -1
- package/dist/chunk-WIV3R2MJ.cjs.map +0 -1
- package/dist/config-FLOUCYHH.cjs +0 -19
- package/dist/config-PLJTDINX.js +0 -6
- package/dist/migrations-DOPZXFK3.js +0 -4
- package/dist/migrations-TYYC66P4.cjs +0 -13
package/dist/index.js
CHANGED
|
@@ -1,37 +1,37 @@
|
|
|
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-
|
|
1
|
+
import { createAuth } from './chunk-IQZA2OY5.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-UOFRE5PY.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-UOFRE5PY.js';
|
|
4
|
+
import './chunk-VVYVFCML.js';
|
|
5
5
|
import './chunk-RMRJGMDE.js';
|
|
6
6
|
import { SettingsService, setAppInstance } from './chunk-RQ6N3FTV.js';
|
|
7
7
|
export { Logger, getLogger, initLogger } from './chunk-RQ6N3FTV.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-
|
|
11
|
+
import { requireAuth, DocumentTypeRegistry, requireRbac, requireRole, getJwtExpirySecondsFromDb, AuthManager, metricsMiddleware, bootstrapMiddleware, securityHeadersMiddleware, csrfProtection } from './chunk-PA2UIFB7.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-PA2UIFB7.js';
|
|
13
13
|
import { RbacService, DocumentsService } from './chunk-PDC7DLOV.js';
|
|
14
|
-
export { RbacService } from './chunk-PDC7DLOV.js';
|
|
14
|
+
export { DocumentsService, RbacService } from './chunk-PDC7DLOV.js';
|
|
15
15
|
import { nanoid } from './chunk-GCDZZNIN.js';
|
|
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-
|
|
16
|
+
import { PluginService, PLUGIN_REGISTRY, invalidateTenantCache, getCollectionRegistry, TENANT_COOKIE, MULTI_TENANT_PLUGIN_ID, collectionRecordToRow, tenantMiddleware } from './chunk-KIB7K5LV.js';
|
|
17
|
+
export { PluginBootstrapService, PluginService as PluginServiceClass, getAvailableCollectionNames, loadCollectionConfig, loadCollectionConfigs, registerCollections, validateCollectionConfig } from './chunk-KIB7K5LV.js';
|
|
18
|
+
export { MigrationService } from './chunk-HYO2MSFI.js';
|
|
19
19
|
export { renderFilterBar } from './chunk-JQISFW6U.js';
|
|
20
20
|
import { renderAdminLayout } from './chunk-OBA2RYZN.js';
|
|
21
21
|
export { getConfirmationDialogScript, renderAlert, renderConfirmationDialog, renderForm, renderFormField, renderPagination, renderTable } from './chunk-OBA2RYZN.js';
|
|
22
22
|
import { init_admin_layout_catalyst_template, renderAdminLayoutCatalyst } from './chunk-5V62WT6M.js';
|
|
23
23
|
export { renderAdminLayoutCatalyst } from './chunk-5V62WT6M.js';
|
|
24
|
-
import { TurnstileService, HookSystemImpl, createPluginWirer, registerPluginRoutes, setPluginMenu } from './chunk-
|
|
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-
|
|
26
|
-
import { definePlugin, setPluginDefinitions } from './chunk-
|
|
27
|
-
export { applySchemaDefaults, definePlugin, isDefinedPlugin, parseConfigSchema, parseFormDataToSettings, renderSchemaFields } from './chunk-
|
|
24
|
+
import { TurnstileService, HookSystemImpl, createPluginWirer, registerPluginRoutes, setPluginMenu, resolvePluginMenuItems } from './chunk-IXUNNFZZ.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-IXUNNFZZ.js';
|
|
26
|
+
import { definePlugin, setPluginDefinitions } from './chunk-7P2IJM4K.js';
|
|
27
|
+
export { applySchemaDefaults, definePlugin, isDefinedPlugin, parseConfigSchema, parseFormDataToSettings, renderSchemaFields } from './chunk-7P2IJM4K.js';
|
|
28
28
|
import { setHookSystem } from './chunk-RNZFGN4R.js';
|
|
29
29
|
export { getHookSystem, getTypedHooks, hasHookSystem, resetHookSystem, setHookSystem } from './chunk-RNZFGN4R.js';
|
|
30
30
|
export { QueryFilterBuilder, TemplateRenderer, buildQuery, renderTemplate, templateRenderer } from './chunk-QZGABF2M.js';
|
|
31
31
|
export { metricsTracker } from './chunk-FICTAGD4.js';
|
|
32
32
|
import './chunk-X7ZAEI5S.js';
|
|
33
|
-
import { getCoreVersion, package_default } from './chunk-
|
|
34
|
-
export { SONICJS_VERSION, getCoreVersion } from './chunk-
|
|
33
|
+
import { getCoreVersion, package_default } from './chunk-JRMBHDGM.js';
|
|
34
|
+
export { SONICJS_VERSION, getCoreVersion } from './chunk-JRMBHDGM.js';
|
|
35
35
|
import { escapeHtml, sanitizeInput } from './chunk-TQABQWOP.js';
|
|
36
36
|
export { escapeHtml, sanitizeInput, sanitizeObject } from './chunk-TQABQWOP.js';
|
|
37
37
|
export { HOOKS } from './chunk-QXOZI5Q2.js';
|
|
@@ -6646,6 +6646,457 @@ var securityAuditPlugin = definePlugin({
|
|
|
6646
6646
|
deactivate: async () => console.log("[SecurityAudit] Plugin deactivated")
|
|
6647
6647
|
});
|
|
6648
6648
|
|
|
6649
|
+
// src/plugins/core-plugins/api-keys-plugin/services/api-key-service.ts
|
|
6650
|
+
var API_KEY_QUERYABLE = [
|
|
6651
|
+
{ name: "keyHash", kind: "scalar", type: "text", column: "q_apikey_hash" },
|
|
6652
|
+
{ name: "userId", kind: "scalar", type: "text", column: "q_apikey_user_id" },
|
|
6653
|
+
{ name: "revoked", kind: "scalar", type: "integer", column: "q_apikey_revoked" }
|
|
6654
|
+
];
|
|
6655
|
+
var KEY_PREFIX = "sk_";
|
|
6656
|
+
var KEY_BYTES = 24;
|
|
6657
|
+
var DISPLAY_PREFIX_LEN = KEY_PREFIX.length + 8;
|
|
6658
|
+
function generateApiKeySecret() {
|
|
6659
|
+
const bytes = new Uint8Array(KEY_BYTES);
|
|
6660
|
+
crypto.getRandomValues(bytes);
|
|
6661
|
+
let hex = "";
|
|
6662
|
+
for (const b of bytes) hex += b.toString(16).padStart(2, "0");
|
|
6663
|
+
return KEY_PREFIX + hex;
|
|
6664
|
+
}
|
|
6665
|
+
async function hashApiKey(secret) {
|
|
6666
|
+
const data = new TextEncoder().encode(secret);
|
|
6667
|
+
const digest = await crypto.subtle.digest("SHA-256", data);
|
|
6668
|
+
const view = new Uint8Array(digest);
|
|
6669
|
+
let hex = "";
|
|
6670
|
+
for (const b of view) hex += b.toString(16).padStart(2, "0");
|
|
6671
|
+
return hex;
|
|
6672
|
+
}
|
|
6673
|
+
var ApiKeyService = class {
|
|
6674
|
+
constructor(db, tenantId = "default") {
|
|
6675
|
+
this.db = db;
|
|
6676
|
+
this.tenantId = tenantId;
|
|
6677
|
+
}
|
|
6678
|
+
docService() {
|
|
6679
|
+
return new DocumentsService(this.db, {
|
|
6680
|
+
queryableFields: API_KEY_QUERYABLE,
|
|
6681
|
+
tenantId: this.tenantId,
|
|
6682
|
+
maxVersionsPerRoot: 1
|
|
6683
|
+
});
|
|
6684
|
+
}
|
|
6685
|
+
/** Count a user's active (non-revoked) keys — used to enforce the per-user cap. */
|
|
6686
|
+
async countForUser(userId) {
|
|
6687
|
+
const row = await this.db.prepare(
|
|
6688
|
+
`SELECT COUNT(*) AS c FROM documents
|
|
6689
|
+
WHERE type_id = 'api_key' AND tenant_id = ? AND is_current_draft = 1
|
|
6690
|
+
AND deleted_at IS NULL AND q_apikey_user_id = ? AND q_apikey_revoked = 0`
|
|
6691
|
+
).bind(this.tenantId, userId).first();
|
|
6692
|
+
return row?.c ?? 0;
|
|
6693
|
+
}
|
|
6694
|
+
/**
|
|
6695
|
+
* Mint a new key for a user. The returned `key` is the only time the plaintext
|
|
6696
|
+
* exists outside the caller — it is hashed before storage.
|
|
6697
|
+
*/
|
|
6698
|
+
async create(input) {
|
|
6699
|
+
const name = input.name.trim() || "API Key";
|
|
6700
|
+
const secret = generateApiKeySecret();
|
|
6701
|
+
const keyHash = await hashApiKey(secret);
|
|
6702
|
+
const prefix = secret.slice(0, DISPLAY_PREFIX_LEN);
|
|
6703
|
+
const expiresAt = input.expiresAt ?? null;
|
|
6704
|
+
const doc = await this.docService().create(
|
|
6705
|
+
createDocumentSchema.parse({
|
|
6706
|
+
typeId: "api_key",
|
|
6707
|
+
tenantId: this.tenantId,
|
|
6708
|
+
title: name,
|
|
6709
|
+
ownerId: input.userId,
|
|
6710
|
+
publishOnCreate: true,
|
|
6711
|
+
data: {
|
|
6712
|
+
name,
|
|
6713
|
+
userId: input.userId,
|
|
6714
|
+
keyHash,
|
|
6715
|
+
keyPrefix: prefix,
|
|
6716
|
+
revoked: 0,
|
|
6717
|
+
lastUsedAt: null,
|
|
6718
|
+
expiresAt
|
|
6719
|
+
}
|
|
6720
|
+
}),
|
|
6721
|
+
input.userId
|
|
6722
|
+
);
|
|
6723
|
+
return { id: doc.rootId, key: secret, name, prefix, expiresAt };
|
|
6724
|
+
}
|
|
6725
|
+
/** List a user's non-revoked keys (metadata only — never the secret or hash). */
|
|
6726
|
+
async list(userId) {
|
|
6727
|
+
const res = await this.db.prepare(
|
|
6728
|
+
`SELECT root_id, data, created_at FROM documents
|
|
6729
|
+
WHERE type_id = 'api_key' AND tenant_id = ? AND is_current_draft = 1
|
|
6730
|
+
AND deleted_at IS NULL AND q_apikey_user_id = ? AND q_apikey_revoked = 0
|
|
6731
|
+
ORDER BY created_at DESC`
|
|
6732
|
+
).bind(this.tenantId, userId).all();
|
|
6733
|
+
return (res.results ?? []).map((row) => {
|
|
6734
|
+
const d = JSON.parse(row.data);
|
|
6735
|
+
return {
|
|
6736
|
+
id: row.root_id,
|
|
6737
|
+
name: d.name ?? "API Key",
|
|
6738
|
+
prefix: d.keyPrefix ?? "",
|
|
6739
|
+
createdAt: row.created_at,
|
|
6740
|
+
lastUsedAt: d.lastUsedAt ?? null,
|
|
6741
|
+
expiresAt: d.expiresAt ?? null
|
|
6742
|
+
};
|
|
6743
|
+
});
|
|
6744
|
+
}
|
|
6745
|
+
/**
|
|
6746
|
+
* Revoke (hard-delete) a key owned by `userId`. Credentials are erased, not
|
|
6747
|
+
* soft-flagged. Returns false if the key does not exist or is not owned by
|
|
6748
|
+
* the caller (no information leak about other users' keys).
|
|
6749
|
+
*/
|
|
6750
|
+
async revoke(rootId, userId) {
|
|
6751
|
+
const row = await this.db.prepare(
|
|
6752
|
+
`SELECT q_apikey_user_id AS owner FROM documents
|
|
6753
|
+
WHERE root_id = ? AND tenant_id = ? AND type_id = 'api_key' AND is_current_draft = 1 AND deleted_at IS NULL`
|
|
6754
|
+
).bind(rootId, this.tenantId).first();
|
|
6755
|
+
if (!row || row.owner !== userId) return false;
|
|
6756
|
+
await this.docService().erase(rootId, this.tenantId);
|
|
6757
|
+
return true;
|
|
6758
|
+
}
|
|
6759
|
+
/**
|
|
6760
|
+
* Resolve a presented secret to its owning user, or null. Rejects unknown,
|
|
6761
|
+
* revoked, expired keys and inactive users. Best-effort updates lastUsedAt.
|
|
6762
|
+
*/
|
|
6763
|
+
async resolve(secret) {
|
|
6764
|
+
if (!secret || !secret.startsWith(KEY_PREFIX)) return null;
|
|
6765
|
+
const keyHash = await hashApiKey(secret);
|
|
6766
|
+
const keyRow2 = await this.db.prepare(
|
|
6767
|
+
`SELECT root_id, data FROM documents
|
|
6768
|
+
WHERE type_id = 'api_key' AND tenant_id = ? AND is_current_draft = 1 AND deleted_at IS NULL
|
|
6769
|
+
AND q_apikey_hash = ? AND q_apikey_revoked = 0
|
|
6770
|
+
LIMIT 1`
|
|
6771
|
+
).bind(this.tenantId, keyHash).first();
|
|
6772
|
+
if (!keyRow2) return null;
|
|
6773
|
+
const d = JSON.parse(keyRow2.data);
|
|
6774
|
+
if (d.expiresAt != null && Date.now() > Number(d.expiresAt)) return null;
|
|
6775
|
+
const user = await this.db.prepare(`SELECT id, email, role, is_active, is_super_admin FROM auth_user WHERE id = ?`).bind(d.userId).first();
|
|
6776
|
+
if (!user || user.is_active !== 1) return null;
|
|
6777
|
+
try {
|
|
6778
|
+
await this.touchLastUsed(keyRow2.root_id, d);
|
|
6779
|
+
} catch {
|
|
6780
|
+
}
|
|
6781
|
+
return {
|
|
6782
|
+
userId: user.id,
|
|
6783
|
+
email: user.email,
|
|
6784
|
+
role: user.role ?? "viewer",
|
|
6785
|
+
isSuperAdmin: user.is_super_admin === 1
|
|
6786
|
+
};
|
|
6787
|
+
}
|
|
6788
|
+
/** Update lastUsedAt in-place (single-version type, no history churn). */
|
|
6789
|
+
async touchLastUsed(rootId, data) {
|
|
6790
|
+
const next = JSON.stringify({ ...data, lastUsedAt: Date.now() });
|
|
6791
|
+
await this.db.prepare(
|
|
6792
|
+
`UPDATE documents SET data = ? WHERE root_id = ? AND tenant_id = ? AND type_id = 'api_key' AND is_current_draft = 1`
|
|
6793
|
+
).bind(next, rootId, this.tenantId).run();
|
|
6794
|
+
}
|
|
6795
|
+
};
|
|
6796
|
+
|
|
6797
|
+
// src/plugins/core-plugins/api-keys-plugin/components/keys-page.ts
|
|
6798
|
+
init_admin_layout_catalyst_template();
|
|
6799
|
+
function fmtDate(ms) {
|
|
6800
|
+
if (!ms) return "\u2014";
|
|
6801
|
+
try {
|
|
6802
|
+
return new Date(ms).toISOString().slice(0, 10);
|
|
6803
|
+
} catch {
|
|
6804
|
+
return "\u2014";
|
|
6805
|
+
}
|
|
6806
|
+
}
|
|
6807
|
+
function keyRow(k) {
|
|
6808
|
+
const name = escapeHtml(k.name);
|
|
6809
|
+
const prefix = escapeHtml(k.prefix);
|
|
6810
|
+
const id = escapeHtml(k.id);
|
|
6811
|
+
return `
|
|
6812
|
+
<tr class="border-t border-zinc-950/5 dark:border-white/10" data-key-id="${id}">
|
|
6813
|
+
<td class="py-3 pr-4 text-sm font-medium text-zinc-950 dark:text-white">${name}</td>
|
|
6814
|
+
<td class="py-3 pr-4 text-sm font-mono text-zinc-500 dark:text-zinc-400">${prefix}\u2026</td>
|
|
6815
|
+
<td class="py-3 pr-4 text-sm text-zinc-500 dark:text-zinc-400">${fmtDate(k.createdAt ? k.createdAt * 1e3 : null)}</td>
|
|
6816
|
+
<td class="py-3 pr-4 text-sm text-zinc-500 dark:text-zinc-400">${k.lastUsedAt ? fmtDate(k.lastUsedAt) : "Never"}</td>
|
|
6817
|
+
<td class="py-3 pr-4 text-sm text-zinc-500 dark:text-zinc-400">${k.expiresAt ? fmtDate(k.expiresAt) : "Never"}</td>
|
|
6818
|
+
<td class="py-3 text-right">
|
|
6819
|
+
<button type="button" onclick="revokeApiKey('${id}', '${name.replace(/'/g, "\\'")}')"
|
|
6820
|
+
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">
|
|
6821
|
+
Revoke
|
|
6822
|
+
</button>
|
|
6823
|
+
</td>
|
|
6824
|
+
</tr>`;
|
|
6825
|
+
}
|
|
6826
|
+
function renderApiKeysPage(data) {
|
|
6827
|
+
const { keys, user, version, dynamicMenuItems } = data;
|
|
6828
|
+
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>`;
|
|
6829
|
+
const content2 = `
|
|
6830
|
+
<div>
|
|
6831
|
+
<div class="sm:flex sm:items-center sm:justify-between mb-6">
|
|
6832
|
+
<div class="sm:flex-auto">
|
|
6833
|
+
<h1 class="text-2xl/8 font-semibold text-zinc-950 dark:text-white sm:text-xl/8">API Keys</h1>
|
|
6834
|
+
<p class="mt-2 text-sm/6 text-zinc-500 dark:text-zinc-400">
|
|
6835
|
+
Long-lived secrets for headless / server-to-server REST access. Send a key as the
|
|
6836
|
+
<code class="font-mono">x-api-key</code> header or <code class="font-mono">Authorization: Bearer <key></code>.
|
|
6837
|
+
The secret is shown once at creation \u2014 store it now.
|
|
6838
|
+
</p>
|
|
6839
|
+
</div>
|
|
6840
|
+
<div class="mt-4 sm:mt-0 sm:ml-16">
|
|
6841
|
+
<button type="button" onclick="document.getElementById('create-key-modal').classList.remove('hidden')"
|
|
6842
|
+
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">
|
|
6843
|
+
Create API key
|
|
6844
|
+
</button>
|
|
6845
|
+
</div>
|
|
6846
|
+
</div>
|
|
6847
|
+
|
|
6848
|
+
<!-- Newly-created secret banner (populated by JS, shown once) -->
|
|
6849
|
+
<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">
|
|
6850
|
+
<p class="text-sm font-medium text-emerald-800 dark:text-emerald-300 mb-2">
|
|
6851
|
+
Copy your new key now \u2014 it will not be shown again.
|
|
6852
|
+
</p>
|
|
6853
|
+
<div class="flex items-center gap-2">
|
|
6854
|
+
<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>
|
|
6855
|
+
<button type="button" onclick="copyNewKey()"
|
|
6856
|
+
class="rounded-lg bg-emerald-600 px-3 py-2 text-sm font-semibold text-white hover:bg-emerald-500 transition-colors">
|
|
6857
|
+
Copy
|
|
6858
|
+
</button>
|
|
6859
|
+
</div>
|
|
6860
|
+
</div>
|
|
6861
|
+
|
|
6862
|
+
<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">
|
|
6863
|
+
<table class="w-full text-left">
|
|
6864
|
+
<thead>
|
|
6865
|
+
<tr class="text-xs font-semibold uppercase tracking-wide text-zinc-500 dark:text-zinc-400">
|
|
6866
|
+
<th class="pb-2 pr-4">Name</th>
|
|
6867
|
+
<th class="pb-2 pr-4">Prefix</th>
|
|
6868
|
+
<th class="pb-2 pr-4">Created</th>
|
|
6869
|
+
<th class="pb-2 pr-4">Last used</th>
|
|
6870
|
+
<th class="pb-2 pr-4">Expires</th>
|
|
6871
|
+
<th class="pb-2 text-right">Actions</th>
|
|
6872
|
+
</tr>
|
|
6873
|
+
</thead>
|
|
6874
|
+
<tbody id="keys-tbody">${rows}</tbody>
|
|
6875
|
+
</table>
|
|
6876
|
+
</div>
|
|
6877
|
+
</div>
|
|
6878
|
+
|
|
6879
|
+
<!-- Create modal -->
|
|
6880
|
+
<div id="create-key-modal" class="hidden fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4">
|
|
6881
|
+
<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">
|
|
6882
|
+
<h2 class="text-base font-semibold text-zinc-950 dark:text-white mb-4">Create API key</h2>
|
|
6883
|
+
<label class="block text-sm font-medium text-zinc-700 dark:text-zinc-300 mb-1">Name</label>
|
|
6884
|
+
<input id="new-key-name" type="text" placeholder="e.g. CI deploy token"
|
|
6885
|
+
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">
|
|
6886
|
+
<label class="block text-sm font-medium text-zinc-700 dark:text-zinc-300 mb-1">Expires in (days, optional)</label>
|
|
6887
|
+
<input id="new-key-expiry" type="number" min="1" max="3650" placeholder="Never"
|
|
6888
|
+
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">
|
|
6889
|
+
<div class="flex justify-end gap-2">
|
|
6890
|
+
<button type="button" onclick="document.getElementById('create-key-modal').classList.add('hidden')"
|
|
6891
|
+
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">
|
|
6892
|
+
Cancel
|
|
6893
|
+
</button>
|
|
6894
|
+
<button type="button" onclick="createApiKey()"
|
|
6895
|
+
class="rounded-lg bg-cyan-600 px-4 py-2 text-sm font-semibold text-white hover:bg-cyan-500 transition-colors">
|
|
6896
|
+
Create
|
|
6897
|
+
</button>
|
|
6898
|
+
</div>
|
|
6899
|
+
</div>
|
|
6900
|
+
</div>
|
|
6901
|
+
|
|
6902
|
+
<script>
|
|
6903
|
+
// CSRF: the csrf_token cookie is JS-readable (httpOnly:false); echo it back
|
|
6904
|
+
// as X-CSRF-Token on state-changing requests (signed double-submit).
|
|
6905
|
+
function csrfHeader() {
|
|
6906
|
+
const m = document.cookie.match(/(?:^|; )csrf_token=([^;]+)/)
|
|
6907
|
+
return m ? { 'X-CSRF-Token': decodeURIComponent(m[1]) } : {}
|
|
6908
|
+
}
|
|
6909
|
+
async function createApiKey() {
|
|
6910
|
+
const name = document.getElementById('new-key-name').value.trim()
|
|
6911
|
+
if (!name) { window.showNotification && window.showNotification('Name is required', 'error'); return }
|
|
6912
|
+
const expiry = parseInt(document.getElementById('new-key-expiry').value, 10)
|
|
6913
|
+
const body = { name }
|
|
6914
|
+
if (Number.isFinite(expiry) && expiry > 0) body.expiresInDays = expiry
|
|
6915
|
+
const res = await fetch('/admin/plugins/api-keys/api/keys', {
|
|
6916
|
+
method: 'POST',
|
|
6917
|
+
headers: { 'Content-Type': 'application/json', ...csrfHeader() },
|
|
6918
|
+
body: JSON.stringify(body),
|
|
6919
|
+
})
|
|
6920
|
+
if (!res.ok) {
|
|
6921
|
+
const e = await res.json().catch(() => ({}))
|
|
6922
|
+
window.showNotification && window.showNotification(e.error || 'Failed to create key', 'error')
|
|
6923
|
+
return
|
|
6924
|
+
}
|
|
6925
|
+
const { apiKey } = await res.json()
|
|
6926
|
+
document.getElementById('create-key-modal').classList.add('hidden')
|
|
6927
|
+
document.getElementById('new-key-value').textContent = apiKey.key
|
|
6928
|
+
document.getElementById('new-key-banner').classList.remove('hidden')
|
|
6929
|
+
setTimeout(() => location.reload(), 1500)
|
|
6930
|
+
}
|
|
6931
|
+
function copyNewKey() {
|
|
6932
|
+
const v = document.getElementById('new-key-value').textContent
|
|
6933
|
+
navigator.clipboard.writeText(v).then(() => window.showNotification && window.showNotification('Copied', 'success'))
|
|
6934
|
+
}
|
|
6935
|
+
async function revokeApiKey(id, name) {
|
|
6936
|
+
if (!confirm('Revoke "' + name + '"? This cannot be undone and will break any client using it.')) return
|
|
6937
|
+
const res = await fetch('/admin/plugins/api-keys/api/keys/' + id, { method: 'DELETE', headers: { ...csrfHeader() } })
|
|
6938
|
+
if (res.ok) {
|
|
6939
|
+
const row = document.querySelector('[data-key-id="' + id + '"]')
|
|
6940
|
+
if (row) row.remove()
|
|
6941
|
+
window.showNotification && window.showNotification('Key revoked', 'success')
|
|
6942
|
+
} else {
|
|
6943
|
+
window.showNotification && window.showNotification('Failed to revoke', 'error')
|
|
6944
|
+
}
|
|
6945
|
+
}
|
|
6946
|
+
</script>`;
|
|
6947
|
+
const layoutData = {
|
|
6948
|
+
title: "API Keys",
|
|
6949
|
+
pageTitle: "API Keys",
|
|
6950
|
+
currentPath: "/admin/plugins/api-keys",
|
|
6951
|
+
user,
|
|
6952
|
+
content: content2,
|
|
6953
|
+
version,
|
|
6954
|
+
dynamicMenuItems
|
|
6955
|
+
};
|
|
6956
|
+
return renderAdminLayoutCatalyst(layoutData);
|
|
6957
|
+
}
|
|
6958
|
+
|
|
6959
|
+
// src/plugins/core-plugins/api-keys-plugin/types.ts
|
|
6960
|
+
var DEFAULT_SETTINGS3 = {
|
|
6961
|
+
maxKeysPerUser: 50,
|
|
6962
|
+
defaultExpiryDays: 0
|
|
6963
|
+
};
|
|
6964
|
+
|
|
6965
|
+
// src/plugins/core-plugins/api-keys-plugin/routes/admin.ts
|
|
6966
|
+
var adminRoutes4 = new Hono();
|
|
6967
|
+
var DAY_MS = 24 * 60 * 60 * 1e3;
|
|
6968
|
+
var createSchema = z.object({
|
|
6969
|
+
name: z.string().min(1).max(100),
|
|
6970
|
+
// Optional lifetime in days; omitted/null → plugin default (which may be "never").
|
|
6971
|
+
expiresInDays: z.number().int().positive().max(3650).nullish()
|
|
6972
|
+
});
|
|
6973
|
+
async function getSettings3(db) {
|
|
6974
|
+
try {
|
|
6975
|
+
const plugin2 = await new PluginService(db).getPlugin("api-keys");
|
|
6976
|
+
if (plugin2?.settings) {
|
|
6977
|
+
const s = typeof plugin2.settings === "string" ? JSON.parse(plugin2.settings) : plugin2.settings;
|
|
6978
|
+
return { ...DEFAULT_SETTINGS3, ...s };
|
|
6979
|
+
}
|
|
6980
|
+
} catch {
|
|
6981
|
+
}
|
|
6982
|
+
return DEFAULT_SETTINGS3;
|
|
6983
|
+
}
|
|
6984
|
+
adminRoutes4.use("*", requireAuth());
|
|
6985
|
+
adminRoutes4.use("*", async (c, next) => {
|
|
6986
|
+
const user = c.get("user");
|
|
6987
|
+
if (user?.role !== "admin") {
|
|
6988
|
+
return c.json({ error: "Access denied" }, 403);
|
|
6989
|
+
}
|
|
6990
|
+
return next();
|
|
6991
|
+
});
|
|
6992
|
+
adminRoutes4.get("/", async (c) => {
|
|
6993
|
+
const user = c.get("user");
|
|
6994
|
+
const tenantId = c.get("tenantId") || "default";
|
|
6995
|
+
const keys = await new ApiKeyService(c.env.DB, tenantId).list(user.userId);
|
|
6996
|
+
return c.html(
|
|
6997
|
+
renderApiKeysPage({
|
|
6998
|
+
keys,
|
|
6999
|
+
user: { name: user.email, email: user.email, role: user.role },
|
|
7000
|
+
version: c.get("appVersion"),
|
|
7001
|
+
dynamicMenuItems: c.get("pluginMenuItems")
|
|
7002
|
+
})
|
|
7003
|
+
);
|
|
7004
|
+
});
|
|
7005
|
+
adminRoutes4.get("/api/keys", async (c) => {
|
|
7006
|
+
const user = c.get("user");
|
|
7007
|
+
const tenantId = c.get("tenantId") || "default";
|
|
7008
|
+
const keys = await new ApiKeyService(c.env.DB, tenantId).list(user.userId);
|
|
7009
|
+
return c.json({ keys });
|
|
7010
|
+
});
|
|
7011
|
+
adminRoutes4.post("/api/keys", async (c) => {
|
|
7012
|
+
const user = c.get("user");
|
|
7013
|
+
const tenantId = c.get("tenantId") || "default";
|
|
7014
|
+
const body = await c.req.json().catch(() => ({}));
|
|
7015
|
+
const parsed = createSchema.safeParse(body);
|
|
7016
|
+
if (!parsed.success) {
|
|
7017
|
+
return c.json({ error: "Invalid request", details: parsed.error.flatten() }, 400);
|
|
7018
|
+
}
|
|
7019
|
+
const settings = await getSettings3(c.env.DB);
|
|
7020
|
+
const svc = new ApiKeyService(c.env.DB, tenantId);
|
|
7021
|
+
if (await svc.countForUser(user.userId) >= settings.maxKeysPerUser) {
|
|
7022
|
+
return c.json({ error: `API key limit reached (max ${settings.maxKeysPerUser})` }, 409);
|
|
7023
|
+
}
|
|
7024
|
+
const days = parsed.data.expiresInDays ?? (settings.defaultExpiryDays > 0 ? settings.defaultExpiryDays : null);
|
|
7025
|
+
const expiresAt = days ? Date.now() + days * DAY_MS : null;
|
|
7026
|
+
const created = await svc.create({ userId: user.userId, name: parsed.data.name, expiresAt });
|
|
7027
|
+
return c.json({ apiKey: created }, 201);
|
|
7028
|
+
});
|
|
7029
|
+
adminRoutes4.delete("/api/keys/:id", async (c) => {
|
|
7030
|
+
const user = c.get("user");
|
|
7031
|
+
const tenantId = c.get("tenantId") || "default";
|
|
7032
|
+
const ok = await new ApiKeyService(c.env.DB, tenantId).revoke(c.req.param("id") ?? "", user.userId);
|
|
7033
|
+
if (!ok) return c.json({ error: "API key not found" }, 404);
|
|
7034
|
+
return c.json({ success: true });
|
|
7035
|
+
});
|
|
7036
|
+
|
|
7037
|
+
// src/plugins/core-plugins/api-keys-plugin/middleware/api-key-auth.ts
|
|
7038
|
+
function apiKeyAuthMiddleware() {
|
|
7039
|
+
return async (c, next) => {
|
|
7040
|
+
if (!c.get("user")) {
|
|
7041
|
+
const authz = c.req.header("authorization") || "";
|
|
7042
|
+
const bearer = authz.toLowerCase().startsWith("bearer ") ? authz.slice(7).trim() : "";
|
|
7043
|
+
const presented = c.req.header("x-api-key") || (bearer.startsWith("sk_") ? bearer : "");
|
|
7044
|
+
if (presented) {
|
|
7045
|
+
try {
|
|
7046
|
+
const tenantId = c.get("tenantId") || "default";
|
|
7047
|
+
const resolved = await new ApiKeyService(c.env.DB, tenantId).resolve(presented);
|
|
7048
|
+
if (resolved) {
|
|
7049
|
+
c.set("user", {
|
|
7050
|
+
userId: resolved.userId,
|
|
7051
|
+
email: resolved.email,
|
|
7052
|
+
role: resolved.role,
|
|
7053
|
+
isSuperAdmin: resolved.isSuperAdmin,
|
|
7054
|
+
// API keys are stateless bearer creds — no session window.
|
|
7055
|
+
exp: 0,
|
|
7056
|
+
iat: 0
|
|
7057
|
+
});
|
|
7058
|
+
}
|
|
7059
|
+
} catch {
|
|
7060
|
+
}
|
|
7061
|
+
}
|
|
7062
|
+
}
|
|
7063
|
+
await next();
|
|
7064
|
+
};
|
|
7065
|
+
}
|
|
7066
|
+
|
|
7067
|
+
// src/plugins/core-plugins/api-keys-plugin/index.ts
|
|
7068
|
+
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>`;
|
|
7069
|
+
var apiKeysPlugin = definePlugin({
|
|
7070
|
+
id: "api-keys",
|
|
7071
|
+
version: "1.0.0-beta.1",
|
|
7072
|
+
name: "API Keys",
|
|
7073
|
+
description: "Programmatic API access keys for headless / server-to-server REST access.",
|
|
7074
|
+
sonicjsVersionRange: "^3.0.0",
|
|
7075
|
+
author: { name: "SonicJS Team" },
|
|
7076
|
+
register(app2) {
|
|
7077
|
+
app2.route("/admin/plugins/api-keys", adminRoutes4);
|
|
7078
|
+
},
|
|
7079
|
+
menu: [
|
|
7080
|
+
{ label: "API Keys", path: "/admin/plugins/api-keys", icon: KEY_ICON, order: 86 }
|
|
7081
|
+
],
|
|
7082
|
+
configSchema: {
|
|
7083
|
+
maxKeysPerUser: {
|
|
7084
|
+
type: "number",
|
|
7085
|
+
label: "Max keys per user",
|
|
7086
|
+
description: "Hard cap on active keys a single user may hold.",
|
|
7087
|
+
default: 50
|
|
7088
|
+
},
|
|
7089
|
+
defaultExpiryDays: {
|
|
7090
|
+
type: "number",
|
|
7091
|
+
label: "Default expiry (days)",
|
|
7092
|
+
description: "Lifetime applied to new keys when no explicit expiry is given. 0 = never expires.",
|
|
7093
|
+
default: 0
|
|
7094
|
+
}
|
|
7095
|
+
},
|
|
7096
|
+
activate: async () => console.log("[ApiKeys] Plugin activated"),
|
|
7097
|
+
deactivate: async () => console.log("[ApiKeys] Plugin deactivated")
|
|
7098
|
+
});
|
|
7099
|
+
|
|
6649
7100
|
// src/plugins/core-plugins/stripe-plugin/services/subscription-service.ts
|
|
6650
7101
|
var SubscriptionService = class {
|
|
6651
7102
|
constructor(db) {
|
|
@@ -7373,7 +7824,7 @@ function renderEventPagination(page, totalPages, type, status) {
|
|
|
7373
7824
|
}
|
|
7374
7825
|
|
|
7375
7826
|
// src/plugins/core-plugins/stripe-plugin/types.ts
|
|
7376
|
-
var
|
|
7827
|
+
var DEFAULT_SETTINGS4 = {
|
|
7377
7828
|
stripePublishableKey: "",
|
|
7378
7829
|
stripeSecretKey: "",
|
|
7379
7830
|
stripeWebhookSecret: "",
|
|
@@ -7383,28 +7834,28 @@ var DEFAULT_SETTINGS3 = {
|
|
|
7383
7834
|
};
|
|
7384
7835
|
|
|
7385
7836
|
// src/plugins/core-plugins/stripe-plugin/routes/admin.ts
|
|
7386
|
-
var
|
|
7387
|
-
|
|
7388
|
-
|
|
7837
|
+
var adminRoutes5 = new Hono();
|
|
7838
|
+
adminRoutes5.use("*", requireAuth());
|
|
7839
|
+
adminRoutes5.use("*", async (c, next) => {
|
|
7389
7840
|
const user = c.get("user");
|
|
7390
7841
|
if (user?.role !== "admin") {
|
|
7391
7842
|
return c.text("Access denied", 403);
|
|
7392
7843
|
}
|
|
7393
7844
|
return next();
|
|
7394
7845
|
});
|
|
7395
|
-
async function
|
|
7846
|
+
async function getSettings4(db) {
|
|
7396
7847
|
try {
|
|
7397
7848
|
const pluginService = new PluginService(db);
|
|
7398
7849
|
const plugin2 = await pluginService.getPlugin("stripe");
|
|
7399
7850
|
if (plugin2?.settings) {
|
|
7400
7851
|
const settings = typeof plugin2.settings === "string" ? JSON.parse(plugin2.settings) : plugin2.settings;
|
|
7401
|
-
return { ...
|
|
7852
|
+
return { ...DEFAULT_SETTINGS4, ...settings };
|
|
7402
7853
|
}
|
|
7403
7854
|
} catch {
|
|
7404
7855
|
}
|
|
7405
|
-
return
|
|
7856
|
+
return DEFAULT_SETTINGS4;
|
|
7406
7857
|
}
|
|
7407
|
-
|
|
7858
|
+
adminRoutes5.get("/", async (c) => {
|
|
7408
7859
|
const db = c.env.DB;
|
|
7409
7860
|
const user = c.get("user");
|
|
7410
7861
|
const subscriptionService = new SubscriptionService(db);
|
|
@@ -7427,7 +7878,7 @@ adminRoutes4.get("/", async (c) => {
|
|
|
7427
7878
|
});
|
|
7428
7879
|
return c.html(html4);
|
|
7429
7880
|
});
|
|
7430
|
-
|
|
7881
|
+
adminRoutes5.get("/events", async (c) => {
|
|
7431
7882
|
const db = c.env.DB;
|
|
7432
7883
|
const user = c.get("user");
|
|
7433
7884
|
const eventService = new StripeEventService(db);
|
|
@@ -7453,10 +7904,10 @@ adminRoutes4.get("/events", async (c) => {
|
|
|
7453
7904
|
});
|
|
7454
7905
|
return c.html(html4);
|
|
7455
7906
|
});
|
|
7456
|
-
|
|
7907
|
+
adminRoutes5.get("/settings", async (c) => {
|
|
7457
7908
|
const db = c.env.DB;
|
|
7458
7909
|
const user = c.get("user");
|
|
7459
|
-
const settings = await
|
|
7910
|
+
const settings = await getSettings4(db);
|
|
7460
7911
|
const { renderAdminLayoutCatalyst: renderAdminLayoutCatalyst2 } = await import('./admin-layout-catalyst.template-YQ4EMF2J.js');
|
|
7461
7912
|
const content2 = `
|
|
7462
7913
|
<div>
|
|
@@ -7563,7 +8014,7 @@ adminRoutes4.get("/settings", async (c) => {
|
|
|
7563
8014
|
dynamicMenuItems: c.get("pluginMenuItems")
|
|
7564
8015
|
}));
|
|
7565
8016
|
});
|
|
7566
|
-
|
|
8017
|
+
adminRoutes5.post("/settings", async (c) => {
|
|
7567
8018
|
try {
|
|
7568
8019
|
const body = await c.req.json();
|
|
7569
8020
|
const db = c.env.DB;
|
|
@@ -7714,17 +8165,17 @@ function timingSafeEqual(a, b) {
|
|
|
7714
8165
|
|
|
7715
8166
|
// src/plugins/core-plugins/stripe-plugin/routes/api.ts
|
|
7716
8167
|
var apiRoutes3 = new Hono();
|
|
7717
|
-
async function
|
|
8168
|
+
async function getSettings5(db) {
|
|
7718
8169
|
try {
|
|
7719
8170
|
const pluginService = new PluginService(db);
|
|
7720
8171
|
const plugin2 = await pluginService.getPlugin("stripe");
|
|
7721
8172
|
if (plugin2?.settings) {
|
|
7722
8173
|
const settings = typeof plugin2.settings === "string" ? JSON.parse(plugin2.settings) : plugin2.settings;
|
|
7723
|
-
return { ...
|
|
8174
|
+
return { ...DEFAULT_SETTINGS4, ...settings };
|
|
7724
8175
|
}
|
|
7725
8176
|
} catch {
|
|
7726
8177
|
}
|
|
7727
|
-
return
|
|
8178
|
+
return DEFAULT_SETTINGS4;
|
|
7728
8179
|
}
|
|
7729
8180
|
function mapStripeStatus(status) {
|
|
7730
8181
|
const map = {
|
|
@@ -7741,7 +8192,7 @@ function mapStripeStatus(status) {
|
|
|
7741
8192
|
}
|
|
7742
8193
|
apiRoutes3.post("/webhook", async (c) => {
|
|
7743
8194
|
const db = c.env.DB;
|
|
7744
|
-
const settings = await
|
|
8195
|
+
const settings = await getSettings5(db);
|
|
7745
8196
|
if (!settings.stripeWebhookSecret) {
|
|
7746
8197
|
return c.json({ error: "Webhook secret not configured" }, 500);
|
|
7747
8198
|
}
|
|
@@ -7871,7 +8322,7 @@ apiRoutes3.post("/create-checkout-session", requireAuth(), async (c) => {
|
|
|
7871
8322
|
const db = c.env.DB;
|
|
7872
8323
|
const user = c.get("user");
|
|
7873
8324
|
if (!user) return c.json({ error: "Unauthorized" }, 401);
|
|
7874
|
-
const settings = await
|
|
8325
|
+
const settings = await getSettings5(db);
|
|
7875
8326
|
if (!settings.stripeSecretKey) {
|
|
7876
8327
|
return c.json({ error: "Stripe not configured" }, 500);
|
|
7877
8328
|
}
|
|
@@ -7948,7 +8399,7 @@ apiRoutes3.post("/sync-subscriptions", requireAuth(), async (c) => {
|
|
|
7948
8399
|
const user = c.get("user");
|
|
7949
8400
|
if (user?.role !== "admin") return c.json({ error: "Access denied" }, 403);
|
|
7950
8401
|
const db = c.env.DB;
|
|
7951
|
-
const settings = await
|
|
8402
|
+
const settings = await getSettings5(db);
|
|
7952
8403
|
if (!settings.stripeSecretKey) {
|
|
7953
8404
|
return c.json({ error: "Stripe secret key not configured" }, 400);
|
|
7954
8405
|
}
|
|
@@ -8023,7 +8474,7 @@ var stripePlugin = definePlugin({
|
|
|
8023
8474
|
sonicjsVersionRange: "^3.0.0",
|
|
8024
8475
|
author: { name: "SonicJS Team" },
|
|
8025
8476
|
register(app2) {
|
|
8026
|
-
app2.route("/admin/plugins/stripe",
|
|
8477
|
+
app2.route("/admin/plugins/stripe", adminRoutes5);
|
|
8027
8478
|
app2.route("/api/stripe", apiRoutes3);
|
|
8028
8479
|
},
|
|
8029
8480
|
menu: [
|
|
@@ -11095,7 +11546,16 @@ function pluginMenuMiddleware() {
|
|
|
11095
11546
|
}
|
|
11096
11547
|
} catch {
|
|
11097
11548
|
}
|
|
11098
|
-
|
|
11549
|
+
const user = c.get("user");
|
|
11550
|
+
const singletonItems = resolvePluginMenuItems(user ? { role: user.role } : void 0);
|
|
11551
|
+
const existingPaths = new Set(activeMenuItems.map((i) => i.path));
|
|
11552
|
+
for (const item of singletonItems) {
|
|
11553
|
+
if (!existingPaths.has(item.path)) {
|
|
11554
|
+
activeMenuItems.push({ label: item.label, path: item.path, icon: item.icon, order: item.order });
|
|
11555
|
+
}
|
|
11556
|
+
}
|
|
11557
|
+
activeMenuItems.sort((a, b) => a.order - b.order);
|
|
11558
|
+
c.set("pluginMenuItems", activeMenuItems.map((m) => ({ label: m.label, path: m.path, icon: resolveIcon(m.icon) || m.icon || "" })));
|
|
11099
11559
|
await next();
|
|
11100
11560
|
const finalItems = c.get("pluginMenuItems") ?? [];
|
|
11101
11561
|
if (finalItems.length > 0 && c.res.headers.get("content-type")?.includes("text/html")) {
|
|
@@ -11113,16 +11573,16 @@ function pluginMenuMiddleware() {
|
|
|
11113
11573
|
};
|
|
11114
11574
|
}
|
|
11115
11575
|
init_admin_layout_catalyst_template();
|
|
11116
|
-
var
|
|
11117
|
-
|
|
11118
|
-
|
|
11576
|
+
var adminRoutes6 = new Hono();
|
|
11577
|
+
adminRoutes6.use("*", requireAuth());
|
|
11578
|
+
adminRoutes6.use("*", async (c, next) => {
|
|
11119
11579
|
const user = c.get("user");
|
|
11120
11580
|
if (user?.role !== "admin") {
|
|
11121
11581
|
return c.text("Access denied", 403);
|
|
11122
11582
|
}
|
|
11123
11583
|
return next();
|
|
11124
11584
|
});
|
|
11125
|
-
|
|
11585
|
+
adminRoutes6.get("/", async (c) => {
|
|
11126
11586
|
const user = c.get("user");
|
|
11127
11587
|
const db = c.env.DB;
|
|
11128
11588
|
let totalRequests = 0;
|
|
@@ -11478,7 +11938,7 @@ var analyticsPlugin = definePlugin({
|
|
|
11478
11938
|
author: { name: "SonicJS Team", email: "team@sonicjs.com" },
|
|
11479
11939
|
register(app2) {
|
|
11480
11940
|
app2.route("/api/events", apiRoutes4);
|
|
11481
|
-
app2.route("/admin/analytics",
|
|
11941
|
+
app2.route("/admin/analytics", adminRoutes6);
|
|
11482
11942
|
},
|
|
11483
11943
|
menu: [
|
|
11484
11944
|
{
|
|
@@ -11760,8 +12220,8 @@ apiRoutes5.delete("/:id", async (c) => {
|
|
|
11760
12220
|
return c.json({ success: false, error: "Failed to delete variable" }, 500);
|
|
11761
12221
|
}
|
|
11762
12222
|
});
|
|
11763
|
-
var
|
|
11764
|
-
|
|
12223
|
+
var adminRoutes7 = new Hono();
|
|
12224
|
+
adminRoutes7.use("*", async (c, next) => {
|
|
11765
12225
|
try {
|
|
11766
12226
|
const db = c.env?.DB;
|
|
11767
12227
|
if (db) {
|
|
@@ -11772,7 +12232,7 @@ adminRoutes6.use("*", async (c, next) => {
|
|
|
11772
12232
|
}
|
|
11773
12233
|
await next();
|
|
11774
12234
|
});
|
|
11775
|
-
|
|
12235
|
+
adminRoutes7.get("/", async (c) => {
|
|
11776
12236
|
const db = c.env.DB;
|
|
11777
12237
|
let variables = [];
|
|
11778
12238
|
try {
|
|
@@ -11802,7 +12262,7 @@ adminRoutes6.get("/", async (c) => {
|
|
|
11802
12262
|
}
|
|
11803
12263
|
return c.html(renderAdminPage(variables, { editorActive, activeEditorName, enableEditorIntegration }));
|
|
11804
12264
|
});
|
|
11805
|
-
|
|
12265
|
+
adminRoutes7.put("/:id", async (c) => {
|
|
11806
12266
|
const db = c.env.DB;
|
|
11807
12267
|
const id = c.req.param("id");
|
|
11808
12268
|
let body;
|
|
@@ -11818,7 +12278,7 @@ adminRoutes6.put("/:id", async (c) => {
|
|
|
11818
12278
|
}
|
|
11819
12279
|
return c.html('<span class="text-green-400 text-xs">Saved</span>');
|
|
11820
12280
|
});
|
|
11821
|
-
|
|
12281
|
+
adminRoutes7.post("/:id/toggle", async (c) => {
|
|
11822
12282
|
const db = c.env.DB;
|
|
11823
12283
|
const id = c.req.param("id");
|
|
11824
12284
|
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();
|
|
@@ -11826,7 +12286,7 @@ adminRoutes6.post("/:id/toggle", async (c) => {
|
|
|
11826
12286
|
c.header("HX-Redirect", "/admin/global-variables");
|
|
11827
12287
|
return c.body(null, 204);
|
|
11828
12288
|
});
|
|
11829
|
-
|
|
12289
|
+
adminRoutes7.post("/", async (c) => {
|
|
11830
12290
|
const db = c.env.DB;
|
|
11831
12291
|
const form = await c.req.parseBody();
|
|
11832
12292
|
const key = (form.key || "").trim();
|
|
@@ -11847,7 +12307,7 @@ adminRoutes6.post("/", async (c) => {
|
|
|
11847
12307
|
c.header("HX-Redirect", "/admin/global-variables");
|
|
11848
12308
|
return c.body(null, 204);
|
|
11849
12309
|
});
|
|
11850
|
-
|
|
12310
|
+
adminRoutes7.post("/settings/editor-integration", async (c) => {
|
|
11851
12311
|
const db = c.env.DB;
|
|
11852
12312
|
try {
|
|
11853
12313
|
const row = await db.prepare("SELECT settings FROM plugins WHERE id = 'global-variables'").first();
|
|
@@ -11859,7 +12319,7 @@ adminRoutes6.post("/settings/editor-integration", async (c) => {
|
|
|
11859
12319
|
return c.json({ success: false, error: "Failed to update setting" }, 500);
|
|
11860
12320
|
}
|
|
11861
12321
|
});
|
|
11862
|
-
|
|
12322
|
+
adminRoutes7.delete("/:id", async (c) => {
|
|
11863
12323
|
const db = c.env.DB;
|
|
11864
12324
|
await db.prepare("DELETE FROM global_variables WHERE id = ?").bind(c.req.param("id")).run();
|
|
11865
12325
|
invalidateVariablesCache();
|
|
@@ -12190,7 +12650,7 @@ var globalVariablesPlugin = definePlugin({
|
|
|
12190
12650
|
capabilities: ["hooks.content:subscribe"],
|
|
12191
12651
|
register(app2) {
|
|
12192
12652
|
app2.route("/api/global-variables", apiRoutes5);
|
|
12193
|
-
app2.route("/admin/global-variables",
|
|
12653
|
+
app2.route("/admin/global-variables", adminRoutes7);
|
|
12194
12654
|
},
|
|
12195
12655
|
menu: [
|
|
12196
12656
|
{ label: "Global Variables", path: "/admin/global-variables", icon: "bolt", order: 45, permissions: ["global-variables:view"] }
|
|
@@ -12511,8 +12971,8 @@ apiRoutes6.delete("/:id", async (c) => {
|
|
|
12511
12971
|
return c.json({ success: false, error: "Failed to delete shortcode" }, 500);
|
|
12512
12972
|
}
|
|
12513
12973
|
});
|
|
12514
|
-
var
|
|
12515
|
-
|
|
12974
|
+
var adminRoutes8 = new Hono();
|
|
12975
|
+
adminRoutes8.use("*", async (c, next) => {
|
|
12516
12976
|
try {
|
|
12517
12977
|
const db = c.env?.DB;
|
|
12518
12978
|
if (db) {
|
|
@@ -12523,7 +12983,7 @@ adminRoutes7.use("*", async (c, next) => {
|
|
|
12523
12983
|
}
|
|
12524
12984
|
await next();
|
|
12525
12985
|
});
|
|
12526
|
-
|
|
12986
|
+
adminRoutes8.get("/", async (c) => {
|
|
12527
12987
|
const db = c.env.DB;
|
|
12528
12988
|
let shortcodes = [];
|
|
12529
12989
|
try {
|
|
@@ -12553,7 +13013,7 @@ adminRoutes7.get("/", async (c) => {
|
|
|
12553
13013
|
}
|
|
12554
13014
|
return c.html(renderAdminPage2(shortcodes, { editorActive, activeEditorName, enableEditorIntegration }));
|
|
12555
13015
|
});
|
|
12556
|
-
|
|
13016
|
+
adminRoutes8.post("/", async (c) => {
|
|
12557
13017
|
const db = c.env.DB;
|
|
12558
13018
|
const form = await c.req.parseBody();
|
|
12559
13019
|
const name = (form.name || "").trim();
|
|
@@ -12574,7 +13034,7 @@ adminRoutes7.post("/", async (c) => {
|
|
|
12574
13034
|
c.header("HX-Redirect", "/admin/shortcodes");
|
|
12575
13035
|
return c.body(null, 204);
|
|
12576
13036
|
});
|
|
12577
|
-
|
|
13037
|
+
adminRoutes8.post("/settings/editor-integration", async (c) => {
|
|
12578
13038
|
const db = c.env.DB;
|
|
12579
13039
|
try {
|
|
12580
13040
|
const row = await db.prepare("SELECT settings FROM plugins WHERE id = 'shortcodes'").first();
|
|
@@ -12586,7 +13046,7 @@ adminRoutes7.post("/settings/editor-integration", async (c) => {
|
|
|
12586
13046
|
return c.json({ success: false, error: "Failed to update setting" }, 500);
|
|
12587
13047
|
}
|
|
12588
13048
|
});
|
|
12589
|
-
|
|
13049
|
+
adminRoutes8.delete("/:id", async (c) => {
|
|
12590
13050
|
await c.env.DB.prepare("DELETE FROM shortcodes WHERE id = ?").bind(c.req.param("id")).run();
|
|
12591
13051
|
return c.html("");
|
|
12592
13052
|
});
|
|
@@ -12797,7 +13257,7 @@ var shortcodesPlugin = definePlugin({
|
|
|
12797
13257
|
capabilities: ["hooks.content:subscribe"],
|
|
12798
13258
|
register(app2) {
|
|
12799
13259
|
app2.route("/api/shortcodes", apiRoutes6);
|
|
12800
|
-
app2.route("/admin/shortcodes",
|
|
13260
|
+
app2.route("/admin/shortcodes", adminRoutes8);
|
|
12801
13261
|
},
|
|
12802
13262
|
menu: [
|
|
12803
13263
|
{ label: "Shortcodes", path: "/admin/shortcodes", icon: "bolt", order: 46, permissions: ["shortcodes:view"] }
|
|
@@ -12906,6 +13366,9 @@ var helloWorldPlugin = definePlugin({
|
|
|
12906
13366
|
console.info("\u274C Hello World plugin deactivated");
|
|
12907
13367
|
}
|
|
12908
13368
|
});
|
|
13369
|
+
function createHelloWorldPlugin() {
|
|
13370
|
+
return helloWorldPlugin;
|
|
13371
|
+
}
|
|
12909
13372
|
|
|
12910
13373
|
// src/plugins/core-plugins/multi-tenant-plugin/manifest.json
|
|
12911
13374
|
var manifest_default2 = {
|
|
@@ -16079,6 +16542,7 @@ function createSonicJSApp(config = {}) {
|
|
|
16079
16542
|
const magicLinkPlugin = createMagicLinkAuthPlugin();
|
|
16080
16543
|
const corePluginsBeforeCatchAll = [
|
|
16081
16544
|
securityAuditPlugin,
|
|
16545
|
+
apiKeysPlugin,
|
|
16082
16546
|
aiSearchPlugin,
|
|
16083
16547
|
oauthProvidersPlugin,
|
|
16084
16548
|
userProfilesPlugin,
|
|
@@ -16220,6 +16684,7 @@ function createSonicJSApp(config = {}) {
|
|
|
16220
16684
|
}
|
|
16221
16685
|
await next();
|
|
16222
16686
|
});
|
|
16687
|
+
app2.use("*", apiKeyAuthMiddleware());
|
|
16223
16688
|
if (config.middleware?.afterAuth) {
|
|
16224
16689
|
for (const middleware of config.middleware.afterAuth) {
|
|
16225
16690
|
app2.use("*", middleware);
|
|
@@ -16318,7 +16783,10 @@ function createSonicJSApp(config = {}) {
|
|
|
16318
16783
|
...corePluginsAfterCatchAll,
|
|
16319
16784
|
...config.plugins?.register ?? []
|
|
16320
16785
|
];
|
|
16321
|
-
|
|
16786
|
+
const userPlugins = (config.plugins?.register ?? []).filter(
|
|
16787
|
+
(p) => !PLUGIN_REGISTRY[p.id]
|
|
16788
|
+
);
|
|
16789
|
+
setPluginMenu(userPlugins.flatMap((p) => p.menu ?? []));
|
|
16322
16790
|
setPluginDefinitions(allMountedPlugins);
|
|
16323
16791
|
}
|
|
16324
16792
|
app2.get("/favicon.svg", (c) => {
|
|
@@ -19947,6 +20415,6 @@ function createDb(d1) {
|
|
|
19947
20415
|
// src/index.ts
|
|
19948
20416
|
var VERSION = package_default.version;
|
|
19949
20417
|
|
|
19950
|
-
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 };
|
|
20418
|
+
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 };
|
|
19951
20419
|
//# sourceMappingURL=index.js.map
|
|
19952
20420
|
//# sourceMappingURL=index.js.map
|