neon 2.47.0 → 3.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 +54 -0
- package/dist/_shared/auth_selection.js +76 -79
- package/dist/_shared/credentials.js +166 -187
- package/dist/_shared/env-core/env.js +395 -0
- package/dist/_shared/env-core/reuse-secrets.js +179 -0
- package/dist/_shared/paths.js +129 -126
- package/dist/_shared/profiles.js +192 -242
- package/dist/_shared/secure_file.js +36 -38
- package/dist/_virtual/_rolldown/runtime.js +13 -0
- package/dist/analytics.js +163 -207
- package/dist/api.js +815 -758
- package/dist/auth.js +121 -141
- package/dist/auth_context.js +39 -53
- package/dist/cli.js +4 -7
- package/dist/commands/api.js +220 -250
- package/dist/commands/api_keys.js +251 -314
- package/dist/commands/auth.js +283 -328
- package/dist/commands/bootstrap.js +372 -437
- package/dist/commands/branches.js +304 -455
- package/dist/commands/bucket.js +374 -514
- package/dist/commands/checkout.js +213 -298
- package/dist/commands/config.js +575 -658
- package/dist/commands/connection_string.js +137 -165
- package/dist/commands/data_api.js +238 -260
- package/dist/commands/databases.js +67 -76
- package/dist/commands/deploy.js +31 -25
- package/dist/commands/dev.js +642 -681
- package/dist/commands/diff.js +156 -200
- package/dist/commands/env.js +243 -303
- package/dist/commands/functions.js +275 -341
- package/dist/commands/index.js +70 -65
- package/dist/commands/init.js +84 -119
- package/dist/commands/inspect.js +55 -55
- package/dist/commands/ip_allow.js +88 -120
- package/dist/commands/link.js +874 -1019
- package/dist/commands/logs.js +291 -0
- package/dist/commands/neon_auth.js +725 -933
- package/dist/commands/operations.js +34 -25
- package/dist/commands/orgs.js +28 -18
- package/dist/commands/profile.js +614 -845
- package/dist/commands/projects.js +313 -373
- package/dist/commands/psql.js +60 -58
- package/dist/commands/roles.js +55 -58
- package/dist/commands/schema_diff.js +87 -131
- package/dist/commands/set_context.js +34 -26
- package/dist/commands/snapshots.js +288 -413
- package/dist/commands/status.js +41 -37
- package/dist/commands/user.js +21 -10
- package/dist/commands/vpc_endpoints.js +85 -113
- package/dist/config.js +7 -6
- package/dist/config_format.js +50 -66
- package/dist/config_template.js +128 -157
- package/dist/context.js +183 -235
- package/dist/current_branch_fast_path.js +40 -49
- package/dist/dev/env.js +313 -394
- package/dist/dev/functions.js +54 -64
- package/dist/dev/inputs.js +46 -58
- package/dist/dev/runtime.js +135 -164
- package/dist/dev/websocket.js +766 -959
- package/dist/env.js +27 -33
- package/dist/env_file.js +118 -132
- package/dist/env_services.js +36 -38
- package/dist/errors.js +57 -68
- package/dist/functions_api.js +45 -43
- package/dist/help.js +189 -140
- package/dist/index.js +182 -257
- package/dist/init/agents.js +137 -118
- package/dist/init/auth.js +58 -68
- package/dist/init/bootstrap.js +325 -396
- package/dist/init/build_config.js +4 -2
- package/dist/init/detect_agent.js +56 -101
- package/dist/init/editors.js +35 -52
- package/dist/init/enrich_output.js +51 -66
- package/dist/init/extension.js +134 -171
- package/dist/init/inspect.js +179 -266
- package/dist/init/interactive.js +510 -622
- package/dist/init/neonctl.js +117 -168
- package/dist/init/orchestrate.js +157 -173
- package/dist/init/phases/auth.js +188 -202
- package/dist/init/phases/cleanup.js +23 -23
- package/dist/init/phases/db.js +251 -277
- package/dist/init/phases/getting_started.js +213 -223
- package/dist/init/phases/mcp.js +174 -224
- package/dist/init/phases/migrations.js +247 -248
- package/dist/init/phases/neon_auth.js +114 -133
- package/dist/init/phases/setup.js +546 -703
- package/dist/init/phases/skills.js +75 -86
- package/dist/init/phases/status.js +72 -67
- package/dist/init/resolve_context.js +102 -99
- package/dist/init/route_command.js +91 -98
- package/dist/init/skills.js +174 -218
- package/dist/init/vsix.js +77 -99
- package/dist/log.js +17 -16
- package/dist/neon_services.js +104 -129
- package/dist/parameters.gen.js +481 -471
- package/dist/pkg.js +17 -19
- package/dist/profile_keys.js +44 -47
- package/dist/psql/cli.js +44 -47
- package/dist/psql/command/cmd_cond.js +231 -406
- package/dist/psql/command/cmd_connect.js +557 -764
- package/dist/psql/command/cmd_copy.js +727 -983
- package/dist/psql/command/cmd_describe.js +1499 -1688
- package/dist/psql/command/cmd_format.js +733 -905
- package/dist/psql/command/cmd_io.js +1293 -2082
- package/dist/psql/command/cmd_lo.js +297 -359
- package/dist/psql/command/cmd_meta.js +727 -878
- package/dist/psql/command/cmd_misc.js +138 -172
- package/dist/psql/command/cmd_pipeline.js +547 -1099
- package/dist/psql/command/cmd_restrict.js +119 -155
- package/dist/psql/command/cmd_show.js +529 -688
- package/dist/psql/command/dispatch.js +261 -325
- package/dist/psql/command/inputQueue.js +35 -33
- package/dist/psql/command/shared.js +49 -63
- package/dist/psql/complete/filenames.js +90 -133
- package/dist/psql/complete/index.js +59 -97
- package/dist/psql/complete/matcher.js +236 -300
- package/dist/psql/complete/psqlVars.js +218 -223
- package/dist/psql/complete/queries.js +159 -177
- package/dist/psql/complete/rules.js +1493 -2299
- package/dist/psql/core/common.js +762 -1180
- package/dist/psql/core/help.js +456 -546
- package/dist/psql/core/mainloop.js +692 -1302
- package/dist/psql/core/prompt.js +391 -408
- package/dist/psql/core/settings.js +429 -644
- package/dist/psql/core/sqlHelp.js +480 -554
- package/dist/psql/core/startup.js +626 -815
- package/dist/psql/core/syncVars.js +67 -110
- package/dist/psql/core/variables.js +156 -278
- package/dist/psql/describe/formatters.js +884 -1285
- package/dist/psql/describe/processNamePattern.js +173 -260
- package/dist/psql/describe/queries.js +1368 -2403
- package/dist/psql/describe/versionGate.js +32 -41
- package/dist/psql/index.js +1414 -1927
- package/dist/psql/io/history.js +232 -271
- package/dist/psql/io/input.js +103 -108
- package/dist/psql/io/lineEditor/buffer.js +238 -319
- package/dist/psql/io/lineEditor/complete.js +135 -213
- package/dist/psql/io/lineEditor/filename.js +139 -148
- package/dist/psql/io/lineEditor/index.js +653 -870
- package/dist/psql/io/lineEditor/keymap.js +544 -702
- package/dist/psql/io/lineEditor/vt100.js +294 -341
- package/dist/psql/io/pgpass.js +158 -187
- package/dist/psql/io/pgservice.js +146 -183
- package/dist/psql/io/psqlrc.js +328 -403
- package/dist/psql/print/aligned.js +1020 -1683
- package/dist/psql/print/asciidoc.js +180 -214
- package/dist/psql/print/crosstab.js +281 -442
- package/dist/psql/print/csv.js +48 -70
- package/dist/psql/print/html.js +195 -226
- package/dist/psql/print/json.js +75 -88
- package/dist/psql/print/latex.js +291 -364
- package/dist/psql/print/pager.js +171 -242
- package/dist/psql/print/troff.js +194 -226
- package/dist/psql/print/unaligned.js +69 -95
- package/dist/psql/print/units.js +167 -169
- package/dist/psql/scanner/slash.js +428 -483
- package/dist/psql/scanner/sql.js +445 -889
- package/dist/psql/scanner/stringutils.js +309 -379
- package/dist/psql/types/index.js +2 -7
- package/dist/psql/types/scanner.js +25 -22
- package/dist/psql/wire/connection.js +2042 -2803
- package/dist/psql/wire/copy.js +84 -100
- package/dist/psql/wire/notify.js +39 -59
- package/dist/psql/wire/pipeline.js +305 -518
- package/dist/psql/wire/protocol.js +349 -417
- package/dist/psql/wire/sasl.js +180 -265
- package/dist/psql/wire/tls.js +400 -561
- package/dist/storage_api.js +115 -129
- package/dist/test_utils/fixtures.js +94 -113
- package/dist/test_utils/oauth_server.js +10 -7
- package/dist/test_utils/project_dir.js +33 -0
- package/dist/utils/ai_gateway_notice.js +131 -162
- package/dist/utils/api_enums.js +21 -28
- package/dist/utils/auth.js +10 -4
- package/dist/utils/branch_notice.js +20 -19
- package/dist/utils/branch_picker.js +83 -89
- package/dist/utils/cli_name.js +15 -12
- package/dist/utils/compute_units.js +20 -27
- package/dist/utils/config_diff.js +127 -158
- package/dist/utils/enrichers.js +95 -148
- package/dist/utils/esbuild.js +133 -147
- package/dist/utils/flags.js +35 -47
- package/dist/utils/formats.js +8 -15
- package/dist/utils/git_diff.js +69 -80
- package/dist/utils/inspect_db.js +101 -143
- package/dist/utils/inspect_queries.js +179 -142
- package/dist/utils/middlewares.js +37 -44
- package/dist/utils/openapi.js +87 -99
- package/dist/utils/package_manager.js +312 -110
- package/dist/utils/point_in_time.js +49 -53
- package/dist/utils/psql.js +89 -106
- package/dist/utils/service_picker.js +55 -58
- package/dist/utils/string.js +5 -5
- package/dist/utils/ui.js +38 -55
- package/dist/utils/write_sync.js +26 -35
- package/dist/utils/zip.js +4 -3
- package/dist/writer.js +67 -87
- package/package.json +9 -7
package/dist/utils/cli_name.js
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import { basename } from "node:path";
|
|
2
|
+
//#region src/utils/cli_name.ts
|
|
2
3
|
/**
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
4
|
+
* The name this CLI was invoked as: `neon` (current) or `neonctl` (legacy alias).
|
|
5
|
+
*
|
|
6
|
+
* Use this for any user-facing string that suggests a command to run — help text,
|
|
7
|
+
* error hints, and especially `--agent` `next_command_template` values, which an agent
|
|
8
|
+
* executes verbatim. Hardcoding `neonctl` breaks those on installs of the `neon` package,
|
|
9
|
+
* which no longer ships a `neonctl` binary (removed in `neon@2.38.0`).
|
|
10
|
+
*
|
|
11
|
+
* Derived from `process.argv[1]`, which is fixed for the process lifetime, so the result
|
|
12
|
+
* is stable whether this is called at module load or per invocation. Mirrors the name used
|
|
13
|
+
* for yargs `.scriptName()` in `index.ts`.
|
|
14
|
+
*/
|
|
15
|
+
const getCliName = () => basename(process.argv[1] ?? "") === "neonctl" ? "neonctl" : "neon";
|
|
16
|
+
//#endregion
|
|
17
|
+
export { getCliName };
|
|
@@ -1,28 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
throw new Error("Autoscaling min should be a number");
|
|
20
|
-
}
|
|
21
|
-
if (isNaN(maxAutoscaling)) {
|
|
22
|
-
throw new Error("Autoscaling max should be a number");
|
|
23
|
-
}
|
|
24
|
-
return {
|
|
25
|
-
autoscaling_limit_min_cu: minAutoscaling,
|
|
26
|
-
autoscaling_limit_max_cu: maxAutoscaling,
|
|
27
|
-
};
|
|
1
|
+
//#region src/utils/compute_units.ts
|
|
2
|
+
const getComputeUnits = (autoscaling) => {
|
|
3
|
+
const fixedSizeAutoscaling = Number(autoscaling);
|
|
4
|
+
if (!isNaN(fixedSizeAutoscaling)) return {
|
|
5
|
+
autoscaling_limit_min_cu: fixedSizeAutoscaling,
|
|
6
|
+
autoscaling_limit_max_cu: fixedSizeAutoscaling
|
|
7
|
+
};
|
|
8
|
+
if (!autoscaling.includes("-")) throw new Error("Autoscaling should be either fixed size (e.g. 2) or min and max sizes delimited with a dash (e.g. \"0.5-1\")");
|
|
9
|
+
const [min, max] = autoscaling.split("-");
|
|
10
|
+
if (!min || !max) throw new Error("Autoscaling should be either fixed size (e.g. 2) or min and max sizes delimited with a dash (e.g. \"0.5-1\")");
|
|
11
|
+
const minAutoscaling = Number(min);
|
|
12
|
+
const maxAutoscaling = Number(max);
|
|
13
|
+
if (isNaN(minAutoscaling)) throw new Error("Autoscaling min should be a number");
|
|
14
|
+
if (isNaN(maxAutoscaling)) throw new Error("Autoscaling max should be a number");
|
|
15
|
+
return {
|
|
16
|
+
autoscaling_limit_min_cu: minAutoscaling,
|
|
17
|
+
autoscaling_limit_max_cu: maxAutoscaling
|
|
18
|
+
};
|
|
28
19
|
};
|
|
20
|
+
//#endregion
|
|
21
|
+
export { getComputeUnits };
|
|
@@ -1,185 +1,154 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
|
+
//#region src/utils/config_diff.ts
|
|
2
3
|
const UNSET = "(unset)";
|
|
3
4
|
/**
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
* Shared palette for the config diff, matching `neon diff`'s `git diff` styling
|
|
6
|
+
* (bold headers, red "before", green "after", dim connective glyphs). When
|
|
7
|
+
* `color` is false every entry is the identity function, so the identical layout
|
|
8
|
+
* renders without ANSI codes for `--no-color`, non-TTY pipes, and test snapshots.
|
|
9
|
+
*/
|
|
9
10
|
const palette = (color) => {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
11
|
+
const id = (s) => s;
|
|
12
|
+
if (!color) return {
|
|
13
|
+
title: id,
|
|
14
|
+
group: id,
|
|
15
|
+
added: id,
|
|
16
|
+
removed: id,
|
|
17
|
+
arrow: id
|
|
18
|
+
};
|
|
19
|
+
return {
|
|
20
|
+
title: (s) => chalk.bold(s),
|
|
21
|
+
group: (s) => chalk.bold(s),
|
|
22
|
+
added: (s) => chalk.green(s),
|
|
23
|
+
removed: (s) => chalk.red(s),
|
|
24
|
+
arrow: (s) => chalk.dim(s)
|
|
25
|
+
};
|
|
21
26
|
};
|
|
22
27
|
const isPlainObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
23
28
|
const stringifyValue = (value) => {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
if (typeof value === "boolean" || typeof value === "number") {
|
|
29
|
-
return String(value);
|
|
30
|
-
}
|
|
31
|
-
return JSON.stringify(value);
|
|
29
|
+
if (value === void 0 || value === null || value === "") return UNSET;
|
|
30
|
+
if (typeof value === "string") return value;
|
|
31
|
+
if (typeof value === "boolean" || typeof value === "number") return String(value);
|
|
32
|
+
return JSON.stringify(value);
|
|
32
33
|
};
|
|
33
34
|
/**
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
35
|
+
* Expand one policy field into flat {@link FieldChange}s. When either side is a
|
|
36
|
+
* plain object (compute settings, Data API settings) it splits into one
|
|
37
|
+
* `field.key` entry per key across both sides, so the diff reads as sorted
|
|
38
|
+
* scalar lines (`computeSettings.autoscalingLimitMaxCu 2 → 4`) rather than an
|
|
39
|
+
* opaque JSON blob. Scalars produce a single entry.
|
|
40
|
+
*/
|
|
40
41
|
const expandField = (field, current, desired) => {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
? { current: stringifyValue(current) }
|
|
56
|
-
: {}),
|
|
57
|
-
desired: stringifyValue(desired),
|
|
58
|
-
},
|
|
59
|
-
];
|
|
42
|
+
if (isPlainObject(current) || isPlainObject(desired)) {
|
|
43
|
+
const cur = isPlainObject(current) ? current : {};
|
|
44
|
+
const des = isPlainObject(desired) ? desired : {};
|
|
45
|
+
return Array.from(/* @__PURE__ */ new Set([...Object.keys(cur), ...Object.keys(des)])).sort().map((key) => ({
|
|
46
|
+
field: `${field}.${key}`,
|
|
47
|
+
...key in cur ? { current: stringifyValue(cur[key]) } : {},
|
|
48
|
+
desired: stringifyValue(des[key])
|
|
49
|
+
}));
|
|
50
|
+
}
|
|
51
|
+
return [{
|
|
52
|
+
field,
|
|
53
|
+
...current !== void 0 ? { current: stringifyValue(current) } : {},
|
|
54
|
+
desired: stringifyValue(desired)
|
|
55
|
+
}];
|
|
60
56
|
};
|
|
61
57
|
/** Render the indented `field current → desired` lines for one branch group. */
|
|
62
58
|
const renderFieldLines = (fields, paint) => {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
: ` ${name} ${arrow} ${paint.added(f.desired)}`;
|
|
70
|
-
});
|
|
59
|
+
const width = fields.reduce((max, f) => Math.max(max, f.field.length), 0);
|
|
60
|
+
return fields.map((f) => {
|
|
61
|
+
const name = f.field.padEnd(width);
|
|
62
|
+
const arrow = paint.arrow("→");
|
|
63
|
+
return f.current !== void 0 ? ` ${name} ${paint.removed(f.current)} ${arrow} ${paint.added(f.desired)}` : ` ${name} ${arrow} ${paint.added(f.desired)}`;
|
|
64
|
+
});
|
|
71
65
|
};
|
|
72
66
|
/** Group field changes by branch, each block sorted alphabetically by field. */
|
|
73
67
|
const renderBranchGroups = (byBranch, paint) => {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
68
|
+
const lines = [];
|
|
69
|
+
const groups = [...byBranch.entries()].sort((a, b) => a[0].localeCompare(b[0]));
|
|
70
|
+
for (const [branch, fields] of groups) {
|
|
71
|
+
const sorted = [...fields].sort((a, b) => a.field.localeCompare(b.field));
|
|
72
|
+
lines.push(` ${paint.group(`~ ${branch}`)}`);
|
|
73
|
+
lines.push(...renderFieldLines(sorted, paint));
|
|
74
|
+
}
|
|
75
|
+
return lines;
|
|
82
76
|
};
|
|
83
77
|
/** Friendly label for a service change identifier (`bucket:x` → `bucket x`). */
|
|
84
78
|
const serviceLabel = (identifier) => {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
return `bucket ${identifier.slice("bucket:".length)}`;
|
|
91
|
-
}
|
|
92
|
-
if (identifier.startsWith("function:")) {
|
|
93
|
-
return `function ${identifier.slice("function:".length)}`;
|
|
94
|
-
}
|
|
95
|
-
return identifier;
|
|
79
|
+
if (identifier === "auth") return "Neon Auth";
|
|
80
|
+
if (identifier === "dataApi") return "Data API";
|
|
81
|
+
if (identifier.startsWith("bucket:")) return `bucket ${identifier.slice(7)}`;
|
|
82
|
+
if (identifier.startsWith("function:")) return `function ${identifier.slice(9)}`;
|
|
83
|
+
return identifier;
|
|
96
84
|
};
|
|
97
85
|
/**
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
86
|
+
* The desired-only field changes for an applied/planned **branch** update. The
|
|
87
|
+
* synthesized `AppliedChange.details` carry the new value keyed by `field`
|
|
88
|
+
* (`parent`→`parent`, `ttl`→`expiresAt`, `protected`→`protected`,
|
|
89
|
+
* `computeSettings`→`settings`); the previous value isn't threaded through in
|
|
90
|
+
* Phase 1, so these render as `field → desired` (no red "before"). Object
|
|
91
|
+
* settings expand into sub-fields.
|
|
92
|
+
*
|
|
93
|
+
* `parent` only ever arrives from a branch creation (it cannot be changed
|
|
94
|
+
* afterwards), where it reports the parent the policy named.
|
|
95
|
+
*/
|
|
108
96
|
const appliedBranchFields = (change) => {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
case "computeSettings":
|
|
119
|
-
return expandField("computeSettings", undefined, details.settings);
|
|
120
|
-
default:
|
|
121
|
-
return expandField(field, undefined, details.settings);
|
|
122
|
-
}
|
|
97
|
+
const details = change.details ?? {};
|
|
98
|
+
const field = typeof details.field === "string" ? details.field : "setting";
|
|
99
|
+
switch (field) {
|
|
100
|
+
case "parent": return expandField("parent", void 0, details.parent);
|
|
101
|
+
case "ttl": return expandField("ttl", void 0, details.expiresAt);
|
|
102
|
+
case "protected": return expandField("protected", void 0, details.protected);
|
|
103
|
+
case "computeSettings": return expandField("computeSettings", void 0, details.settings);
|
|
104
|
+
default: return expandField(field, void 0, details.settings);
|
|
105
|
+
}
|
|
123
106
|
};
|
|
124
107
|
/**
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
const existing = byBranch.get(change.identifier) ?? [];
|
|
153
|
-
byBranch.set(change.identifier, [
|
|
154
|
-
...existing,
|
|
155
|
-
...appliedBranchFields(change),
|
|
156
|
-
]);
|
|
157
|
-
}
|
|
158
|
-
lines.push(...renderBranchGroups(byBranch, paint));
|
|
159
|
-
return lines.join("\n");
|
|
108
|
+
* Render the applied (or planned) changes as a `git diff`-style list:
|
|
109
|
+
*
|
|
110
|
+
* - **Service changes** (auth / Data API / buckets / functions) are additions
|
|
111
|
+
* with no meaningful "before", so they list as green `+ <label>` lines
|
|
112
|
+
* (`~ <label>` for the lone Data API settings *update*).
|
|
113
|
+
* - **Branch setting changes** group per branch and render as sorted
|
|
114
|
+
* `field → value` lines under a `~ <branch>` header.
|
|
115
|
+
*
|
|
116
|
+
* Returns "" when there is nothing to show. Pure — callers own the heading
|
|
117
|
+
* spacing and any surrounding summary.
|
|
118
|
+
*/
|
|
119
|
+
const renderAppliedChanges = (changes, title, opts) => {
|
|
120
|
+
if (changes.length === 0) return "";
|
|
121
|
+
const paint = palette(opts.color);
|
|
122
|
+
const lines = [paint.title(title)];
|
|
123
|
+
const services = changes.filter((c) => c.kind === "service").sort((a, b) => a.identifier.localeCompare(b.identifier));
|
|
124
|
+
for (const service of services) {
|
|
125
|
+
const label = serviceLabel(service.identifier);
|
|
126
|
+
lines.push(service.action === "create" ? ` ${paint.added(`+ ${label}`)}` : ` ${paint.arrow(`~ ${label}`)}`);
|
|
127
|
+
}
|
|
128
|
+
const byBranch = /* @__PURE__ */ new Map();
|
|
129
|
+
for (const change of changes.filter((c) => c.kind === "branch")) {
|
|
130
|
+
const existing = byBranch.get(change.identifier) ?? [];
|
|
131
|
+
byBranch.set(change.identifier, [...existing, ...appliedBranchFields(change)]);
|
|
132
|
+
}
|
|
133
|
+
lines.push(...renderBranchGroups(byBranch, paint));
|
|
134
|
+
return lines.join("\n");
|
|
160
135
|
};
|
|
161
136
|
/**
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
...expandField(conflict.field, conflict.current, conflict.desired),
|
|
178
|
-
]);
|
|
179
|
-
}
|
|
180
|
-
const lines = [
|
|
181
|
-
paint.title("Branch settings differ (re-run with --update-existing to apply)"),
|
|
182
|
-
...renderBranchGroups(byBranch, paint),
|
|
183
|
-
];
|
|
184
|
-
return lines.join("\n");
|
|
137
|
+
* Render branch-setting **conflicts** (drift the policy wants to change but that
|
|
138
|
+
* needs `--update-existing`) as a `git diff`-style before→after report: grouped
|
|
139
|
+
* per branch, sorted by field, `current → desired` with the old value in red and
|
|
140
|
+
* the new in green. Conflicts already carry both sides, so this is the fullest
|
|
141
|
+
* form of the diff. Returns "" when there are no conflicts.
|
|
142
|
+
*/
|
|
143
|
+
const renderBranchSettingConflicts = (conflicts, opts) => {
|
|
144
|
+
if (conflicts.length === 0) return "";
|
|
145
|
+
const paint = palette(opts.color);
|
|
146
|
+
const byBranch = /* @__PURE__ */ new Map();
|
|
147
|
+
for (const conflict of conflicts) {
|
|
148
|
+
const existing = byBranch.get(conflict.identifier) ?? [];
|
|
149
|
+
byBranch.set(conflict.identifier, [...existing, ...expandField(conflict.field, conflict.current, conflict.desired)]);
|
|
150
|
+
}
|
|
151
|
+
return [paint.title("Branch settings differ (re-run with --update-existing to apply)"), ...renderBranchGroups(byBranch, paint)].join("\n");
|
|
185
152
|
};
|
|
153
|
+
//#endregion
|
|
154
|
+
export { renderAppliedChanges, renderBranchSettingConflicts };
|