@nuasite/cms 0.36.1 → 0.37.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/dist/editor.js CHANGED
@@ -381,7 +381,7 @@ function PS(t, e) {
381
381
  function LS(t, e) {
382
382
  return typeof e == "function" ? e(t) : e;
383
383
  }
384
- const o3 = "0.36.1", a3 = o3, nt = {
384
+ const o3 = "0.37.0", a3 = o3, nt = {
385
385
  /** Highlight overlay for hovered elements */
386
386
  HIGHLIGHT: 2147483644,
387
387
  /** Hover outline for elements/components */
package/package.json CHANGED
@@ -14,7 +14,7 @@
14
14
  "directory": "packages/astro-cms"
15
15
  },
16
16
  "license": "Apache-2.0",
17
- "version": "0.36.1",
17
+ "version": "0.37.0",
18
18
  "module": "src/index.ts",
19
19
  "types": "src/index.ts",
20
20
  "type": "module",
@@ -57,6 +57,12 @@ export const expectedDeletions = new Set<string>()
57
57
  export interface DevMiddlewareOptions {
58
58
  enableCmsApi?: boolean
59
59
  mediaAdapter?: MediaStorageAdapter
60
+ /**
61
+ * Predicate that returns true for request URLs which should bypass CMS rewriting
62
+ * (typically vendor HTML under Astro's publicDir whose inline scripts can be
63
+ * corrupted by injected markers).
64
+ */
65
+ isPublicStaticFile?: (urlPath: string) => boolean
60
66
  }
61
67
 
62
68
  export function createDevMiddleware(
@@ -67,6 +73,8 @@ export function createDevMiddleware(
67
73
  idCounter: { value: number },
68
74
  options: DevMiddlewareOptions = {},
69
75
  ) {
76
+ const isPublicStaticFile = options.isPublicStaticFile ?? (() => false)
77
+
70
78
  // Serve uploaded media files directly from disk.
71
79
  // Vite's public dir middleware caches file listings, so newly uploaded files
72
80
  // may not be available immediately. This middleware bypasses that cache.
@@ -244,9 +252,17 @@ export function createDevMiddleware(
244
252
 
245
253
  // Transform HTML responses — only buffer when Content-Type is text/html
246
254
  server.middlewares.use((req, res, next) => {
255
+ const requestUrl = req.url || 'unknown'
256
+
257
+ // Vendor HTML under publicDir is passed through untouched — the CMS rewriter
258
+ // can corrupt files with inline-script patterns it doesn't expect.
259
+ if (isPublicStaticFile(requestUrl)) {
260
+ next()
261
+ return
262
+ }
263
+
247
264
  const originalWrite = res.write
248
265
  const originalEnd = res.end
249
- const requestUrl = req.url || 'unknown'
250
266
  let chunks: Buffer[] | null = null
251
267
  let isHtml: boolean | null = null
252
268
 
package/src/index.ts CHANGED
@@ -15,6 +15,7 @@ import { createLocalStorageAdapter } from './media/local'
15
15
  import type { MediaStorageAdapter } from './media/types'
16
16
  import { rehypeCmsMarker } from './rehype-cms-marker'
17
17
  import type { CmsFeatures, CmsMarkerOptions, ComponentDefinition } from './types'
18
+ import { createPublicStaticFileChecker } from './utils'
18
19
  import { createVitePlugin } from './vite-plugin'
19
20
 
20
21
  export interface NuaCmsOptions extends CmsMarkerOptions {
@@ -100,6 +101,7 @@ export default function nuaCms(options: NuaCmsOptions = {}): AstroIntegration {
100
101
  : cmsConfig
101
102
 
102
103
  let componentDefinitions: Record<string, ComponentDefinition> = {}
104
+ let isPublicStaticFile: ((urlPath: string) => boolean) | undefined
103
105
 
104
106
  const idCounter = { value: 0 }
105
107
  const manifestWriter = new ManifestWriter(manifestFile, componentDefinitions)
@@ -306,6 +308,10 @@ export default function nuaCms(options: NuaCmsOptions = {}): AstroIntegration {
306
308
  })
307
309
  },
308
310
 
311
+ 'astro:config:done': ({ config }) => {
312
+ isPublicStaticFile = createPublicStaticFileChecker(fileURLToPath(config.publicDir))
313
+ },
314
+
309
315
  'astro:server:setup': ({ server, logger }) => {
310
316
  createDevMiddleware(
311
317
  server,
@@ -313,7 +319,7 @@ export default function nuaCms(options: NuaCmsOptions = {}): AstroIntegration {
313
319
  manifestWriter,
314
320
  componentDefinitions,
315
321
  idCounter,
316
- { enableCmsApi, mediaAdapter },
322
+ { enableCmsApi, mediaAdapter, isPublicStaticFile },
317
323
  )
318
324
  logger.info('CMS dev middleware initialized')
319
325
  if (enableCmsApi) {
@@ -418,3 +424,4 @@ export type {
418
424
  TextStyleValue,
419
425
  TwitterCardData,
420
426
  } from './types'
427
+ export { createPublicStaticFileChecker } from './utils'
package/src/utils.ts CHANGED
@@ -1,8 +1,49 @@
1
1
  import { createHash } from 'node:crypto'
2
+ import { statSync } from 'node:fs'
2
3
  import path from 'node:path'
3
4
  import { getProjectRoot } from './config'
4
5
  import type { ManifestEntry } from './types'
5
6
 
7
+ /**
8
+ * Build a checker that decides whether a request URL maps to an existing file
9
+ * under Astro's `publicDir`. Used to bypass HTML rewriting for vendor pages
10
+ * whose inline scripts can be corrupted by injected markers or content-length
11
+ * mismatches.
12
+ *
13
+ * Cache lives for the dev server's lifetime; vendor HTML is essentially static,
14
+ * and the cache is cleared on restart.
15
+ */
16
+ export function createPublicStaticFileChecker(publicDir: string | undefined): (urlPath: string) => boolean {
17
+ if (!publicDir) return () => false
18
+ const cache = new Map<string, boolean>()
19
+
20
+ return (urlPath: string) => {
21
+ const cleaned = urlPath.split('?')[0] || ''
22
+ if (!cleaned.startsWith('/') || cleaned.includes('..')) return false
23
+
24
+ const cached = cache.get(cleaned)
25
+ if (cached !== undefined) return cached
26
+
27
+ const candidates = [path.join(publicDir, cleaned)]
28
+ if (cleaned.endsWith('/')) {
29
+ candidates.push(path.join(publicDir, cleaned, 'index.html'))
30
+ }
31
+
32
+ let exists = false
33
+ for (const p of candidates) {
34
+ try {
35
+ if (statSync(p).isFile()) {
36
+ exists = true
37
+ break
38
+ }
39
+ } catch {}
40
+ }
41
+
42
+ cache.set(cleaned, exists)
43
+ return exists
44
+ }
45
+ }
46
+
6
47
  /**
7
48
  * Normalize a page path by removing query strings, hashes, and trailing slashes.
8
49
  * Handles both full URLs and plain pathnames.