drupal-mcp-connector 2.19.0 → 2.19.1
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/CHANGELOG.md +14 -0
- package/README.md +3 -2
- package/package.json +1 -1
- package/src/lib/dispatch.js +6 -6
- package/src/lib/errors.js +0 -11
- package/src/lib/evidence.js +0 -6
- package/src/lib/governance.js +2 -8
- package/src/lib/link-checker.js +3 -3
- package/src/lib/operations.js +2 -2
- package/src/lib/policy-enforcement.js +4 -4
- package/src/lib/principal.js +3 -3
- package/src/lib/relay/edge.js +2 -2
- package/src/lib/security.js +1 -18
- package/src/lib/tool-prompts.js +2 -2
- package/src/lib/usage.js +0 -9
- package/src/lib/verify.js +3 -3
- package/src/tools/moderation.js +1 -1
- package/src/tools/paragraphs.js +1 -1
- package/src/lib/draft-write.js +0 -19
- package/src/lib/node-draft-inventory.js +0 -5
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [2.19.1] - 2026-09-17
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
- **Remove leftover Sentinel facades (#328).** `draft-write.js` and
|
|
14
|
+
`node-draft-inventory.js` were re-exports of `sentinel-draft.js`. Tests
|
|
15
|
+
import the client directly. Unused exports (`toolMessage`, `redactResponse`)
|
|
16
|
+
are gone; `DIAGNOSTIC_TOOLS` and `POLICY_DIGEST` each live in one place.
|
|
17
|
+
- README and docs now report **123 tools across 27 modules** and **128 prompts**
|
|
18
|
+
(one per tool plus 5 workflow prompts). Codegen (`drupal_codegen_*`) shipped
|
|
19
|
+
in 2.16.0 but was missing from the public counts and the npm project page.
|
|
20
|
+
|
|
10
21
|
## [2.19.0] - 2026-09-16
|
|
11
22
|
|
|
12
23
|
### Added
|
|
@@ -1679,6 +1690,9 @@ The connector is now **dual-protocol**: every tool runs against an abstract back
|
|
|
1679
1690
|
- User tools gained explicit PII-access assertions.
|
|
1680
1691
|
- Whole tree lint-clean (`npm run lint`) with object-injection sinks rewritten to safe lookups.
|
|
1681
1692
|
|
|
1693
|
+
[2.19.1]: https://github.com/Wilkes-Liberty/drupal-mcp-connector/releases/tag/v2.19.1
|
|
1694
|
+
[2.19.0]: https://github.com/Wilkes-Liberty/drupal-mcp-connector/releases/tag/v2.19.0
|
|
1695
|
+
[2.18.0]: https://github.com/Wilkes-Liberty/drupal-mcp-connector/releases/tag/v2.18.0
|
|
1682
1696
|
[2.17.0]: https://github.com/Wilkes-Liberty/drupal-mcp-connector/releases/tag/v2.17.0
|
|
1683
1697
|
[2.16.0]: https://github.com/Wilkes-Liberty/drupal-mcp-connector/releases/tag/v2.16.0
|
|
1684
1698
|
[2.15.2]: https://github.com/Wilkes-Liberty/drupal-mcp-connector/releases/tag/v2.15.2
|
package/README.md
CHANGED
|
@@ -68,7 +68,7 @@ See **[docs/architecture.md](docs/architecture.md)** for the backend abstraction
|
|
|
68
68
|
|
|
69
69
|
## Features
|
|
70
70
|
|
|
71
|
-
###
|
|
71
|
+
### 123 Tools Across 27 Modules
|
|
72
72
|
|
|
73
73
|
| Module | Tools |
|
|
74
74
|
|--------|-------|
|
|
@@ -77,6 +77,7 @@ See **[docs/architecture.md](docs/architecture.md)** for the backend abstraction
|
|
|
77
77
|
| **Users** | List, get, create, update, block/unblock, role management (PII-gated) |
|
|
78
78
|
| **Media** | List types, CRUD, file upload, orphaned-media detection |
|
|
79
79
|
| **GraphQL** | Execute a query, schema introspection (mutation-gated) |
|
|
80
|
+
| **Codegen** | Optional graphql_compose_codegen inspect/diff/generate (generate is `--dry-run` text) |
|
|
80
81
|
| **Entities** | Generic CRUD for *any* Drupal entity type (paragraphs, commerce, webforms, …) |
|
|
81
82
|
| **Site** | Site info, content-type discovery, configured-site listing |
|
|
82
83
|
| **Reports** | Content summary, stale content, field completeness, SEO/accessibility audits, taxonomy usage, user activity, revision hotspots (10 read-only reports) |
|
|
@@ -308,7 +309,7 @@ an operator channel: keep the agent's credentials off it, and pin
|
|
|
308
309
|
| [OAuth client_credentials](docs/oauth-client-credentials.md) | Production OAuth deploy: scope→role mapping, JSON:API writes, config persistence, secret handling, troubleshooting |
|
|
309
310
|
| [Architecture](docs/architecture.md) | Backend abstraction, canonical model, and how to extend it |
|
|
310
311
|
| [GraphQL Setup](docs/graphql-local-setup.md) | GraphQL Compose backend + local TLS notes |
|
|
311
|
-
| [Tools Reference](docs/tools-reference.md) | Full reference for all
|
|
312
|
+
| [Tools Reference](docs/tools-reference.md) | Full reference for all 123 tools |
|
|
312
313
|
| [Security Guide](docs/security.md) | Presets, entity access control, field redaction |
|
|
313
314
|
| [Security Hardening](docs/security-hardening.md) | Optional transport, identity, and secrets controls |
|
|
314
315
|
| [Verification](docs/verification.md) | Prove a secure install: static + live checks, negative probes, evidence artefact, managed residuals |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "drupal-mcp-connector",
|
|
3
|
-
"version": "2.19.
|
|
3
|
+
"version": "2.19.1",
|
|
4
4
|
"description": "Drupal MCP Connector — multi-site MCP server for Drupal with JSON:API and GraphQL, governed writes, draft translations, content tools, audit reports, and an SSH Drush bridge.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
package/src/lib/dispatch.js
CHANGED
|
@@ -15,10 +15,10 @@ import { resolveSecurityConfig, assertNotReadOnly,
|
|
|
15
15
|
import { toolError, toolResult } from "./errors.js";
|
|
16
16
|
import { BackendCapabilityError, BackendResolutionError } from "./backends/errors.js";
|
|
17
17
|
import { inferOperation } from "./operations.js";
|
|
18
|
-
import { assertSourceGovernance, GovernanceError
|
|
18
|
+
import { assertSourceGovernance, GovernanceError } from "./governance.js";
|
|
19
19
|
import {
|
|
20
|
-
assertPrincipalEntitlement, callerTargetHints,
|
|
21
|
-
principalHasScope, resolveAuthoritativeTarget,
|
|
20
|
+
assertPrincipalEntitlement, callerTargetHints, DIAGNOSTIC_TOOLS,
|
|
21
|
+
getRequestIdentity, principalHasScope, resolveAuthoritativeTarget,
|
|
22
22
|
} from "./principal.js";
|
|
23
23
|
import { assertExplicitSiteForWrite, withResolvedTarget } from "./site-target.js";
|
|
24
24
|
import { buildDataFlowContext, consumeBudgetIfEnforced, runWithDataFlow } from "./data-flow.js";
|
|
@@ -55,7 +55,7 @@ export function listResolvableSiteConfigs() {
|
|
|
55
55
|
* @returns {?{site: object, source: string, name: string}}
|
|
56
56
|
* @throws {SecurityError}
|
|
57
57
|
*/
|
|
58
|
-
|
|
58
|
+
function resolveCallTarget(toolName, rawArgs, context = {}) {
|
|
59
59
|
if (toolName === "drupal_list_sites") return null;
|
|
60
60
|
if (toolName === "drupal_governance_status" && callerTargetHints(rawArgs).length === 0) {
|
|
61
61
|
return null;
|
|
@@ -157,7 +157,7 @@ export async function securityMiddleware(toolName, args, handler, context = {})
|
|
|
157
157
|
const assertCallAllowed = async () => {
|
|
158
158
|
// Source-governance gate (#176). The diagnostic tools stay callable while
|
|
159
159
|
// governance fails — they are how an operator learns which condition failed.
|
|
160
|
-
if (!
|
|
160
|
+
if (!DIAGNOSTIC_TOOLS.has(toolName)) {
|
|
161
161
|
await assertSourceGovernance(site);
|
|
162
162
|
}
|
|
163
163
|
|
|
@@ -188,7 +188,7 @@ export async function securityMiddleware(toolName, args, handler, context = {})
|
|
|
188
188
|
await assertCallAllowed();
|
|
189
189
|
// Charge only after governance and policy gates pass, so an outage or a
|
|
190
190
|
// local deny cannot exhaust the window. Diagnostics do not consume.
|
|
191
|
-
if (!
|
|
191
|
+
if (!DIAGNOSTIC_TOOLS.has(toolName)) {
|
|
192
192
|
consumeBudgetIfEnforced("chained_action");
|
|
193
193
|
}
|
|
194
194
|
return handler(nextArgs);
|
package/src/lib/errors.js
CHANGED
|
@@ -25,14 +25,3 @@ export function toolResult(data) {
|
|
|
25
25
|
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Wrap a plain string message (for confirmations, warnings, etc.).
|
|
31
|
-
* @param {string} text Message text.
|
|
32
|
-
* @returns {{content: Array<{type: string, text: string}>}}
|
|
33
|
-
*/
|
|
34
|
-
export function toolMessage(text) {
|
|
35
|
-
return {
|
|
36
|
-
content: [{ type: "text", text }],
|
|
37
|
-
};
|
|
38
|
-
}
|
package/src/lib/evidence.js
CHANGED
|
@@ -36,12 +36,6 @@ export const EXECUTION_IDS = Object.freeze([
|
|
|
36
36
|
"receiptId",
|
|
37
37
|
]);
|
|
38
38
|
|
|
39
|
-
export const RECONCILE_STATES = Object.freeze([
|
|
40
|
-
"settled",
|
|
41
|
-
"incomplete",
|
|
42
|
-
"mismatched",
|
|
43
|
-
]);
|
|
44
|
-
|
|
45
39
|
const DEFAULT_MAX_RECORDS = 10_000;
|
|
46
40
|
|
|
47
41
|
const FORBIDDEN_EXPORT_KEYS = new Set([
|
package/src/lib/governance.js
CHANGED
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
|
|
19
19
|
import fetch from "node-fetch";
|
|
20
20
|
import { authHeadersAsync, clientHeaders } from "./config.js";
|
|
21
|
+
import { DIAGNOSTIC_TOOLS } from "./principal.js";
|
|
21
22
|
|
|
22
23
|
/** How long a passing verification stays fresh before it must be re-proven. */
|
|
23
24
|
export const OK_TTL_MS = 60_000;
|
|
@@ -25,13 +26,6 @@ export const OK_TTL_MS = 60_000;
|
|
|
25
26
|
/** How long a failed verification is held before the next attempt re-checks. */
|
|
26
27
|
export const FAIL_TTL_MS = 5_000;
|
|
27
28
|
|
|
28
|
-
/** Tools that stay discoverable and callable while governance is failing —
|
|
29
|
-
* the diagnostic surface an operator needs to see WHY it is failing. */
|
|
30
|
-
export const GOVERNANCE_DIAGNOSTIC_TOOLS = new Set([
|
|
31
|
-
"drupal_list_sites",
|
|
32
|
-
"drupal_governance_status",
|
|
33
|
-
]);
|
|
34
|
-
|
|
35
29
|
/** Denial for a governed path whose source-governance contract is not verified. */
|
|
36
30
|
export class GovernanceError extends Error {
|
|
37
31
|
/**
|
|
@@ -203,5 +197,5 @@ export async function filterDiscoverableTools(definitions, sites) {
|
|
|
203
197
|
const verdicts = await Promise.all(sites.map(async (site) =>
|
|
204
198
|
!requiresGovernance(site) || (await verifySourceGovernance(site)).ok));
|
|
205
199
|
if (verdicts.some(Boolean)) return definitions;
|
|
206
|
-
return definitions.filter((d) =>
|
|
200
|
+
return definitions.filter((d) => DIAGNOSTIC_TOOLS.has(d.name));
|
|
207
201
|
}
|
package/src/lib/link-checker.js
CHANGED
|
@@ -18,11 +18,11 @@
|
|
|
18
18
|
import nodeFetch from "node-fetch";
|
|
19
19
|
|
|
20
20
|
/** Default per-request timeout (ms). */
|
|
21
|
-
|
|
21
|
+
const DEFAULT_TIMEOUT_MS = 5000;
|
|
22
22
|
/** Default number of concurrent in-flight checks. */
|
|
23
|
-
|
|
23
|
+
const DEFAULT_CONCURRENCY = 5;
|
|
24
24
|
/** Default hard ceiling on URLs checked in one call. */
|
|
25
|
-
|
|
25
|
+
const DEFAULT_MAX_LINKS = 200;
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
28
|
* Hostnames that must never be probed regardless of allowlist — loopback and
|
package/src/lib/operations.js
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
import { graphqlHasMutation } from "./security.js";
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
const WRITE_PREFIXES = ["drupal_create_", "drupal_update_", "drupal_upload_",
|
|
16
16
|
"drupal_block_", "drupal_drush_cache", "drupal_drush_cron",
|
|
17
17
|
"drupal_drush_config_export", "drupal_drush_config_import",
|
|
18
18
|
"drupal_drush_updatedb", "drupal_drush_module_enable",
|
|
@@ -22,7 +22,7 @@ export const WRITE_PREFIXES = ["drupal_create_", "drupal_update_", "drupal_uploa
|
|
|
22
22
|
// Governed config write (also gated inside the handler by the config-write cap):
|
|
23
23
|
"drupal_config_set"];
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
const DESTRUCTIVE_PREFIXES = ["drupal_delete_", "drupal_drush_module_disable"];
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
28
|
* Classify a tool's operation intent from its name prefix.
|
|
@@ -11,11 +11,11 @@
|
|
|
11
11
|
import { createHash, createHmac, randomUUID, timingSafeEqual } from "node:crypto";
|
|
12
12
|
import { SEAL_PREFIX } from "./policy-promotion.js";
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
const POLICY_BUNDLE_VERSION = 1;
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
const DEFAULT_BUNDLE_TTL = 86400 * 30;
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
const EMERGENCY_DENY = "*";
|
|
19
19
|
|
|
20
20
|
export const EMERGENCY_DIGEST = "emergency-deny";
|
|
21
21
|
|
|
@@ -43,7 +43,7 @@ function normalize(value) {
|
|
|
43
43
|
* @param {object} claims
|
|
44
44
|
* @returns {string}
|
|
45
45
|
*/
|
|
46
|
-
|
|
46
|
+
function canonicalJson(claims) {
|
|
47
47
|
return JSON.stringify(normalize(claims));
|
|
48
48
|
}
|
|
49
49
|
|
package/src/lib/principal.js
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
16
16
|
import { getDefaultSiteName, getInboundGrants } from "./config.js";
|
|
17
17
|
import { inferOperation } from "./operations.js";
|
|
18
|
+
import { POLICY_DIGEST } from "./policy-promotion.js";
|
|
18
19
|
import { resolveSecurityConfig, SecurityError } from "./security.js";
|
|
19
20
|
|
|
20
21
|
const identityStore = new AsyncLocalStorage();
|
|
@@ -23,7 +24,6 @@ const identityStore = new AsyncLocalStorage();
|
|
|
23
24
|
export const TARGET_HINT_KEYS = Object.freeze(["site", "environment", "tenant", "target"]);
|
|
24
25
|
|
|
25
26
|
const ACTOR_UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
26
|
-
const POLICY_DIGEST = /^[0-9a-f]{64}$/i;
|
|
27
27
|
|
|
28
28
|
function tableHasKeys(table) {
|
|
29
29
|
return Object.keys(table).some((key) => {
|
|
@@ -129,7 +129,7 @@ function grantNameList(values) {
|
|
|
129
129
|
* @param {object|null} actors
|
|
130
130
|
* @returns {object|null}
|
|
131
131
|
*/
|
|
132
|
-
|
|
132
|
+
function normalizeActors(actors) {
|
|
133
133
|
if (!actors || typeof actors !== "object" || Array.isArray(actors)) return null;
|
|
134
134
|
const entries = [];
|
|
135
135
|
for (const [rawKey, value] of Object.entries(actors)) {
|
|
@@ -201,7 +201,7 @@ export function resolveActor({ identity = null, actors = null } = {}) {
|
|
|
201
201
|
* @param {object|null} policies
|
|
202
202
|
* @returns {object|null}
|
|
203
203
|
*/
|
|
204
|
-
|
|
204
|
+
function normalizePolicies(policies) {
|
|
205
205
|
if (!policies || typeof policies !== "object" || Array.isArray(policies)) return null;
|
|
206
206
|
const entries = [];
|
|
207
207
|
for (const [rawKey, value] of Object.entries(policies)) {
|
package/src/lib/relay/edge.js
CHANGED
|
@@ -348,7 +348,7 @@ function callerApprovalHint(args = {}) {
|
|
|
348
348
|
* @param {unknown} raw
|
|
349
349
|
* @returns {string[]|{invalid: true, reason: string}}
|
|
350
350
|
*/
|
|
351
|
-
|
|
351
|
+
function normalizeApprovalRequiredTools(raw) {
|
|
352
352
|
if (raw === null || raw === undefined) return [];
|
|
353
353
|
if (Array.isArray(raw)) {
|
|
354
354
|
return [...new Set(
|
|
@@ -415,7 +415,7 @@ export class EdgeStartupError extends Error {
|
|
|
415
415
|
* @param {Record<string, string|string[]>} [headers]
|
|
416
416
|
* @returns {Record<string, string>}
|
|
417
417
|
*/
|
|
418
|
-
|
|
418
|
+
function fanDownHeaders(headers = {}) {
|
|
419
419
|
const entries = [];
|
|
420
420
|
for (const [name, value] of Object.entries(forwardHeaders(headers))) {
|
|
421
421
|
const key = String(name).toLowerCase();
|
package/src/lib/security.js
CHANGED
|
@@ -387,7 +387,7 @@ export function hasScope(site, scope) {
|
|
|
387
387
|
* @param {object} site Resolved site config.
|
|
388
388
|
* @returns {boolean}
|
|
389
389
|
*/
|
|
390
|
-
|
|
390
|
+
function isGovernedSetup(site) {
|
|
391
391
|
return site?.requireGovernance === true || Boolean(site?.oauth);
|
|
392
392
|
}
|
|
393
393
|
|
|
@@ -723,23 +723,6 @@ export function redactCanonicalEntity(entity, secConfig, entityType) {
|
|
|
723
723
|
return { ...entity, fields: redactedFields, ...baseOverrides };
|
|
724
724
|
}
|
|
725
725
|
|
|
726
|
-
/**
|
|
727
|
-
* Redact a full JSON:API response by redacting each item under `.data`.
|
|
728
|
-
* @param {?object} response JSON:API response with a `data` object or array.
|
|
729
|
-
* @param {object} secConfig Resolved security config.
|
|
730
|
-
* @param {string} entityType Entity type for the response data.
|
|
731
|
-
* @returns {?object} New response; original is not mutated.
|
|
732
|
-
*/
|
|
733
|
-
export function redactResponse(response, secConfig, entityType) {
|
|
734
|
-
if (!response?.data) return response;
|
|
735
|
-
return {
|
|
736
|
-
...response,
|
|
737
|
-
data: Array.isArray(response.data)
|
|
738
|
-
? response.data.map((r) => redactResource(r, secConfig, entityType))
|
|
739
|
-
: redactResource(response.data, secConfig, entityType),
|
|
740
|
-
};
|
|
741
|
-
}
|
|
742
|
-
|
|
743
726
|
// ---------------------------------------------------------------------------
|
|
744
727
|
// Security summary tool (exposed as drupal_security_info)
|
|
745
728
|
// ---------------------------------------------------------------------------
|
package/src/lib/tool-prompts.js
CHANGED
|
@@ -29,7 +29,7 @@ export const promptNameToToolName = (name) => name.replace(/-/g, "_");
|
|
|
29
29
|
* @param {object} spec - A JSON-Schema property spec.
|
|
30
30
|
* @returns {string} e.g. "string", "boolean (true/false)", "object (pass as JSON)".
|
|
31
31
|
*/
|
|
32
|
-
|
|
32
|
+
function typeHint(spec) {
|
|
33
33
|
const t = Array.isArray(spec?.type) ? spec.type[0] : spec?.type;
|
|
34
34
|
switch (t) {
|
|
35
35
|
case "boolean": return "boolean (true/false)";
|
|
@@ -84,7 +84,7 @@ export function buildToolPrompts(definitions) {
|
|
|
84
84
|
* @param {object} args - Arguments supplied to the prompt (all strings per MCP).
|
|
85
85
|
* @returns {string} A user-role instruction message body.
|
|
86
86
|
*/
|
|
87
|
-
|
|
87
|
+
function renderToolInstruction(def, args = {}) {
|
|
88
88
|
const params = paramList(def.inputSchema);
|
|
89
89
|
const required = params.filter((p) => p.required);
|
|
90
90
|
const optional = params.filter((p) => !p.required);
|
package/src/lib/usage.js
CHANGED
|
@@ -31,15 +31,6 @@ export const USAGE_DECISIONS = Object.freeze(["allow", "deny"]);
|
|
|
31
31
|
*/
|
|
32
32
|
export const RECEIPT_OUTCOMES = Object.freeze(["ok", "failed", "unknown"]);
|
|
33
33
|
|
|
34
|
-
/** Reconciliation states over one request / decision / receipt chain. */
|
|
35
|
-
export const RECONCILE_STATES = Object.freeze([
|
|
36
|
-
"settled",
|
|
37
|
-
"denied",
|
|
38
|
-
"missing",
|
|
39
|
-
"duplicate",
|
|
40
|
-
"uncertain",
|
|
41
|
-
]);
|
|
42
|
-
|
|
43
34
|
const PHASE_SET = new Set(USAGE_PHASES);
|
|
44
35
|
const DECISION_SET = new Set(USAGE_DECISIONS);
|
|
45
36
|
const OUTCOME_SET = new Set(RECEIPT_OUTCOMES);
|
package/src/lib/verify.js
CHANGED
|
@@ -30,9 +30,9 @@ import { resolveInboundAuthConfig, resolveInboundAuthMode } from "./http-auth.js
|
|
|
30
30
|
* and does not fail it: a verifier a secure install can never pass is a
|
|
31
31
|
* verifier people stop running.
|
|
32
32
|
*/
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
const PASS = "pass";
|
|
34
|
+
const FAIL = "fail";
|
|
35
|
+
const SKIPPED = "skipped";
|
|
36
36
|
export const NOT_APPLICABLE = "n/a";
|
|
37
37
|
|
|
38
38
|
/** Every static check, in report order. */
|
package/src/tools/moderation.js
CHANGED
|
@@ -39,7 +39,7 @@ const SAMPLE_CAP = 500;
|
|
|
39
39
|
* @param {unknown} err
|
|
40
40
|
* @returns {boolean}
|
|
41
41
|
*/
|
|
42
|
-
|
|
42
|
+
function isUnfilterableModerationState(err) {
|
|
43
43
|
const msg = String(err?.message || "");
|
|
44
44
|
if (!/moderation_state/i.test(msg)) return false;
|
|
45
45
|
return /not found/i.test(msg) || /not filterable/i.test(msg) || /invalid filter/i.test(msg);
|
package/src/tools/paragraphs.js
CHANGED
|
@@ -57,7 +57,7 @@ import {
|
|
|
57
57
|
* @param {number|string|null|undefined} [revisionId] Current revision id.
|
|
58
58
|
* @returns {{type: string, id: string, meta?: {target_revision_id: number}}}
|
|
59
59
|
*/
|
|
60
|
-
|
|
60
|
+
function embedRef(bundle, id, revisionId) {
|
|
61
61
|
return embedParagraphRef(bundle, id, revisionId);
|
|
62
62
|
}
|
|
63
63
|
|
package/src/lib/draft-write.js
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Compatibility facade for the Sentinel HTTP client.
|
|
3
|
-
* New call sites should import from `./sentinel-draft.js`.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
export {
|
|
7
|
-
assertDraftLangcode,
|
|
8
|
-
assertInventoryDraftLanguage,
|
|
9
|
-
createTranslationDraft,
|
|
10
|
-
isMissingDraftEndpoint,
|
|
11
|
-
isMissingTranslationEndpoint,
|
|
12
|
-
readDraftTranslation,
|
|
13
|
-
readNodeDraftInventory,
|
|
14
|
-
readTranslationInventory,
|
|
15
|
-
resolveNodeTranslationPair,
|
|
16
|
-
rewriteTranslationWorkingRevisionError,
|
|
17
|
-
supportsSentinelDraft,
|
|
18
|
-
writeDraft,
|
|
19
|
-
} from "./sentinel-draft.js";
|