@sonicjs-cms/core 2.18.1 → 3.0.0-beta.10
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 +52 -52
- package/dist/admin-documents-form.template-DDSH6ROU.js +6 -0
- package/dist/{admin-layout-catalyst.template-UMTIN66R.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-HFD37TY5.cjs.map → admin-documents-form.template-LSZKGA5J.cjs.map} +1 -1
- package/dist/{filter-bar.template-DlVYMk-T.d.cts → admin-layout-catalyst.template-DrwDUfsE.d.cts} +25 -1
- package/dist/{filter-bar.template-DlVYMk-T.d.ts → 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-KDHKVLXR.cjs.map +1 -0
- package/dist/admin-layout-catalyst.template-YQ4EMF2J.js +7 -0
- package/dist/admin-layout-catalyst.template-YQ4EMF2J.js.map +1 -0
- package/dist/app-Bo0X1OWX.d.ts +1268 -0
- package/dist/app-Do66yCcV.d.cts +1268 -0
- package/dist/cache-DDARE4QE.js +4 -0
- package/dist/cache-DDARE4QE.js.map +1 -0
- package/dist/cache-LVYS4BPL.cjs +33 -0
- package/dist/cache-LVYS4BPL.cjs.map +1 -0
- package/dist/chunk-2CB4KY7I.cjs +771 -0
- package/dist/chunk-2CB4KY7I.cjs.map +1 -0
- package/dist/{chunk-ABB34XUS.cjs → chunk-3KYKEXV7.cjs} +667 -19
- package/dist/chunk-3KYKEXV7.cjs.map +1 -0
- package/dist/chunk-4BTBSXMR.cjs +912 -0
- package/dist/chunk-4BTBSXMR.cjs.map +1 -0
- package/dist/{chunk-55RDMDOP.js → chunk-5V62WT6M.js} +181 -57
- package/dist/chunk-5V62WT6M.js.map +1 -0
- package/dist/{chunk-XXDFQERJ.js → chunk-6OC6MF3C.js} +7192 -9806
- package/dist/chunk-6OC6MF3C.js.map +1 -0
- package/dist/chunk-AI663NBO.js +821 -0
- package/dist/chunk-AI663NBO.js.map +1 -0
- package/dist/chunk-ALDRXTUO.js +273 -0
- package/dist/chunk-ALDRXTUO.js.map +1 -0
- package/dist/{chunk-TFNTM3OA.js → chunk-ATUPB6MN.js} +645 -15
- package/dist/chunk-ATUPB6MN.js.map +1 -0
- package/dist/chunk-BLMTL57B.js +767 -0
- package/dist/chunk-BLMTL57B.js.map +1 -0
- package/dist/{chunk-4ZSNJDLS.cjs → chunk-CRGUD4KC.cjs} +9 -9
- package/dist/chunk-CRGUD4KC.cjs.map +1 -0
- package/dist/chunk-F67UK75A.cjs +158 -0
- package/dist/chunk-F67UK75A.cjs.map +1 -0
- package/dist/chunk-GCDZZNIN.js +192 -0
- package/dist/chunk-GCDZZNIN.js.map +1 -0
- package/dist/chunk-HIKBY7MS.cjs +70 -0
- package/dist/chunk-HIKBY7MS.cjs.map +1 -0
- package/dist/chunk-IDCZBF35.js +1186 -0
- package/dist/chunk-IDCZBF35.js.map +1 -0
- package/dist/chunk-IESEVHXL.js +66 -0
- package/dist/chunk-IESEVHXL.js.map +1 -0
- package/dist/chunk-IGADDMXH.js +387 -0
- package/dist/chunk-IGADDMXH.js.map +1 -0
- package/dist/chunk-IHTXB7AT.cjs +276 -0
- package/dist/chunk-IHTXB7AT.cjs.map +1 -0
- package/dist/chunk-IVPRUGTY.js +242 -0
- package/dist/chunk-IVPRUGTY.js.map +1 -0
- package/dist/{chunk-SQ6FNXU2.cjs → chunk-IXUHXTHW.cjs} +2 -151
- package/dist/chunk-IXUHXTHW.cjs.map +1 -0
- package/dist/chunk-J6JTWD2A.cjs +100 -0
- package/dist/chunk-J6JTWD2A.cjs.map +1 -0
- package/dist/chunk-JEQ7FLOD.cjs +199 -0
- package/dist/chunk-JEQ7FLOD.cjs.map +1 -0
- package/dist/{chunk-ON5ZMSU4.js → chunk-JQISFW6U.js} +3 -3
- package/dist/chunk-JQISFW6U.js.map +1 -0
- package/dist/chunk-K25XHMM3.js +566 -0
- package/dist/chunk-K25XHMM3.js.map +1 -0
- package/dist/{chunk-UYJ6TJHX.cjs → chunk-K623Q6WD.cjs} +181 -56
- package/dist/chunk-K623Q6WD.cjs.map +1 -0
- package/dist/chunk-MUNO67TT.cjs +1219 -0
- package/dist/chunk-MUNO67TT.cjs.map +1 -0
- package/dist/chunk-N32OWET6.cjs +327 -0
- package/dist/chunk-N32OWET6.cjs.map +1 -0
- package/dist/chunk-NUKJ54GA.cjs +245 -0
- package/dist/chunk-NUKJ54GA.cjs.map +1 -0
- package/dist/{chunk-XWIA3HVX.js → chunk-OBA2RYZN.js} +6 -1249
- package/dist/chunk-OBA2RYZN.js.map +1 -0
- package/dist/chunk-PMGOBS6X.cjs +408 -0
- package/dist/chunk-PMGOBS6X.cjs.map +1 -0
- package/dist/{chunk-OHYBNCVL.cjs → chunk-PXNTCCPE.cjs} +10 -1256
- package/dist/chunk-PXNTCCPE.cjs.map +1 -0
- package/dist/chunk-PYVFXCSD.js +1828 -0
- package/dist/chunk-PYVFXCSD.js.map +1 -0
- package/dist/{chunk-MGFRZO24.js → chunk-QZGABF2M.js} +3 -149
- package/dist/chunk-QZGABF2M.js.map +1 -0
- package/dist/{chunk-T3Q5V33G.cjs → chunk-R4ILO3W6.cjs} +876 -829
- package/dist/chunk-R4ILO3W6.cjs.map +1 -0
- package/dist/chunk-RMRJGMDE.js +323 -0
- package/dist/chunk-RMRJGMDE.js.map +1 -0
- package/dist/chunk-RNZFGN4R.js +88 -0
- package/dist/chunk-RNZFGN4R.js.map +1 -0
- package/dist/chunk-RQ6N3FTV.js +900 -0
- package/dist/chunk-RQ6N3FTV.js.map +1 -0
- package/dist/{chunk-SXXTQETM.cjs → chunk-TO6EY4P7.cjs} +8722 -11323
- package/dist/chunk-TO6EY4P7.cjs.map +1 -0
- package/dist/chunk-V464XBYS.js +154 -0
- package/dist/chunk-V464XBYS.js.map +1 -0
- package/dist/chunk-YA3TJ65D.cjs +575 -0
- package/dist/chunk-YA3TJ65D.cjs.map +1 -0
- package/dist/chunk-YP7GW2G5.cjs +866 -0
- package/dist/chunk-YP7GW2G5.cjs.map +1 -0
- package/dist/{collection-config-B4PG-AaF.d.cts → collection-config-JgHOpFCG.d.cts} +30 -2
- package/dist/{collection-config-B4PG-AaF.d.ts → collection-config-JgHOpFCG.d.ts} +30 -2
- package/dist/config-HFXANXCC.js +6 -0
- package/dist/config-HFXANXCC.js.map +1 -0
- package/dist/config-ON6FNMYX.cjs +19 -0
- package/dist/config-ON6FNMYX.cjs.map +1 -0
- package/dist/define-plugin-BzNHc1ZI.d.ts +1321 -0
- package/dist/define-plugin-IWDKYaVm.d.cts +1321 -0
- package/dist/document-projection-TDWRJX3Z.cjs +13 -0
- package/dist/document-projection-TDWRJX3Z.cjs.map +1 -0
- package/dist/document-projection-YYMC6I4U.js +4 -0
- package/dist/document-projection-YYMC6I4U.js.map +1 -0
- package/dist/index.cjs +13737 -4327
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +331 -493
- package/dist/index.d.ts +331 -493
- package/dist/index.js +13456 -4068
- package/dist/index.js.map +1 -1
- package/dist/middleware.cjs +38 -32
- package/dist/middleware.d.cts +69 -7
- package/dist/middleware.d.ts +69 -7
- package/dist/middleware.js +9 -3
- package/dist/migrations-2XHQEGOQ.cjs +13 -0
- package/dist/{migrations-IYNTWDC6.cjs.map → migrations-2XHQEGOQ.cjs.map} +1 -1
- package/dist/migrations-PE3CDVSM.js +4 -0
- package/dist/{migrations-R337UD46.js.map → migrations-PE3CDVSM.js.map} +1 -1
- package/dist/{plugin-bootstrap-DfVerYV4.d.cts → plugin-bootstrap-B8ThJU21.d.cts} +4315 -1661
- package/dist/{plugin-bootstrap-P_ciLp_C.d.ts → plugin-bootstrap-qu8hJgUt.d.ts} +4315 -1661
- package/dist/plugins.cjs +171 -12
- package/dist/plugins.d.cts +36 -2
- package/dist/plugins.d.ts +36 -2
- package/dist/plugins.js +5 -2
- package/dist/rbac-O73MFKDA.js +5 -0
- package/dist/rbac-O73MFKDA.js.map +1 -0
- package/dist/rbac-VONLJJKB.cjs +14 -0
- package/dist/rbac-VONLJJKB.cjs.map +1 -0
- package/dist/routes.cjs +42 -46
- package/dist/routes.d.cts +56 -146
- package/dist/routes.d.ts +56 -146
- package/dist/routes.js +18 -10
- package/dist/services.cjs +43 -76
- package/dist/services.d.cts +93 -55
- package/dist/services.d.ts +93 -55
- package/dist/services.js +6 -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 -29
- package/dist/templates.d.cts +2 -89
- package/dist/templates.d.ts +2 -89
- package/dist/templates.js +3 -3
- package/dist/types-Dea1eNxU.d.cts +286 -0
- package/dist/types-Dea1eNxU.d.ts +286 -0
- package/dist/types.d.cts +2 -2
- package/dist/types.d.ts +2 -2
- package/dist/utils.cjs +21 -20
- package/dist/utils.d.cts +2 -2
- package/dist/utils.d.ts +2 -2
- package/dist/utils.js +3 -2
- package/migrations/0001_core.sql +184 -0
- package/migrations/0002_documents.sql +163 -0
- package/package.json +12 -7
- package/dist/admin-layout-catalyst.template-HFD37TY5.cjs +0 -17
- package/dist/admin-layout-catalyst.template-UMTIN66R.js +0 -7
- package/dist/app-C9esKLmh.d.cts +0 -112
- package/dist/app-C9esKLmh.d.ts +0 -112
- package/dist/chunk-4R3NOOL3.js +0 -2217
- package/dist/chunk-4R3NOOL3.js.map +0 -1
- package/dist/chunk-4ZSNJDLS.cjs.map +0 -1
- package/dist/chunk-55RDMDOP.js.map +0 -1
- package/dist/chunk-635JAMSE.cjs +0 -653
- package/dist/chunk-635JAMSE.cjs.map +0 -1
- package/dist/chunk-ABB34XUS.cjs.map +0 -1
- package/dist/chunk-C54YUA23.cjs +0 -2219
- package/dist/chunk-C54YUA23.cjs.map +0 -1
- package/dist/chunk-DSUJ5YQH.cjs +0 -722
- package/dist/chunk-DSUJ5YQH.cjs.map +0 -1
- package/dist/chunk-EW5NOBVU.js +0 -1783
- package/dist/chunk-EW5NOBVU.js.map +0 -1
- package/dist/chunk-EXNEW5US.js +0 -648
- package/dist/chunk-EXNEW5US.js.map +0 -1
- package/dist/chunk-I2H5NGJQ.js +0 -692
- package/dist/chunk-I2H5NGJQ.js.map +0 -1
- package/dist/chunk-MGFRZO24.js.map +0 -1
- package/dist/chunk-OHYBNCVL.cjs.map +0 -1
- package/dist/chunk-ON5ZMSU4.js.map +0 -1
- package/dist/chunk-QFWHAFEO.js +0 -1843
- package/dist/chunk-QFWHAFEO.js.map +0 -1
- package/dist/chunk-SQ6FNXU2.cjs.map +0 -1
- package/dist/chunk-SXXTQETM.cjs.map +0 -1
- package/dist/chunk-T3Q5V33G.cjs.map +0 -1
- package/dist/chunk-TFNTM3OA.js.map +0 -1
- package/dist/chunk-UYJ6TJHX.cjs.map +0 -1
- package/dist/chunk-WAEQXGCX.cjs +0 -1898
- package/dist/chunk-WAEQXGCX.cjs.map +0 -1
- package/dist/chunk-XWIA3HVX.js.map +0 -1
- package/dist/chunk-XXDFQERJ.js.map +0 -1
- package/dist/migrations-IYNTWDC6.cjs +0 -13
- package/dist/migrations-R337UD46.js +0 -4
- package/dist/plugin-manager-BoM3Q7o7.d.cts +0 -328
- package/dist/plugin-manager-Efx9RyDX.d.ts +0 -328
- package/migrations/001_initial_schema.sql +0 -170
- package/migrations/002_faq_plugin.sql +0 -86
- package/migrations/003_stage5_enhancements.sql +0 -121
- package/migrations/004_stage6_user_management.sql +0 -183
- package/migrations/005_stage7_workflow_automation.sql +0 -294
- package/migrations/006_plugin_system.sql +0 -155
- package/migrations/007_demo_login_plugin.sql +0 -23
- package/migrations/008_fix_slug_validation.sql +0 -22
- package/migrations/009_system_logging.sql +0 -57
- package/migrations/011_config_managed_collections.sql +0 -15
- package/migrations/012_testimonials_plugin.sql +0 -80
- package/migrations/013_code_examples_plugin.sql +0 -177
- package/migrations/014_fix_plugin_registry.sql +0 -88
- package/migrations/015_add_remaining_plugins.sql +0 -89
- package/migrations/016_remove_duplicate_cache_plugin.sql +0 -17
- package/migrations/017_auth_configurable_fields.sql +0 -49
- package/migrations/018_settings_table.sql +0 -23
- package/migrations/019_remove_blog_posts_collection.sql +0 -15
- package/migrations/020_add_email_plugin.sql +0 -22
- package/migrations/021_add_magic_link_auth_plugin.sql +0 -42
- package/migrations/022_add_tinymce_plugin.sql +0 -25
- package/migrations/023_add_easy_mdx_plugin.sql +0 -25
- package/migrations/024_add_quill_editor_plugin.sql +0 -25
- package/migrations/025_add_easymde_plugin.sql +0 -25
- package/migrations/026_add_otp_login.sql +0 -42
- package/migrations/027_fix_slug_field_type.sql +0 -18
- package/migrations/028_fix_slug_field_type_in_schemas.sql +0 -30
- package/migrations/029_add_forms_system.sql +0 -184
- package/migrations/030_add_turnstile_to_forms.sql +0 -14
- package/migrations/031_ai_search_plugin.sql +0 -45
- package/migrations/032_user_profiles.sql +0 -37
- package/migrations/033_form_content_integration.sql +0 -19
- package/migrations/034_security_audit_plugin.sql +0 -27
- package/migrations/035_user_profiles_data_column.sql +0 -16
- package/migrations/036_analytics_events.sql +0 -22
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { definePlugin, HOOK_CAPABILITY_MAP, SonicCapabilityError, setPluginDefinitions } from './chunk-IGADDMXH.js';
|
|
2
|
+
import { isKnownHookEvent } from './chunk-RNZFGN4R.js';
|
|
3
|
+
import { getCoreVersion } from './chunk-V464XBYS.js';
|
|
2
4
|
import { HOOKS } from './chunk-QXOZI5Q2.js';
|
|
3
5
|
import { __commonJS, __toESM } from './chunk-V4OQ3NZ2.js';
|
|
4
6
|
import { z } from 'zod';
|
|
@@ -2240,7 +2242,7 @@ var PluginValidator = class _PluginValidator {
|
|
|
2240
2242
|
"auth",
|
|
2241
2243
|
"content",
|
|
2242
2244
|
"media",
|
|
2243
|
-
"
|
|
2245
|
+
"auth_user",
|
|
2244
2246
|
"collections"
|
|
2245
2247
|
];
|
|
2246
2248
|
static RESERVED_PATHS = [
|
|
@@ -2292,7 +2294,7 @@ var PluginValidator = class _PluginValidator {
|
|
|
2292
2294
|
if (!/^[a-z][a-z0-9_]*$/.test(model.tableName)) {
|
|
2293
2295
|
errors.push(`Invalid table name format: ${model.tableName}`);
|
|
2294
2296
|
}
|
|
2295
|
-
const systemTables = ["
|
|
2297
|
+
const systemTables = ["auth_user", "collections", "content", "content_versions", "media", "auth_api_tokens"];
|
|
2296
2298
|
if (systemTables.includes(model.tableName)) {
|
|
2297
2299
|
errors.push(`Table name "${model.tableName}" conflicts with system table`);
|
|
2298
2300
|
}
|
|
@@ -3082,6 +3084,638 @@ var PluginManager = class {
|
|
|
3082
3084
|
}
|
|
3083
3085
|
};
|
|
3084
3086
|
|
|
3087
|
+
// src/plugins/topo-sort.ts
|
|
3088
|
+
var PluginDependencyCycleError = class extends Error {
|
|
3089
|
+
cycle;
|
|
3090
|
+
constructor(pluginId2, visitStack) {
|
|
3091
|
+
const idx = visitStack.indexOf(pluginId2);
|
|
3092
|
+
const cycle = idx >= 0 ? [...visitStack.slice(idx), pluginId2] : [...visitStack, pluginId2];
|
|
3093
|
+
super(`Plugin dependency cycle detected: ${cycle.join(" \u2192 ")}`);
|
|
3094
|
+
this.name = "PluginDependencyCycleError";
|
|
3095
|
+
this.cycle = cycle;
|
|
3096
|
+
}
|
|
3097
|
+
};
|
|
3098
|
+
function topoSort(plugins, options = {}) {
|
|
3099
|
+
const byId = /* @__PURE__ */ new Map();
|
|
3100
|
+
for (const p of plugins) {
|
|
3101
|
+
const id = pluginId(p);
|
|
3102
|
+
if (id) byId.set(id, p);
|
|
3103
|
+
}
|
|
3104
|
+
const result = [];
|
|
3105
|
+
const visited = /* @__PURE__ */ new Set();
|
|
3106
|
+
const visiting = /* @__PURE__ */ new Set();
|
|
3107
|
+
function visit(p) {
|
|
3108
|
+
const id = pluginId(p) ?? Math.random().toString();
|
|
3109
|
+
if (visited.has(id)) return;
|
|
3110
|
+
if (visiting.has(id)) throw new PluginDependencyCycleError(id, [...visiting]);
|
|
3111
|
+
visiting.add(id);
|
|
3112
|
+
for (const dep of p.dependencies ?? []) {
|
|
3113
|
+
const depPlugin = byId.get(dep);
|
|
3114
|
+
if (!depPlugin) {
|
|
3115
|
+
if (options.strict) {
|
|
3116
|
+
throw new Error(
|
|
3117
|
+
`Plugin "${id}" depends on "${dep}" which is not in the plugin list.`
|
|
3118
|
+
);
|
|
3119
|
+
} else {
|
|
3120
|
+
console.warn(
|
|
3121
|
+
`[plugins] Plugin "${id}" declares dependency "${dep}" which is not registered. The dependency will be skipped \u2014 boot order may be incorrect.`
|
|
3122
|
+
);
|
|
3123
|
+
}
|
|
3124
|
+
continue;
|
|
3125
|
+
}
|
|
3126
|
+
visit(depPlugin);
|
|
3127
|
+
}
|
|
3128
|
+
visiting.delete(id);
|
|
3129
|
+
visited.add(id);
|
|
3130
|
+
result.push(p);
|
|
3131
|
+
}
|
|
3132
|
+
for (const p of plugins) visit(p);
|
|
3133
|
+
return result;
|
|
3134
|
+
}
|
|
3135
|
+
function pluginId(p) {
|
|
3136
|
+
return p.id ?? p.name ?? void 0;
|
|
3137
|
+
}
|
|
3138
|
+
|
|
3139
|
+
// src/plugins/mount.ts
|
|
3140
|
+
var PluginRegisterMustBeSyncError = class extends Error {
|
|
3141
|
+
constructor(pluginName) {
|
|
3142
|
+
super(
|
|
3143
|
+
`Plugin "${pluginName}" register() returned a Promise. register() must be synchronous because Hono's router locks after the first request. Move async work (hook subscriptions, services, crons) to onBoot()/lifecycle hooks.`
|
|
3144
|
+
);
|
|
3145
|
+
this.name = "PluginRegisterMustBeSyncError";
|
|
3146
|
+
}
|
|
3147
|
+
};
|
|
3148
|
+
function sortRoutesByPriority(routes) {
|
|
3149
|
+
return routes.map((route, index) => ({ route, index })).sort((a, b) => {
|
|
3150
|
+
const pa = a.route.priority ?? 0;
|
|
3151
|
+
const pb = b.route.priority ?? 0;
|
|
3152
|
+
if (pb !== pa) return pb - pa;
|
|
3153
|
+
return a.index - b.index;
|
|
3154
|
+
}).map((entry) => entry.route);
|
|
3155
|
+
}
|
|
3156
|
+
function mountPlugin(app, plugin, result) {
|
|
3157
|
+
if (!plugin || typeof plugin !== "object" || !plugin.name) {
|
|
3158
|
+
result?.skipped.push({ plugin: String(plugin?.name ?? "unknown"), reason: "not a valid plugin object" });
|
|
3159
|
+
return;
|
|
3160
|
+
}
|
|
3161
|
+
if (Array.isArray(plugin.routes) && plugin.routes.length > 0) {
|
|
3162
|
+
for (const route of sortRoutesByPriority(plugin.routes)) {
|
|
3163
|
+
if (!route || !route.path || !route.handler) {
|
|
3164
|
+
result?.skipped.push({ plugin: plugin.name, reason: `invalid route entry (missing path or handler)` });
|
|
3165
|
+
continue;
|
|
3166
|
+
}
|
|
3167
|
+
app.route(route.path, route.handler);
|
|
3168
|
+
result?.mounted.push({ plugin: plugin.name, path: route.path });
|
|
3169
|
+
}
|
|
3170
|
+
}
|
|
3171
|
+
if (typeof plugin.register === "function") {
|
|
3172
|
+
const maybePromise = plugin.register(app);
|
|
3173
|
+
if (maybePromise && typeof maybePromise.then === "function") {
|
|
3174
|
+
throw new PluginRegisterMustBeSyncError(plugin.name);
|
|
3175
|
+
}
|
|
3176
|
+
}
|
|
3177
|
+
}
|
|
3178
|
+
function registerPluginRoutes(app, plugins, options = {}) {
|
|
3179
|
+
const result = { mounted: [], skipped: [] };
|
|
3180
|
+
const warnOnDuplicatePath = options.warnOnDuplicatePath ?? (typeof process === "undefined" || process.env?.NODE_ENV !== "production");
|
|
3181
|
+
const seenPaths = /* @__PURE__ */ new Map();
|
|
3182
|
+
const sortByDependencies = options.sortByDependencies ?? true;
|
|
3183
|
+
const sorted = sortByDependencies ? topoSort(plugins.filter((p) => !!p && typeof p === "object"), {
|
|
3184
|
+
strict: options.strict
|
|
3185
|
+
}) : plugins.filter((p) => !!p && typeof p === "object");
|
|
3186
|
+
for (const plugin of sorted) {
|
|
3187
|
+
if (!plugin) continue;
|
|
3188
|
+
const before = result.mounted.length;
|
|
3189
|
+
mountPlugin(app, plugin, result);
|
|
3190
|
+
if (warnOnDuplicatePath) {
|
|
3191
|
+
for (let i = before; i < result.mounted.length; i++) {
|
|
3192
|
+
const entry = result.mounted[i];
|
|
3193
|
+
if (!entry) continue;
|
|
3194
|
+
const { plugin: owner, path } = entry;
|
|
3195
|
+
const prior = seenPaths.get(path);
|
|
3196
|
+
if (prior && prior !== owner) {
|
|
3197
|
+
console.warn(
|
|
3198
|
+
`[plugins] Duplicate route path "${path}" mounted by "${owner}" \u2014 already claimed by "${prior}". The first registration wins; the later one is shadowed.`
|
|
3199
|
+
);
|
|
3200
|
+
} else if (!prior) {
|
|
3201
|
+
seenPaths.set(path, owner);
|
|
3202
|
+
}
|
|
3203
|
+
}
|
|
3204
|
+
}
|
|
3205
|
+
}
|
|
3206
|
+
return result;
|
|
3207
|
+
}
|
|
3208
|
+
|
|
3209
|
+
// src/plugins/wire.ts
|
|
3210
|
+
async function wireRegisteredPlugins(plugins, context, options = {}) {
|
|
3211
|
+
const result = { subscribed: 0, booted: [], errors: [] };
|
|
3212
|
+
const sortByDeps = options.sortByDependencies ?? true;
|
|
3213
|
+
const raw = plugins.filter((p) => !!p && typeof p === "object");
|
|
3214
|
+
const valid = sortByDeps ? topoSort(raw, { strict: options.strict }) : raw;
|
|
3215
|
+
for (const plugin of valid) {
|
|
3216
|
+
const name = plugin.name ?? "unknown";
|
|
3217
|
+
if (!Array.isArray(plugin.hooks) || plugin.hooks.length === 0) continue;
|
|
3218
|
+
for (const hook of plugin.hooks) {
|
|
3219
|
+
if (!hook || typeof hook.name !== "string" || typeof hook.handler !== "function") {
|
|
3220
|
+
result.errors.push({ plugin: name, phase: "subscribe", error: new Error("invalid hook entry") });
|
|
3221
|
+
continue;
|
|
3222
|
+
}
|
|
3223
|
+
if (plugin.capabilities !== void 0 && isKnownHookEvent(hook.name)) {
|
|
3224
|
+
const requiredCap = HOOK_CAPABILITY_MAP[hook.name];
|
|
3225
|
+
if (requiredCap && !plugin.capabilities.includes(requiredCap)) {
|
|
3226
|
+
const capErr = new SonicCapabilityError(requiredCap, name);
|
|
3227
|
+
if (options.strict) {
|
|
3228
|
+
result.errors.push({ plugin: name, phase: "subscribe", error: capErr });
|
|
3229
|
+
} else {
|
|
3230
|
+
console.warn(`[plugins] ${capErr.message} Hook "${hook.name}" will not be registered.`);
|
|
3231
|
+
}
|
|
3232
|
+
continue;
|
|
3233
|
+
}
|
|
3234
|
+
}
|
|
3235
|
+
try {
|
|
3236
|
+
context.hooks.register(hook.name, hook.handler, hook.priority);
|
|
3237
|
+
result.subscribed++;
|
|
3238
|
+
} catch (error) {
|
|
3239
|
+
result.errors.push({ plugin: name, phase: "subscribe", error });
|
|
3240
|
+
}
|
|
3241
|
+
}
|
|
3242
|
+
}
|
|
3243
|
+
for (const plugin of valid) {
|
|
3244
|
+
const name = plugin.name ?? "unknown";
|
|
3245
|
+
if (typeof plugin.onBoot !== "function") continue;
|
|
3246
|
+
try {
|
|
3247
|
+
await plugin.onBoot(context);
|
|
3248
|
+
result.booted.push(name);
|
|
3249
|
+
} catch (error) {
|
|
3250
|
+
result.errors.push({ plugin: name, phase: "onBoot", error });
|
|
3251
|
+
}
|
|
3252
|
+
}
|
|
3253
|
+
if (context.env?.DB) {
|
|
3254
|
+
reflectWiredPlugins(valid, context.env.DB).catch((err) => {
|
|
3255
|
+
console.warn("[plugins] DB reflection failed (non-fatal):", err);
|
|
3256
|
+
});
|
|
3257
|
+
}
|
|
3258
|
+
return result;
|
|
3259
|
+
}
|
|
3260
|
+
async function reflectWiredPlugins(plugins, db) {
|
|
3261
|
+
const now = Date.now();
|
|
3262
|
+
for (const plugin of plugins) {
|
|
3263
|
+
const id = plugin.id ?? plugin.name;
|
|
3264
|
+
if (!id) continue;
|
|
3265
|
+
const displayName = plugin.name ?? id;
|
|
3266
|
+
const version = plugin.version ?? "0.0.0";
|
|
3267
|
+
const description = plugin.description ?? "";
|
|
3268
|
+
const initialStatus = plugin.defaultActive ? "active" : "inactive";
|
|
3269
|
+
try {
|
|
3270
|
+
await db.prepare(
|
|
3271
|
+
`INSERT INTO plugins (id, name, display_name, description, version, author, category,
|
|
3272
|
+
status, is_core, installed_at, last_updated)
|
|
3273
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?)
|
|
3274
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
3275
|
+
version = excluded.version,
|
|
3276
|
+
display_name = excluded.display_name,
|
|
3277
|
+
last_updated = excluded.last_updated`
|
|
3278
|
+
).bind(id, id, displayName, description, version, "core", "core", initialStatus, now, now).run();
|
|
3279
|
+
} catch {
|
|
3280
|
+
}
|
|
3281
|
+
}
|
|
3282
|
+
}
|
|
3283
|
+
function createPluginWirer(plugins, ctxFactory) {
|
|
3284
|
+
let started;
|
|
3285
|
+
return () => {
|
|
3286
|
+
if (!started) {
|
|
3287
|
+
const list = typeof plugins === "function" ? plugins() : plugins;
|
|
3288
|
+
started = wireRegisteredPlugins(list, ctxFactory());
|
|
3289
|
+
}
|
|
3290
|
+
return started;
|
|
3291
|
+
};
|
|
3292
|
+
}
|
|
3293
|
+
|
|
3294
|
+
// src/plugins/sdk/register-plugins.ts
|
|
3295
|
+
var import_semver2 = __toESM(require_semver2(), 1);
|
|
3296
|
+
|
|
3297
|
+
// src/services/plugin-menu-singleton.ts
|
|
3298
|
+
var PUZZLE_PIECE = `<svg class="h-5 w-5" fill="currentColor" viewBox="0 0 20 20"><path d="M14.5 2A1.5 1.5 0 0013 3.5V4H8.5A1.5 1.5 0 007 5.5V10h-.5a1.5 1.5 0 100 3H7v4.5A1.5 1.5 0 008.5 19H13v-.5a1.5 1.5 0 113 0V19h.5a1.5 1.5 0 001.5-1.5V13h-.5a1.5 1.5 0 110-3h.5V5.5A1.5 1.5 0 0017 4h-.5v-.5A1.5 1.5 0 0014.5 2z"/></svg>`;
|
|
3299
|
+
var MENU_ICON_MAP = {
|
|
3300
|
+
"puzzle-piece": PUZZLE_PIECE,
|
|
3301
|
+
envelope: `<svg class="h-5 w-5" fill="currentColor" viewBox="0 0 20 20"><path d="M2.003 5.884L10 9.882l7.997-3.998A2 2 0 0016 4H4a2 2 0 00-1.997 1.884z"/><path d="M18 8.118l-8 4-8-4V14a2 2 0 002 2h12a2 2 0 002-2V8.118z"/></svg>`,
|
|
3302
|
+
cog: `<svg class="h-5 w-5" fill="currentColor" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M11.49 3.17c-.38-1.56-2.6-1.56-2.98 0a1.532 1.532 0 01-2.286.948c-1.372-.836-2.942.734-2.106 2.106.54.886.061 2.042-.947 2.287-1.561.379-1.561 2.6 0 2.978a1.532 1.532 0 01.947 2.287c-.836 1.372.734 2.942 2.106 2.106a1.532 1.532 0 012.287.947c.379 1.561 2.6 1.561 2.978 0a1.533 1.533 0 012.287-.947c1.372.836 2.942-.734 2.106-2.106a1.533 1.533 0 01.947-2.287c1.561-.379 1.561-2.6 0-2.978a1.532 1.532 0 01-.947-2.287c.836-1.372-.734-2.942-2.106-2.106a1.532 1.532 0 01-2.287-.947zM10 13a3 3 0 100-6 3 3 0 000 6z" clip-rule="evenodd"/></svg>`,
|
|
3303
|
+
chart: `<svg class="h-5 w-5" fill="currentColor" viewBox="0 0 20 20"><path d="M2 11a1 1 0 011-1h2a1 1 0 011 1v5a1 1 0 01-1 1H3a1 1 0 01-1-1v-5zM8 7a1 1 0 011-1h2a1 1 0 011 1v9a1 1 0 01-1 1H9a1 1 0 01-1-1V7zM14 4a1 1 0 011-1h2a1 1 0 011 1v12a1 1 0 01-1 1h-2a1 1 0 01-1-1V4z"/></svg>`,
|
|
3304
|
+
sparkles: `<svg class="h-5 w-5" fill="currentColor" viewBox="0 0 20 20"><path d="M9 4.804A7.968 7.968 0 005.5 4c-1.255 0-2.443.29-3.5.804v10A7.969 7.969 0 015.5 14c1.669 0 3.218.51 4.5 1.385A7.962 7.962 0 0114.5 14c1.255 0 2.443.29 3.5.804v-10A7.968 7.968 0 0014.5 4c-1.255 0-2.443.29-3.5.804V12a1 1 0 11-2 0V4.804z"/></svg>`,
|
|
3305
|
+
bolt: `<svg class="h-5 w-5" fill="currentColor" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M11.3 1.046A1 1 0 0112 2v5h4a1 1 0 01.82 1.573l-7 10A1 1 0 018 18v-5H4a1 1 0 01-.82-1.573l7-10a1 1 0 011.12-.38z" clip-rule="evenodd"/></svg>`,
|
|
3306
|
+
document: `<svg class="h-5 w-5" fill="currentColor" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M4 4a2 2 0 012-2h8a2 2 0 012 2v12a2 2 0 01-2 2H6a2 2 0 01-2-2V4zm3 1h6v2H7V5zm0 4h6v2H7V9zm0 4h4v2H7v-2z" clip-rule="evenodd"/></svg>`,
|
|
3307
|
+
lock: `<svg class="h-5 w-5" fill="currentColor" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z" clip-rule="evenodd"/></svg>`,
|
|
3308
|
+
photo: `<svg class="h-5 w-5" fill="currentColor" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M4 3a2 2 0 00-2 2v10a2 2 0 002 2h12a2 2 0 002-2V5a2 2 0 00-2-2H4zm12 12H4l4-8 3 6 2-4 3 6z" clip-rule="evenodd"/></svg>`
|
|
3309
|
+
};
|
|
3310
|
+
function resolveIcon(name) {
|
|
3311
|
+
if (!name) return PUZZLE_PIECE;
|
|
3312
|
+
if (name.startsWith("<svg")) return name;
|
|
3313
|
+
return MENU_ICON_MAP[name] ?? PUZZLE_PIECE;
|
|
3314
|
+
}
|
|
3315
|
+
var menuItems = [];
|
|
3316
|
+
function setPluginMenu(items) {
|
|
3317
|
+
menuItems = [...items];
|
|
3318
|
+
}
|
|
3319
|
+
function getPluginMenu() {
|
|
3320
|
+
return menuItems;
|
|
3321
|
+
}
|
|
3322
|
+
function resetPluginMenu() {
|
|
3323
|
+
menuItems = [];
|
|
3324
|
+
}
|
|
3325
|
+
function resolvePluginMenuItems(user) {
|
|
3326
|
+
const isAdmin = user?.role === "admin";
|
|
3327
|
+
const userPerms = new Set(user?.permissions ?? []);
|
|
3328
|
+
return menuItems.filter((m) => {
|
|
3329
|
+
if (!m.permissions || m.permissions.length === 0) return true;
|
|
3330
|
+
if (isAdmin) return true;
|
|
3331
|
+
return m.permissions.some((p) => userPerms.has(p));
|
|
3332
|
+
}).slice().sort((a, b) => (a.order ?? 100) - (b.order ?? 100)).map((m) => ({
|
|
3333
|
+
label: m.label,
|
|
3334
|
+
path: m.path,
|
|
3335
|
+
icon: resolveIcon(m.icon),
|
|
3336
|
+
order: m.order ?? 100
|
|
3337
|
+
}));
|
|
3338
|
+
}
|
|
3339
|
+
|
|
3340
|
+
// src/plugins/cron.ts
|
|
3341
|
+
function collectCrons(plugins) {
|
|
3342
|
+
const out = [];
|
|
3343
|
+
for (const plugin of plugins) {
|
|
3344
|
+
if (!plugin || !Array.isArray(plugin.crons)) continue;
|
|
3345
|
+
const name = plugin.name ?? "unknown";
|
|
3346
|
+
for (const cron of plugin.crons) {
|
|
3347
|
+
if (cron && typeof cron.schedule === "string" && typeof cron.hookFamily === "string") {
|
|
3348
|
+
out.push({ plugin: name, schedule: cron.schedule, hookFamily: cron.hookFamily });
|
|
3349
|
+
}
|
|
3350
|
+
}
|
|
3351
|
+
}
|
|
3352
|
+
return out;
|
|
3353
|
+
}
|
|
3354
|
+
function collectCronSchedules(plugins) {
|
|
3355
|
+
return [...new Set(collectCrons(plugins).map((c) => c.schedule))];
|
|
3356
|
+
}
|
|
3357
|
+
async function dispatchCronTick(plugins, cron, scheduledTime, context) {
|
|
3358
|
+
const result = { invoked: [], errors: [], unmatched: true };
|
|
3359
|
+
for (const plugin of plugins) {
|
|
3360
|
+
if (!plugin || typeof plugin.onCronTick !== "function" || !Array.isArray(plugin.crons)) continue;
|
|
3361
|
+
const name = plugin.name ?? "unknown";
|
|
3362
|
+
const matches = plugin.crons.filter((c) => c && c.schedule === cron);
|
|
3363
|
+
for (const match of matches) {
|
|
3364
|
+
result.unmatched = false;
|
|
3365
|
+
const event = { cron, scheduledTime, hookFamily: match.hookFamily };
|
|
3366
|
+
try {
|
|
3367
|
+
await plugin.onCronTick(event, context);
|
|
3368
|
+
result.invoked.push({ plugin: name, hookFamily: match.hookFamily });
|
|
3369
|
+
} catch (error) {
|
|
3370
|
+
result.errors.push({ plugin: name, hookFamily: match.hookFamily, error });
|
|
3371
|
+
}
|
|
3372
|
+
}
|
|
3373
|
+
}
|
|
3374
|
+
return result;
|
|
3375
|
+
}
|
|
3376
|
+
function createScheduledHandler(options) {
|
|
3377
|
+
return async (controller, env, ctx) => {
|
|
3378
|
+
if (options.disabled) {
|
|
3379
|
+
return { invoked: [], errors: [], unmatched: true };
|
|
3380
|
+
}
|
|
3381
|
+
if (options.boot) {
|
|
3382
|
+
try {
|
|
3383
|
+
await options.boot(env);
|
|
3384
|
+
} catch (err) {
|
|
3385
|
+
console.error("[cron] boot failed:", err);
|
|
3386
|
+
}
|
|
3387
|
+
}
|
|
3388
|
+
const plugins = typeof options.plugins === "function" ? options.plugins() : options.plugins;
|
|
3389
|
+
const work = dispatchCronTick(plugins, controller.cron, controller.scheduledTime, {
|
|
3390
|
+
hooks: options.getHooks(),
|
|
3391
|
+
env
|
|
3392
|
+
});
|
|
3393
|
+
ctx?.waitUntil?.(work.catch(() => {
|
|
3394
|
+
}));
|
|
3395
|
+
return work;
|
|
3396
|
+
};
|
|
3397
|
+
}
|
|
3398
|
+
|
|
3399
|
+
// src/plugins/sdk/register-plugins.ts
|
|
3400
|
+
var RegisterPluginsError = class extends Error {
|
|
3401
|
+
constructor(reason, details) {
|
|
3402
|
+
super(`registerPlugins(${reason}): ${JSON.stringify(details)}`);
|
|
3403
|
+
this.reason = reason;
|
|
3404
|
+
this.details = details;
|
|
3405
|
+
this.name = "RegisterPluginsError";
|
|
3406
|
+
}
|
|
3407
|
+
};
|
|
3408
|
+
function registerPlugins(app, plugins, host) {
|
|
3409
|
+
const list = plugins.filter((p) => !!p && typeof p === "object");
|
|
3410
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3411
|
+
for (const p of list) {
|
|
3412
|
+
if (!p.id || typeof p.id !== "string")
|
|
3413
|
+
throw new RegisterPluginsError("invalid_id", { plugin: p });
|
|
3414
|
+
if (!import_semver2.default.valid(p.version))
|
|
3415
|
+
throw new RegisterPluginsError("invalid_semver", { id: p.id, version: p.version });
|
|
3416
|
+
if (seen.has(p.id))
|
|
3417
|
+
throw new RegisterPluginsError("duplicate_id", { id: p.id });
|
|
3418
|
+
seen.add(p.id);
|
|
3419
|
+
if (p.sonicjsVersionRange) {
|
|
3420
|
+
try {
|
|
3421
|
+
if (!import_semver2.default.satisfies(getCoreVersion(), p.sonicjsVersionRange)) {
|
|
3422
|
+
console.warn(
|
|
3423
|
+
`[plugins] ${p.id} declares sonicjsVersionRange "${p.sonicjsVersionRange}" but core is "${getCoreVersion()}". Plugin may not work correctly.`
|
|
3424
|
+
);
|
|
3425
|
+
}
|
|
3426
|
+
} catch {
|
|
3427
|
+
}
|
|
3428
|
+
}
|
|
3429
|
+
}
|
|
3430
|
+
let mountResult;
|
|
3431
|
+
try {
|
|
3432
|
+
mountResult = registerPluginRoutes(app, list, {
|
|
3433
|
+
source: host.source,
|
|
3434
|
+
strict: host.strict,
|
|
3435
|
+
...host.mountOptions
|
|
3436
|
+
});
|
|
3437
|
+
} catch (err) {
|
|
3438
|
+
const pluginId2 = err && typeof err === "object" && "message" in err ? String(err.message).match(/Plugin "([^"]+)"/)?.[1] ?? "unknown" : "unknown";
|
|
3439
|
+
throw new RegisterPluginsError("register_returned_promise", { id: pluginId2, error: String(err) });
|
|
3440
|
+
}
|
|
3441
|
+
const menu = list.flatMap((p) => p.menu ?? []);
|
|
3442
|
+
setPluginMenu(menu);
|
|
3443
|
+
setPluginDefinitions(list);
|
|
3444
|
+
const crons = list.flatMap((p) => p.crons ?? []);
|
|
3445
|
+
const cronSchedules = collectCronSchedules(list);
|
|
3446
|
+
const byId = /* @__PURE__ */ new Map();
|
|
3447
|
+
for (const p of list) {
|
|
3448
|
+
byId.set(p.id, {
|
|
3449
|
+
id: p.id,
|
|
3450
|
+
displayName: p.displayName ?? p.name ?? p.id,
|
|
3451
|
+
version: p.version,
|
|
3452
|
+
capabilities: p.capabilities ?? []
|
|
3453
|
+
});
|
|
3454
|
+
}
|
|
3455
|
+
let wirePromise;
|
|
3456
|
+
const boot = (envOverride) => {
|
|
3457
|
+
if (!wirePromise) {
|
|
3458
|
+
const env = envOverride ?? host.env ?? {};
|
|
3459
|
+
wirePromise = wireRegisteredPlugins(list, { hooks: host.hookSystem, env }, { strict: host.strict });
|
|
3460
|
+
}
|
|
3461
|
+
return wirePromise;
|
|
3462
|
+
};
|
|
3463
|
+
return {
|
|
3464
|
+
byId,
|
|
3465
|
+
order: list.map((p) => p.id),
|
|
3466
|
+
menu,
|
|
3467
|
+
crons,
|
|
3468
|
+
cronSchedules,
|
|
3469
|
+
mountResult,
|
|
3470
|
+
boot
|
|
3471
|
+
};
|
|
3472
|
+
}
|
|
3473
|
+
|
|
3474
|
+
// src/plugins/core-plugins/turnstile-plugin/manifest.json
|
|
3475
|
+
var manifest_default = {
|
|
3476
|
+
id: "turnstile",
|
|
3477
|
+
name: "Cloudflare Turnstile",
|
|
3478
|
+
description: "CAPTCHA-free bot protection using Cloudflare Turnstile. Provides reusable verification for any form.",
|
|
3479
|
+
version: "1.0.0",
|
|
3480
|
+
author: "SonicJS",
|
|
3481
|
+
category: "security",
|
|
3482
|
+
icon: "shield-check",
|
|
3483
|
+
homepage: "https://developers.cloudflare.com/turnstile/",
|
|
3484
|
+
repository: "https://github.com/sonicjs/sonicjs",
|
|
3485
|
+
license: "MIT",
|
|
3486
|
+
permissions: [
|
|
3487
|
+
"settings:write",
|
|
3488
|
+
"admin:access"
|
|
3489
|
+
],
|
|
3490
|
+
dependencies: [],
|
|
3491
|
+
configSchema: {
|
|
3492
|
+
siteKey: {
|
|
3493
|
+
type: "string",
|
|
3494
|
+
label: "Site Key",
|
|
3495
|
+
description: "Your Cloudflare Turnstile site key (public)",
|
|
3496
|
+
required: true
|
|
3497
|
+
},
|
|
3498
|
+
secretKey: {
|
|
3499
|
+
type: "string",
|
|
3500
|
+
label: "Secret Key",
|
|
3501
|
+
description: "Your Cloudflare Turnstile secret key (private)",
|
|
3502
|
+
required: true,
|
|
3503
|
+
sensitive: true
|
|
3504
|
+
},
|
|
3505
|
+
theme: {
|
|
3506
|
+
type: "select",
|
|
3507
|
+
label: "Widget Theme",
|
|
3508
|
+
description: "Visual theme for the Turnstile widget",
|
|
3509
|
+
default: "auto",
|
|
3510
|
+
options: [
|
|
3511
|
+
{
|
|
3512
|
+
value: "light",
|
|
3513
|
+
label: "Light"
|
|
3514
|
+
},
|
|
3515
|
+
{
|
|
3516
|
+
value: "dark",
|
|
3517
|
+
label: "Dark"
|
|
3518
|
+
},
|
|
3519
|
+
{
|
|
3520
|
+
value: "auto",
|
|
3521
|
+
label: "Auto"
|
|
3522
|
+
}
|
|
3523
|
+
]
|
|
3524
|
+
},
|
|
3525
|
+
size: {
|
|
3526
|
+
type: "select",
|
|
3527
|
+
label: "Widget Size",
|
|
3528
|
+
description: "Size of the Turnstile widget",
|
|
3529
|
+
default: "normal",
|
|
3530
|
+
options: [
|
|
3531
|
+
{
|
|
3532
|
+
value: "normal",
|
|
3533
|
+
label: "Normal"
|
|
3534
|
+
},
|
|
3535
|
+
{
|
|
3536
|
+
value: "compact",
|
|
3537
|
+
label: "Compact"
|
|
3538
|
+
}
|
|
3539
|
+
]
|
|
3540
|
+
},
|
|
3541
|
+
mode: {
|
|
3542
|
+
type: "select",
|
|
3543
|
+
label: "Widget Mode",
|
|
3544
|
+
description: "Managed: Adaptive challenge. Non-Interactive: Always visible, minimal friction. Invisible: No visible widget",
|
|
3545
|
+
default: "managed",
|
|
3546
|
+
options: [
|
|
3547
|
+
{
|
|
3548
|
+
value: "managed",
|
|
3549
|
+
label: "Managed (Recommended)"
|
|
3550
|
+
},
|
|
3551
|
+
{
|
|
3552
|
+
value: "non-interactive",
|
|
3553
|
+
label: "Non-Interactive"
|
|
3554
|
+
},
|
|
3555
|
+
{
|
|
3556
|
+
value: "invisible",
|
|
3557
|
+
label: "Invisible"
|
|
3558
|
+
}
|
|
3559
|
+
]
|
|
3560
|
+
},
|
|
3561
|
+
appearance: {
|
|
3562
|
+
type: "select",
|
|
3563
|
+
label: "Appearance",
|
|
3564
|
+
description: "When the Turnstile challenge is executed. Always: Verifies immediately. Execute: Challenge on form submit. Interaction Only: Only after user interaction",
|
|
3565
|
+
default: "always",
|
|
3566
|
+
options: [
|
|
3567
|
+
{
|
|
3568
|
+
value: "always",
|
|
3569
|
+
label: "Always"
|
|
3570
|
+
},
|
|
3571
|
+
{
|
|
3572
|
+
value: "execute",
|
|
3573
|
+
label: "Execute"
|
|
3574
|
+
},
|
|
3575
|
+
{
|
|
3576
|
+
value: "interaction-only",
|
|
3577
|
+
label: "Interaction Only"
|
|
3578
|
+
}
|
|
3579
|
+
]
|
|
3580
|
+
},
|
|
3581
|
+
preClearance: {
|
|
3582
|
+
type: "boolean",
|
|
3583
|
+
label: "Enable Pre-clearance",
|
|
3584
|
+
description: "Issue a clearance cookie that bypasses Cloudflare Firewall Rules (as if the user passed a challenge on your proxied site)",
|
|
3585
|
+
default: false
|
|
3586
|
+
},
|
|
3587
|
+
preClearanceLevel: {
|
|
3588
|
+
type: "select",
|
|
3589
|
+
label: "Pre-clearance Level",
|
|
3590
|
+
description: "Controls which Cloudflare Firewall Rules the clearance cookie bypasses. Only applies if Pre-clearance is enabled",
|
|
3591
|
+
default: "managed",
|
|
3592
|
+
options: [
|
|
3593
|
+
{
|
|
3594
|
+
value: "interactive",
|
|
3595
|
+
label: "Interactive - Bypasses Interactive, Managed & JS Challenge Rules"
|
|
3596
|
+
},
|
|
3597
|
+
{
|
|
3598
|
+
value: "managed",
|
|
3599
|
+
label: "Managed - Bypasses Managed & JS Challenge Rules"
|
|
3600
|
+
},
|
|
3601
|
+
{
|
|
3602
|
+
value: "non-interactive",
|
|
3603
|
+
label: "Non-interactive - Bypasses JS Challenge Rules only"
|
|
3604
|
+
}
|
|
3605
|
+
]
|
|
3606
|
+
},
|
|
3607
|
+
enabled: {
|
|
3608
|
+
type: "boolean",
|
|
3609
|
+
label: "Enable Turnstile",
|
|
3610
|
+
description: "Enable or disable Turnstile verification globally",
|
|
3611
|
+
default: true
|
|
3612
|
+
}
|
|
3613
|
+
},
|
|
3614
|
+
adminMenu: {
|
|
3615
|
+
label: "Turnstile",
|
|
3616
|
+
icon: "shield-check",
|
|
3617
|
+
href: "/admin/plugins/turnstile/settings",
|
|
3618
|
+
parentId: "plugins",
|
|
3619
|
+
order: 100
|
|
3620
|
+
},
|
|
3621
|
+
codeName: "turnstile-plugin",
|
|
3622
|
+
iconEmoji: "\u{1F6E1}\uFE0F",
|
|
3623
|
+
is_core: true,
|
|
3624
|
+
defaultSettings: {
|
|
3625
|
+
siteKey: "",
|
|
3626
|
+
secretKey: "",
|
|
3627
|
+
theme: "auto",
|
|
3628
|
+
size: "normal",
|
|
3629
|
+
mode: "managed",
|
|
3630
|
+
appearance: "always",
|
|
3631
|
+
preClearanceEnabled: false,
|
|
3632
|
+
preClearanceLevel: "managed",
|
|
3633
|
+
enabled: false
|
|
3634
|
+
}
|
|
3635
|
+
};
|
|
3636
|
+
|
|
3637
|
+
// src/plugins/core-plugins/turnstile-plugin/services/turnstile.ts
|
|
3638
|
+
var TurnstileService = class {
|
|
3639
|
+
db;
|
|
3640
|
+
VERIFY_URL = "https://challenges.cloudflare.com/turnstile/v0/siteverify";
|
|
3641
|
+
constructor(db) {
|
|
3642
|
+
this.db = db;
|
|
3643
|
+
}
|
|
3644
|
+
/**
|
|
3645
|
+
* Get Turnstile settings from database
|
|
3646
|
+
*/
|
|
3647
|
+
async getSettings() {
|
|
3648
|
+
try {
|
|
3649
|
+
const plugin = await this.db.prepare(`SELECT settings FROM plugins WHERE id = ? LIMIT 1`).bind(manifest_default.id).first();
|
|
3650
|
+
if (!plugin || !plugin.settings) {
|
|
3651
|
+
return null;
|
|
3652
|
+
}
|
|
3653
|
+
return JSON.parse(plugin.settings);
|
|
3654
|
+
} catch (error) {
|
|
3655
|
+
console.error("Error getting Turnstile settings:", error);
|
|
3656
|
+
return null;
|
|
3657
|
+
}
|
|
3658
|
+
}
|
|
3659
|
+
/**
|
|
3660
|
+
* Verify a Turnstile token with Cloudflare
|
|
3661
|
+
*/
|
|
3662
|
+
async verifyToken(token, remoteIp) {
|
|
3663
|
+
try {
|
|
3664
|
+
const settings = await this.getSettings();
|
|
3665
|
+
if (!settings) {
|
|
3666
|
+
return { success: false, error: "Turnstile not configured" };
|
|
3667
|
+
}
|
|
3668
|
+
if (!settings.enabled) {
|
|
3669
|
+
return { success: true };
|
|
3670
|
+
}
|
|
3671
|
+
if (!settings.secretKey) {
|
|
3672
|
+
return { success: false, error: "Turnstile secret key not configured" };
|
|
3673
|
+
}
|
|
3674
|
+
const formData = new FormData();
|
|
3675
|
+
formData.append("secret", settings.secretKey);
|
|
3676
|
+
formData.append("response", token);
|
|
3677
|
+
if (remoteIp) {
|
|
3678
|
+
formData.append("remoteip", remoteIp);
|
|
3679
|
+
}
|
|
3680
|
+
const response = await fetch(this.VERIFY_URL, {
|
|
3681
|
+
method: "POST",
|
|
3682
|
+
body: formData
|
|
3683
|
+
});
|
|
3684
|
+
if (!response.ok) {
|
|
3685
|
+
return { success: false, error: "Turnstile verification request failed" };
|
|
3686
|
+
}
|
|
3687
|
+
const result = await response.json();
|
|
3688
|
+
if (!result.success) {
|
|
3689
|
+
const errorCode = result["error-codes"]?.[0] || "unknown-error";
|
|
3690
|
+
return { success: false, error: `Turnstile verification failed: ${errorCode}` };
|
|
3691
|
+
}
|
|
3692
|
+
return { success: true };
|
|
3693
|
+
} catch (error) {
|
|
3694
|
+
console.error("Error verifying Turnstile token:", error);
|
|
3695
|
+
return { success: false, error: "Turnstile verification error" };
|
|
3696
|
+
}
|
|
3697
|
+
}
|
|
3698
|
+
/**
|
|
3699
|
+
* Save Turnstile settings to database
|
|
3700
|
+
*/
|
|
3701
|
+
async saveSettings(settings) {
|
|
3702
|
+
try {
|
|
3703
|
+
await this.db.prepare(`UPDATE plugins SET settings = ?, updated_at = ? WHERE id = ?`).bind(JSON.stringify(settings), Date.now(), manifest_default.id).run();
|
|
3704
|
+
console.log("Turnstile settings saved successfully");
|
|
3705
|
+
} catch (error) {
|
|
3706
|
+
console.error("Error saving Turnstile settings:", error);
|
|
3707
|
+
throw new Error("Failed to save Turnstile settings");
|
|
3708
|
+
}
|
|
3709
|
+
}
|
|
3710
|
+
/**
|
|
3711
|
+
* Check if Turnstile is enabled
|
|
3712
|
+
*/
|
|
3713
|
+
async isEnabled() {
|
|
3714
|
+
const settings = await this.getSettings();
|
|
3715
|
+
return settings?.enabled === true && !!settings.siteKey && !!settings.secretKey;
|
|
3716
|
+
}
|
|
3717
|
+
};
|
|
3718
|
+
|
|
3085
3719
|
// src/plugins/core-plugins/turnstile-plugin/middleware/verify.ts
|
|
3086
3720
|
async function verifyTurnstile(c, next) {
|
|
3087
3721
|
const db = c.get("db") || c.env?.DB;
|
|
@@ -3157,19 +3791,15 @@ function createTurnstileMiddleware(options) {
|
|
|
3157
3791
|
}
|
|
3158
3792
|
|
|
3159
3793
|
// src/plugins/core-plugins/turnstile-plugin/index.ts
|
|
3160
|
-
|
|
3161
|
-
|
|
3794
|
+
definePlugin({
|
|
3795
|
+
id: manifest_default.id,
|
|
3162
3796
|
version: manifest_default.version,
|
|
3797
|
+
name: manifest_default.name,
|
|
3163
3798
|
description: manifest_default.description,
|
|
3799
|
+
sonicjsVersionRange: "^3.0.0",
|
|
3164
3800
|
author: { name: manifest_default.author }
|
|
3165
|
-
})
|
|
3166
|
-
description: manifest_default.description,
|
|
3167
|
-
author: { name: manifest_default.author }
|
|
3168
|
-
}).addService("turnstile", TurnstileService).addSingleMiddleware("verifyTurnstile", verifyTurnstile, {
|
|
3169
|
-
description: "Verify Cloudflare Turnstile token",
|
|
3170
|
-
global: false
|
|
3171
|
-
}).build();
|
|
3801
|
+
});
|
|
3172
3802
|
|
|
3173
|
-
export { HookSystemImpl, HookUtils, PluginManager, PluginRegistryImpl, PluginValidator, ScopedHookSystem, createTurnstileMiddleware, verifyTurnstile };
|
|
3174
|
-
//# sourceMappingURL=chunk-
|
|
3175
|
-
//# sourceMappingURL=chunk-
|
|
3803
|
+
export { HookSystemImpl, HookUtils, PluginDependencyCycleError, PluginManager, PluginRegisterMustBeSyncError, PluginRegistryImpl, PluginValidator, RegisterPluginsError, ScopedHookSystem, TurnstileService, collectCronSchedules, collectCrons, createPluginWirer, createScheduledHandler, createTurnstileMiddleware, dispatchCronTick, getPluginMenu, mountPlugin, registerPluginRoutes, registerPlugins, resetPluginMenu, resolvePluginMenuItems, setPluginMenu, topoSort, verifyTurnstile, wireRegisteredPlugins };
|
|
3804
|
+
//# sourceMappingURL=chunk-ATUPB6MN.js.map
|
|
3805
|
+
//# sourceMappingURL=chunk-ATUPB6MN.js.map
|