@beechcms/api 0.4.0-preview.4 → 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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@beechcms/api",
3
- "version": "0.4.0-preview.4",
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.4",
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({
@@ -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
  }
package/src/types.ts CHANGED
@@ -26,6 +26,7 @@ export interface Env {
26
26
  FORGOT_PASSWORD_RATE_LIMITER?: RateLimit
27
27
  RESET_PASSWORD_RATE_LIMITER?: RateLimit
28
28
  ENV?: string
29
+ ASSETS?: Fetcher
29
30
  }
30
31
 
31
32
  export interface Variables {