@sonicjs-cms/core 2.19.0 → 3.0.0-beta.11
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-4NPCDK6B.js → chunk-3PU4WVU6.js} +557 -90
- package/dist/chunk-3PU4WVU6.js.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-6H66MSSL.js +273 -0
- package/dist/chunk-6H66MSSL.js.map +1 -0
- package/dist/chunk-AI663NBO.js +821 -0
- package/dist/chunk-AI663NBO.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-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-HPAJKZAQ.js +387 -0
- package/dist/chunk-HPAJKZAQ.js.map +1 -0
- package/dist/chunk-IESEVHXL.js +66 -0
- package/dist/chunk-IESEVHXL.js.map +1 -0
- package/dist/chunk-IVPRUGTY.js +242 -0
- package/dist/chunk-IVPRUGTY.js.map +1 -0
- package/dist/{chunk-JZVHLLSI.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-R4FOLLFB.cjs → chunk-K342JMA3.cjs} +8730 -11520
- package/dist/chunk-K342JMA3.cjs.map +1 -0
- package/dist/{chunk-UYJ6TJHX.cjs → chunk-K623Q6WD.cjs} +181 -56
- package/dist/chunk-K623Q6WD.cjs.map +1 -0
- package/dist/chunk-KV3CM5RK.cjs +158 -0
- package/dist/chunk-KV3CM5RK.cjs.map +1 -0
- package/dist/{chunk-ABB34XUS.cjs → chunk-MKKGA3C4.cjs} +667 -19
- package/dist/chunk-MKKGA3C4.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-ORF4CT74.cjs +276 -0
- package/dist/chunk-ORF4CT74.cjs.map +1 -0
- package/dist/{chunk-TFNTM3OA.js → chunk-PDYRDYXI.js} +645 -15
- package/dist/chunk-PDYRDYXI.js.map +1 -0
- package/dist/{chunk-OHYBNCVL.cjs → chunk-PXNTCCPE.cjs} +10 -1256
- package/dist/chunk-PXNTCCPE.cjs.map +1 -0
- package/dist/{chunk-E4YFJBM2.cjs → chunk-QJNKSFDJ.cjs} +876 -829
- package/dist/chunk-QJNKSFDJ.cjs.map +1 -0
- package/dist/chunk-QLFTG3QJ.js +1828 -0
- package/dist/chunk-QLFTG3QJ.js.map +1 -0
- package/dist/{chunk-BU7SFHGP.js → chunk-QZGABF2M.js} +3 -149
- package/dist/chunk-QZGABF2M.js.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-OCL3HMEG.js → chunk-SXLVXD2X.js} +7004 -9807
- package/dist/chunk-SXLVXD2X.js.map +1 -0
- package/dist/chunk-UHRHZXVR.cjs +408 -0
- package/dist/chunk-UHRHZXVR.cjs.map +1 -0
- package/dist/chunk-YA3TJ65D.cjs +575 -0
- package/dist/chunk-YA3TJ65D.cjs.map +1 -0
- package/dist/{chunk-7A4CB7T3.cjs → chunk-YJEBDJDV.cjs} +561 -91
- package/dist/chunk-YJEBDJDV.cjs.map +1 -0
- package/dist/chunk-YP7GW2G5.cjs +866 -0
- package/dist/chunk-YP7GW2G5.cjs.map +1 -0
- package/dist/chunk-ZUEIQFE5.js +154 -0
- package/dist/chunk-ZUEIQFE5.js.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 +13739 -4328
- 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 -4067
- package/dist/index.js.map +1 -1
- package/dist/middleware.cjs +38 -32
- package/dist/middleware.d.cts +50 -7
- package/dist/middleware.d.ts +50 -7
- package/dist/middleware.js +9 -3
- package/dist/migrations-XQLBY7E5.js +4 -0
- package/dist/{migrations-H5IXZNCO.js.map → migrations-XQLBY7E5.js.map} +1 -1
- package/dist/migrations-ZXJEUTFA.cjs +13 -0
- package/dist/{migrations-566IIPS2.cjs.map → migrations-ZXJEUTFA.cjs.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-4NPCDK6B.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-7A4CB7T3.cjs.map +0 -1
- package/dist/chunk-ABB34XUS.cjs.map +0 -1
- package/dist/chunk-BU7SFHGP.js.map +0 -1
- package/dist/chunk-E4YFJBM2.cjs.map +0 -1
- package/dist/chunk-EXNEW5US.js +0 -648
- package/dist/chunk-EXNEW5US.js.map +0 -1
- package/dist/chunk-JZV22DEV.js +0 -1783
- package/dist/chunk-JZV22DEV.js.map +0 -1
- package/dist/chunk-JZVHLLSI.cjs.map +0 -1
- package/dist/chunk-OCL3HMEG.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-R4FOLLFB.cjs.map +0 -1
- package/dist/chunk-RLMUFFUD.cjs +0 -2219
- package/dist/chunk-RLMUFFUD.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-ZYAYUIZE.js +0 -2217
- package/dist/chunk-ZYAYUIZE.js.map +0 -1
- package/dist/migrations-566IIPS2.cjs +0 -13
- package/dist/migrations-H5IXZNCO.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,10 +1,368 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { RbacService } from './chunk-BLMTL57B.js';
|
|
2
|
+
import { loadCollectionConfigs, getCollectionRegistry, PluginBootstrapService, getTelemetryService } from './chunk-QLFTG3QJ.js';
|
|
3
|
+
import { ensureScalarSchema, MigrationService } from './chunk-6H66MSSL.js';
|
|
4
|
+
import { init_admin_layout_catalyst_template, setBranchLabel } from './chunk-5V62WT6M.js';
|
|
5
|
+
import { hasHookSystem, getHookSystem } from './chunk-RNZFGN4R.js';
|
|
3
6
|
import { metricsTracker } from './chunk-FICTAGD4.js';
|
|
7
|
+
import { z } from 'zod';
|
|
4
8
|
import { sign, verify } from 'hono/jwt';
|
|
5
9
|
import { getCookie, setCookie } from 'hono/cookie';
|
|
6
10
|
|
|
11
|
+
// src/services/document-type-registry.ts
|
|
12
|
+
function rowToDocumentType(row) {
|
|
13
|
+
return {
|
|
14
|
+
id: row.id,
|
|
15
|
+
name: row.name,
|
|
16
|
+
displayName: row.display_name,
|
|
17
|
+
description: row.description,
|
|
18
|
+
schema: JSON.parse(row.schema),
|
|
19
|
+
queryableFields: JSON.parse(row.queryable_fields),
|
|
20
|
+
settings: JSON.parse(row.settings),
|
|
21
|
+
pluginId: row.plugin_id,
|
|
22
|
+
source: row.source,
|
|
23
|
+
schemaVersion: row.schema_version,
|
|
24
|
+
isSystem: row.is_system === 1,
|
|
25
|
+
isActive: row.is_active === 1,
|
|
26
|
+
isAuth: row.is_auth === 1,
|
|
27
|
+
createdAt: row.created_at,
|
|
28
|
+
updatedAt: row.updated_at
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
var DocumentTypeRegistry = class {
|
|
32
|
+
constructor(db) {
|
|
33
|
+
this.db = db;
|
|
34
|
+
}
|
|
35
|
+
cache = /* @__PURE__ */ new Map();
|
|
36
|
+
// Register or update a document type. Idempotent: bumps schema_version only when schema changes.
|
|
37
|
+
async register(def) {
|
|
38
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
39
|
+
const existing = await this.findById(def.id);
|
|
40
|
+
const schemaJson = JSON.stringify({ queryableFields: def.queryableFields ?? [], settings: def.settings ?? {} });
|
|
41
|
+
const queryableJson = JSON.stringify(def.queryableFields ?? []);
|
|
42
|
+
const settingsJson = JSON.stringify(def.settings ?? {});
|
|
43
|
+
if (existing) {
|
|
44
|
+
const schemaChanged = schemaJson !== JSON.stringify(existing.schema);
|
|
45
|
+
const newVersion = schemaChanged ? existing.schemaVersion + 1 : existing.schemaVersion;
|
|
46
|
+
await this.db.prepare(
|
|
47
|
+
`UPDATE document_types SET
|
|
48
|
+
display_name = ?,
|
|
49
|
+
description = ?,
|
|
50
|
+
schema = ?,
|
|
51
|
+
queryable_fields = ?,
|
|
52
|
+
settings = ?,
|
|
53
|
+
plugin_id = ?,
|
|
54
|
+
schema_version = ?,
|
|
55
|
+
is_active = 1,
|
|
56
|
+
is_auth = ?,
|
|
57
|
+
updated_at = ?
|
|
58
|
+
WHERE id = ?`
|
|
59
|
+
).bind(
|
|
60
|
+
def.displayName,
|
|
61
|
+
def.description ?? null,
|
|
62
|
+
schemaJson,
|
|
63
|
+
queryableJson,
|
|
64
|
+
settingsJson,
|
|
65
|
+
def.pluginId ?? null,
|
|
66
|
+
newVersion,
|
|
67
|
+
def.isAuth ? 1 : 0,
|
|
68
|
+
now,
|
|
69
|
+
def.id
|
|
70
|
+
).run();
|
|
71
|
+
await ensureScalarSchema(this.db, def.id, def.queryableFields ?? []);
|
|
72
|
+
const updated = await this.findById(def.id);
|
|
73
|
+
this.cache.set(def.id, updated);
|
|
74
|
+
return updated;
|
|
75
|
+
}
|
|
76
|
+
await this.db.prepare(
|
|
77
|
+
`INSERT INTO document_types (id, name, display_name, description, schema, queryable_fields, settings, plugin_id, source, schema_version, is_system, is_active, is_auth, created_at, updated_at)
|
|
78
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 1, 0, 1, ?, ?, ?)`
|
|
79
|
+
).bind(
|
|
80
|
+
def.id,
|
|
81
|
+
def.name ?? def.id,
|
|
82
|
+
def.displayName,
|
|
83
|
+
def.description ?? null,
|
|
84
|
+
schemaJson,
|
|
85
|
+
queryableJson,
|
|
86
|
+
settingsJson,
|
|
87
|
+
def.pluginId ?? null,
|
|
88
|
+
def.source ?? "code",
|
|
89
|
+
def.isAuth ? 1 : 0,
|
|
90
|
+
now,
|
|
91
|
+
now
|
|
92
|
+
).run();
|
|
93
|
+
await ensureScalarSchema(this.db, def.id, def.queryableFields ?? []);
|
|
94
|
+
const created = await this.findById(def.id);
|
|
95
|
+
this.cache.set(def.id, created);
|
|
96
|
+
return created;
|
|
97
|
+
}
|
|
98
|
+
async findById(id) {
|
|
99
|
+
if (this.cache.has(id)) return this.cache.get(id);
|
|
100
|
+
const row = await this.db.prepare("SELECT * FROM document_types WHERE id = ?").bind(id).first();
|
|
101
|
+
if (!row) return null;
|
|
102
|
+
const dt = rowToDocumentType(row);
|
|
103
|
+
this.cache.set(id, dt);
|
|
104
|
+
return dt;
|
|
105
|
+
}
|
|
106
|
+
async findAll(activeOnly = true) {
|
|
107
|
+
const sql = activeOnly ? "SELECT * FROM document_types WHERE is_active = 1 ORDER BY name" : "SELECT * FROM document_types ORDER BY name";
|
|
108
|
+
const result = await this.db.prepare(sql).all();
|
|
109
|
+
return (result.results ?? []).map(rowToDocumentType);
|
|
110
|
+
}
|
|
111
|
+
async deactivate(id) {
|
|
112
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
113
|
+
await this.db.prepare("UPDATE document_types SET is_active = 0, updated_at = ? WHERE id = ?").bind(now, id).run();
|
|
114
|
+
this.cache.delete(id);
|
|
115
|
+
}
|
|
116
|
+
clearCache() {
|
|
117
|
+
this.cache.clear();
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
// src/services/document-types-seed.ts
|
|
122
|
+
var anyObject = z.record(z.string(), z.unknown());
|
|
123
|
+
async function bootstrapDocumentTypes(db) {
|
|
124
|
+
const registry = new DocumentTypeRegistry(db);
|
|
125
|
+
await registry.register({
|
|
126
|
+
id: "site_settings",
|
|
127
|
+
name: "site_settings",
|
|
128
|
+
displayName: "Site Settings",
|
|
129
|
+
description: "Global site configuration (internal; managed via admin settings UI)",
|
|
130
|
+
source: "system",
|
|
131
|
+
schema: anyObject,
|
|
132
|
+
settings: {
|
|
133
|
+
internal: true,
|
|
134
|
+
maxVersionsPerRoot: 1,
|
|
135
|
+
baseGrants: { admin: ["read", "create", "update", "delete", "manage"] }
|
|
136
|
+
},
|
|
137
|
+
queryableFields: []
|
|
138
|
+
});
|
|
139
|
+
await registry.register({
|
|
140
|
+
id: "blog_post",
|
|
141
|
+
name: "blog_post",
|
|
142
|
+
displayName: "Blog Post",
|
|
143
|
+
description: "Blog post (document-backed; edited via the content collection UI)",
|
|
144
|
+
source: "system",
|
|
145
|
+
schema: anyObject,
|
|
146
|
+
settings: {
|
|
147
|
+
baseGrants: { public: ["read"], admin: ["read", "create", "update", "delete", "publish", "manage"], editor: ["read", "create", "update", "publish"], viewer: ["read"] },
|
|
148
|
+
maxVersionsPerRoot: 50
|
|
149
|
+
},
|
|
150
|
+
queryableFields: [
|
|
151
|
+
{ name: "difficulty", kind: "scalar", type: "text", column: "q_blog_difficulty" },
|
|
152
|
+
{ name: "author", kind: "scalar", type: "text", column: "q_blog_author" }
|
|
153
|
+
]
|
|
154
|
+
});
|
|
155
|
+
await registry.register({
|
|
156
|
+
id: "plugin",
|
|
157
|
+
name: "plugin",
|
|
158
|
+
displayName: "Plugin",
|
|
159
|
+
description: "System plugin record (managed by the plugin bootstrap service)",
|
|
160
|
+
source: "system",
|
|
161
|
+
schema: anyObject,
|
|
162
|
+
settings: {
|
|
163
|
+
baseGrants: { admin: ["read", "create", "update", "delete", "publish", "manage"] },
|
|
164
|
+
maxVersionsPerRoot: 1,
|
|
165
|
+
internal: true
|
|
166
|
+
},
|
|
167
|
+
queryableFields: [
|
|
168
|
+
{ name: "status", kind: "scalar", type: "text", column: "q_plugin_status" },
|
|
169
|
+
{ name: "category", kind: "scalar", type: "text", column: "q_plugin_category" },
|
|
170
|
+
{ name: "isCore", kind: "scalar", type: "integer", column: "q_plugin_is_core" }
|
|
171
|
+
]
|
|
172
|
+
});
|
|
173
|
+
await registry.register({
|
|
174
|
+
id: "tenant",
|
|
175
|
+
name: "tenant",
|
|
176
|
+
displayName: "Tenant",
|
|
177
|
+
description: "Tenant record (managed by the multi-tenant plugin; slug = tenant id)",
|
|
178
|
+
source: "system",
|
|
179
|
+
schema: anyObject,
|
|
180
|
+
settings: {
|
|
181
|
+
baseGrants: { admin: ["read", "create", "update", "delete", "manage"] },
|
|
182
|
+
maxVersionsPerRoot: 1,
|
|
183
|
+
internal: true
|
|
184
|
+
},
|
|
185
|
+
queryableFields: [
|
|
186
|
+
{ name: "status", kind: "scalar", type: "text", column: "q_tenant_status" },
|
|
187
|
+
{ name: "domain", kind: "scalar", type: "text", column: "q_tenant_domain" }
|
|
188
|
+
]
|
|
189
|
+
});
|
|
190
|
+
await registry.register({
|
|
191
|
+
id: "user_profile",
|
|
192
|
+
name: "user_profile",
|
|
193
|
+
displayName: "User Profile",
|
|
194
|
+
description: "Per-user profile record (auth-owned; one document per user, slug = userId)",
|
|
195
|
+
source: "system",
|
|
196
|
+
isAuth: true,
|
|
197
|
+
schema: anyObject,
|
|
198
|
+
settings: {
|
|
199
|
+
// Hidden from the content admin surfaces; a single mutable record (no version history).
|
|
200
|
+
internal: true,
|
|
201
|
+
maxVersionsPerRoot: 1,
|
|
202
|
+
pii: true,
|
|
203
|
+
baseGrants: { admin: ["read", "create", "update", "delete", "manage"] }
|
|
204
|
+
},
|
|
205
|
+
queryableFields: []
|
|
206
|
+
});
|
|
207
|
+
await registry.register({
|
|
208
|
+
id: "media_asset",
|
|
209
|
+
name: "media_asset",
|
|
210
|
+
displayName: "Media Asset",
|
|
211
|
+
description: "Uploaded media file metadata (managed via the media library; backs an R2 object)",
|
|
212
|
+
source: "system",
|
|
213
|
+
schema: anyObject,
|
|
214
|
+
settings: {
|
|
215
|
+
internal: true,
|
|
216
|
+
maxVersionsPerRoot: 5,
|
|
217
|
+
baseGrants: {
|
|
218
|
+
admin: ["read", "create", "update", "delete", "manage"],
|
|
219
|
+
editor: ["read", "create", "update"],
|
|
220
|
+
author: ["read", "create"],
|
|
221
|
+
viewer: ["read"]
|
|
222
|
+
}
|
|
223
|
+
},
|
|
224
|
+
queryableFields: [
|
|
225
|
+
{ name: "mimeType", kind: "scalar", type: "text", column: "q_media_mime" },
|
|
226
|
+
{ name: "folder", kind: "scalar", type: "text", column: "q_media_folder" },
|
|
227
|
+
{ name: "size", kind: "scalar", type: "integer", column: "q_media_size" },
|
|
228
|
+
{ name: "tags", kind: "facet", type: "text" }
|
|
229
|
+
]
|
|
230
|
+
});
|
|
231
|
+
await registry.register({
|
|
232
|
+
id: "plugin_activity",
|
|
233
|
+
name: "plugin_activity",
|
|
234
|
+
displayName: "Plugin Activity",
|
|
235
|
+
description: "Plugin lifecycle event log (installed/activated/deactivated/settings_updated/error)",
|
|
236
|
+
source: "system",
|
|
237
|
+
schema: anyObject,
|
|
238
|
+
settings: {
|
|
239
|
+
internal: true,
|
|
240
|
+
maxVersionsPerRoot: 1,
|
|
241
|
+
baseGrants: { admin: ["read", "create", "manage"] }
|
|
242
|
+
},
|
|
243
|
+
queryableFields: [
|
|
244
|
+
{ name: "pluginId", kind: "scalar", type: "text", column: "q_plugin_activity_plugin_id" },
|
|
245
|
+
{ name: "action", kind: "scalar", type: "text", column: "q_plugin_activity_action" }
|
|
246
|
+
]
|
|
247
|
+
});
|
|
248
|
+
await registry.register({
|
|
249
|
+
id: "security_event",
|
|
250
|
+
name: "security_event",
|
|
251
|
+
displayName: "Security Event",
|
|
252
|
+
description: "Security audit event (login attempts, lockouts, suspicious activity)",
|
|
253
|
+
source: "system",
|
|
254
|
+
schema: anyObject,
|
|
255
|
+
settings: {
|
|
256
|
+
internal: true,
|
|
257
|
+
maxVersionsPerRoot: 1,
|
|
258
|
+
baseGrants: { admin: ["read", "create", "manage"] }
|
|
259
|
+
},
|
|
260
|
+
queryableFields: [
|
|
261
|
+
{ name: "eventType", kind: "scalar", type: "text", column: "q_sa_event_type" },
|
|
262
|
+
{ name: "severity", kind: "scalar", type: "text", column: "q_sa_severity" },
|
|
263
|
+
{ name: "userId", kind: "scalar", type: "text", column: "q_sa_user_id" },
|
|
264
|
+
{ name: "email", kind: "scalar", type: "text", column: "q_sa_email" },
|
|
265
|
+
{ name: "ipAddress", kind: "scalar", type: "text", column: "q_sa_ip_address" },
|
|
266
|
+
{ name: "blocked", kind: "scalar", type: "integer", column: "q_sa_blocked" }
|
|
267
|
+
]
|
|
268
|
+
});
|
|
269
|
+
await registry.register({
|
|
270
|
+
id: "analytics_event",
|
|
271
|
+
name: "analytics_event",
|
|
272
|
+
displayName: "Analytics Event",
|
|
273
|
+
description: "Tracked analytics event (page view, user action, custom event)",
|
|
274
|
+
source: "system",
|
|
275
|
+
schema: anyObject,
|
|
276
|
+
settings: {
|
|
277
|
+
internal: true,
|
|
278
|
+
maxVersionsPerRoot: 1,
|
|
279
|
+
baseGrants: { admin: ["read", "create", "manage"] }
|
|
280
|
+
},
|
|
281
|
+
queryableFields: [
|
|
282
|
+
{ name: "event", kind: "scalar", type: "text", column: "q_evt_event" },
|
|
283
|
+
{ name: "category", kind: "scalar", type: "text", column: "q_evt_category" },
|
|
284
|
+
{ name: "userId", kind: "scalar", type: "text", column: "q_evt_user_id" },
|
|
285
|
+
{ name: "sessionId", kind: "scalar", type: "text", column: "q_evt_session_id" },
|
|
286
|
+
{ name: "path", kind: "scalar", type: "text", column: "q_evt_path" }
|
|
287
|
+
]
|
|
288
|
+
});
|
|
289
|
+
await registry.register({
|
|
290
|
+
id: "media_asset",
|
|
291
|
+
name: "media_asset",
|
|
292
|
+
displayName: "Media Asset",
|
|
293
|
+
description: "Media file metadata (R2 object key + intrinsic properties; URL derived at read time)",
|
|
294
|
+
source: "system",
|
|
295
|
+
schema: anyObject,
|
|
296
|
+
settings: {
|
|
297
|
+
baseGrants: { public: ["read"], admin: ["read", "create", "update", "delete", "publish", "manage"], editor: ["read", "create", "update"] },
|
|
298
|
+
maxVersionsPerRoot: 5
|
|
299
|
+
},
|
|
300
|
+
queryableFields: [
|
|
301
|
+
{ name: "mimeType", kind: "scalar", type: "text", column: "q_media_mime" },
|
|
302
|
+
{ name: "folder", kind: "scalar", type: "text", column: "q_media_folder" },
|
|
303
|
+
{ name: "size", kind: "scalar", type: "integer", column: "q_media_size" },
|
|
304
|
+
{ name: "tags", kind: "facet", type: "text" }
|
|
305
|
+
]
|
|
306
|
+
});
|
|
307
|
+
for (const [id, displayName, description] of [
|
|
308
|
+
["rbac_role", "RBAC Role", "Role record with embedded grants (auth-owned)"],
|
|
309
|
+
["rbac_verb", "RBAC Verb", "Permission verb (auth-owned)"],
|
|
310
|
+
["rbac_user_roles", "RBAC User Roles", "Per-user role assignments (auth-owned; slug = userId)"]
|
|
311
|
+
]) {
|
|
312
|
+
await registry.register({
|
|
313
|
+
id,
|
|
314
|
+
name: id,
|
|
315
|
+
displayName,
|
|
316
|
+
description,
|
|
317
|
+
source: "system",
|
|
318
|
+
isAuth: true,
|
|
319
|
+
schema: anyObject,
|
|
320
|
+
settings: {
|
|
321
|
+
internal: true,
|
|
322
|
+
maxVersionsPerRoot: 1,
|
|
323
|
+
baseGrants: { admin: ["read", "create", "update", "delete", "manage"] }
|
|
324
|
+
},
|
|
325
|
+
queryableFields: []
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
async function autoRegisterCollectionDocumentTypes(db) {
|
|
330
|
+
const registry = new DocumentTypeRegistry(db);
|
|
331
|
+
const collections = getCollectionRegistry().listActive();
|
|
332
|
+
const registered = [];
|
|
333
|
+
for (const collection of collections) {
|
|
334
|
+
if (collection.internal) continue;
|
|
335
|
+
if (collection.name === "blog_post") continue;
|
|
336
|
+
try {
|
|
337
|
+
await registry.register({
|
|
338
|
+
id: collection.name,
|
|
339
|
+
name: collection.name,
|
|
340
|
+
displayName: collection.displayName,
|
|
341
|
+
description: collection.description,
|
|
342
|
+
source: "system",
|
|
343
|
+
schema: anyObject,
|
|
344
|
+
settings: {
|
|
345
|
+
baseGrants: {
|
|
346
|
+
public: ["read"],
|
|
347
|
+
admin: ["read", "create", "update", "delete", "publish", "manage"],
|
|
348
|
+
editor: ["read", "create", "update", "publish"],
|
|
349
|
+
viewer: ["read"]
|
|
350
|
+
},
|
|
351
|
+
maxVersionsPerRoot: 50,
|
|
352
|
+
...collection.versioning ? { versioning: true } : {}
|
|
353
|
+
},
|
|
354
|
+
queryableFields: []
|
|
355
|
+
});
|
|
356
|
+
registered.push(collection.name);
|
|
357
|
+
} catch (error) {
|
|
358
|
+
console.error(`[document-types-seed] Failed to register collection "${collection.name}":`, error);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
return registered;
|
|
362
|
+
}
|
|
363
|
+
|
|
7
364
|
// src/middleware/bootstrap.ts
|
|
365
|
+
init_admin_layout_catalyst_template();
|
|
8
366
|
var bootstrapComplete = false;
|
|
9
367
|
function verifySecurityConfig(env) {
|
|
10
368
|
const warnings = [];
|
|
@@ -45,6 +403,9 @@ function verifySecurityConfig(env) {
|
|
|
45
403
|
}
|
|
46
404
|
function bootstrapMiddleware(config = {}) {
|
|
47
405
|
return async (c, next) => {
|
|
406
|
+
if (hasHookSystem()) {
|
|
407
|
+
c.set("hookSystem", getHookSystem());
|
|
408
|
+
}
|
|
48
409
|
if (bootstrapComplete) {
|
|
49
410
|
return next();
|
|
50
411
|
}
|
|
@@ -52,22 +413,54 @@ function bootstrapMiddleware(config = {}) {
|
|
|
52
413
|
if (path.startsWith("/images/") || path.startsWith("/assets/") || path === "/health" || path.endsWith(".js") || path.endsWith(".css") || path.endsWith(".png") || path.endsWith(".jpg") || path.endsWith(".ico")) {
|
|
53
414
|
return next();
|
|
54
415
|
}
|
|
416
|
+
const host = c.req.header("host") || "";
|
|
417
|
+
const isLocalhost = host.includes("localhost") || host.includes("127.0.0.1");
|
|
418
|
+
const gitBranch = c.env.GIT_BRANCH;
|
|
419
|
+
setBranchLabel(isLocalhost && gitBranch ? gitBranch : void 0);
|
|
55
420
|
try {
|
|
56
421
|
console.log("[Bootstrap] Starting system initialization...");
|
|
57
|
-
console.log("[Bootstrap]
|
|
422
|
+
console.log("[Bootstrap] Checking schema compatibility...");
|
|
58
423
|
const migrationService = new MigrationService(c.env.DB);
|
|
59
|
-
await migrationService.
|
|
60
|
-
console.log("[Bootstrap] Syncing collection configurations...");
|
|
424
|
+
await migrationService.ensureSchemaCompatibility();
|
|
61
425
|
try {
|
|
62
|
-
|
|
426
|
+
const kv = c.env.CACHE_KV;
|
|
427
|
+
if (kv) {
|
|
428
|
+
const { setGlobalKVNamespace } = await import('./cache-DDARE4QE.js');
|
|
429
|
+
setGlobalKVNamespace(kv);
|
|
430
|
+
}
|
|
63
431
|
} catch (error) {
|
|
64
|
-
console.error("[Bootstrap] Error
|
|
432
|
+
console.error("[Bootstrap] Error wiring CACHE_KV namespace:", error);
|
|
65
433
|
}
|
|
66
|
-
console.log("[Bootstrap]
|
|
434
|
+
console.log("[Bootstrap] Populating collection registry...");
|
|
67
435
|
try {
|
|
68
|
-
await
|
|
436
|
+
const configs = await loadCollectionConfigs();
|
|
437
|
+
getCollectionRegistry().register(configs);
|
|
438
|
+
console.log(`[Bootstrap] Registry populated with ${configs.length} collection(s)`);
|
|
69
439
|
} catch (error) {
|
|
70
|
-
console.error("[Bootstrap] Error
|
|
440
|
+
console.error("[Bootstrap] Error populating collection registry:", error);
|
|
441
|
+
}
|
|
442
|
+
console.log("[Bootstrap] Registering document types...");
|
|
443
|
+
try {
|
|
444
|
+
await bootstrapDocumentTypes(c.env.DB);
|
|
445
|
+
} catch (error) {
|
|
446
|
+
console.error("[Bootstrap] Error registering document types:", error);
|
|
447
|
+
}
|
|
448
|
+
try {
|
|
449
|
+
await repairMissingCredentialAccounts(c.env.DB);
|
|
450
|
+
} catch (error) {
|
|
451
|
+
console.error("[Bootstrap] Error repairing credential accounts:", error);
|
|
452
|
+
}
|
|
453
|
+
try {
|
|
454
|
+
const { RbacService: RbacService2 } = await import('./rbac-O73MFKDA.js');
|
|
455
|
+
await new RbacService2(c.env.DB, c.env.CACHE_KV).ensureSystemRbacSeed();
|
|
456
|
+
} catch (error) {
|
|
457
|
+
console.error("[Bootstrap] Error seeding RBAC documents:", error);
|
|
458
|
+
}
|
|
459
|
+
try {
|
|
460
|
+
const auto = await autoRegisterCollectionDocumentTypes(c.env.DB);
|
|
461
|
+
if (auto.length) console.log(`[Bootstrap] Document-backed collections registered: ${auto.join(", ")}`);
|
|
462
|
+
} catch (error) {
|
|
463
|
+
console.error("[Bootstrap] Error auto-registering collection document types:", error);
|
|
71
464
|
}
|
|
72
465
|
if (!config.plugins?.disableAll) {
|
|
73
466
|
console.log("[Bootstrap] Bootstrapping core plugins...");
|
|
@@ -81,6 +474,52 @@ function bootstrapMiddleware(config = {}) {
|
|
|
81
474
|
}
|
|
82
475
|
bootstrapComplete = true;
|
|
83
476
|
console.log("[Bootstrap] System initialization completed");
|
|
477
|
+
try {
|
|
478
|
+
const registry = getCollectionRegistry();
|
|
479
|
+
const collections = registry.listActive();
|
|
480
|
+
const countResult = await c.env.DB.prepare(
|
|
481
|
+
`SELECT type_id, COUNT(*) AS cnt FROM documents
|
|
482
|
+
WHERE is_current_draft = 1 AND deleted_at IS NULL GROUP BY type_id`
|
|
483
|
+
).all();
|
|
484
|
+
const countMap = {};
|
|
485
|
+
let docTotal = 0;
|
|
486
|
+
for (const row of countResult.results ?? []) {
|
|
487
|
+
countMap[row.type_id] = row.cnt;
|
|
488
|
+
docTotal += row.cnt;
|
|
489
|
+
}
|
|
490
|
+
const fieldTypeHistogram = {};
|
|
491
|
+
for (const col of collections) {
|
|
492
|
+
const props = col.schema?.properties ?? {};
|
|
493
|
+
for (const field of Object.values(props)) {
|
|
494
|
+
const ft = field?.type ?? "unknown";
|
|
495
|
+
fieldTypeHistogram[ft] = (fieldTypeHistogram[ft] ?? 0) + 1;
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
const activePlugins = (config.plugins?.register ?? []).map((p) => p.name ?? "unknown");
|
|
499
|
+
let installationId = "unknown";
|
|
500
|
+
try {
|
|
501
|
+
const kv = c.env.KV;
|
|
502
|
+
if (kv) {
|
|
503
|
+
installationId = await kv.get("_sonicjs_installation_id") ?? "";
|
|
504
|
+
if (!installationId) {
|
|
505
|
+
installationId = crypto.randomUUID();
|
|
506
|
+
await kv.put("_sonicjs_installation_id", installationId);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
} catch {
|
|
510
|
+
}
|
|
511
|
+
const telemetry = getTelemetryService();
|
|
512
|
+
await telemetry.trackProjectSnapshot({
|
|
513
|
+
installation_id: installationId,
|
|
514
|
+
collection_names: collections.map((c2) => c2.name),
|
|
515
|
+
collection_counts: countMap,
|
|
516
|
+
active_plugins: activePlugins,
|
|
517
|
+
field_type_histogram: fieldTypeHistogram,
|
|
518
|
+
doc_total: docTotal,
|
|
519
|
+
sonicjs_version: c.env.SONICJS_VERSION ?? "unknown"
|
|
520
|
+
});
|
|
521
|
+
} catch {
|
|
522
|
+
}
|
|
84
523
|
} catch (error) {
|
|
85
524
|
console.error("[Bootstrap] Error during system initialization:", error);
|
|
86
525
|
}
|
|
@@ -88,6 +527,27 @@ function bootstrapMiddleware(config = {}) {
|
|
|
88
527
|
return next();
|
|
89
528
|
};
|
|
90
529
|
}
|
|
530
|
+
async function repairMissingCredentialAccounts(db) {
|
|
531
|
+
const { results } = await db.prepare(`
|
|
532
|
+
SELECT u.id, u.password_hash
|
|
533
|
+
FROM auth_user u
|
|
534
|
+
WHERE u.password_hash IS NOT NULL AND u.password_hash != ''
|
|
535
|
+
AND NOT EXISTS (
|
|
536
|
+
SELECT 1 FROM auth_account a
|
|
537
|
+
WHERE a.user_id = u.id AND a.provider_id = 'credential'
|
|
538
|
+
)
|
|
539
|
+
`).all();
|
|
540
|
+
if (!results.length) return;
|
|
541
|
+
console.log(`[Bootstrap] Repairing ${results.length} user(s) missing credential auth_account rows`);
|
|
542
|
+
const nowSec = Math.floor(Date.now() / 1e3);
|
|
543
|
+
for (const user of results) {
|
|
544
|
+
await db.prepare(`
|
|
545
|
+
INSERT OR IGNORE INTO auth_account (id, user_id, account_id, provider_id, password, created_at, updated_at)
|
|
546
|
+
VALUES (?, ?, ?, 'credential', ?, ?, ?)
|
|
547
|
+
`).bind(`cred-${user.id}`, user.id, user.id, user.password_hash, nowSec, nowSec).run();
|
|
548
|
+
}
|
|
549
|
+
console.log(`[Bootstrap] Credential account repair complete (${results.length} repaired)`);
|
|
550
|
+
}
|
|
91
551
|
var JWT_SECRET_FALLBACK = "your-super-secret-jwt-key-change-in-production";
|
|
92
552
|
var DEFAULT_JWT_EXPIRES_IN_SECONDS = 60 * 60 * 24 * 30;
|
|
93
553
|
function parseDuration(input) {
|
|
@@ -119,14 +579,10 @@ async function getJwtExpirySecondsFromDb(db, env) {
|
|
|
119
579
|
if (envParsed) return envParsed;
|
|
120
580
|
if (db) {
|
|
121
581
|
try {
|
|
122
|
-
const row = await db.prepare("SELECT
|
|
123
|
-
if (row?.
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
stored = JSON.parse(row.value);
|
|
127
|
-
} catch {
|
|
128
|
-
}
|
|
129
|
-
const parsed = parseDuration(stored);
|
|
582
|
+
const row = await db.prepare("SELECT data FROM documents WHERE type_id = 'site_settings' AND slug = 'security' AND tenant_id = 'default' AND is_current_draft = 1 AND deleted_at IS NULL").first();
|
|
583
|
+
if (row?.data) {
|
|
584
|
+
const data = JSON.parse(row.data);
|
|
585
|
+
const parsed = parseDuration(data.jwtExpiresIn);
|
|
130
586
|
if (parsed) return parsed;
|
|
131
587
|
}
|
|
132
588
|
} catch (err) {
|
|
@@ -141,14 +597,10 @@ async function getJwtRefreshGraceSecondsFromDb(db, env) {
|
|
|
141
597
|
if (envParsed) return envParsed;
|
|
142
598
|
if (db) {
|
|
143
599
|
try {
|
|
144
|
-
const row = await db.prepare("SELECT
|
|
145
|
-
if (row?.
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
stored = JSON.parse(row.value);
|
|
149
|
-
} catch {
|
|
150
|
-
}
|
|
151
|
-
const parsed = parseDuration(stored);
|
|
600
|
+
const row = await db.prepare("SELECT data FROM documents WHERE type_id = 'site_settings' AND slug = 'security' AND tenant_id = 'default' AND is_current_draft = 1 AND deleted_at IS NULL").first();
|
|
601
|
+
if (row?.data) {
|
|
602
|
+
const data = JSON.parse(row.data);
|
|
603
|
+
const parsed = parseDuration(data.jwtRefreshGraceSeconds?.toString());
|
|
152
604
|
if (parsed) return parsed;
|
|
153
605
|
}
|
|
154
606
|
} catch (err) {
|
|
@@ -374,52 +826,15 @@ var AuthManager = class _AuthManager {
|
|
|
374
826
|
};
|
|
375
827
|
var requireAuth = () => {
|
|
376
828
|
return async (c, next) => {
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
if (!token) {
|
|
380
|
-
token = getCookie(c, "auth_token");
|
|
381
|
-
}
|
|
382
|
-
if (!token) {
|
|
383
|
-
const acceptHeader = c.req.header("Accept") || "";
|
|
384
|
-
if (acceptHeader.includes("text/html")) {
|
|
385
|
-
return c.redirect("/auth/login?error=Please login to access the admin area");
|
|
386
|
-
}
|
|
387
|
-
return c.json({ error: "Authentication required" }, 401);
|
|
388
|
-
}
|
|
389
|
-
const kv = c.env?.KV;
|
|
390
|
-
let payload = null;
|
|
391
|
-
if (kv) {
|
|
392
|
-
const cacheKey = `auth:${token.substring(0, 20)}`;
|
|
393
|
-
const cached = await kv.get(cacheKey, "json");
|
|
394
|
-
if (cached) {
|
|
395
|
-
payload = cached;
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
if (!payload) {
|
|
399
|
-
const jwtSecret = c.env?.JWT_SECRET;
|
|
400
|
-
payload = await AuthManager.verifyToken(token, jwtSecret);
|
|
401
|
-
if (payload && kv) {
|
|
402
|
-
const cacheKey = `auth:${token.substring(0, 20)}`;
|
|
403
|
-
await kv.put(cacheKey, JSON.stringify(payload), { expirationTtl: 300 });
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
if (!payload) {
|
|
407
|
-
const acceptHeader = c.req.header("Accept") || "";
|
|
408
|
-
if (acceptHeader.includes("text/html")) {
|
|
409
|
-
return c.redirect("/auth/login?error=Your session has expired, please login again");
|
|
410
|
-
}
|
|
411
|
-
return c.json({ error: "Invalid or expired token" }, 401);
|
|
412
|
-
}
|
|
413
|
-
c.set("user", payload);
|
|
414
|
-
return await next();
|
|
415
|
-
} catch (error) {
|
|
416
|
-
console.error("Auth middleware error:", error);
|
|
829
|
+
const user = c.get("user");
|
|
830
|
+
if (!user) {
|
|
417
831
|
const acceptHeader = c.req.header("Accept") || "";
|
|
418
832
|
if (acceptHeader.includes("text/html")) {
|
|
419
|
-
return c.redirect("/auth/login?error=
|
|
833
|
+
return c.redirect("/auth/login?error=Please login to access the admin area");
|
|
420
834
|
}
|
|
421
|
-
return c.json({ error: "Authentication
|
|
835
|
+
return c.json({ error: "Authentication required" }, 401);
|
|
422
836
|
}
|
|
837
|
+
return await next();
|
|
423
838
|
};
|
|
424
839
|
};
|
|
425
840
|
var requireRole = (requiredRole) => {
|
|
@@ -443,25 +858,36 @@ var requireRole = (requiredRole) => {
|
|
|
443
858
|
return await next();
|
|
444
859
|
};
|
|
445
860
|
};
|
|
446
|
-
var
|
|
861
|
+
var requireRbac = (resource, verb) => {
|
|
447
862
|
return async (c, next) => {
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
863
|
+
const user = c.get("user");
|
|
864
|
+
if (!user) {
|
|
865
|
+
const acceptHeader = c.req.header("Accept") || "";
|
|
866
|
+
if (acceptHeader.includes("text/html")) {
|
|
867
|
+
return c.redirect("/auth/login?error=Please login to access the admin area");
|
|
452
868
|
}
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
869
|
+
return c.json({ error: "Authentication required" }, 401);
|
|
870
|
+
}
|
|
871
|
+
const cachedPerms = c.get("rbacPerms");
|
|
872
|
+
let allowed;
|
|
873
|
+
if (cachedPerms !== void 0) {
|
|
874
|
+
allowed = cachedPerms.includes(`${resource}:${verb}`);
|
|
875
|
+
} else {
|
|
876
|
+
allowed = await new RbacService(c.env.DB).can(user.userId, resource, verb);
|
|
877
|
+
}
|
|
878
|
+
if (!allowed) {
|
|
879
|
+
const acceptHeader = c.req.header("Accept") || "";
|
|
880
|
+
if (acceptHeader.includes("text/html")) {
|
|
881
|
+
return c.redirect("/auth/login?error=You do not have permission to access this area");
|
|
459
882
|
}
|
|
460
|
-
return
|
|
461
|
-
} catch (error) {
|
|
462
|
-
console.error("Optional auth error:", error);
|
|
463
|
-
return await next();
|
|
883
|
+
return c.json({ error: "Insufficient permissions" }, 403);
|
|
464
884
|
}
|
|
885
|
+
return await next();
|
|
886
|
+
};
|
|
887
|
+
};
|
|
888
|
+
var optionalAuth = () => {
|
|
889
|
+
return async (_c, next) => {
|
|
890
|
+
return await next();
|
|
465
891
|
};
|
|
466
892
|
};
|
|
467
893
|
|
|
@@ -529,11 +955,17 @@ var DEFAULT_EXEMPT_PATHS = [
|
|
|
529
955
|
"/auth/login",
|
|
530
956
|
"/auth/register",
|
|
531
957
|
"/auth/seed-admin",
|
|
958
|
+
"/test-seed-defaults",
|
|
959
|
+
"/test-cleanup",
|
|
532
960
|
"/auth/accept-invitation",
|
|
533
961
|
"/auth/reset-password",
|
|
534
962
|
"/auth/request-password-reset",
|
|
535
963
|
"/auth/otp",
|
|
536
964
|
"/auth/magic-link",
|
|
965
|
+
"/auth/sign-out",
|
|
966
|
+
"/auth/sign-in",
|
|
967
|
+
"/auth/sign-up",
|
|
968
|
+
"/auth/get-session",
|
|
537
969
|
"/auth/verify",
|
|
538
970
|
"/api/stripe/webhook",
|
|
539
971
|
"/api/events"
|
|
@@ -697,6 +1129,45 @@ var securityHeadersMiddleware = () => {
|
|
|
697
1129
|
};
|
|
698
1130
|
};
|
|
699
1131
|
|
|
1132
|
+
// src/middleware/plugin-middleware.ts
|
|
1133
|
+
async function isPluginActive(db, pluginId) {
|
|
1134
|
+
try {
|
|
1135
|
+
const docResult = await db.prepare(
|
|
1136
|
+
`SELECT json_extract(data, '$.status') as status FROM documents
|
|
1137
|
+
WHERE slug = ? AND type_id = 'plugin' AND tenant_id = 'default'
|
|
1138
|
+
AND is_current_draft = 1 AND deleted_at IS NULL`
|
|
1139
|
+
).bind(pluginId).first();
|
|
1140
|
+
return docResult?.status === "active";
|
|
1141
|
+
} catch (error) {
|
|
1142
|
+
console.error(`[isPluginActive] Error checking plugin status for ${pluginId}:`, error);
|
|
1143
|
+
return false;
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
async function requireActivePlugin(db, pluginId) {
|
|
1147
|
+
const isActive = await isPluginActive(db, pluginId);
|
|
1148
|
+
if (!isActive) {
|
|
1149
|
+
throw new Error(`Plugin '${pluginId}' is required but is not active`);
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
async function requireActivePlugins(db, pluginIds) {
|
|
1153
|
+
for (const pluginId of pluginIds) {
|
|
1154
|
+
await requireActivePlugin(db, pluginId);
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
async function getActivePlugins(db) {
|
|
1158
|
+
try {
|
|
1159
|
+
const { results } = await db.prepare(
|
|
1160
|
+
`SELECT slug as id, json_extract(data, '$.status') as status, data FROM documents
|
|
1161
|
+
WHERE type_id = 'plugin' AND tenant_id = 'default'
|
|
1162
|
+
AND q_plugin_status = 'active' AND is_current_draft = 1 AND deleted_at IS NULL`
|
|
1163
|
+
).all();
|
|
1164
|
+
return results || [];
|
|
1165
|
+
} catch (error) {
|
|
1166
|
+
console.error("[getActivePlugins] Error fetching active plugins:", error);
|
|
1167
|
+
return [];
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
|
|
700
1171
|
// src/middleware/index.ts
|
|
701
1172
|
var loggingMiddleware = () => async (_c, next) => await next();
|
|
702
1173
|
var detailedLoggingMiddleware = () => async (_c, next) => await next();
|
|
@@ -709,11 +1180,7 @@ var requirePermission = () => async (_c, next) => await next();
|
|
|
709
1180
|
var requireAnyPermission = () => async (_c, next) => await next();
|
|
710
1181
|
var logActivity = () => {
|
|
711
1182
|
};
|
|
712
|
-
var requireActivePlugin = () => async (_c, next) => await next();
|
|
713
|
-
var requireActivePlugins = () => async (_c, next) => await next();
|
|
714
|
-
var getActivePlugins = () => [];
|
|
715
|
-
var isPluginActive = () => false;
|
|
716
1183
|
|
|
717
|
-
export { AuthManager, PermissionManager, bootstrapMiddleware, cacheHeaders, compressionMiddleware, csrfProtection, detailedLoggingMiddleware, generateCsrfToken, getActivePlugins, getJwtExpirySeconds, getJwtExpirySecondsFromDb, getJwtRefreshGraceSecondsFromDb, isPluginActive, logActivity, loggingMiddleware, metricsMiddleware, optionalAuth, performanceLoggingMiddleware, rateLimit, requireActivePlugin, requireActivePlugins, requireAnyPermission, requireAuth, requirePermission, requireRole, securityHeadersMiddleware, securityLoggingMiddleware, validateCsrfToken, verifySecurityConfig };
|
|
718
|
-
//# sourceMappingURL=chunk-
|
|
719
|
-
//# sourceMappingURL=chunk-
|
|
1184
|
+
export { AuthManager, DocumentTypeRegistry, PermissionManager, bootstrapDocumentTypes, bootstrapMiddleware, cacheHeaders, compressionMiddleware, csrfProtection, detailedLoggingMiddleware, generateCsrfToken, getActivePlugins, getJwtExpirySeconds, getJwtExpirySecondsFromDb, getJwtRefreshGraceSecondsFromDb, isPluginActive, logActivity, loggingMiddleware, metricsMiddleware, optionalAuth, performanceLoggingMiddleware, rateLimit, requireActivePlugin, requireActivePlugins, requireAnyPermission, requireAuth, requirePermission, requireRbac, requireRole, securityHeadersMiddleware, securityLoggingMiddleware, validateCsrfToken, verifySecurityConfig };
|
|
1185
|
+
//# sourceMappingURL=chunk-3PU4WVU6.js.map
|
|
1186
|
+
//# sourceMappingURL=chunk-3PU4WVU6.js.map
|