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
package/dist/runner.js
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { loadSnapshot } from "./manifest.js";
|
|
2
|
+
import { reconcileCollections } from "./reconcilers/collections.js";
|
|
3
|
+
import { reconcileFields } from "./reconcilers/fields.js";
|
|
4
|
+
import { reconcileRelations } from "./reconcilers/relations.js";
|
|
5
|
+
import { reconcileRoles } from "./reconcilers/roles.js";
|
|
6
|
+
import { reconcilePolicies } from "./reconcilers/policies.js";
|
|
7
|
+
import { reconcilePermissions } from "./reconcilers/permissions.js";
|
|
8
|
+
import { reconcileFlowsPass1, reconcileFlowsPass2 } from "./reconcilers/flows.js";
|
|
9
|
+
import { reconcileOperationsPass1, reconcileOperationsPass2, } from "./reconcilers/operations.js";
|
|
10
|
+
import { reconcileMigrations } from "./reconcilers/migrations.js";
|
|
11
|
+
import { reconcileRegister } from "./reconcilers/register.js";
|
|
12
|
+
import { reconcileSeeds } from "./reconcilers/seeds.js";
|
|
13
|
+
import { buildIdentity } from "./identity.js";
|
|
14
|
+
export function summarize(results, target) {
|
|
15
|
+
const counts = {
|
|
16
|
+
created: 0,
|
|
17
|
+
updated: 0,
|
|
18
|
+
unchanged: 0,
|
|
19
|
+
skipped: 0,
|
|
20
|
+
failed: 0,
|
|
21
|
+
};
|
|
22
|
+
for (const r of results)
|
|
23
|
+
counts[r.action] += 1;
|
|
24
|
+
return { target, results, counts };
|
|
25
|
+
}
|
|
26
|
+
export async function run(input) {
|
|
27
|
+
const snapshot = await loadSnapshot(input.paths);
|
|
28
|
+
const results = [];
|
|
29
|
+
// Migrations first — they may introduce raw-SQL tables and columns that
|
|
30
|
+
// subsequent reconcilers reference. Idempotent (tracked per-file in
|
|
31
|
+
// lola_deploy_migrations on the target).
|
|
32
|
+
if (input.entities.has("migrations") && input.migrationsDir) {
|
|
33
|
+
results.push(...(await reconcileMigrations({
|
|
34
|
+
migrationsDir: input.migrationsDir,
|
|
35
|
+
client: input.client,
|
|
36
|
+
opts: input.opts,
|
|
37
|
+
})));
|
|
38
|
+
// Register manifests for raw-SQL adopted tables. Runs alongside migrations
|
|
39
|
+
// because the two are conceptually paired: a migration creates the raw
|
|
40
|
+
// table, its manifest teaches Directus about the columns. Piggy-backs on
|
|
41
|
+
// the `migrations` entity kind so callers don't need to opt in twice.
|
|
42
|
+
results.push(...(await reconcileRegister({
|
|
43
|
+
registerDir: input.paths.registerDir,
|
|
44
|
+
client: input.client,
|
|
45
|
+
opts: input.opts,
|
|
46
|
+
})));
|
|
47
|
+
}
|
|
48
|
+
// Order matters:
|
|
49
|
+
// collections → fields → relations (schema, string keys)
|
|
50
|
+
// roles → policies → permissions (auto-id, cross-refs by name)
|
|
51
|
+
if (input.entities.has("collections")) {
|
|
52
|
+
results.push(...(await reconcileCollections({
|
|
53
|
+
collections: snapshot.collections,
|
|
54
|
+
registerManifests: snapshot.registerManifests,
|
|
55
|
+
client: input.client,
|
|
56
|
+
opts: input.opts,
|
|
57
|
+
})));
|
|
58
|
+
}
|
|
59
|
+
if (input.entities.has("fields")) {
|
|
60
|
+
results.push(...(await reconcileFields({
|
|
61
|
+
fieldsByCollection: snapshot.fieldsByCollection,
|
|
62
|
+
registerManifests: snapshot.registerManifests,
|
|
63
|
+
client: input.client,
|
|
64
|
+
opts: input.opts,
|
|
65
|
+
})));
|
|
66
|
+
}
|
|
67
|
+
if (input.entities.has("relations")) {
|
|
68
|
+
results.push(...(await reconcileRelations({
|
|
69
|
+
relationsByCollection: snapshot.relationsByCollection,
|
|
70
|
+
client: input.client,
|
|
71
|
+
opts: input.opts,
|
|
72
|
+
})));
|
|
73
|
+
}
|
|
74
|
+
// Auto-id entities need an identity index built once per phase.
|
|
75
|
+
const needsIdentity = input.entities.has("policies") ||
|
|
76
|
+
input.entities.has("permissions") ||
|
|
77
|
+
input.entities.has("roles") ||
|
|
78
|
+
input.entities.has("flows") ||
|
|
79
|
+
input.entities.has("operations");
|
|
80
|
+
if (needsIdentity) {
|
|
81
|
+
if (input.entities.has("roles")) {
|
|
82
|
+
results.push(...(await reconcileRoles({
|
|
83
|
+
roles: snapshot.roles,
|
|
84
|
+
client: input.client,
|
|
85
|
+
opts: input.opts,
|
|
86
|
+
})));
|
|
87
|
+
}
|
|
88
|
+
const identity1 = await buildIdentity(input.client, snapshot.policies, snapshot.roles, snapshot.flows, snapshot.operations);
|
|
89
|
+
if (input.entities.has("policies")) {
|
|
90
|
+
results.push(...(await reconcilePolicies({
|
|
91
|
+
policies: snapshot.policies,
|
|
92
|
+
identity: identity1,
|
|
93
|
+
client: input.client,
|
|
94
|
+
opts: input.opts,
|
|
95
|
+
})));
|
|
96
|
+
}
|
|
97
|
+
if (input.entities.has("permissions")) {
|
|
98
|
+
// Re-fetch identity so policies just created are resolvable.
|
|
99
|
+
const identity2 = await buildIdentity(input.client, snapshot.policies, snapshot.roles, snapshot.flows, snapshot.operations);
|
|
100
|
+
results.push(...(await reconcilePermissions({
|
|
101
|
+
permissions: snapshot.permissions,
|
|
102
|
+
identity: identity2,
|
|
103
|
+
client: input.client,
|
|
104
|
+
opts: input.opts,
|
|
105
|
+
})));
|
|
106
|
+
}
|
|
107
|
+
// Flows + operations: two-pass to break the mutual FK cycle.
|
|
108
|
+
if (input.entities.has("flows") || input.entities.has("operations")) {
|
|
109
|
+
const identityF = await buildIdentity(input.client, snapshot.policies, snapshot.roles, snapshot.flows, snapshot.operations);
|
|
110
|
+
if (input.entities.has("flows")) {
|
|
111
|
+
results.push(...(await reconcileFlowsPass1({
|
|
112
|
+
flows: snapshot.flows,
|
|
113
|
+
identity: identityF,
|
|
114
|
+
client: input.client,
|
|
115
|
+
opts: input.opts,
|
|
116
|
+
})));
|
|
117
|
+
}
|
|
118
|
+
if (input.entities.has("operations")) {
|
|
119
|
+
// Refresh identity so newly-created flow ids become resolvable.
|
|
120
|
+
const identityO = await buildIdentity(input.client, snapshot.policies, snapshot.roles, snapshot.flows, snapshot.operations);
|
|
121
|
+
results.push(...(await reconcileOperationsPass1({
|
|
122
|
+
operations: snapshot.operations,
|
|
123
|
+
identity: identityO,
|
|
124
|
+
client: input.client,
|
|
125
|
+
opts: input.opts,
|
|
126
|
+
})));
|
|
127
|
+
// Second pass on operations: resolve/reject refs.
|
|
128
|
+
const identityO2 = await buildIdentity(input.client, snapshot.policies, snapshot.roles, snapshot.flows, snapshot.operations);
|
|
129
|
+
results.push(...(await reconcileOperationsPass2({
|
|
130
|
+
operations: snapshot.operations,
|
|
131
|
+
identity: identityO2,
|
|
132
|
+
client: input.client,
|
|
133
|
+
opts: input.opts,
|
|
134
|
+
})));
|
|
135
|
+
}
|
|
136
|
+
if (input.entities.has("flows")) {
|
|
137
|
+
// Final pass on flows: link each flow's entry `operation` to its
|
|
138
|
+
// freshly-reconciled server op id.
|
|
139
|
+
const identityFinal = await buildIdentity(input.client, snapshot.policies, snapshot.roles, snapshot.flows, snapshot.operations);
|
|
140
|
+
results.push(...(await reconcileFlowsPass2({
|
|
141
|
+
flows: snapshot.flows,
|
|
142
|
+
identity: identityFinal,
|
|
143
|
+
client: input.client,
|
|
144
|
+
opts: input.opts,
|
|
145
|
+
})));
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
// Seed data — data-tables (messaging_templates, notification_types, …). Runs
|
|
150
|
+
// last so any referenced collections/policies/flows exist first.
|
|
151
|
+
if (input.entities.has("seeds") && input.seedDir) {
|
|
152
|
+
results.push(...(await reconcileSeeds({
|
|
153
|
+
seedDir: input.seedDir,
|
|
154
|
+
client: input.client,
|
|
155
|
+
opts: input.opts,
|
|
156
|
+
})));
|
|
157
|
+
}
|
|
158
|
+
return summarize(results, input.target);
|
|
159
|
+
}
|
|
160
|
+
//# sourceMappingURL=runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner.js","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"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"}
|
package/dist/sanitize.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// Strip server-managed keys from a payload before POST/PATCH.
|
|
2
|
+
// Directus in practice ignores unknown top-level keys on writes, but sending
|
|
3
|
+
// Tractr's `_syncId` or stale timestamps is confusing at best and could break
|
|
4
|
+
// on a future Directus release. Also recursively cleans nested `meta` which
|
|
5
|
+
// carries its own auto-id in some entity kinds.
|
|
6
|
+
const SERVER_ONLY_KEYS = new Set([
|
|
7
|
+
"_syncId",
|
|
8
|
+
"id",
|
|
9
|
+
"date_created",
|
|
10
|
+
"user_created",
|
|
11
|
+
"date_updated",
|
|
12
|
+
"user_updated",
|
|
13
|
+
]);
|
|
14
|
+
function stripKeys(obj) {
|
|
15
|
+
const out = {};
|
|
16
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
17
|
+
if (SERVER_ONLY_KEYS.has(k))
|
|
18
|
+
continue;
|
|
19
|
+
out[k] = v;
|
|
20
|
+
}
|
|
21
|
+
return out;
|
|
22
|
+
}
|
|
23
|
+
export function sanitizeForWrite(payload) {
|
|
24
|
+
const cleaned = stripKeys(payload);
|
|
25
|
+
const meta = cleaned["meta"];
|
|
26
|
+
if (meta && typeof meta === "object" && !Array.isArray(meta)) {
|
|
27
|
+
cleaned["meta"] = stripKeys(meta);
|
|
28
|
+
}
|
|
29
|
+
return cleaned;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=sanitize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sanitize.js","sourceRoot":"","sources":["../src/sanitize.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,6EAA6E;AAC7E,8EAA8E;AAC9E,4EAA4E;AAC5E,gDAAgD;AAEhD,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC;IAC/B,SAAS;IACT,IAAI;IACJ,cAAc;IACd,cAAc;IACd,cAAc;IACd,cAAc;CACf,CAAC,CAAC;AAEH,SAAS,SAAS,CAAC,GAA4B;IAC7C,MAAM,GAAG,GAA4B,EAAE,CAAC;IACxC,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACzC,IAAI,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC;YAAE,SAAS;QACtC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACb,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,OAAgC;IAC/D,MAAM,OAAO,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;IACnC,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC7B,IAAI,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QAC7D,OAAO,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC,IAA+B,CAAC,CAAC;IAC/D,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
package/dist/sql.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
// Split a SQL blob into individual statements. Respects:
|
|
2
|
+
// -- line comments (up to newline)
|
|
3
|
+
// /* block comments */
|
|
4
|
+
// 'single-quoted' strings (with '' escape)
|
|
5
|
+
// $$ or $tag$ dollar-quoted blocks (Postgres)
|
|
6
|
+
//
|
|
7
|
+
// Naive splitters (e.g. `raw-query/execute`'s server-side one that we've been
|
|
8
|
+
// dodging all day) don't understand comments and blow up on any semicolon in
|
|
9
|
+
// a comment. We do it correctly here.
|
|
10
|
+
export function splitSql(input) {
|
|
11
|
+
const out = [];
|
|
12
|
+
let buf = "";
|
|
13
|
+
let i = 0;
|
|
14
|
+
const n = input.length;
|
|
15
|
+
const push = () => {
|
|
16
|
+
const trimmed = buf.trim();
|
|
17
|
+
if (trimmed)
|
|
18
|
+
out.push(trimmed);
|
|
19
|
+
buf = "";
|
|
20
|
+
};
|
|
21
|
+
while (i < n) {
|
|
22
|
+
const c = input[i];
|
|
23
|
+
const c2 = input[i + 1] ?? "";
|
|
24
|
+
// Line comment: --... until newline
|
|
25
|
+
if (c === "-" && c2 === "-") {
|
|
26
|
+
buf += c + c2;
|
|
27
|
+
i += 2;
|
|
28
|
+
while (i < n && input[i] !== "\n") {
|
|
29
|
+
buf += input[i];
|
|
30
|
+
i += 1;
|
|
31
|
+
}
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
// Block comment: /* ... */ (non-nested, per SQL spec's most common usage)
|
|
35
|
+
if (c === "/" && c2 === "*") {
|
|
36
|
+
buf += c + c2;
|
|
37
|
+
i += 2;
|
|
38
|
+
while (i < n && !(input[i] === "*" && input[i + 1] === "/")) {
|
|
39
|
+
buf += input[i];
|
|
40
|
+
i += 1;
|
|
41
|
+
}
|
|
42
|
+
if (i < n) {
|
|
43
|
+
buf += "*/";
|
|
44
|
+
i += 2;
|
|
45
|
+
}
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
// Single-quoted string: '...' with '' escape
|
|
49
|
+
if (c === "'") {
|
|
50
|
+
buf += c;
|
|
51
|
+
i += 1;
|
|
52
|
+
while (i < n) {
|
|
53
|
+
const ch = input[i];
|
|
54
|
+
buf += ch;
|
|
55
|
+
i += 1;
|
|
56
|
+
if (ch === "'") {
|
|
57
|
+
if (input[i] === "'") {
|
|
58
|
+
buf += "'";
|
|
59
|
+
i += 1;
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
// Dollar-quoted block: $tag$ ... $tag$ (tag can be empty)
|
|
68
|
+
if (c === "$") {
|
|
69
|
+
const tagEnd = input.indexOf("$", i + 1);
|
|
70
|
+
// Consider it a dollar quote only if what's between the two $ is an
|
|
71
|
+
// identifier-like tag (letters/digits/_) or empty AND the closing tag
|
|
72
|
+
// appears later.
|
|
73
|
+
if (tagEnd !== -1) {
|
|
74
|
+
const tag = input.slice(i + 1, tagEnd);
|
|
75
|
+
if (/^[A-Za-z0-9_]*$/.test(tag)) {
|
|
76
|
+
const closer = `$${tag}$`;
|
|
77
|
+
const closeAt = input.indexOf(closer, tagEnd + 1);
|
|
78
|
+
if (closeAt !== -1) {
|
|
79
|
+
buf += input.slice(i, closeAt + closer.length);
|
|
80
|
+
i = closeAt + closer.length;
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
buf += c;
|
|
86
|
+
i += 1;
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
// Statement terminator
|
|
90
|
+
if (c === ";") {
|
|
91
|
+
buf += ";";
|
|
92
|
+
i += 1;
|
|
93
|
+
push();
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
buf += c;
|
|
97
|
+
i += 1;
|
|
98
|
+
}
|
|
99
|
+
push();
|
|
100
|
+
return out;
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=sql.js.map
|
package/dist/sql.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sql.js","sourceRoot":"","sources":["../src/sql.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "directus-deploy-cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Per-entity, non-atomic Directus deployment tool. Reconciles collections/fields/relations/roles/policies/permissions/flows/operations/migrations/seeds from git to any environment.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"directus-deploy": "dist/cli.js",
|
|
8
|
+
"directus-deploy-mcp": "dist/mcp-server.js"
|
|
9
|
+
},
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "git+https://github.com/lola-market-team/directus-deploy-cli.git"
|
|
13
|
+
},
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"keywords": ["directus", "deploy", "reconcile", "sync", "cli"],
|
|
16
|
+
"publishConfig": {
|
|
17
|
+
"access": "public"
|
|
18
|
+
},
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsc",
|
|
21
|
+
"dev": "tsx src/cli.ts",
|
|
22
|
+
"test": "vitest run",
|
|
23
|
+
"test:live": "vitest run --config vitest.live.config.ts",
|
|
24
|
+
"test:watch": "vitest",
|
|
25
|
+
"typecheck": "tsc --noEmit",
|
|
26
|
+
"prepublishOnly": "npm run build"
|
|
27
|
+
},
|
|
28
|
+
"engines": {
|
|
29
|
+
"node": ">=20"
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
33
|
+
"commander": "^12.1.0"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@types/node": "^20.14.0",
|
|
37
|
+
"tsx": "^4.19.0",
|
|
38
|
+
"typescript": "^5.6.0",
|
|
39
|
+
"vitest": "^2.1.0"
|
|
40
|
+
},
|
|
41
|
+
"files": [
|
|
42
|
+
"dist",
|
|
43
|
+
"README.md"
|
|
44
|
+
]
|
|
45
|
+
}
|