@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 +1 -1
- package/package.json +1 -1
- package/src/dev-middleware.ts +17 -1
- package/src/index.ts +8 -1
- package/src/utils.ts +41 -0
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.
|
|
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
package/src/dev-middleware.ts
CHANGED
|
@@ -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.
|