@sonicjs-cms/core 2.3.17 → 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/dist/{chunk-CPXAVWCU.js → chunk-3YUHXWSG.js} +278 -3
  2. package/dist/chunk-3YUHXWSG.js.map +1 -0
  3. package/dist/chunk-AI2JJIJX.cjs +211 -0
  4. package/dist/chunk-AI2JJIJX.cjs.map +1 -0
  5. package/dist/{chunk-TMQOLXLY.js → chunk-BHNDALCA.js} +56 -4
  6. package/dist/chunk-BHNDALCA.js.map +1 -0
  7. package/dist/{chunk-IEWLOVP3.cjs → chunk-I4V3VZWF.cjs} +46 -2
  8. package/dist/chunk-I4V3VZWF.cjs.map +1 -0
  9. package/dist/{chunk-DTLB6UIH.cjs → chunk-LWG2MWDA.cjs} +280 -2
  10. package/dist/chunk-LWG2MWDA.cjs.map +1 -0
  11. package/dist/{chunk-QBWD6FKH.js → chunk-OJZ45OJD.js} +559 -281
  12. package/dist/chunk-OJZ45OJD.js.map +1 -0
  13. package/dist/chunk-QDBNW7KQ.js +209 -0
  14. package/dist/chunk-QDBNW7KQ.js.map +1 -0
  15. package/dist/{chunk-VYL6RIV6.js → chunk-TJTWRO4G.js} +5 -5
  16. package/dist/chunk-TJTWRO4G.js.map +1 -0
  17. package/dist/{chunk-74DP754U.cjs → chunk-UAQL2VWX.cjs} +644 -366
  18. package/dist/chunk-UAQL2VWX.cjs.map +1 -0
  19. package/dist/{chunk-B6YJRVFQ.js → chunk-VEL7QRYI.js} +46 -2
  20. package/dist/chunk-VEL7QRYI.js.map +1 -0
  21. package/dist/{chunk-YHJB26RJ.cjs → chunk-YYV3XQOQ.cjs} +6 -6
  22. package/dist/chunk-YYV3XQOQ.cjs.map +1 -0
  23. package/dist/{chunk-2XCJ3HT5.cjs → chunk-ZWV3EBZ7.cjs} +58 -3
  24. package/dist/chunk-ZWV3EBZ7.cjs.map +1 -0
  25. package/dist/{collection-config-FLlGtsh9.d.cts → collection-config-B6gMPunn.d.cts} +9 -1
  26. package/dist/{collection-config-FLlGtsh9.d.ts → collection-config-B6gMPunn.d.ts} +9 -1
  27. package/dist/index.cjs +114 -85
  28. package/dist/index.cjs.map +1 -1
  29. package/dist/index.d.cts +4 -4
  30. package/dist/index.d.ts +4 -4
  31. package/dist/index.js +37 -8
  32. package/dist/index.js.map +1 -1
  33. package/dist/middleware.cjs +23 -23
  34. package/dist/middleware.js +2 -2
  35. package/dist/migrations-NIEUFG44.cjs +13 -0
  36. package/dist/{migrations-EOV7NJZ7.cjs.map → migrations-NIEUFG44.cjs.map} +1 -1
  37. package/dist/migrations-TGZKJKV4.js +4 -0
  38. package/dist/{migrations-6HKPNPTK.js.map → migrations-TGZKJKV4.js.map} +1 -1
  39. package/dist/{plugin-bootstrap-C0E3jdz-.d.cts → plugin-bootstrap-SHsdjE6X.d.cts} +1 -1
  40. package/dist/{plugin-bootstrap-CDh0JHtW.d.ts → plugin-bootstrap-dYhD9fQR.d.ts} +1 -1
  41. package/dist/plugin-manager-Baa6xXqB.d.ts +328 -0
  42. package/dist/plugin-manager-vBal9Zip.d.cts +328 -0
  43. package/dist/plugins.cjs +20 -7
  44. package/dist/plugins.d.cts +53 -310
  45. package/dist/plugins.d.ts +53 -310
  46. package/dist/plugins.js +2 -1
  47. package/dist/routes.cjs +25 -24
  48. package/dist/routes.js +5 -4
  49. package/dist/services.cjs +2 -2
  50. package/dist/services.d.cts +2 -2
  51. package/dist/services.d.ts +2 -2
  52. package/dist/services.js +1 -1
  53. package/dist/types.d.cts +1 -1
  54. package/dist/types.d.ts +1 -1
  55. package/dist/utils.cjs +23 -11
  56. package/dist/utils.d.cts +38 -1
  57. package/dist/utils.d.ts +38 -1
  58. package/dist/utils.js +1 -1
  59. package/migrations/027_fix_slug_field_type.sql +18 -0
  60. package/migrations/028_fix_slug_field_type_in_schemas.sql +30 -0
  61. package/package.json +2 -1
  62. package/dist/chunk-2XCJ3HT5.cjs.map +0 -1
  63. package/dist/chunk-74DP754U.cjs.map +0 -1
  64. package/dist/chunk-B6YJRVFQ.js.map +0 -1
  65. package/dist/chunk-CPXAVWCU.js.map +0 -1
  66. package/dist/chunk-DTLB6UIH.cjs.map +0 -1
  67. package/dist/chunk-IEWLOVP3.cjs.map +0 -1
  68. package/dist/chunk-QBWD6FKH.js.map +0 -1
  69. package/dist/chunk-TMQOLXLY.js.map +0 -1
  70. package/dist/chunk-VYL6RIV6.js.map +0 -1
  71. package/dist/chunk-YHJB26RJ.cjs.map +0 -1
  72. package/dist/migrations-6HKPNPTK.js +0 -4
  73. package/dist/migrations-EOV7NJZ7.cjs +0 -13
