@decocms/blocks-admin 7.6.0 → 7.8.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 +2 -2
- package/src/admin/decofile.test.ts +28 -6
- package/src/admin/decofile.ts +20 -8
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@decocms/blocks-admin",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.8.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.
|
|
28
|
+
"@decocms/blocks": "7.8.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 {
|
|
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
|
|
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(
|
|
108
|
-
expect(store.get(
|
|
109
|
-
expect(store.get(
|
|
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")),
|
package/src/admin/decofile.ts
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
import {
|
|
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
|
|
84
|
-
* it up on their next revision poll. No-op (returns false)
|
|
85
|
-
*
|
|
86
|
-
*
|
|
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(
|
|
95
|
-
if (revision) await kv.put(
|
|
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
|
|