@decocms/blocks 7.28.0-beta.3 → 7.28.0-beta.4

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": "@decocms/blocks",
3
- "version": "7.28.0-beta.3",
3
+ "version": "7.28.0-beta.4",
4
4
  "type": "module",
5
5
  "engines": {
6
6
  "node": ">=24"
@@ -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
+ });
@@ -108,12 +108,38 @@ export function previewApiOriginForHost(
108
108
  return `${local ? "http" : "https"}://${host}${port === undefined ? "" : `:${port}`}`;
109
109
  }
110
110
 
111
- /** Hosts allowed to render drafts (`DECO_ALLOWED_PREVIEW_HOSTS`, comma list). */
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
+ let sitePreviewHosts: string[] = [];
120
+
121
+ /** Install the site-declared preview hosts. Called by the framework binding at setup. */
122
+ export function setDraftPreviewHosts(hosts: readonly unknown[]): void {
123
+ sitePreviewHosts = hosts
124
+ .filter((h): h is string => typeof h === "string")
125
+ .map((h) => h.trim().toLowerCase())
126
+ .filter(Boolean);
127
+ }
128
+
129
+ /**
130
+ * Hosts allowed to render drafts.
131
+ *
132
+ * The site block is the expected source — the opt-in lives in the repo,
133
+ * reviewed in a PR, versioned with branches. `DECO_ALLOWED_PREVIEW_HOSTS`
134
+ * REPLACES it when set: an operational escape hatch (kill a bad value without
135
+ * a deploy, add a machine-specific port) — not the primary configuration.
136
+ */
112
137
  function readAllowedHosts(env: Record<string, string | undefined>): string[] {
113
- return (env.DECO_ALLOWED_PREVIEW_HOSTS ?? "")
138
+ const fromEnv = (env.DECO_ALLOWED_PREVIEW_HOSTS ?? "")
114
139
  .split(",")
115
140
  .map((s) => s.trim().toLowerCase())
116
141
  .filter(Boolean);
142
+ return fromEnv.length > 0 ? fromEnv : sitePreviewHosts;
117
143
  }
118
144
 
119
145
  /**
package/src/cms/index.ts CHANGED
@@ -23,6 +23,7 @@ export {
23
23
  previewApiOriginForHost,
24
24
  resolveDraftDecofile,
25
25
  setDraftOverrideGetter,
26
+ setDraftPreviewHosts,
26
27
  } from "./draftSource";
27
28
  export type { DecoPage, Resolvable } from "./loader";
28
29
  export {