drupal-mcp-connector 2.13.0 → 2.14.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/.agents/commands/drupal-entity-update.md +3 -3
- package/.agents/commands/drupal-update-node.md +3 -3
- package/CHANGELOG.md +66 -12
- package/bin/drupal-mcp-anchor.js +52 -0
- package/bin/drupal-mcp-edge.js +17 -1
- package/config/config.example.json +6 -0
- package/package.json +3 -2
- package/src/lib/anchor.js +338 -0
- package/src/lib/backends/backend-interface.js +1 -1
- package/src/lib/backends/jsonapi.js +2 -2
- package/src/lib/config.js +39 -0
- package/src/lib/contracts/approval.js +5 -0
- package/src/lib/draft-write.js +57 -0
- package/src/lib/evidence.js +607 -0
- package/src/lib/http-auth.js +65 -3
- package/src/lib/patch-preflight.js +18 -7
- package/src/lib/policy-enforcement.js +1 -1
- package/src/lib/policy-promotion.js +1 -1
- package/src/lib/relay/agent.js +1 -1
- package/src/lib/relay/edge.js +559 -15
- package/src/lib/relay/frames.js +1 -1
- package/src/lib/usage.js +1 -2
- package/src/tools/bulk.js +2 -1
- package/src/tools/entities.js +4 -3
- package/src/tools/nodes.js +10 -10
|
@@ -12,19 +12,19 @@
|
|
|
12
12
|
*
|
|
13
13
|
* Two distinct cases share that core 400:
|
|
14
14
|
*
|
|
15
|
-
* - **#166** — `rel:working-copy` resolves.
|
|
16
|
-
*
|
|
17
|
-
*
|
|
15
|
+
* - **#166** — `rel:working-copy` resolves. Both preflight and write use
|
|
16
|
+
* Sentinel's /mcp-draft endpoint with verified live/working revision IDs.
|
|
17
|
+
* Core rejects resourceVersion on PATCH. Never retry the canonical URL.
|
|
18
18
|
* - **#201** — the working-copy alias does not resolve, but core still
|
|
19
19
|
* blocks. That is a stray revision row. Refuse with revision-surgery
|
|
20
20
|
* language. `workingCopy: null` is not proof the node is writable.
|
|
21
21
|
*
|
|
22
|
-
*
|
|
23
|
-
* concurrent write — refuse, do not fall back to discard.
|
|
22
|
+
* Unsupported endpoints and stale revisions fail closed, without discard.
|
|
24
23
|
*/
|
|
25
24
|
|
|
26
25
|
import { entityLooksModerated, hasExplicitModerationState } from "./moderation-default.js";
|
|
27
26
|
import { entityRevisionId } from "./write-revision.js";
|
|
27
|
+
import { writeDraft } from "./draft-write.js";
|
|
28
28
|
|
|
29
29
|
/** Stable error code for a core working-copy / not-latest-revision block. */
|
|
30
30
|
export const PATCH_BLOCKED_CODE = "PATCH_BLOCKED";
|
|
@@ -59,7 +59,7 @@ export const PATCH_WORKING_COPY_STALE_MESSAGE =
|
|
|
59
59
|
|
|
60
60
|
/**
|
|
61
61
|
* Operator message for a core working-copy 400.
|
|
62
|
-
* A resolvable working copy
|
|
62
|
+
* A resolvable working copy gets a new draft revision (#166) — this message is only
|
|
63
63
|
* for the invisible-row case (#201).
|
|
64
64
|
* @returns {string}
|
|
65
65
|
*/
|
|
@@ -300,11 +300,18 @@ export async function preflightPatchWritable({
|
|
|
300
300
|
* @returns {Promise<{resourceVersion: ?string, workingCopy: ?object, liveVid: ?number|string, workingVid: ?number|string}>}
|
|
301
301
|
*/
|
|
302
302
|
export async function prepareGuardedPatch(backend, {
|
|
303
|
-
entityType, bundle, id, existing, attributes,
|
|
303
|
+
entityType, bundle, id, existing, attributes, relationships,
|
|
304
304
|
}) {
|
|
305
305
|
const target = shouldPreflightPatch({ existing, attributes })
|
|
306
306
|
? await resolveWorkingCopyPatchTarget(backend, { entityType, bundle, id, existing })
|
|
307
307
|
: { resourceVersion: undefined, workingCopy: null, liveVid: null, workingVid: null };
|
|
308
|
+
if (target.resourceVersion) {
|
|
309
|
+
target.draftRevision = { liveVid: target.liveVid, workingVid: target.workingVid };
|
|
310
|
+
await writeDraft(backend, {
|
|
311
|
+
entityType, bundle, id, attributes, relationships, draftRevision: target.draftRevision,
|
|
312
|
+
}, true);
|
|
313
|
+
return target;
|
|
314
|
+
}
|
|
308
315
|
await preflightPatchWritable({
|
|
309
316
|
backend, entityType, bundle, id, existing, attributes,
|
|
310
317
|
resourceVersion: target.resourceVersion,
|
|
@@ -323,6 +330,10 @@ export async function prepareGuardedPatch(backend, {
|
|
|
323
330
|
*/
|
|
324
331
|
export async function updateEntityGuarded(backend, input) {
|
|
325
332
|
try {
|
|
333
|
+
if (input?.draftRevision) return await writeDraft(backend, input);
|
|
334
|
+
if (input?.resourceVersion) {
|
|
335
|
+
throw new Error("Core JSON:API does not support revision-selected PATCH. A governed draft preflight is required.");
|
|
336
|
+
}
|
|
326
337
|
return await backend.updateEntity(input);
|
|
327
338
|
} catch (err) {
|
|
328
339
|
if (!isWorkingCopyPatchError(err)) throw err;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Tenant-side local policy enforcement (#253
|
|
2
|
+
* Tenant-side local policy enforcement (#253).
|
|
3
3
|
*
|
|
4
4
|
* Loopback stand-in for mcp_sentinel `McpPolicyBundleRegistry`: mint / verify
|
|
5
5
|
* / activate / simulate / revoke / rollback / emergency deny. The relay edge
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* W&L-operated dual-control promotion ledger (#253
|
|
2
|
+
* W&L-operated dual-control promotion ledger (#253).
|
|
3
3
|
*
|
|
4
4
|
* The edge never mints a Sentinel HMAC seal. A promotion is an already-sealed
|
|
5
5
|
* portable document plus two distinct operator ids. Eligibility is the gate
|
package/src/lib/relay/agent.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Relay tenant agent (#232) — the
|
|
2
|
+
* Relay tenant agent (#232) — the hosted-edge slice, tenant side.
|
|
3
3
|
*
|
|
4
4
|
* Dials OUT to the edge's agent channel and serves the real connector server
|
|
5
5
|
* (`createConnectorServerFactory`) over the framed tunnel. The agent never
|