@decocms/blocks 7.28.0-beta.3 → 7.28.0-beta.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 +1 -1
- package/src/cms/draftSource.test.ts +29 -0
- package/src/cms/draftSource.ts +33 -2
- package/src/cms/index.ts +1 -0
package/package.json
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
parseDraftPointer,
|
|
9
9
|
previewApiOriginForHost,
|
|
10
10
|
resolveDraftDecofile,
|
|
11
|
+
setDraftPreviewHosts,
|
|
11
12
|
} from "./draftSource";
|
|
12
13
|
|
|
13
14
|
const ENV_ON = { DECO_ALLOWED_PREVIEW_HOSTS: "preview.example" };
|
|
@@ -227,3 +228,31 @@ describe("DEFAULT_PREVIEW_API_DOMAINS", () => {
|
|
|
227
228
|
]);
|
|
228
229
|
});
|
|
229
230
|
});
|
|
231
|
+
|
|
232
|
+
describe("site-block preview hosts", () => {
|
|
233
|
+
it("enables the feature from the site block alone — no env needed", () => {
|
|
234
|
+
setDraftPreviewHosts(["fila.vtex.app", "LOCALHOST:3100", 42, " "]);
|
|
235
|
+
try {
|
|
236
|
+
expect(isDraftPreviewEnabled({})).toBe(true);
|
|
237
|
+
expect(isDraftHostAllowed("fila.vtex.app", {})).toBe(true);
|
|
238
|
+
// Sanitized: lowercased, non-strings and blanks dropped.
|
|
239
|
+
expect(isDraftHostAllowed("localhost:3100", {})).toBe(true);
|
|
240
|
+
expect(isDraftHostAllowed("evil.example", {})).toBe(false);
|
|
241
|
+
} finally {
|
|
242
|
+
setDraftPreviewHosts([]);
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
it("env REPLACES the block hosts when set — the operational escape hatch", () => {
|
|
247
|
+
setDraftPreviewHosts(["fila.vtex.app"]);
|
|
248
|
+
try {
|
|
249
|
+
const env = { DECO_ALLOWED_PREVIEW_HOSTS: "other.example" };
|
|
250
|
+
expect(isDraftHostAllowed("other.example", env)).toBe(true);
|
|
251
|
+
// Not merged: env is a kill switch / override, so the block value must
|
|
252
|
+
// not survive alongside it.
|
|
253
|
+
expect(isDraftHostAllowed("fila.vtex.app", env)).toBe(false);
|
|
254
|
+
} finally {
|
|
255
|
+
setDraftPreviewHosts([]);
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
});
|
package/src/cms/draftSource.ts
CHANGED
|
@@ -108,12 +108,43 @@ export function previewApiOriginForHost(
|
|
|
108
108
|
return `${local ? "http" : "https"}://${host}${port === undefined ? "" : `:${port}`}`;
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
-
/**
|
|
111
|
+
/**
|
|
112
|
+
* Hosts declared by the site itself (the global `site` block's `previewHosts`),
|
|
113
|
+
* installed once at setup time by the framework binding.
|
|
114
|
+
*
|
|
115
|
+
* MUST be fed from the setup-time base blocks, never from `loadBlocks()` at
|
|
116
|
+
* request time: the request path merges the draft override, and an allowlist
|
|
117
|
+
* readable through the override could be rewritten by the very draft it gates.
|
|
118
|
+
*/
|
|
119
|
+
// globalThis-backed, like the block loader itself: bundlers can duplicate
|
|
120
|
+
// this module across graphs, and a plain module variable set in one instance
|
|
121
|
+
// is invisible to the others. (The MIDDLEWARE runtime is a separate world
|
|
122
|
+
// even so — which is why the page-side gate is the authoritative one and the
|
|
123
|
+
// middleware only hard-gates when the env override is present.)
|
|
124
|
+
const G = globalThis as { __decoDraftHosts?: string[] };
|
|
125
|
+
|
|
126
|
+
/** Install the site-declared preview hosts. Called by the framework binding at setup. */
|
|
127
|
+
export function setDraftPreviewHosts(hosts: readonly unknown[]): void {
|
|
128
|
+
G.__decoDraftHosts = hosts
|
|
129
|
+
.filter((h): h is string => typeof h === "string")
|
|
130
|
+
.map((h) => h.trim().toLowerCase())
|
|
131
|
+
.filter(Boolean);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Hosts allowed to render drafts.
|
|
136
|
+
*
|
|
137
|
+
* The site block is the expected source — the opt-in lives in the repo,
|
|
138
|
+
* reviewed in a PR, versioned with branches. `DECO_ALLOWED_PREVIEW_HOSTS`
|
|
139
|
+
* REPLACES it when set: an operational escape hatch (kill a bad value without
|
|
140
|
+
* a deploy, add a machine-specific port) — not the primary configuration.
|
|
141
|
+
*/
|
|
112
142
|
function readAllowedHosts(env: Record<string, string | undefined>): string[] {
|
|
113
|
-
|
|
143
|
+
const fromEnv = (env.DECO_ALLOWED_PREVIEW_HOSTS ?? "")
|
|
114
144
|
.split(",")
|
|
115
145
|
.map((s) => s.trim().toLowerCase())
|
|
116
146
|
.filter(Boolean);
|
|
147
|
+
return fromEnv.length > 0 ? fromEnv : (G.__decoDraftHosts ?? []);
|
|
117
148
|
}
|
|
118
149
|
|
|
119
150
|
/**
|