@decocms/blocks-admin 7.6.0 → 7.7.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@decocms/blocks-admin",
3
- "version": "7.6.0",
3
+ "version": "7.7.0",
4
4
  "type": "module",
5
5
  "description": "Deco admin protocol: /live/_meta, /.decofile, /deco/invoke, /deco/render, plus admin-facing site setup and commerce-app auto-configuration",
6
6
  "repository": {
@@ -25,7 +25,7 @@
25
25
  "lint:unused": "knip"
26
26
  },
27
27
  "dependencies": {
28
- "@decocms/blocks": "7.6.0"
28
+ "@decocms/blocks": "7.7.0"
29
29
  },
30
30
  "peerDependencies": {
31
31
  "react": "^19.0.0",
@@ -1,7 +1,17 @@
1
1
  import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
2
- import { KV_KEYS, type KVNamespace, getRevision, loadBlocks, setBlocks } from "@decocms/blocks/cms";
2
+ import {
3
+ getRevision,
4
+ type KVNamespace,
5
+ loadBlocks,
6
+ revisionKey,
7
+ setBlocks,
8
+ snapshotKey,
9
+ } from "@decocms/blocks/cms";
3
10
  import { handleDecofileReload, setFastDeployKVGetter } from "./decofile";
4
11
 
12
+ /** Deployment id the write-through keys its snapshot under. */
13
+ const ID = "sha-cafebabe";
14
+
5
15
  // handleDecofileReload's dev-bypass keys off NODE_ENV === "development" (see
6
16
  // decofile.ts), not import.meta.env.DEV. Vitest itself runs with
7
17
  // NODE_ENV=test (not "development"), so force it here to preserve this
@@ -95,18 +105,18 @@ describe("handleDecofileReload — delta payloads", () => {
95
105
  });
96
106
 
97
107
  describe("handleDecofileReload — KV write-through", () => {
98
- it("writes the snapshot + revision to KV when DECO_KV is bound", async () => {
108
+ it("writes the snapshot + revision to this deployment's keyed entry", async () => {
99
109
  const { kv, store } = makeKV();
100
110
  const res = await reload(
101
111
  { blocks: { "pages-x": { path: "/x" } } },
102
- { DECO_KV: kv, DECO_FAST_DEPLOY: "1" },
112
+ { DECO_KV: kv, DECO_FAST_DEPLOY: "1", DECO_DEPLOYMENT_ID: ID },
103
113
  );
104
114
  const json = (await res.json()) as { kvWritten: boolean; revision: string };
105
115
 
106
116
  expect(json.kvWritten).toBe(true);
107
- expect(store.get(KV_KEYS.SNAPSHOT)).toBe(JSON.stringify(loadBlocks()));
108
- expect(store.get(KV_KEYS.REVISION)).toBe(getRevision());
109
- expect(store.get(KV_KEYS.REVISION)).toBe(json.revision);
117
+ expect(store.get(snapshotKey(ID))).toBe(JSON.stringify(loadBlocks()));
118
+ expect(store.get(revisionKey(ID))).toBe(getRevision());
119
+ expect(store.get(revisionKey(ID))).toBe(json.revision);
110
120
  });
111
121
 
112
122
  it("reports kvWritten=false when no KV binding is present", async () => {
@@ -123,9 +133,21 @@ describe("handleDecofileReload — KV write-through", () => {
123
133
  expect(store.size).toBe(0); // nothing written to KV
124
134
  });
125
135
 
136
+ it("reports kvWritten=false when no deployment id resolves", async () => {
137
+ const { kv, store } = makeKV();
138
+ const res = await reload(
139
+ { blocks: { "pages-x": { path: "/x" } } },
140
+ { DECO_KV: kv, DECO_FAST_DEPLOY: "1" }, // no DECO_DEPLOYMENT_ID
141
+ );
142
+ const json = (await res.json()) as { kvWritten: boolean };
143
+ expect(json.kvWritten).toBe(false);
144
+ expect(store.size).toBe(0);
145
+ });
146
+
126
147
  it("does not fail the request when the KV write throws", async () => {
127
148
  const env = {
128
149
  DECO_FAST_DEPLOY: "1",
150
+ DECO_DEPLOYMENT_ID: ID,
129
151
  DECO_KV: {
130
152
  get: () => Promise.resolve(null),
131
153
  put: () => Promise.reject(new Error("KV down")),
@@ -1,4 +1,11 @@
1
- import { KV_KEYS, getRevision, loadBlocks, setBlocks } from "@decocms/blocks/cms";
1
+ import {
2
+ getDeploymentId,
3
+ getRevision,
4
+ loadBlocks,
5
+ revisionKey,
6
+ setBlocks,
7
+ snapshotKey,
8
+ } from "@decocms/blocks/cms";
2
9
  import { clearLoaderCache } from "@decocms/blocks/sdk/cachedLoader";
3
10
  import { getRuntimeEnv } from "@decocms/blocks/sdk/otelAdapters";
4
11
  import { invalidateMetaCache } from "./meta";
@@ -80,19 +87,24 @@ function applyDelta(
80
87
  }
81
88
 
82
89
  /**
83
- * Write the current in-memory decofile snapshot to KV so other isolates pick
84
- * it up on their next revision poll. No-op (returns false) when fast-deploy is
85
- * disabled. The revision stored MUST equal the runtime's `getRevision()` so
86
- * pollers don't see a permanent mismatch.
90
+ * Write the current in-memory decofile snapshot to KV so other isolates of the
91
+ * SAME deployment pick it up on their next revision poll. No-op (returns false)
92
+ * when fast-deploy is disabled or no deployment id resolves. Writes this
93
+ * worker's OWN keyed entry (`decofile:<id>`) — it is the live version, so no
94
+ * `index:live` lookup is needed. The revision stored MUST equal the runtime's
95
+ * `getRevision()` so pollers don't see a permanent mismatch.
87
96
  */
88
97
  async function writeSnapshotToKV(env: Record<string, unknown> | undefined): Promise<boolean> {
89
98
  const kv = env ? getFastDeployKV(env) : null;
90
- if (!kv) return false;
99
+ if (!kv || !env) return false;
100
+
101
+ const deploymentId = getDeploymentId(env);
102
+ if (!deploymentId) return false;
91
103
 
92
104
  const blocks = loadBlocks();
93
105
  const revision = getRevision();
94
- await kv.put(KV_KEYS.SNAPSHOT, JSON.stringify(blocks));
95
- if (revision) await kv.put(KV_KEYS.REVISION, revision);
106
+ await kv.put(snapshotKey(deploymentId), JSON.stringify(blocks));
107
+ if (revision) await kv.put(revisionKey(deploymentId), revision);
96
108
  return true;
97
109
  }
98
110