@@ -1,3 +1,4 @@
1
+ import { PluginBuilder } from './chunk-QDBNW7KQ.js';
1
2
  import { HOOKS } from './chunk-LOUJRBXV.js';
2
3
  import { __commonJS, __toESM } from './chunk-V4OQ3NZ2.js';
3
4
  import { z } from 'zod';
@@ -3081,6 +3082,280 @@ var PluginManager = class {
3081
3082
  }
3082
3083
  };
3083
3084
 
3084
- export { HookSystemImpl, HookUtils, PluginManager, PluginRegistryImpl, PluginValidator, ScopedHookSystem };
3085
- //# sourceMappingURL=chunk-CPXAVWCU.js.map
3086
- //# sourceMappingURL=chunk-CPXAVWCU.js.map
3085
+ // src/plugins/core-plugins/turnstile-plugin/manifest.json
3086
+ var manifest_default = {
3087
+ id: "turnstile",
3088
+ name: "Cloudflare Turnstile",
3089
+ description: "CAPTCHA-free bot protection using Cloudflare Turnstile. Provides reusable verification for any form.",
3090
+ version: "1.0.0",
3091
+ author: "SonicJS",
3092
+ category: "security",
3093
+ icon: "shield-check",
3094
+ homepage: "https://developers.cloudflare.com/turnstile/",
3095
+ repository: "https://github.com/sonicjs/sonicjs",
3096
+ license: "MIT",
3097
+ permissions: ["settings:write", "admin:access"],
3098
+ dependencies: [],
3099
+ configSchema: {
3100
+ siteKey: {
3101
+ type: "string",
3102
+ label: "Site Key",
3103
+ description: "Your Cloudflare Turnstile site key (public)",
3104
+ required: true
3105
+ },
3106
+ secretKey: {
3107
+ type: "string",
3108
+ label: "Secret Key",
3109
+ description: "Your Cloudflare Turnstile secret key (private)",
3110
+ required: true,
3111
+ sensitive: true
3112
+ },
3113
+ theme: {
3114
+ type: "select",
3115
+ label: "Widget Theme",
3116
+ description: "Visual theme for the Turnstile widget",
3117
+ default: "auto",
3118
+ options: [
3119
+ { value: "light", label: "Light" },
3120
+ { value: "dark", label: "Dark" },
3121
+ { value: "auto", label: "Auto" }
3122
+ ]
3123
+ },
3124
+ size: {
3125
+ type: "select",
3126
+ label: "Widget Size",
3127
+ description: "Size of the Turnstile widget",
3128
+ default: "normal",
3129
+ options: [
3130
+ { value: "normal", label: "Normal" },
3131
+ { value: "compact", label: "Compact" }
3132
+ ]
3133
+ },
3134
+ mode: {
3135
+ type: "select",
3136
+ label: "Widget Mode",
3137
+ description: "Managed: Adaptive challenge. Non-Interactive: Always visible, minimal friction. Invisible: No visible widget",
3138
+ default: "managed",
3139
+ options: [
3140
+ { value: "managed", label: "Managed (Recommended)" },
3141
+ { value: "non-interactive", label: "Non-Interactive" },
3142
+ { value: "invisible", label: "Invisible" }
3143
+ ]
3144
+ },
3145
+ appearance: {
3146
+ type: "select",
3147
+ label: "Appearance",
3148
+ description: "When the Turnstile challenge is executed. Always: Verifies immediately. Execute: Challenge on form submit. Interaction Only: Only after user interaction",
3149
+ default: "always",
3150
+ options: [
3151
+ { value: "always", label: "Always" },
3152
+ { value: "execute", label: "Execute" },
3153
+ { value: "interaction-only", label: "Interaction Only" }
3154
+ ]
3155
+ },
3156
+ preClearance: {
3157
+ type: "boolean",
3158
+ label: "Enable Pre-clearance",
3159
+ description: "Issue a clearance cookie that bypasses Cloudflare Firewall Rules (as if the user passed a challenge on your proxied site)",
3160
+ default: false
3161
+ },
3162
+ preClearanceLevel: {
3163
+ type: "select",
3164
+ label: "Pre-clearance Level",
3165
+ description: "Controls which Cloudflare Firewall Rules the clearance cookie bypasses. Only applies if Pre-clearance is enabled",
3166
+ default: "managed",
3167
+ options: [
3168
+ { value: "interactive", label: "Interactive - Bypasses Interactive, Managed & JS Challenge Rules" },
3169
+ { value: "managed", label: "Managed - Bypasses Managed & JS Challenge Rules" },
3170
+ { value: "non-interactive", label: "Non-interactive - Bypasses JS Challenge Rules only" }
3171
+ ]
3172
+ },
3173
+ enabled: {
3174
+ type: "boolean",
3175
+ label: "Enable Turnstile",
3176
+ description: "Enable or disable Turnstile verification globally",
3177
+ default: true
3178
+ }
3179
+ },
3180
+ adminMenu: {
3181
+ label: "Turnstile",
3182
+ icon: "shield-check",
3183
+ href: "/admin/plugins/turnstile/settings",
3184
+ parentId: "plugins",
3185
+ order: 100
3186
+ }
3187
+ };
3188
+
3189
+ // src/plugins/core-plugins/turnstile-plugin/services/turnstile.ts
3190
+ var TurnstileService = class {
3191
+ db;
3192
+ VERIFY_URL = "https://challenges.cloudflare.com/turnstile/v0/siteverify";
3193
+ constructor(db) {
3194
+ this.db = db;
3195
+ }
3196
+ /**
3197
+ * Get Turnstile settings from database
3198
+ */
3199
+ async getSettings() {
3200
+ try {
3201
+ const plugin = await this.db.prepare(`SELECT settings FROM plugins WHERE id = ? LIMIT 1`).bind(manifest_default.id).first();
3202
+ if (!plugin || !plugin.settings) {
3203
+ return null;
3204
+ }
3205
+ return JSON.parse(plugin.settings);
3206
+ } catch (error) {
3207
+ console.error("Error getting Turnstile settings:", error);
3208
+ return null;
3209
+ }
3210
+ }
3211
+ /**
3212
+ * Verify a Turnstile token with Cloudflare
3213
+ */
3214
+ async verifyToken(token, remoteIp) {
3215
+ try {
3216
+ const settings = await this.getSettings();
3217
+ if (!settings) {
3218
+ return { success: false, error: "Turnstile not configured" };
3219
+ }
3220
+ if (!settings.enabled) {
3221
+ return { success: true };
3222
+ }
3223
+ if (!settings.secretKey) {
3224
+ return { success: false, error: "Turnstile secret key not configured" };
3225
+ }
3226
+ const formData = new FormData();
3227
+ formData.append("secret", settings.secretKey);
3228
+ formData.append("response", token);
3229
+ if (remoteIp) {
3230
+ formData.append("remoteip", remoteIp);
3231
+ }
3232
+ const response = await fetch(this.VERIFY_URL, {
3233
+ method: "POST",
3234
+ body: formData
3235
+ });
3236
+ if (!response.ok) {
3237
+ return { success: false, error: "Turnstile verification request failed" };
3238
+ }
3239
+ const result = await response.json();
3240
+ if (!result.success) {
3241
+ const errorCode = result["error-codes"]?.[0] || "unknown-error";
3242
+ return { success: false, error: `Turnstile verification failed: ${errorCode}` };
3243
+ }
3244
+ return { success: true };
3245
+ } catch (error) {
3246
+ console.error("Error verifying Turnstile token:", error);
3247
+ return { success: false, error: "Turnstile verification error" };
3248
+ }
3249
+ }
3250
+ /**
3251
+ * Save Turnstile settings to database
3252
+ */
3253
+ async saveSettings(settings) {
3254
+ try {
3255
+ await this.db.prepare(`UPDATE plugins SET settings = ?, updated_at = ? WHERE id = ?`).bind(JSON.stringify(settings), Date.now(), manifest_default.id).run();
3256
+ console.log("Turnstile settings saved successfully");
3257
+ } catch (error) {
3258
+ console.error("Error saving Turnstile settings:", error);
3259
+ throw new Error("Failed to save Turnstile settings");
3260
+ }
3261
+ }
3262
+ /**
3263
+ * Check if Turnstile is enabled
3264
+ */
3265
+ async isEnabled() {
3266
+ const settings = await this.getSettings();
3267
+ return settings?.enabled === true && !!settings.siteKey && !!settings.secretKey;
3268
+ }
3269
+ };
3270
+
3271
+ // src/plugins/core-plugins/turnstile-plugin/middleware/verify.ts
3272
+ async function verifyTurnstile(c, next) {
3273
+ const db = c.get("db") || c.env?.DB;
3274
+ if (!db) {
3275
+ console.error("Turnstile middleware: Database not available");
3276
+ return c.json({ error: "Database not available" }, 500);
3277
+ }
3278
+ const turnstileService = new TurnstileService(db);
3279
+ const isEnabled = await turnstileService.isEnabled();
3280
+ if (!isEnabled) {
3281
+ return next();
3282
+ }
3283
+ let token;
3284
+ let body;
3285
+ if (c.req.method === "POST") {
3286
+ const contentType = c.req.header("content-type") || "";
3287
+ if (contentType.includes("application/json")) {
3288
+ body = await c.req.json();
3289
+ token = body["cf-turnstile-response"] || body["turnstile-token"];
3290
+ c.set("requestBody", body);
3291
+ } else if (contentType.includes("application/x-www-form-urlencoded") || contentType.includes("multipart/form-data")) {
3292
+ const formData = await c.req.formData();
3293
+ token = formData.get("cf-turnstile-response")?.toString() || formData.get("turnstile-token")?.toString();
3294
+ }
3295
+ }
3296
+ if (!token) {
3297
+ return c.json({
3298
+ error: "Turnstile token missing",
3299
+ message: "Please complete the verification challenge"
3300
+ }, 400);
3301
+ }
3302
+ const remoteIp = c.req.header("cf-connecting-ip") || c.req.header("x-forwarded-for");
3303
+ const result = await turnstileService.verifyToken(token, remoteIp);
3304
+ if (!result.success) {
3305
+ return c.json({
3306
+ error: "Turnstile verification failed",
3307
+ message: result.error || "Verification failed. Please try again."
3308
+ }, 403);
3309
+ }
3310
+ return next();
3311
+ }
3312
+ function createTurnstileMiddleware(options) {
3313
+ return async (c, next) => {
3314
+ const db = c.get("db") || c.env?.DB;
3315
+ if (!db) {
3316
+ return options?.onError?.(c, "Database not available") || c.json({ error: "Database not available" }, 500);
3317
+ }
3318
+ const turnstileService = new TurnstileService(db);
3319
+ const isEnabled = await turnstileService.isEnabled();
3320
+ if (!isEnabled) {
3321
+ return next();
3322
+ }
3323
+ let token;
3324
+ const contentType = c.req.header("content-type") || "";
3325
+ if (contentType.includes("application/json")) {
3326
+ const body = await c.req.json();
3327
+ token = body["cf-turnstile-response"] || body["turnstile-token"];
3328
+ c.set("requestBody", body);
3329
+ } else if (contentType.includes("application/x-www-form-urlencoded") || contentType.includes("multipart/form-data")) {
3330
+ const formData = await c.req.formData();
3331
+ token = formData.get("cf-turnstile-response")?.toString() || formData.get("turnstile-token")?.toString();
3332
+ }
3333
+ if (!token) {
3334
+ return options?.onMissing?.(c) || c.json({ error: "Turnstile token missing" }, 400);
3335
+ }
3336
+ const remoteIp = c.req.header("cf-connecting-ip") || c.req.header("x-forwarded-for");
3337
+ const result = await turnstileService.verifyToken(token, remoteIp);
3338
+ if (!result.success) {
3339
+ return options?.onError?.(c, result.error || "Verification failed") || c.json({ error: "Turnstile verification failed", message: result.error }, 403);
3340
+ }
3341
+ return next();
3342
+ };
3343
+ }
3344
+
3345
+ // src/plugins/core-plugins/turnstile-plugin/index.ts
3346
+ new PluginBuilder({
3347
+ name: manifest_default.name,
3348
+ version: manifest_default.version,
3349
+ description: manifest_default.description,
3350
+ author: { name: manifest_default.author }
3351
+ }).metadata({
3352
+ description: manifest_default.description,
3353
+ author: { name: manifest_default.author }
3354
+ }).addService("turnstile", TurnstileService).addSingleMiddleware("verifyTurnstile", verifyTurnstile, {
3355
+ description: "Verify Cloudflare Turnstile token",
3356
+ global: false
3357
+ }).build();
3358
+
3359
+ export { HookSystemImpl, HookUtils, PluginManager, PluginRegistryImpl, PluginValidator, ScopedHookSystem, TurnstileService, createTurnstileMiddleware, verifyTurnstile };
3360
+ //# sourceMappingURL=chunk-3YUHXWSG.js.map
3361
+ //# sourceMappingURL=chunk-3YUHXWSG.js.map