@beechcms/api 0.4.0-preview.3 → 0.4.0-preview.5
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/package.json +2 -2
- package/src/factory.ts +23 -0
- package/src/features/password-reset/request.ts +1 -1
- package/src/search-utils.ts +5 -1
- package/src/types.ts +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@beechcms/api",
|
|
3
|
-
"version": "0.4.0-preview.
|
|
3
|
+
"version": "0.4.0-preview.5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./src/factory.ts"
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"@aws-sdk/client-s3": "^3.995.0",
|
|
24
|
-
"@beechcms/core": "^0.4.0-preview.
|
|
24
|
+
"@beechcms/core": "^0.4.0-preview.5",
|
|
25
25
|
"bcryptjs": "^2.4.3",
|
|
26
26
|
"hono": "^4.11.9",
|
|
27
27
|
"jose": "^6.1.3"
|
package/src/factory.ts
CHANGED
|
@@ -118,6 +118,7 @@ export function createBeechApp(config: BeechConfig): Hono<{ Bindings: Env; Varia
|
|
|
118
118
|
|
|
119
119
|
app.use('*', async (c, next) => {
|
|
120
120
|
await next()
|
|
121
|
+
if (c.req.path.startsWith('/admin')) return
|
|
121
122
|
c.header('X-Frame-Options', 'DENY')
|
|
122
123
|
c.header('X-Content-Type-Options', 'nosniff')
|
|
123
124
|
c.header('Referrer-Policy', 'strict-origin-when-cross-origin')
|
|
@@ -271,5 +272,27 @@ export function createBeechApp(config: BeechConfig): Hono<{ Bindings: Env; Varia
|
|
|
271
272
|
apiPublic.route('/', publicRoutes)
|
|
272
273
|
app.route('/api/v1/public', apiPublic)
|
|
273
274
|
|
|
275
|
+
// 7. Dashboard SPA — serve static assets from Workers Assets binding
|
|
276
|
+
app.get('/admin', (c) => c.redirect('/admin/', 301))
|
|
277
|
+
app.get('/admin/*', async (c) => {
|
|
278
|
+
if (!c.env.ASSETS) {
|
|
279
|
+
return c.text('Dashboard not configured. Set up the ASSETS binding in wrangler.toml pointing to @beechcms/dashboard/dist', 503)
|
|
280
|
+
}
|
|
281
|
+
let assetResponse = await c.env.ASSETS.fetch(c.req.raw)
|
|
282
|
+
if (assetResponse.status === 404) {
|
|
283
|
+
// SPA fallback: any unmatched /admin/* route serves index.html
|
|
284
|
+
assetResponse = await c.env.ASSETS.fetch(new Request(new URL('/admin/index.html', c.req.url)))
|
|
285
|
+
}
|
|
286
|
+
// ASSETS returns an immutable Response — wrap it to inject security headers
|
|
287
|
+
const headers = new Headers(assetResponse.headers)
|
|
288
|
+
headers.set('Content-Security-Policy',
|
|
289
|
+
"default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https:; connect-src 'self'; frame-ancestors 'none'"
|
|
290
|
+
)
|
|
291
|
+
headers.set('X-Frame-Options', 'DENY')
|
|
292
|
+
headers.set('X-Content-Type-Options', 'nosniff')
|
|
293
|
+
headers.set('Referrer-Policy', 'strict-origin-when-cross-origin')
|
|
294
|
+
return new Response(assetResponse.body, { status: assetResponse.status, headers })
|
|
295
|
+
})
|
|
296
|
+
|
|
274
297
|
return app
|
|
275
298
|
}
|
|
@@ -67,7 +67,7 @@ export async function requestPasswordReset(
|
|
|
67
67
|
.run()
|
|
68
68
|
|
|
69
69
|
const appUrl = (c.env.APP_URL ?? new URL(c.req.url).origin).replace(/\/$/, '')
|
|
70
|
-
const resetUrl = `${appUrl}/reset-password?token=${token}`
|
|
70
|
+
const resetUrl = `${appUrl}/admin/reset-password?token=${token}`
|
|
71
71
|
|
|
72
72
|
try {
|
|
73
73
|
await sendPasswordResetEmail({
|
package/src/search-utils.ts
CHANGED
|
@@ -175,6 +175,10 @@ export function buildFtsQuery(
|
|
|
175
175
|
|
|
176
176
|
// ─── Mapper ──────────────────────────────────────────────────────────────────
|
|
177
177
|
|
|
178
|
+
function stripHtmlPreserveMark(html: string): string {
|
|
179
|
+
return html.replace(/<(?!\/?mark\b)[^>]*>/gi, ' ').replace(/\s+/g, ' ').trim()
|
|
180
|
+
}
|
|
181
|
+
|
|
178
182
|
export function mapFtsRow(row: FtsRow): SearchResultItem {
|
|
179
183
|
return {
|
|
180
184
|
id: row.entry_id,
|
|
@@ -182,7 +186,7 @@ export function mapFtsRow(row: FtsRow): SearchResultItem {
|
|
|
182
186
|
slug: row.slug,
|
|
183
187
|
status: row.status,
|
|
184
188
|
title: row.title ?? "",
|
|
185
|
-
excerpt: row.excerpt ?? "",
|
|
189
|
+
excerpt: stripHtmlPreserveMark(row.excerpt ?? ""),
|
|
186
190
|
data: {},
|
|
187
191
|
}
|
|
188
192
|
}
|