@beechcms/api 0.6.7 → 0.8.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.
- package/assets/dashboard/0auth_mcp.svg +1 -0
- package/assets/dashboard/assets/{chart-D_uST30B.js → chart-CYgKoF6U.js} +6 -6
- package/assets/dashboard/assets/dist-DHabpZqA.js +140 -0
- package/assets/dashboard/assets/index-BZMSpYrl.js +3613 -0
- package/assets/dashboard/assets/index-Dex2YZcC.css +1 -0
- package/assets/dashboard/assets/json-code-editor-DtZpKDXm.js +12 -0
- package/assets/dashboard/assets/pie-chart-recharts-C7WAhcCk.js +1 -0
- package/assets/dashboard/assets/richtext-render-x0TT0116.js +258 -0
- package/assets/dashboard/assets/timeseries-chart-recharts-B9RquiY6.js +1 -0
- package/assets/dashboard/assets/w3c-keyname-BOAvb0qz.js +1 -0
- package/assets/dashboard/index.html +4 -2
- package/dist/auth/auth.app.d.ts +13 -0
- package/dist/auth/index.d.ts +6 -0
- package/dist/factory.d.ts +14 -1
- package/dist/features/oauth/authorization-request.d.ts +127 -0
- package/dist/features/oauth/authorize.d.ts +97 -0
- package/dist/features/oauth/consents.d.ts +75 -0
- package/dist/features/oauth/constants.d.ts +48 -0
- package/dist/features/oauth/index.d.ts +31 -0
- package/dist/features/oauth/revoke.d.ts +29 -0
- package/dist/features/oauth/token-issuance.d.ts +49 -0
- package/dist/features/oauth/token.d.ts +38 -0
- package/dist/features/search/constants.d.ts +43 -0
- package/dist/features/search/handlers/embed.d.ts +31 -0
- package/dist/features/search/handlers/full-text-search.d.ts +28 -0
- package/dist/features/search/index.d.ts +20 -0
- package/dist/features/search/jobs/semantic-search.hooks.d.ts +21 -0
- package/dist/features/search/jobs/semantic-search.worker.d.ts +101 -0
- package/dist/features/search/public-search.router.d.ts +15 -0
- package/dist/features/search/search.d.ts +14 -6
- package/dist/features/search/semantic-search.hooks.d.ts +2 -0
- package/dist/features/search/semantic-search.worker.d.ts +21 -0
- package/dist/features/search/types.d.ts +100 -0
- package/dist/features/search/utils/search-utils.d.ts +56 -0
- package/dist/features/seeds/seeds.destructive.d.ts +6 -0
- package/dist/features/seeds/seeds.handler.d.ts +14 -0
- package/dist/features/seeds/seeds.helpers.d.ts +118 -0
- package/dist/features/seeds/seeds.mcp.d.ts +37 -0
- package/dist/features/upload/index.d.ts +2 -2
- package/dist/index.js +3544 -1368
- package/dist/middleware/auth.middleware.d.ts +34 -4
- package/dist/middleware/oauth-scope.middleware.d.ts +60 -0
- package/dist/middleware/rate-limit.middleware.d.ts +4 -2
- package/dist/middleware/repository.middleware.d.ts +9 -1
- package/dist/public/api-key-middleware.d.ts +0 -4
- package/dist/public/public-add.d.ts +1 -1
- package/dist/rate-limit/in-memory-rate-limiter.d.ts +1 -8
- package/dist/shared/db/repositories/content.repository.d1.d.ts +4 -2
- package/dist/shared/db/repositories/d1-oauth-authorization-code.repository.d.ts +9 -0
- package/dist/shared/db/repositories/d1-oauth-client.repository.d.ts +6 -0
- package/dist/shared/db/repositories/d1-oauth-consent.repository.d.ts +10 -0
- package/dist/shared/db/repositories/d1-oauth-token.repository.d.ts +12 -0
- package/dist/shared/db/repositories/d1-search.query.d.ts +54 -0
- package/dist/shared/db/repositories/d1-vector.repository.d.ts +11 -0
- package/dist/shared/db/repositories/in-memory-seed.repository.d.ts +2 -1
- package/dist/shared/db/repositories/seed.repository.d1.d.ts +3 -1
- package/dist/shared/db/repositories/time-trap-token.repository.d1.d.ts +7 -0
- package/dist/shared/storage/factory.d.ts +84 -4
- package/dist/shared/storage/r2-bucket.d.ts +127 -0
- package/dist/shared/storage/s3-bucket.d.ts +104 -10
- package/dist/shared/storage/upload.d.ts +33 -5
- package/dist/shared/utils/dual-key-rate-limiter.d.ts +21 -0
- package/dist/shared/utils/media-utils.d.ts +3 -3
- package/dist/shared/utils/opaque-token.d.ts +13 -0
- package/dist/types.d.ts +49 -1
- package/migrations/0000_v040_base.sql +184 -1
- package/migrations/_archive/0000_schema_init.sql +257 -0
- package/migrations/_archive/0001_init.sql +25 -0
- package/migrations/_archive/0002_seed_admin.sql +10 -0
- package/migrations/_archive/0003_refresh_tokens.sql +17 -0
- package/migrations/_archive/0004_seed_projects.sql +18 -0
- package/migrations/_archive/0005_update_projects.sql +56 -0
- package/migrations/_archive/0006_add_slug_and_unique_index.sql +7 -0
- package/migrations/_archive/0007_cleanup_test_data.sql +4 -0
- package/migrations/_archive/0008_seed_content_entries.sql +104 -0
- package/migrations/_archive/0009_public_idempotency.sql +11 -0
- package/migrations/_archive/0010_seed_real_data.sql +31 -0
- package/migrations/_archive/0010_testsite_data.sql +31 -0
- package/migrations/_archive/0011_analytics.sql +10 -0
- package/migrations/_archive/0012_seed_analytics.sql +17 -0
- package/migrations/_archive/0013_system_stats.sql +8 -0
- package/migrations/_archive/0014_activity_logs.sql +15 -0
- package/migrations/_archive/0015_notifications.sql +12 -0
- package/migrations/_archive/0016_fts5_global_search.sql +81 -0
- package/migrations/_archive/0017_seed_clienti.sql +90 -0
- package/migrations/_archive/0018_draft_data.sql +3 -0
- package/migrations/_archive/0019_drop_fts_triggers.sql +7 -0
- package/migrations/_archive/0020_composite_indexes.sql +15 -0
- package/migrations/_archive/0021_media_objects.sql +15 -0
- package/migrations/_archive/0022_analytics_seed.sql +23 -0
- package/migrations/_archive/0023_user_profile.sql +4 -0
- package/migrations/_archive/0024_activity_user_name.sql +3 -0
- package/migrations/_archive/0025_password_reset_tokens.sql +11 -0
- package/migrations/_archive/0026_remove_dev_admin.sql +4 -0
- package/migrations/_archive/0027_v040_doctype_architecture.sql +51 -0
- package/migrations/_archive/0029_fts_all_text_branches.sql +281 -0
- package/migrations/_archive/0031_site_settings.sql +9 -0
- package/migrations/_archive/0032_seeds.sql +28 -0
- package/migrations/_archive/0033_dashboard_layouts.sql +14 -0
- package/migrations/_archive/0034_kanban_foundation.sql +24 -0
- package/migrations/_archive/0035_setup_lock.sql +10 -0
- package/migrations/_archive/0036_notification_type_success.sql +23 -0
- package/migrations/_archive/0037_time_trap_tokens.sql +13 -0
- package/migrations/_archive/0038_oauth_authorization.sql +95 -0
- package/migrations/_archive/0039_oauth_client_beech_mcp.sql +20 -0
- package/package.json +3 -5
- package/assets/dashboard/assets/index-B58kBLrh.css +0 -1
- package/assets/dashboard/assets/index-DjniT5Z9.js +0 -745
- package/assets/dashboard/assets/pie-chart-recharts-CnVomiSi.js +0 -1
- package/assets/dashboard/assets/timeseries-chart-recharts-CTqi8qnV.js +0 -1
- /package/migrations/{0029_automations.sql → _archive/0029_automations.sql} +0 -0
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
-- =============================================================================
|
|
2
|
+
-- Beech CMS — FTS rebuild: index text + richtext branches
|
|
3
|
+
--
|
|
4
|
+
-- Previously only `richtext` branches were indexed. This migration rebuilds
|
|
5
|
+
-- all per-seed FTS5 tables to also include `text` branches (with search:true).
|
|
6
|
+
-- Seeds that had no FTS (team, testimonianze, clienti) get new tables here.
|
|
7
|
+
-- =============================================================================
|
|
8
|
+
|
|
9
|
+
-- ─── articoli ─────────────────────────────────────────────────────────────────
|
|
10
|
+
-- Was: body only. Now: title, body, metaTitle, metaDescription
|
|
11
|
+
|
|
12
|
+
DROP TRIGGER IF EXISTS fts_articoli_insert;
|
|
13
|
+
DROP TRIGGER IF EXISTS fts_articoli_update;
|
|
14
|
+
DROP TRIGGER IF EXISTS fts_articoli_delete;
|
|
15
|
+
DROP TABLE IF EXISTS fts_articoli;
|
|
16
|
+
|
|
17
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS fts_articoli USING fts5(
|
|
18
|
+
entry_id UNINDEXED,
|
|
19
|
+
title,
|
|
20
|
+
body,
|
|
21
|
+
metaTitle,
|
|
22
|
+
metaDescription,
|
|
23
|
+
tokenize = 'unicode61'
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
INSERT INTO fts_articoli(entry_id, title, body, metaTitle, metaDescription)
|
|
27
|
+
SELECT id, title, body, metaTitle, metaDescription FROM content_articoli;
|
|
28
|
+
|
|
29
|
+
CREATE TRIGGER IF NOT EXISTS fts_articoli_insert
|
|
30
|
+
AFTER INSERT ON content_articoli BEGIN
|
|
31
|
+
INSERT INTO fts_articoli(entry_id, title, body, metaTitle, metaDescription)
|
|
32
|
+
VALUES (new.id, new.title, new.body, new.metaTitle, new.metaDescription);
|
|
33
|
+
END;
|
|
34
|
+
|
|
35
|
+
CREATE TRIGGER IF NOT EXISTS fts_articoli_update
|
|
36
|
+
AFTER UPDATE OF title, body, metaTitle, metaDescription ON content_articoli BEGIN
|
|
37
|
+
DELETE FROM fts_articoli WHERE entry_id = old.id;
|
|
38
|
+
INSERT INTO fts_articoli(entry_id, title, body, metaTitle, metaDescription)
|
|
39
|
+
VALUES (new.id, new.title, new.body, new.metaTitle, new.metaDescription);
|
|
40
|
+
END;
|
|
41
|
+
|
|
42
|
+
CREATE TRIGGER IF NOT EXISTS fts_articoli_delete
|
|
43
|
+
AFTER DELETE ON content_articoli BEGIN
|
|
44
|
+
DELETE FROM fts_articoli WHERE entry_id = old.id;
|
|
45
|
+
END;
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
-- ─── prodotti ─────────────────────────────────────────────────────────────────
|
|
49
|
+
-- Was: description only. Now: name, description, metaTitle, metaDescription
|
|
50
|
+
|
|
51
|
+
DROP TRIGGER IF EXISTS fts_prodotti_insert;
|
|
52
|
+
DROP TRIGGER IF EXISTS fts_prodotti_update;
|
|
53
|
+
DROP TRIGGER IF EXISTS fts_prodotti_delete;
|
|
54
|
+
DROP TABLE IF EXISTS fts_prodotti;
|
|
55
|
+
|
|
56
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS fts_prodotti USING fts5(
|
|
57
|
+
entry_id UNINDEXED,
|
|
58
|
+
name,
|
|
59
|
+
description,
|
|
60
|
+
metaTitle,
|
|
61
|
+
metaDescription,
|
|
62
|
+
tokenize = 'unicode61'
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
INSERT INTO fts_prodotti(entry_id, name, description, metaTitle, metaDescription)
|
|
66
|
+
SELECT id, name, description, metaTitle, metaDescription FROM content_prodotti;
|
|
67
|
+
|
|
68
|
+
CREATE TRIGGER IF NOT EXISTS fts_prodotti_insert
|
|
69
|
+
AFTER INSERT ON content_prodotti BEGIN
|
|
70
|
+
INSERT INTO fts_prodotti(entry_id, name, description, metaTitle, metaDescription)
|
|
71
|
+
VALUES (new.id, new.name, new.description, new.metaTitle, new.metaDescription);
|
|
72
|
+
END;
|
|
73
|
+
|
|
74
|
+
CREATE TRIGGER IF NOT EXISTS fts_prodotti_update
|
|
75
|
+
AFTER UPDATE OF name, description, metaTitle, metaDescription ON content_prodotti BEGIN
|
|
76
|
+
DELETE FROM fts_prodotti WHERE entry_id = old.id;
|
|
77
|
+
INSERT INTO fts_prodotti(entry_id, name, description, metaTitle, metaDescription)
|
|
78
|
+
VALUES (new.id, new.name, new.description, new.metaTitle, new.metaDescription);
|
|
79
|
+
END;
|
|
80
|
+
|
|
81
|
+
CREATE TRIGGER IF NOT EXISTS fts_prodotti_delete
|
|
82
|
+
AFTER DELETE ON content_prodotti BEGIN
|
|
83
|
+
DELETE FROM fts_prodotti WHERE entry_id = old.id;
|
|
84
|
+
END;
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
-- ─── team ─────────────────────────────────────────────────────────────────────
|
|
88
|
+
-- Was: no FTS. Now: name, role, bio, linkedIn, metaTitle, metaDescription
|
|
89
|
+
|
|
90
|
+
DROP TRIGGER IF EXISTS fts_team_insert;
|
|
91
|
+
DROP TRIGGER IF EXISTS fts_team_update;
|
|
92
|
+
DROP TRIGGER IF EXISTS fts_team_delete;
|
|
93
|
+
DROP TABLE IF EXISTS fts_team;
|
|
94
|
+
|
|
95
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS fts_team USING fts5(
|
|
96
|
+
entry_id UNINDEXED,
|
|
97
|
+
name,
|
|
98
|
+
role,
|
|
99
|
+
bio,
|
|
100
|
+
linkedIn,
|
|
101
|
+
metaTitle,
|
|
102
|
+
metaDescription,
|
|
103
|
+
tokenize = 'unicode61'
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
INSERT INTO fts_team(entry_id, name, role, bio, linkedIn, metaTitle, metaDescription)
|
|
107
|
+
SELECT id, name, role, bio, linkedIn, metaTitle, metaDescription FROM content_team;
|
|
108
|
+
|
|
109
|
+
CREATE TRIGGER IF NOT EXISTS fts_team_insert
|
|
110
|
+
AFTER INSERT ON content_team BEGIN
|
|
111
|
+
INSERT INTO fts_team(entry_id, name, role, bio, linkedIn, metaTitle, metaDescription)
|
|
112
|
+
VALUES (new.id, new.name, new.role, new.bio, new.linkedIn, new.metaTitle, new.metaDescription);
|
|
113
|
+
END;
|
|
114
|
+
|
|
115
|
+
CREATE TRIGGER IF NOT EXISTS fts_team_update
|
|
116
|
+
AFTER UPDATE OF name, role, bio, linkedIn, metaTitle, metaDescription ON content_team BEGIN
|
|
117
|
+
DELETE FROM fts_team WHERE entry_id = old.id;
|
|
118
|
+
INSERT INTO fts_team(entry_id, name, role, bio, linkedIn, metaTitle, metaDescription)
|
|
119
|
+
VALUES (new.id, new.name, new.role, new.bio, new.linkedIn, new.metaTitle, new.metaDescription);
|
|
120
|
+
END;
|
|
121
|
+
|
|
122
|
+
CREATE TRIGGER IF NOT EXISTS fts_team_delete
|
|
123
|
+
AFTER DELETE ON content_team BEGIN
|
|
124
|
+
DELETE FROM fts_team WHERE entry_id = old.id;
|
|
125
|
+
END;
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
-- ─── testimonianze ────────────────────────────────────────────────────────────
|
|
129
|
+
-- Was: no FTS. Now: author, company, quote, metaTitle, metaDescription
|
|
130
|
+
|
|
131
|
+
DROP TRIGGER IF EXISTS fts_testimonianze_insert;
|
|
132
|
+
DROP TRIGGER IF EXISTS fts_testimonianze_update;
|
|
133
|
+
DROP TRIGGER IF EXISTS fts_testimonianze_delete;
|
|
134
|
+
DROP TABLE IF EXISTS fts_testimonianze;
|
|
135
|
+
|
|
136
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS fts_testimonianze USING fts5(
|
|
137
|
+
entry_id UNINDEXED,
|
|
138
|
+
author,
|
|
139
|
+
company,
|
|
140
|
+
quote,
|
|
141
|
+
metaTitle,
|
|
142
|
+
metaDescription,
|
|
143
|
+
tokenize = 'unicode61'
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
INSERT INTO fts_testimonianze(entry_id, author, company, quote, metaTitle, metaDescription)
|
|
147
|
+
SELECT id, author, company, quote, metaTitle, metaDescription FROM content_testimonianze;
|
|
148
|
+
|
|
149
|
+
CREATE TRIGGER IF NOT EXISTS fts_testimonianze_insert
|
|
150
|
+
AFTER INSERT ON content_testimonianze BEGIN
|
|
151
|
+
INSERT INTO fts_testimonianze(entry_id, author, company, quote, metaTitle, metaDescription)
|
|
152
|
+
VALUES (new.id, new.author, new.company, new.quote, new.metaTitle, new.metaDescription);
|
|
153
|
+
END;
|
|
154
|
+
|
|
155
|
+
CREATE TRIGGER IF NOT EXISTS fts_testimonianze_update
|
|
156
|
+
AFTER UPDATE OF author, company, quote, metaTitle, metaDescription ON content_testimonianze BEGIN
|
|
157
|
+
DELETE FROM fts_testimonianze WHERE entry_id = old.id;
|
|
158
|
+
INSERT INTO fts_testimonianze(entry_id, author, company, quote, metaTitle, metaDescription)
|
|
159
|
+
VALUES (new.id, new.author, new.company, new.quote, new.metaTitle, new.metaDescription);
|
|
160
|
+
END;
|
|
161
|
+
|
|
162
|
+
CREATE TRIGGER IF NOT EXISTS fts_testimonianze_delete
|
|
163
|
+
AFTER DELETE ON content_testimonianze BEGIN
|
|
164
|
+
DELETE FROM fts_testimonianze WHERE entry_id = old.id;
|
|
165
|
+
END;
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
-- ─── pagine ───────────────────────────────────────────────────────────────────
|
|
169
|
+
-- Was: body only. Now: title, body, metaTitle, metaDescription
|
|
170
|
+
|
|
171
|
+
DROP TRIGGER IF EXISTS fts_pagine_insert;
|
|
172
|
+
DROP TRIGGER IF EXISTS fts_pagine_update;
|
|
173
|
+
DROP TRIGGER IF EXISTS fts_pagine_delete;
|
|
174
|
+
DROP TABLE IF EXISTS fts_pagine;
|
|
175
|
+
|
|
176
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS fts_pagine USING fts5(
|
|
177
|
+
entry_id UNINDEXED,
|
|
178
|
+
title,
|
|
179
|
+
body,
|
|
180
|
+
metaTitle,
|
|
181
|
+
metaDescription,
|
|
182
|
+
tokenize = 'unicode61'
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
INSERT INTO fts_pagine(entry_id, title, body, metaTitle, metaDescription)
|
|
186
|
+
SELECT id, title, body, metaTitle, metaDescription FROM content_pagine;
|
|
187
|
+
|
|
188
|
+
CREATE TRIGGER IF NOT EXISTS fts_pagine_insert
|
|
189
|
+
AFTER INSERT ON content_pagine BEGIN
|
|
190
|
+
INSERT INTO fts_pagine(entry_id, title, body, metaTitle, metaDescription)
|
|
191
|
+
VALUES (new.id, new.title, new.body, new.metaTitle, new.metaDescription);
|
|
192
|
+
END;
|
|
193
|
+
|
|
194
|
+
CREATE TRIGGER IF NOT EXISTS fts_pagine_update
|
|
195
|
+
AFTER UPDATE OF title, body, metaTitle, metaDescription ON content_pagine BEGIN
|
|
196
|
+
DELETE FROM fts_pagine WHERE entry_id = old.id;
|
|
197
|
+
INSERT INTO fts_pagine(entry_id, title, body, metaTitle, metaDescription)
|
|
198
|
+
VALUES (new.id, new.title, new.body, new.metaTitle, new.metaDescription);
|
|
199
|
+
END;
|
|
200
|
+
|
|
201
|
+
CREATE TRIGGER IF NOT EXISTS fts_pagine_delete
|
|
202
|
+
AFTER DELETE ON content_pagine BEGIN
|
|
203
|
+
DELETE FROM fts_pagine WHERE entry_id = old.id;
|
|
204
|
+
END;
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
-- ─── clienti ──────────────────────────────────────────────────────────────────
|
|
208
|
+
-- Was: no FTS (no richtext). Now: name, tier, phone (email/passwordHash/internalNote excluded via search:false)
|
|
209
|
+
|
|
210
|
+
DROP TRIGGER IF EXISTS fts_clienti_insert;
|
|
211
|
+
DROP TRIGGER IF EXISTS fts_clienti_update;
|
|
212
|
+
DROP TRIGGER IF EXISTS fts_clienti_delete;
|
|
213
|
+
DROP TABLE IF EXISTS fts_clienti;
|
|
214
|
+
|
|
215
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS fts_clienti USING fts5(
|
|
216
|
+
entry_id UNINDEXED,
|
|
217
|
+
name,
|
|
218
|
+
tier,
|
|
219
|
+
phone,
|
|
220
|
+
tokenize = 'unicode61'
|
|
221
|
+
);
|
|
222
|
+
|
|
223
|
+
INSERT INTO fts_clienti(entry_id, name, tier, phone)
|
|
224
|
+
SELECT id, name, tier, phone FROM content_clienti;
|
|
225
|
+
|
|
226
|
+
CREATE TRIGGER IF NOT EXISTS fts_clienti_insert
|
|
227
|
+
AFTER INSERT ON content_clienti BEGIN
|
|
228
|
+
INSERT INTO fts_clienti(entry_id, name, tier, phone)
|
|
229
|
+
VALUES (new.id, new.name, new.tier, new.phone);
|
|
230
|
+
END;
|
|
231
|
+
|
|
232
|
+
CREATE TRIGGER IF NOT EXISTS fts_clienti_update
|
|
233
|
+
AFTER UPDATE OF name, tier, phone ON content_clienti BEGIN
|
|
234
|
+
DELETE FROM fts_clienti WHERE entry_id = old.id;
|
|
235
|
+
INSERT INTO fts_clienti(entry_id, name, tier, phone)
|
|
236
|
+
VALUES (new.id, new.name, new.tier, new.phone);
|
|
237
|
+
END;
|
|
238
|
+
|
|
239
|
+
CREATE TRIGGER IF NOT EXISTS fts_clienti_delete
|
|
240
|
+
AFTER DELETE ON content_clienti BEGIN
|
|
241
|
+
DELETE FROM fts_clienti WHERE entry_id = old.id;
|
|
242
|
+
END;
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
-- ─── messaggi ─────────────────────────────────────────────────────────────────
|
|
246
|
+
-- Was: message (richtext) only. Now: name, email, subject, message
|
|
247
|
+
|
|
248
|
+
DROP TRIGGER IF EXISTS fts_messaggi_insert;
|
|
249
|
+
DROP TRIGGER IF EXISTS fts_messaggi_update;
|
|
250
|
+
DROP TRIGGER IF EXISTS fts_messaggi_delete;
|
|
251
|
+
DROP TABLE IF EXISTS fts_messaggi;
|
|
252
|
+
|
|
253
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS fts_messaggi USING fts5(
|
|
254
|
+
entry_id UNINDEXED,
|
|
255
|
+
name,
|
|
256
|
+
email,
|
|
257
|
+
subject,
|
|
258
|
+
message,
|
|
259
|
+
tokenize = 'unicode61'
|
|
260
|
+
);
|
|
261
|
+
|
|
262
|
+
INSERT INTO fts_messaggi(entry_id, name, email, subject, message)
|
|
263
|
+
SELECT id, name, email, subject, message FROM content_messaggi;
|
|
264
|
+
|
|
265
|
+
CREATE TRIGGER IF NOT EXISTS fts_messaggi_insert
|
|
266
|
+
AFTER INSERT ON content_messaggi BEGIN
|
|
267
|
+
INSERT INTO fts_messaggi(entry_id, name, email, subject, message)
|
|
268
|
+
VALUES (new.id, new.name, new.email, new.subject, new.message);
|
|
269
|
+
END;
|
|
270
|
+
|
|
271
|
+
CREATE TRIGGER IF NOT EXISTS fts_messaggi_update
|
|
272
|
+
AFTER UPDATE OF name, email, subject, message ON content_messaggi BEGIN
|
|
273
|
+
DELETE FROM fts_messaggi WHERE entry_id = old.id;
|
|
274
|
+
INSERT INTO fts_messaggi(entry_id, name, email, subject, message)
|
|
275
|
+
VALUES (new.id, new.name, new.email, new.subject, new.message);
|
|
276
|
+
END;
|
|
277
|
+
|
|
278
|
+
CREATE TRIGGER IF NOT EXISTS fts_messaggi_delete
|
|
279
|
+
AFTER DELETE ON content_messaggi BEGIN
|
|
280
|
+
DELETE FROM fts_messaggi WHERE entry_id = old.id;
|
|
281
|
+
END;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
-- =============================================================================
|
|
2
|
+
-- Beech CMS v0.4.0 — Site Settings
|
|
3
|
+
-- Key-value store for site-level configuration (title, locale, timezone, etc.)
|
|
4
|
+
-- =============================================================================
|
|
5
|
+
|
|
6
|
+
CREATE TABLE IF NOT EXISTS site_settings (
|
|
7
|
+
key TEXT NOT NULL PRIMARY KEY,
|
|
8
|
+
value TEXT NOT NULL
|
|
9
|
+
);
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
-- =============================================================================
|
|
2
|
+
-- Runtime Seeds — Seed definitions stored in D1 (source of truth at runtime)
|
|
3
|
+
--
|
|
4
|
+
-- `seeds` : one row per content type. `definition` is the full Seed JSON.
|
|
5
|
+
-- `seed_meta` : single-row table holding the registry version token used for
|
|
6
|
+
-- multi-isolate cache invalidation (see docs/Sprints/runtime-seeds).
|
|
7
|
+
-- =============================================================================
|
|
8
|
+
|
|
9
|
+
CREATE TABLE IF NOT EXISTS seeds (
|
|
10
|
+
slug TEXT NOT NULL PRIMARY KEY,
|
|
11
|
+
definition TEXT NOT NULL, -- JSON-serialized Seed
|
|
12
|
+
status TEXT NOT NULL DEFAULT 'active'
|
|
13
|
+
CHECK (status IN ('active', 'deleted')),
|
|
14
|
+
source TEXT NOT NULL DEFAULT 'runtime'
|
|
15
|
+
CHECK (source IN ('code', 'runtime')),
|
|
16
|
+
created_at INTEGER NOT NULL DEFAULT (unixepoch()),
|
|
17
|
+
updated_at INTEGER NOT NULL DEFAULT (unixepoch())
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
CREATE INDEX IF NOT EXISTS idx_seeds_status ON seeds(status);
|
|
21
|
+
|
|
22
|
+
CREATE TABLE IF NOT EXISTS seed_meta (
|
|
23
|
+
id TEXT NOT NULL PRIMARY KEY,
|
|
24
|
+
value TEXT NOT NULL
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
-- registry_version starts at 1; bumped on every seed write (sprint 03/04).
|
|
28
|
+
INSERT OR IGNORE INTO seed_meta (id, value) VALUES ('registry_version', '1');
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
-- =============================================================================
|
|
2
|
+
-- Dashboard Layouts — per-scope dashboard composer layouts
|
|
3
|
+
--
|
|
4
|
+
-- `dashboard_layouts` : one row per scope. Sprint 02 only ever writes the
|
|
5
|
+
-- literal 'default' scope; Sprint 06 introduces
|
|
6
|
+
-- role-scoped rows ('role:admin', 'role:editor', ...).
|
|
7
|
+
-- =============================================================================
|
|
8
|
+
|
|
9
|
+
CREATE TABLE IF NOT EXISTS dashboard_layouts (
|
|
10
|
+
scope TEXT NOT NULL PRIMARY KEY, -- 'default' | 'role:admin' | 'role:editor'
|
|
11
|
+
layout TEXT NOT NULL, -- JSON of DashboardLayout
|
|
12
|
+
updated_at INTEGER NOT NULL DEFAULT (unixepoch()),
|
|
13
|
+
updated_by TEXT NOT NULL -- users.id of the writer
|
|
14
|
+
);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
-- =============================================================================
|
|
2
|
+
-- Kanban Foundation
|
|
3
|
+
-- kanban_positions : per-(seed, axis, entry) fractional-index ordering.
|
|
4
|
+
-- System table — NEVER a column on content_{slug}.
|
|
5
|
+
-- seed_layouts.view_config : additive JSON blob for per-seed dashboard view
|
|
6
|
+
-- preferences (kanban axis/sort/hidden columns). Nullable,
|
|
7
|
+
-- so existing rows are untouched.
|
|
8
|
+
-- =============================================================================
|
|
9
|
+
|
|
10
|
+
CREATE TABLE IF NOT EXISTS kanban_positions (
|
|
11
|
+
seed_slug TEXT NOT NULL,
|
|
12
|
+
entry_id TEXT NOT NULL,
|
|
13
|
+
axis_branch_id TEXT NOT NULL, -- Branch.id (br_XX), not alias
|
|
14
|
+
position TEXT NOT NULL, -- fractional-indexing key
|
|
15
|
+
updated_at INTEGER NOT NULL DEFAULT (unixepoch()),
|
|
16
|
+
PRIMARY KEY (seed_slug, entry_id, axis_branch_id)
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
-- Column fetch path: ORDER BY position within one (seed, axis).
|
|
20
|
+
CREATE INDEX IF NOT EXISTS idx_kanban_positions_column
|
|
21
|
+
ON kanban_positions (seed_slug, axis_branch_id, position);
|
|
22
|
+
|
|
23
|
+
-- Per-seed dashboard view preferences (KB-S02). Additive, nullable.
|
|
24
|
+
ALTER TABLE seed_layouts ADD COLUMN view_config TEXT;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
-- =============================================================================
|
|
2
|
+
-- Beech CMS v0.4.0 — Setup Lock
|
|
3
|
+
-- Single-row marker enforcing that /auth/setup can only complete once, even
|
|
4
|
+
-- under concurrent requests. Insert into this table in the same transaction
|
|
5
|
+
-- as the initial admin user; the PRIMARY KEY conflict rejects the loser.
|
|
6
|
+
-- =============================================================================
|
|
7
|
+
|
|
8
|
+
CREATE TABLE IF NOT EXISTS setup_completed (
|
|
9
|
+
id INTEGER NOT NULL PRIMARY KEY CHECK (id = 1)
|
|
10
|
+
);
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
-- =============================================================================
|
|
2
|
+
-- Beech CMS v0.4.0 — Notification Type Success Support
|
|
3
|
+
-- Updates notifications CHECK constraint to include 'success'
|
|
4
|
+
-- =============================================================================
|
|
5
|
+
|
|
6
|
+
CREATE TABLE IF NOT EXISTS notifications_dg_tmp (
|
|
7
|
+
id TEXT NOT NULL PRIMARY KEY,
|
|
8
|
+
title TEXT NOT NULL,
|
|
9
|
+
message TEXT NOT NULL,
|
|
10
|
+
type TEXT NOT NULL DEFAULT 'info' CHECK (type IN ('info', 'success', 'warning', 'error')),
|
|
11
|
+
is_read INTEGER NOT NULL DEFAULT 0 CHECK (is_read IN (0, 1)),
|
|
12
|
+
created_at INTEGER NOT NULL DEFAULT (unixepoch())
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
INSERT INTO notifications_dg_tmp (id, title, message, type, is_read, created_at)
|
|
16
|
+
SELECT id, title, message, type, is_read, created_at FROM notifications;
|
|
17
|
+
|
|
18
|
+
DROP TABLE notifications;
|
|
19
|
+
|
|
20
|
+
ALTER TABLE notifications_dg_tmp RENAME TO notifications;
|
|
21
|
+
|
|
22
|
+
CREATE INDEX IF NOT EXISTS idx_notifications_created ON notifications(created_at);
|
|
23
|
+
CREATE INDEX IF NOT EXISTS idx_notifications_unread ON notifications(is_read);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
-- =============================================================================
|
|
2
|
+
-- PUBLIC TIME-TRAP TOKENS
|
|
3
|
+
-- Single-use tracking for HMAC time-trap tokens to prevent replay attacks.
|
|
4
|
+
-- =============================================================================
|
|
5
|
+
|
|
6
|
+
CREATE TABLE IF NOT EXISTS public_time_trap_tokens (
|
|
7
|
+
token_hash TEXT NOT NULL PRIMARY KEY,
|
|
8
|
+
used_at INTEGER NOT NULL,
|
|
9
|
+
expires_at INTEGER NOT NULL
|
|
10
|
+
);
|
|
11
|
+
|
|
12
|
+
CREATE INDEX IF NOT EXISTS idx_time_trap_tokens_expires
|
|
13
|
+
ON public_time_trap_tokens (expires_at);
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
-- =============================================================================
|
|
2
|
+
-- OAUTH 2.1 AUTHORIZATION SERVER
|
|
3
|
+
-- Authorization code + PKCE grant. Every credential (code, access token, refresh
|
|
4
|
+
-- token) is persisted as a SHA-256 hex hash only — never plaintext — replicating
|
|
5
|
+
-- the refresh_tokens contract in 0000_v040_base.sql.
|
|
6
|
+
-- Expired rows are filtered at read time via expires_at; no background pruning job.
|
|
7
|
+
-- =============================================================================
|
|
8
|
+
|
|
9
|
+
-- 1. CLIENTS -----------------------------------------------------------------
|
|
10
|
+
-- Static registry. No dynamic client registration (RFC 7591) is supported.
|
|
11
|
+
CREATE TABLE IF NOT EXISTS oauth_clients (
|
|
12
|
+
client_id TEXT NOT NULL PRIMARY KEY,
|
|
13
|
+
name TEXT NOT NULL,
|
|
14
|
+
redirect_uris TEXT NOT NULL, -- JSON array of strings
|
|
15
|
+
allowed_scopes TEXT NOT NULL, -- space-delimited, RFC 6749 §3.3
|
|
16
|
+
is_public INTEGER NOT NULL DEFAULT 1
|
|
17
|
+
CHECK (is_public IN (0, 1)), -- 1 = public client, no secret
|
|
18
|
+
created_at INTEGER NOT NULL DEFAULT (unixepoch()),
|
|
19
|
+
disabled_at INTEGER DEFAULT NULL
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
-- 2. AUTHORIZATION CODES -----------------------------------------------------
|
|
23
|
+
-- Single use. consumed_at is set on first redemption; a second redemption of the
|
|
24
|
+
-- same code must cascade-revoke every token issued from it (OAuth 2.1 replay
|
|
25
|
+
-- mitigation) via oauth_tokens.authorization_code_hash.
|
|
26
|
+
CREATE TABLE IF NOT EXISTS oauth_authorization_codes (
|
|
27
|
+
code_hash TEXT NOT NULL PRIMARY KEY,
|
|
28
|
+
client_id TEXT NOT NULL REFERENCES oauth_clients(client_id) ON DELETE CASCADE,
|
|
29
|
+
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
30
|
+
scope TEXT NOT NULL, -- space-delimited granted scopes
|
|
31
|
+
redirect_uri TEXT NOT NULL,
|
|
32
|
+
code_challenge TEXT NOT NULL,
|
|
33
|
+
code_challenge_method TEXT NOT NULL DEFAULT 'S256'
|
|
34
|
+
CHECK (code_challenge_method = 'S256'),
|
|
35
|
+
expires_at INTEGER NOT NULL,
|
|
36
|
+
created_at INTEGER NOT NULL DEFAULT (unixepoch()),
|
|
37
|
+
consumed_at INTEGER DEFAULT NULL
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
CREATE INDEX IF NOT EXISTS idx_oauth_codes_user ON oauth_authorization_codes(user_id);
|
|
41
|
+
CREATE INDEX IF NOT EXISTS idx_oauth_codes_expires ON oauth_authorization_codes(expires_at);
|
|
42
|
+
|
|
43
|
+
-- 3. TOKENS ------------------------------------------------------------------
|
|
44
|
+
-- Access and refresh tokens share one table: identical lifecycle, distinguished
|
|
45
|
+
-- by token_type. authorization_code_hash links a token back to its originating
|
|
46
|
+
-- code so replay of that code can revoke the whole family in one UPDATE.
|
|
47
|
+
CREATE TABLE IF NOT EXISTS oauth_tokens (
|
|
48
|
+
id TEXT NOT NULL PRIMARY KEY,
|
|
49
|
+
token_hash TEXT NOT NULL,
|
|
50
|
+
token_type TEXT NOT NULL
|
|
51
|
+
CHECK (token_type IN ('access', 'refresh')),
|
|
52
|
+
client_id TEXT NOT NULL REFERENCES oauth_clients(client_id) ON DELETE CASCADE,
|
|
53
|
+
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
54
|
+
scope TEXT NOT NULL, -- space-delimited
|
|
55
|
+
authorization_code_hash TEXT NOT NULL,
|
|
56
|
+
expires_at INTEGER NOT NULL,
|
|
57
|
+
created_at INTEGER NOT NULL DEFAULT (unixepoch()),
|
|
58
|
+
revoked_at INTEGER DEFAULT NULL
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
CREATE INDEX IF NOT EXISTS idx_oauth_tokens_hash ON oauth_tokens(token_hash);
|
|
62
|
+
CREATE INDEX IF NOT EXISTS idx_oauth_tokens_code ON oauth_tokens(authorization_code_hash);
|
|
63
|
+
CREATE INDEX IF NOT EXISTS idx_oauth_tokens_client ON oauth_tokens(client_id, user_id);
|
|
64
|
+
CREATE INDEX IF NOT EXISTS idx_oauth_tokens_user ON oauth_tokens(user_id);
|
|
65
|
+
CREATE INDEX IF NOT EXISTS idx_oauth_tokens_expires ON oauth_tokens(expires_at);
|
|
66
|
+
|
|
67
|
+
-- 4. CONSENTS ---------------------------------------------------------------
|
|
68
|
+
-- One live row per (client, user). scopes holds the cumulative granted set, so a
|
|
69
|
+
-- repeat authorize request for an already-granted subset can skip the consent
|
|
70
|
+
-- screen, while a superset must re-prompt for the delta only.
|
|
71
|
+
CREATE TABLE IF NOT EXISTS oauth_consents (
|
|
72
|
+
id TEXT NOT NULL PRIMARY KEY,
|
|
73
|
+
client_id TEXT NOT NULL REFERENCES oauth_clients(client_id) ON DELETE CASCADE,
|
|
74
|
+
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
75
|
+
scopes TEXT NOT NULL, -- space-delimited
|
|
76
|
+
created_at INTEGER NOT NULL DEFAULT (unixepoch()),
|
|
77
|
+
updated_at INTEGER NOT NULL DEFAULT (unixepoch()),
|
|
78
|
+
revoked_at INTEGER DEFAULT NULL
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_oauth_consents_pair ON oauth_consents(client_id, user_id);
|
|
82
|
+
CREATE INDEX IF NOT EXISTS idx_oauth_consents_user ON oauth_consents(user_id);
|
|
83
|
+
|
|
84
|
+
-- 5. SEEDED CLIENT -----------------------------------------------------------
|
|
85
|
+
-- The MCP server is the only client today. Loopback redirect per OAuth 2.1
|
|
86
|
+
-- §8.4.2: the port is assigned at runtime by the local listener, so Sprint 2
|
|
87
|
+
-- matches host+path and ignores the port. No client secret: public client.
|
|
88
|
+
INSERT OR IGNORE INTO oauth_clients (client_id, name, redirect_uris, allowed_scopes, is_public)
|
|
89
|
+
VALUES (
|
|
90
|
+
'beech-mcp-cli',
|
|
91
|
+
'BeechCMS MCP Server',
|
|
92
|
+
'["http://127.0.0.1/callback"]',
|
|
93
|
+
'schema:read schema:write',
|
|
94
|
+
1
|
|
95
|
+
);
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
-- =============================================================================
|
|
2
|
+
-- OAUTH CLIENT REGISTRY — @beechcms/mcp
|
|
3
|
+
-- Static registration of the first-party MCP client. 0038 declares the registry
|
|
4
|
+
-- static (no RFC 7591 dynamic registration), so the row is seeded by migration.
|
|
5
|
+
-- Public client (is_public = 1): a stdio CLI cannot hold a secret, PKCE S256 is
|
|
6
|
+
-- the proof of possession instead.
|
|
7
|
+
-- The redirect URI is registered WITHOUT a port: matchesRegisteredRedirectUri()
|
|
8
|
+
-- compares loopback URIs on protocol + hostname + pathname only (OAuth 2.1
|
|
9
|
+
-- §8.4.2), because the CLI binds an ephemeral port at runtime.
|
|
10
|
+
-- Idempotent: INSERT OR IGNORE keeps `beech db:reset` and re-runs safe.
|
|
11
|
+
-- =============================================================================
|
|
12
|
+
|
|
13
|
+
INSERT OR IGNORE INTO oauth_clients (client_id, name, redirect_uris, allowed_scopes, is_public)
|
|
14
|
+
VALUES (
|
|
15
|
+
'beech-mcp',
|
|
16
|
+
'BeechCMS MCP Server',
|
|
17
|
+
'["http://127.0.0.1/oauth/callback"]',
|
|
18
|
+
'schema:read schema:write',
|
|
19
|
+
1
|
|
20
|
+
);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@beechcms/api",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/factory.d.ts",
|
|
@@ -12,15 +12,13 @@
|
|
|
12
12
|
},
|
|
13
13
|
"files": [
|
|
14
14
|
"dist/",
|
|
15
|
-
"migrations/
|
|
16
|
-
"migrations/0029_automations.sql",
|
|
17
|
-
"migrations/0030_test_seeds.sql",
|
|
15
|
+
"migrations/",
|
|
18
16
|
"assets/"
|
|
19
17
|
],
|
|
20
18
|
"dependencies": {
|
|
21
19
|
"@aws-sdk/client-s3": "^3.995.0",
|
|
22
20
|
"@aws-sdk/s3-request-presigner": "^3.995.0",
|
|
23
|
-
"@beechcms/core": "^0.
|
|
21
|
+
"@beechcms/core": "^0.8.0",
|
|
24
22
|
"@upstash/qstash": "^2.11.0",
|
|
25
23
|
"bcryptjs": "^2.4.3",
|
|
26
24
|
"hono": "^4.12.34",
|