directus-deploy-cli 0.1.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/README.md +62 -0
- package/dist/cli.js +132 -0
- package/dist/cli.js.map +1 -0
- package/dist/diff.js +31 -0
- package/dist/diff.js.map +1 -0
- package/dist/http.js +114 -0
- package/dist/http.js.map +1 -0
- package/dist/identity.js +124 -0
- package/dist/identity.js.map +1 -0
- package/dist/manifest.js +84 -0
- package/dist/manifest.js.map +1 -0
- package/dist/mcp-server.js +197 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/reconcilers/collections.js +82 -0
- package/dist/reconcilers/collections.js.map +1 -0
- package/dist/reconcilers/fields.js +92 -0
- package/dist/reconcilers/fields.js.map +1 -0
- package/dist/reconcilers/flows.js +122 -0
- package/dist/reconcilers/flows.js.map +1 -0
- package/dist/reconcilers/migrations.js +182 -0
- package/dist/reconcilers/migrations.js.map +1 -0
- package/dist/reconcilers/operations.js +164 -0
- package/dist/reconcilers/operations.js.map +1 -0
- package/dist/reconcilers/permissions.js +87 -0
- package/dist/reconcilers/permissions.js.map +1 -0
- package/dist/reconcilers/policies.js +105 -0
- package/dist/reconcilers/policies.js.map +1 -0
- package/dist/reconcilers/register.js +183 -0
- package/dist/reconcilers/register.js.map +1 -0
- package/dist/reconcilers/relations.js +56 -0
- package/dist/reconcilers/relations.js.map +1 -0
- package/dist/reconcilers/roles.js +71 -0
- package/dist/reconcilers/roles.js.map +1 -0
- package/dist/reconcilers/seeds.js +162 -0
- package/dist/reconcilers/seeds.js.map +1 -0
- package/dist/report.js +16 -0
- package/dist/report.js.map +1 -0
- package/dist/runner.js +160 -0
- package/dist/runner.js.map +1 -0
- package/dist/sanitize.js +31 -0
- package/dist/sanitize.js.map +1 -0
- package/dist/sql.js +102 -0
- package/dist/sql.js.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +45 -0
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// MCP server wrapping directus-deploy's reconciler graph. Speaks the Model
|
|
3
|
+
// Context Protocol on stdio so any MCP-aware Claude client (Chrome
|
|
4
|
+
// extension, Code CLI, Desktop, Claude in Cursor, …) can call plan/apply/
|
|
5
|
+
// verify as structured tools instead of shelling out.
|
|
6
|
+
//
|
|
7
|
+
// Usage in a Claude .mcp.json:
|
|
8
|
+
// {
|
|
9
|
+
// "mcpServers": {
|
|
10
|
+
// "directus-deploy": {
|
|
11
|
+
// "command": "node",
|
|
12
|
+
// "args": ["<abs-path>/node_modules/directus-deploy-cli/dist/mcp-server.js"],
|
|
13
|
+
// "env": { "DIRECTUS_URL": "...", "DIRECTUS_TOKEN": "..." }
|
|
14
|
+
// }
|
|
15
|
+
// }
|
|
16
|
+
// }
|
|
17
|
+
//
|
|
18
|
+
// Tools exposed:
|
|
19
|
+
// - directus_plan(target, entities?, only_collections?, snapshot_dir?, config_dir?,
|
|
20
|
+
// register_dir?, migrations_dir?, seed_dir?) — dry-run report.
|
|
21
|
+
// - directus_apply(...same shape...) — reconcile.
|
|
22
|
+
// - directus_verify(...same shape...) — drift check; error result when drift found.
|
|
23
|
+
//
|
|
24
|
+
// Each tool returns the JSON report (see src/types.ts RunReport).
|
|
25
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
26
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
27
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
28
|
+
import { createDirectusClient } from "./http.js";
|
|
29
|
+
import { run } from "./runner.js";
|
|
30
|
+
const ALL_ENTITIES = [
|
|
31
|
+
"collections",
|
|
32
|
+
"fields",
|
|
33
|
+
"relations",
|
|
34
|
+
"roles",
|
|
35
|
+
"policies",
|
|
36
|
+
"permissions",
|
|
37
|
+
"flows",
|
|
38
|
+
"operations",
|
|
39
|
+
"migrations",
|
|
40
|
+
"seeds",
|
|
41
|
+
];
|
|
42
|
+
const COMMON_INPUT_SCHEMA = {
|
|
43
|
+
type: "object",
|
|
44
|
+
properties: {
|
|
45
|
+
url: {
|
|
46
|
+
type: "string",
|
|
47
|
+
description: "Directus base URL (defaults to $DIRECTUS_URL).",
|
|
48
|
+
},
|
|
49
|
+
token: {
|
|
50
|
+
type: "string",
|
|
51
|
+
description: "Directus admin token (defaults to $DIRECTUS_TOKEN).",
|
|
52
|
+
},
|
|
53
|
+
target: {
|
|
54
|
+
type: "string",
|
|
55
|
+
description: "Friendly label for the run report (defaults to URL hostname).",
|
|
56
|
+
},
|
|
57
|
+
entities: {
|
|
58
|
+
type: "array",
|
|
59
|
+
items: { type: "string", enum: ALL_ENTITIES },
|
|
60
|
+
description: `Subset of ${ALL_ENTITIES.join(", ")} to reconcile. Defaults to all.`,
|
|
61
|
+
},
|
|
62
|
+
only_collections: {
|
|
63
|
+
type: "array",
|
|
64
|
+
items: { type: "string" },
|
|
65
|
+
description: "Restrict the run to these collection names.",
|
|
66
|
+
},
|
|
67
|
+
snapshot_dir: {
|
|
68
|
+
type: "string",
|
|
69
|
+
description: "Absolute path to directus_config/snapshot/",
|
|
70
|
+
},
|
|
71
|
+
config_dir: {
|
|
72
|
+
type: "string",
|
|
73
|
+
description: "Absolute path to directus_config/collections/",
|
|
74
|
+
},
|
|
75
|
+
register_dir: {
|
|
76
|
+
type: "string",
|
|
77
|
+
description: "Absolute path to migrations/register/",
|
|
78
|
+
},
|
|
79
|
+
migrations_dir: {
|
|
80
|
+
type: "string",
|
|
81
|
+
description: "Absolute path to migrations/",
|
|
82
|
+
},
|
|
83
|
+
seed_dir: {
|
|
84
|
+
type: "string",
|
|
85
|
+
description: "Absolute path to directus_config/seed/",
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
required: [],
|
|
89
|
+
};
|
|
90
|
+
function requireEnv(arg, envVar, flag) {
|
|
91
|
+
const v = arg ?? process.env[envVar];
|
|
92
|
+
if (!v)
|
|
93
|
+
throw new Error(`missing ${flag} argument or $${envVar}`);
|
|
94
|
+
return v;
|
|
95
|
+
}
|
|
96
|
+
function toDefaultDir(cwd, name) {
|
|
97
|
+
// Node's Path module is fine here — but avoid adding another import: the
|
|
98
|
+
// Directus paths are usually absolute in caller-provided args anyway.
|
|
99
|
+
return `${cwd.replace(/\/+$/, "")}/${name}`;
|
|
100
|
+
}
|
|
101
|
+
async function runReport(args, opts) {
|
|
102
|
+
const url = requireEnv(args.url, "DIRECTUS_URL", "url");
|
|
103
|
+
const token = requireEnv(args.token, "DIRECTUS_TOKEN", "token");
|
|
104
|
+
const target = args.target ?? new URL(url).hostname;
|
|
105
|
+
const entities = new Set((args.entities ?? ALL_ENTITIES));
|
|
106
|
+
const cwd = process.cwd();
|
|
107
|
+
const client = createDirectusClient({ baseUrl: url, token });
|
|
108
|
+
return run({
|
|
109
|
+
target,
|
|
110
|
+
paths: {
|
|
111
|
+
snapshotDir: args.snapshot_dir ?? toDefaultDir(cwd, "directus_config/snapshot"),
|
|
112
|
+
configDir: args.config_dir ?? toDefaultDir(cwd, "directus_config/collections"),
|
|
113
|
+
registerDir: args.register_dir ?? toDefaultDir(cwd, "migrations/register"),
|
|
114
|
+
},
|
|
115
|
+
migrationsDir: args.migrations_dir ?? toDefaultDir(cwd, "migrations"),
|
|
116
|
+
seedDir: args.seed_dir ?? toDefaultDir(cwd, "directus_config/seed"),
|
|
117
|
+
client,
|
|
118
|
+
opts: {
|
|
119
|
+
dryRun: opts.dryRun,
|
|
120
|
+
onlyCollections: args.only_collections?.length
|
|
121
|
+
? new Set(args.only_collections)
|
|
122
|
+
: undefined,
|
|
123
|
+
},
|
|
124
|
+
entities,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
async function handlePlan(args) {
|
|
128
|
+
return runReport(args, { dryRun: true });
|
|
129
|
+
}
|
|
130
|
+
async function handleApply(args) {
|
|
131
|
+
return runReport(args, { dryRun: false });
|
|
132
|
+
}
|
|
133
|
+
async function handleVerify(args) {
|
|
134
|
+
const report = await runReport(args, { dryRun: true });
|
|
135
|
+
const drift = report.counts.created + report.counts.updated;
|
|
136
|
+
return { report, drift };
|
|
137
|
+
}
|
|
138
|
+
async function main() {
|
|
139
|
+
const server = new Server({ name: "directus-deploy", version: "0.1.0" }, { capabilities: { tools: {} } });
|
|
140
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
141
|
+
tools: [
|
|
142
|
+
{
|
|
143
|
+
name: "directus_plan",
|
|
144
|
+
description: "Dry-run against a Directus target: report what would change, no writes. Returns the full JSON report.",
|
|
145
|
+
inputSchema: COMMON_INPUT_SCHEMA,
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
name: "directus_apply",
|
|
149
|
+
description: "Reconcile the target env to match directus_config/. Per-entity, non-atomic — a single failure never aborts the run. Returns the full JSON report.",
|
|
150
|
+
inputSchema: COMMON_INPUT_SCHEMA,
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
name: "directus_verify",
|
|
154
|
+
description: "Post-apply drift check: dry-run then fail if any entity would be created or updated. Returns { report, drift } — drift > 0 means the target has diverged from git.",
|
|
155
|
+
inputSchema: COMMON_INPUT_SCHEMA,
|
|
156
|
+
},
|
|
157
|
+
],
|
|
158
|
+
}));
|
|
159
|
+
server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
160
|
+
const args = (req.params.arguments ?? {});
|
|
161
|
+
try {
|
|
162
|
+
let payload;
|
|
163
|
+
switch (req.params.name) {
|
|
164
|
+
case "directus_plan":
|
|
165
|
+
payload = await handlePlan(args);
|
|
166
|
+
break;
|
|
167
|
+
case "directus_apply":
|
|
168
|
+
payload = await handleApply(args);
|
|
169
|
+
break;
|
|
170
|
+
case "directus_verify":
|
|
171
|
+
payload = await handleVerify(args);
|
|
172
|
+
break;
|
|
173
|
+
default:
|
|
174
|
+
throw new Error(`unknown tool: ${req.params.name}`);
|
|
175
|
+
}
|
|
176
|
+
return {
|
|
177
|
+
content: [
|
|
178
|
+
{ type: "text", text: JSON.stringify(payload, null, 2) },
|
|
179
|
+
],
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
catch (e) {
|
|
183
|
+
const msg = e.message;
|
|
184
|
+
return {
|
|
185
|
+
isError: true,
|
|
186
|
+
content: [{ type: "text", text: msg }],
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
const transport = new StdioServerTransport();
|
|
191
|
+
await server.connect(transport);
|
|
192
|
+
}
|
|
193
|
+
main().catch((e) => {
|
|
194
|
+
process.stderr.write(`directus-deploy MCP: fatal ${e.message}\n`);
|
|
195
|
+
process.exit(1);
|
|
196
|
+
});
|
|
197
|
+
//# sourceMappingURL=mcp-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-server.js","sourceRoot":"","sources":["../src/mcp-server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { diffSubset } from "../diff.js";
|
|
2
|
+
import { sanitizeForWrite } from "../sanitize.js";
|
|
3
|
+
export async function reconcileCollections(input) {
|
|
4
|
+
const results = [];
|
|
5
|
+
for (const desired of input.collections) {
|
|
6
|
+
const name = String(desired.collection ?? "");
|
|
7
|
+
if (!name)
|
|
8
|
+
continue;
|
|
9
|
+
if (input.opts.onlyCollections && !input.opts.onlyCollections.has(name))
|
|
10
|
+
continue;
|
|
11
|
+
const label = `collections/${name}`;
|
|
12
|
+
// Three-tier: adopted raw-SQL tables get delegated to register-table.mjs
|
|
13
|
+
// (M4) — for M1 we surface the intent as a SKIPPED entry so nobody's
|
|
14
|
+
// surprised.
|
|
15
|
+
if (input.registerManifests.has(name)) {
|
|
16
|
+
results.push({
|
|
17
|
+
kind: "collections",
|
|
18
|
+
label,
|
|
19
|
+
action: "skipped",
|
|
20
|
+
reason: "raw-SQL adopted — owned by register-table (v0.4/M4)",
|
|
21
|
+
});
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
let existing;
|
|
25
|
+
try {
|
|
26
|
+
const got = await input.client.get(`/collections/${name}`);
|
|
27
|
+
existing = Array.isArray(got) ? null : got;
|
|
28
|
+
}
|
|
29
|
+
catch (e) {
|
|
30
|
+
results.push({
|
|
31
|
+
kind: "collections",
|
|
32
|
+
label,
|
|
33
|
+
action: "failed",
|
|
34
|
+
reason: e.message,
|
|
35
|
+
});
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
const payload = sanitizeForWrite(desired);
|
|
39
|
+
if (existing === null) {
|
|
40
|
+
if (!input.opts.dryRun) {
|
|
41
|
+
try {
|
|
42
|
+
await input.client.post("/collections", payload);
|
|
43
|
+
}
|
|
44
|
+
catch (e) {
|
|
45
|
+
results.push({
|
|
46
|
+
kind: "collections",
|
|
47
|
+
label,
|
|
48
|
+
action: "failed",
|
|
49
|
+
reason: e.message,
|
|
50
|
+
});
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
results.push({ kind: "collections", label, action: "created" });
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
const desiredMeta = payload.meta ?? {};
|
|
58
|
+
const existingMeta = existing.meta ?? {};
|
|
59
|
+
if (diffSubset(desiredMeta, existingMeta)) {
|
|
60
|
+
if (!input.opts.dryRun) {
|
|
61
|
+
try {
|
|
62
|
+
await input.client.patch(`/collections/${name}`, { meta: desiredMeta });
|
|
63
|
+
}
|
|
64
|
+
catch (e) {
|
|
65
|
+
results.push({
|
|
66
|
+
kind: "collections",
|
|
67
|
+
label,
|
|
68
|
+
action: "failed",
|
|
69
|
+
reason: e.message,
|
|
70
|
+
});
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
results.push({ kind: "collections", label, action: "updated" });
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
results.push({ kind: "collections", label, action: "unchanged" });
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return results;
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=collections.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collections.js","sourceRoot":"","sources":["../../src/reconcilers/collections.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { diffSubset } from "../diff.js";
|
|
2
|
+
import { sanitizeForWrite } from "../sanitize.js";
|
|
3
|
+
export async function reconcileFields(input) {
|
|
4
|
+
const results = [];
|
|
5
|
+
for (const [collection, fields] of input.fieldsByCollection) {
|
|
6
|
+
if (input.opts.onlyCollections && !input.opts.onlyCollections.has(collection))
|
|
7
|
+
continue;
|
|
8
|
+
// Adopted raw-SQL tables — register-table.mjs owns the fields; skipping
|
|
9
|
+
// avoids the classic "PATCH with type=unknown" cascade that broke pgvector
|
|
10
|
+
// embeddings on test/staging.
|
|
11
|
+
if (input.registerManifests.has(collection)) {
|
|
12
|
+
results.push({
|
|
13
|
+
kind: "fields",
|
|
14
|
+
label: `fields/${collection}/*`,
|
|
15
|
+
action: "skipped",
|
|
16
|
+
reason: "raw-SQL adopted — owned by register-table",
|
|
17
|
+
});
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
for (const desired of fields) {
|
|
21
|
+
const field = String(desired.field ?? "");
|
|
22
|
+
if (!field)
|
|
23
|
+
continue;
|
|
24
|
+
const label = `fields/${collection}.${field}`;
|
|
25
|
+
let existing;
|
|
26
|
+
try {
|
|
27
|
+
const got = await input.client.get(`/fields/${collection}/${field}`);
|
|
28
|
+
existing = Array.isArray(got) ? null : got;
|
|
29
|
+
}
|
|
30
|
+
catch (e) {
|
|
31
|
+
results.push({ kind: "fields", label, action: "failed", reason: e.message });
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
// Skip fields that Directus tracks as adopted-but-unregistered
|
|
35
|
+
// (type=unknown, meta=null). Patching would silently promote them into
|
|
36
|
+
// managed state and diverge from the DB.
|
|
37
|
+
if (existing !== null &&
|
|
38
|
+
(existing["type"] === "unknown" || existing["meta"] === null || existing["meta"] === undefined)) {
|
|
39
|
+
results.push({
|
|
40
|
+
kind: "fields",
|
|
41
|
+
label,
|
|
42
|
+
action: "skipped",
|
|
43
|
+
reason: "unregistered raw-SQL column (type=unknown)",
|
|
44
|
+
});
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
const payload = sanitizeForWrite(desired);
|
|
48
|
+
const desiredMeta = payload.meta ?? {};
|
|
49
|
+
// Only send schema when it *actually* differs. Re-asserting unchanged
|
|
50
|
+
// schema on PK / sequence-backed columns makes Directus emit
|
|
51
|
+
// ALTER COLUMN … DROP NOT NULL which Postgres rejects (verified today).
|
|
52
|
+
const desiredSchema = payload.schema ?? undefined;
|
|
53
|
+
const existingSchema = existing?.schema ?? {};
|
|
54
|
+
const desiredShape = {
|
|
55
|
+
type: payload.type,
|
|
56
|
+
meta: desiredMeta,
|
|
57
|
+
};
|
|
58
|
+
if (desiredSchema && (existing === null || diffSubset(desiredSchema, existingSchema))) {
|
|
59
|
+
desiredShape["schema"] = desiredSchema;
|
|
60
|
+
}
|
|
61
|
+
if (existing === null) {
|
|
62
|
+
if (!input.opts.dryRun) {
|
|
63
|
+
try {
|
|
64
|
+
await input.client.post(`/fields/${collection}`, payload);
|
|
65
|
+
}
|
|
66
|
+
catch (e) {
|
|
67
|
+
results.push({ kind: "fields", label, action: "failed", reason: e.message });
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
results.push({ kind: "fields", label, action: "created" });
|
|
72
|
+
}
|
|
73
|
+
else if (diffSubset(desiredShape, existing)) {
|
|
74
|
+
if (!input.opts.dryRun) {
|
|
75
|
+
try {
|
|
76
|
+
await input.client.patch(`/fields/${collection}/${field}`, desiredShape);
|
|
77
|
+
}
|
|
78
|
+
catch (e) {
|
|
79
|
+
results.push({ kind: "fields", label, action: "failed", reason: e.message });
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
results.push({ kind: "fields", label, action: "updated" });
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
results.push({ kind: "fields", label, action: "unchanged" });
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return results;
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=fields.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fields.js","sourceRoot":"","sources":["../../src/reconcilers/fields.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { diffSubset } from "../diff.js";
|
|
2
|
+
import { sanitizeForWrite } from "../sanitize.js";
|
|
3
|
+
import { resolveOpSyncIdToServerId } from "../identity.js";
|
|
4
|
+
async function listServerFlows(client) {
|
|
5
|
+
const raw = await client.get("/flows?limit=-1");
|
|
6
|
+
if (raw === null)
|
|
7
|
+
return [];
|
|
8
|
+
if (Array.isArray(raw))
|
|
9
|
+
return raw;
|
|
10
|
+
const data = raw.data;
|
|
11
|
+
return Array.isArray(data) ? data : [];
|
|
12
|
+
}
|
|
13
|
+
function indexByName(rows) {
|
|
14
|
+
const map = new Map();
|
|
15
|
+
for (const r of rows) {
|
|
16
|
+
const n = String(r.name ?? "");
|
|
17
|
+
if (n)
|
|
18
|
+
map.set(n, r);
|
|
19
|
+
}
|
|
20
|
+
return map;
|
|
21
|
+
}
|
|
22
|
+
function stripSideEffects(obj) {
|
|
23
|
+
// Directus emits `operations` (junction ids) on GET but we manage ops in
|
|
24
|
+
// their own reconciler. Also strip `user_created` etc. via sanitize.
|
|
25
|
+
const { operations: _o, ...rest } = obj;
|
|
26
|
+
return rest;
|
|
27
|
+
}
|
|
28
|
+
export async function reconcileFlowsPass1(input) {
|
|
29
|
+
const results = [];
|
|
30
|
+
const serverByName = indexByName(await listServerFlows(input.client));
|
|
31
|
+
for (const desired of input.flows) {
|
|
32
|
+
const name = String(desired.name ?? "");
|
|
33
|
+
if (!name)
|
|
34
|
+
continue;
|
|
35
|
+
const label = `flows/${name}`;
|
|
36
|
+
const existing = serverByName.get(name) ?? null;
|
|
37
|
+
const raw = sanitizeForWrite(desired);
|
|
38
|
+
// Send with operation=null in the first pass so ops (which reference this
|
|
39
|
+
// flow) can be created without racing the flow-op link.
|
|
40
|
+
const payload = stripSideEffects({ ...raw, operation: null });
|
|
41
|
+
if (existing === null) {
|
|
42
|
+
if (!input.opts.dryRun) {
|
|
43
|
+
try {
|
|
44
|
+
await input.client.post("/flows", payload);
|
|
45
|
+
}
|
|
46
|
+
catch (e) {
|
|
47
|
+
results.push({ kind: "flows", label, action: "failed", reason: e.message });
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
results.push({ kind: "flows", label, action: "created" });
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
const existingStripped = stripSideEffects(existing);
|
|
55
|
+
// Skip `operation` in this pass — it's handled by Pass 2.
|
|
56
|
+
const { operation: _do, ...desiredForDiff } = payload;
|
|
57
|
+
const { operation: _eo, ...existingForDiff } = existingStripped;
|
|
58
|
+
if (diffSubset(desiredForDiff, existingForDiff)) {
|
|
59
|
+
const id = String(existing.id ?? "");
|
|
60
|
+
if (!input.opts.dryRun) {
|
|
61
|
+
try {
|
|
62
|
+
await input.client.patch(`/flows/${id}`, desiredForDiff);
|
|
63
|
+
}
|
|
64
|
+
catch (e) {
|
|
65
|
+
results.push({ kind: "flows", label, action: "failed", reason: e.message });
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
results.push({ kind: "flows", label, action: "updated" });
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
results.push({ kind: "flows", label, action: "unchanged" });
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return results;
|
|
76
|
+
}
|
|
77
|
+
// Pass 2: after operations are reconciled, set each flow's `operation` FK to
|
|
78
|
+
// the resolved server op id.
|
|
79
|
+
export async function reconcileFlowsPass2(input) {
|
|
80
|
+
const results = [];
|
|
81
|
+
const serverByName = indexByName(await listServerFlows(input.client));
|
|
82
|
+
for (const desired of input.flows) {
|
|
83
|
+
const name = String(desired.name ?? "");
|
|
84
|
+
if (!name)
|
|
85
|
+
continue;
|
|
86
|
+
const desiredOpSync = String(desired.operation ?? "");
|
|
87
|
+
if (!desiredOpSync)
|
|
88
|
+
continue; // flow with no entry op — nothing to link
|
|
89
|
+
const existing = serverByName.get(name);
|
|
90
|
+
if (!existing)
|
|
91
|
+
continue; // Pass 1 already reported the failure
|
|
92
|
+
const serverOpId = resolveOpSyncIdToServerId(desiredOpSync, input.identity);
|
|
93
|
+
const currentOp = String(existing.operation ?? "");
|
|
94
|
+
const label = `flows/${name} (link op)`;
|
|
95
|
+
if (!serverOpId) {
|
|
96
|
+
results.push({
|
|
97
|
+
kind: "flows",
|
|
98
|
+
label,
|
|
99
|
+
action: "failed",
|
|
100
|
+
reason: `unresolved entry op _syncId '${desiredOpSync}'`,
|
|
101
|
+
});
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
if (currentOp === serverOpId) {
|
|
105
|
+
// already linked — no report entry (already counted in pass 1)
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
if (!input.opts.dryRun) {
|
|
109
|
+
const id = String(existing.id ?? "");
|
|
110
|
+
try {
|
|
111
|
+
await input.client.patch(`/flows/${id}`, { operation: serverOpId });
|
|
112
|
+
}
|
|
113
|
+
catch (e) {
|
|
114
|
+
results.push({ kind: "flows", label, action: "failed", reason: e.message });
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
results.push({ kind: "flows", label, action: "updated" });
|
|
119
|
+
}
|
|
120
|
+
return results;
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=flows.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flows.js","sourceRoot":"","sources":["../../src/reconcilers/flows.ts"],"names":[],"mappings":"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"}
|