redkite 0.1.6
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/LICENSE +21 -0
- package/README.md +819 -0
- package/bin/redkite.mjs +12 -0
- package/dist/build.d.ts +27 -0
- package/dist/build.d.ts.map +1 -0
- package/dist/build.js +132 -0
- package/dist/build.js.map +1 -0
- package/dist/checks.d.ts +4 -0
- package/dist/checks.d.ts.map +1 -0
- package/dist/checks.js +49 -0
- package/dist/checks.js.map +1 -0
- package/dist/cli/agent.d.ts +2 -0
- package/dist/cli/agent.d.ts.map +1 -0
- package/dist/cli/agent.js +24 -0
- package/dist/cli/agent.js.map +1 -0
- package/dist/cli/config.d.ts +5 -0
- package/dist/cli/config.d.ts.map +1 -0
- package/dist/cli/config.js +217 -0
- package/dist/cli/config.js.map +1 -0
- package/dist/cli/index.d.ts +11 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +438 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/log.d.ts +9 -0
- package/dist/cli/log.d.ts.map +1 -0
- package/dist/cli/log.js +128 -0
- package/dist/cli/log.js.map +1 -0
- package/dist/cli/screen.d.ts +34 -0
- package/dist/cli/screen.d.ts.map +1 -0
- package/dist/cli/screen.js +298 -0
- package/dist/cli/screen.js.map +1 -0
- package/dist/cli/viewer.d.ts +9 -0
- package/dist/cli/viewer.d.ts.map +1 -0
- package/dist/cli/viewer.js +139 -0
- package/dist/cli/viewer.js.map +1 -0
- package/dist/config.d.ts +7 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +79 -0
- package/dist/config.js.map +1 -0
- package/dist/deploy.d.ts +19 -0
- package/dist/deploy.d.ts.map +1 -0
- package/dist/deploy.js +275 -0
- package/dist/deploy.js.map +1 -0
- package/dist/docker.d.ts +96 -0
- package/dist/docker.d.ts.map +1 -0
- package/dist/docker.js +325 -0
- package/dist/docker.js.map +1 -0
- package/dist/dockerfile.d.ts +14 -0
- package/dist/dockerfile.d.ts.map +1 -0
- package/dist/dockerfile.js +160 -0
- package/dist/dockerfile.js.map +1 -0
- package/dist/health.d.ts +13 -0
- package/dist/health.d.ts.map +1 -0
- package/dist/health.js +54 -0
- package/dist/health.js.map +1 -0
- package/dist/host.d.ts +21 -0
- package/dist/host.d.ts.map +1 -0
- package/dist/host.js +27 -0
- package/dist/host.js.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/layout.d.ts +5 -0
- package/dist/layout.d.ts.map +1 -0
- package/dist/layout.js +45 -0
- package/dist/layout.js.map +1 -0
- package/dist/localHost.d.ts +7 -0
- package/dist/localHost.d.ts.map +1 -0
- package/dist/localHost.js +32 -0
- package/dist/localHost.js.map +1 -0
- package/dist/log.d.ts +14 -0
- package/dist/log.d.ts.map +1 -0
- package/dist/log.js +15 -0
- package/dist/log.js.map +1 -0
- package/dist/nginx.d.ts +4 -0
- package/dist/nginx.d.ts.map +1 -0
- package/dist/nginx.js +53 -0
- package/dist/nginx.js.map +1 -0
- package/dist/pipeline.d.ts +103 -0
- package/dist/pipeline.d.ts.map +1 -0
- package/dist/pipeline.js +142 -0
- package/dist/pipeline.js.map +1 -0
- package/dist/presets/index.d.ts +3 -0
- package/dist/presets/index.d.ts.map +1 -0
- package/dist/presets/index.js +3 -0
- package/dist/presets/index.js.map +1 -0
- package/dist/presets/nextApp.d.ts +15 -0
- package/dist/presets/nextApp.d.ts.map +1 -0
- package/dist/presets/nextApp.js +53 -0
- package/dist/presets/nextApp.js.map +1 -0
- package/dist/presets/nodeApp.d.ts +19 -0
- package/dist/presets/nodeApp.d.ts.map +1 -0
- package/dist/presets/nodeApp.js +29 -0
- package/dist/presets/nodeApp.js.map +1 -0
- package/dist/secrets/bitwarden.d.ts +3 -0
- package/dist/secrets/bitwarden.d.ts.map +1 -0
- package/dist/secrets/bitwarden.js +6 -0
- package/dist/secrets/bitwarden.js.map +1 -0
- package/dist/secrets/refs.d.ts +9 -0
- package/dist/secrets/refs.d.ts.map +1 -0
- package/dist/secrets/refs.js +20 -0
- package/dist/secrets/refs.js.map +1 -0
- package/dist/secrets/store.d.ts +9 -0
- package/dist/secrets/store.d.ts.map +1 -0
- package/dist/secrets/store.js +104 -0
- package/dist/secrets/store.js.map +1 -0
- package/dist/services/ensure.d.ts +18 -0
- package/dist/services/ensure.d.ts.map +1 -0
- package/dist/services/ensure.js +93 -0
- package/dist/services/ensure.js.map +1 -0
- package/dist/services/index.d.ts +19 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +27 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/planned.d.ts +20 -0
- package/dist/services/planned.d.ts.map +1 -0
- package/dist/services/planned.js +77 -0
- package/dist/services/planned.js.map +1 -0
- package/dist/shell.d.ts +11 -0
- package/dist/shell.d.ts.map +1 -0
- package/dist/shell.js +65 -0
- package/dist/shell.js.map +1 -0
- package/dist/source.d.ts +16 -0
- package/dist/source.d.ts.map +1 -0
- package/dist/source.js +108 -0
- package/dist/source.js.map +1 -0
- package/dist/sshHost.d.ts +15 -0
- package/dist/sshHost.d.ts.map +1 -0
- package/dist/sshHost.js +91 -0
- package/dist/sshHost.js.map +1 -0
- package/dist/steps.d.ts +27 -0
- package/dist/steps.d.ts.map +1 -0
- package/dist/steps.js +69 -0
- package/dist/steps.js.map +1 -0
- package/dist/topology.d.ts +40 -0
- package/dist/topology.d.ts.map +1 -0
- package/dist/topology.js +113 -0
- package/dist/topology.js.map +1 -0
- package/dist/types.d.ts +100 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +64 -0
- package/src/build.ts +236 -0
- package/src/checks.ts +65 -0
- package/src/cli/agent.ts +28 -0
- package/src/cli/config.ts +275 -0
- package/src/cli/index.ts +559 -0
- package/src/cli/log.ts +168 -0
- package/src/cli/screen.ts +409 -0
- package/src/cli/viewer.ts +192 -0
- package/src/config.ts +90 -0
- package/src/deploy.ts +409 -0
- package/src/docker.ts +433 -0
- package/src/dockerfile.ts +228 -0
- package/src/health.ts +83 -0
- package/src/host.ts +54 -0
- package/src/index.ts +25 -0
- package/src/layout.ts +41 -0
- package/src/localHost.ts +50 -0
- package/src/log.ts +38 -0
- package/src/nginx.ts +63 -0
- package/src/pipeline.ts +335 -0
- package/src/presets/index.ts +2 -0
- package/src/presets/nextApp.ts +70 -0
- package/src/presets/nodeApp.ts +46 -0
- package/src/secrets/bitwarden.ts +7 -0
- package/src/secrets/refs.ts +32 -0
- package/src/secrets/store.ts +147 -0
- package/src/services/ensure.ts +160 -0
- package/src/services/index.ts +48 -0
- package/src/services/planned.ts +119 -0
- package/src/shell.ts +95 -0
- package/src/source.ts +171 -0
- package/src/sshHost.ts +145 -0
- package/src/steps.ts +101 -0
- package/src/topology.ts +199 -0
- package/src/types.ts +243 -0
package/bin/redkite.mjs
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { main } from "../dist/cli/index.js";
|
|
3
|
+
|
|
4
|
+
// Node warns about a .ts config in a CommonJS package before redkite gets to say
|
|
5
|
+
// the same thing usefully, and its advice, .mjs, is wrong for a TypeScript file
|
|
6
|
+
process.removeAllListeners("warning");
|
|
7
|
+
process.on("warning", (warning) => {
|
|
8
|
+
if (warning.message.startsWith("Failed to load the ES module")) return;
|
|
9
|
+
console.warn(`${warning.name}: ${warning.message}`);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
await main(process.argv.slice(2));
|
package/dist/build.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Docker } from "./docker.js";
|
|
2
|
+
import type { Host } from "./host.js";
|
|
3
|
+
import type { AppTopology } from "./topology.js";
|
|
4
|
+
import type { AppSpec } from "./types.js";
|
|
5
|
+
export type BuildContext = {
|
|
6
|
+
host: Host;
|
|
7
|
+
docker: Docker;
|
|
8
|
+
deliver?: {
|
|
9
|
+
host: Host;
|
|
10
|
+
docker: Docker;
|
|
11
|
+
};
|
|
12
|
+
env: string;
|
|
13
|
+
files: Record<string, string>;
|
|
14
|
+
branch: string;
|
|
15
|
+
environment: string;
|
|
16
|
+
detail?: (message: string) => void;
|
|
17
|
+
output?: (line: string) => void;
|
|
18
|
+
};
|
|
19
|
+
export type BuildResult = {
|
|
20
|
+
release: string;
|
|
21
|
+
fingerprint: string;
|
|
22
|
+
tag: string;
|
|
23
|
+
builderTag: string;
|
|
24
|
+
cached: boolean;
|
|
25
|
+
};
|
|
26
|
+
export declare function build(app: AppSpec, topology: AppTopology, context: BuildContext): Promise<BuildResult>;
|
|
27
|
+
//# sourceMappingURL=build.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../src/build.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEtC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAM1C,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,IAAI,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IAGf,OAAO,CAAC,EAAE;QAAE,IAAI,EAAE,IAAI,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAEzC,GAAG,EAAE,MAAM,CAAC;IAEZ,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAEnC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACjC,CAAC;AAOF,MAAM,MAAM,WAAW,GAAG;IACxB,OAAO,EAAE,MAAM,CAAC;IAEhB,WAAW,EAAE,MAAM,CAAC;IAEpB,GAAG,EAAE,MAAM,CAAC;IAIZ,UAAU,EAAE,MAAM,CAAC;IAEnB,MAAM,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF,wBAAsB,KAAK,CACzB,GAAG,EAAE,OAAO,EACZ,QAAQ,EAAE,WAAW,EACrB,OAAO,EAAE,YAAY,GACpB,OAAO,CAAC,WAAW,CAAC,CAuFtB"}
|
package/dist/build.js
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { BUILDER_STAGE, renderDockerfile, renderDockerignore } from "./dockerfile.js";
|
|
4
|
+
import { prepareSource } from "./source.js";
|
|
5
|
+
// Bumped when the pipeline changes shape without the config changing. The tag
|
|
6
|
+
// below is what tells a host it already holds an image, and a host that trusts
|
|
7
|
+
// the commit alone serves the last pipeline's output forever
|
|
8
|
+
const PIPELINE = "4";
|
|
9
|
+
export async function build(app, topology, context) {
|
|
10
|
+
const { host, docker } = context;
|
|
11
|
+
const spec = app.build;
|
|
12
|
+
const detail = context.detail ?? (() => { });
|
|
13
|
+
const source = await prepareSource(host, {
|
|
14
|
+
name: topology.container,
|
|
15
|
+
repo: app.repo,
|
|
16
|
+
// Already absolute when the CLI loaded the config, because a path is read
|
|
17
|
+
// against the deployment file rather than wherever this was run
|
|
18
|
+
path: app.path && resolve(app.path),
|
|
19
|
+
include: app.include,
|
|
20
|
+
branch: context.branch,
|
|
21
|
+
submodules: spec.submodules,
|
|
22
|
+
detail,
|
|
23
|
+
});
|
|
24
|
+
const release = source.release;
|
|
25
|
+
const fingerprint = fingerprintOf(app, context, release);
|
|
26
|
+
const tag = `${topology.container}:${release}-${fingerprint}`;
|
|
27
|
+
// Always, rather than where something remembered to ask for it. It costs the
|
|
28
|
+
// export of layers the runtime build produced anyway, and a flag that has to
|
|
29
|
+
// be set before a step can run is a flag that will be missing
|
|
30
|
+
const builderTag = `${topology.container}-builder:${release}-${fingerprint}`;
|
|
31
|
+
// Asked of the daemon that will run the container, not the one that builds.
|
|
32
|
+
// An image this machine holds and the host does not is one still to be sent
|
|
33
|
+
const runner = context.deliver?.docker ?? docker;
|
|
34
|
+
// The whole build is skipped, not just a transfer. Nothing about this commit,
|
|
35
|
+
// this pipeline or these secrets differs from the image already sitting there
|
|
36
|
+
if (await held(runner, tag, builderTag)) {
|
|
37
|
+
detail(`already built at ${release.slice(0, 7)}`);
|
|
38
|
+
await runner.image.retag(tag, topology.container);
|
|
39
|
+
return { release, fingerprint, tag, builderTag, cached: true };
|
|
40
|
+
}
|
|
41
|
+
const secrets = await writeSecrets(app, context, fingerprint);
|
|
42
|
+
const dockerfile = await host.write(`${app.name}.Dockerfile`, renderDockerfile(spec, {
|
|
43
|
+
caches: topology.caches,
|
|
44
|
+
port: topology.port,
|
|
45
|
+
release,
|
|
46
|
+
environment: context.environment,
|
|
47
|
+
envSecret: secrets.env.id,
|
|
48
|
+
fileSecrets: Object.fromEntries(secrets.files.map((file) => [file.path, file.id])),
|
|
49
|
+
dir: app.dir,
|
|
50
|
+
}));
|
|
51
|
+
// BuildKit reads this beside the Dockerfile rather than inside the context,
|
|
52
|
+
// which is what lets the checkout stay a checkout: the repository keeps its
|
|
53
|
+
// own .dockerignore, and .git never enters the build
|
|
54
|
+
await host.write(`${app.name}.Dockerfile.dockerignore`, renderDockerignore(app.include));
|
|
55
|
+
const invocation = {
|
|
56
|
+
context: source.tree,
|
|
57
|
+
dockerfile,
|
|
58
|
+
secrets: Object.fromEntries([secrets.env, ...secrets.files].map((secret) => [secret.id, secret.src])),
|
|
59
|
+
};
|
|
60
|
+
detail(`building ${release.slice(0, 7)}`);
|
|
61
|
+
await docker.image.build({ ...invocation, tags: [tag, topology.container] }, watch(detail, context.output));
|
|
62
|
+
// Every layer of this was just built, so it costs the export alone
|
|
63
|
+
detail("keeping the builder");
|
|
64
|
+
await docker.image.build({ ...invocation, tags: [builderTag], target: BUILDER_STAGE }, watch(detail, context.output));
|
|
65
|
+
await ship(context, [tag, topology.container, builderTag], detail);
|
|
66
|
+
return { release, fingerprint, tag, builderTag, cached: false };
|
|
67
|
+
}
|
|
68
|
+
// One stream, rather than a tarball written here, copied, and read there. The
|
|
69
|
+
// tags travel inside the archive, so nothing has to be named again on arrival
|
|
70
|
+
async function ship(context, tags, detail) {
|
|
71
|
+
const deliver = context.deliver;
|
|
72
|
+
if (!deliver)
|
|
73
|
+
return;
|
|
74
|
+
const named = tags.filter((tag) => tag !== undefined);
|
|
75
|
+
detail(`shipping ${named.length} images`);
|
|
76
|
+
const result = await deliver.host.pipe(`docker save ${named.join(" ")}`, "docker load", context.output);
|
|
77
|
+
if (result.code !== 0) {
|
|
78
|
+
throw new Error(`Could not ship the image: ${result.stderr || result.stdout}`);
|
|
79
|
+
}
|
|
80
|
+
await deliver.docker.track((state) => {
|
|
81
|
+
for (const tag of named)
|
|
82
|
+
state.images.add(tag);
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
async function held(docker, tag, builderTag) {
|
|
86
|
+
if (!(await docker.image.exists(tag)))
|
|
87
|
+
return false;
|
|
88
|
+
// A runtime image without the builder that produced it would run the
|
|
89
|
+
// migration from whatever release happened to be tagged last
|
|
90
|
+
return await docker.image.exists(builderTag);
|
|
91
|
+
}
|
|
92
|
+
// The fingerprint is part of every id, because a secret mount is not part of a
|
|
93
|
+
// layer's cache key. Without it a changed environment file is answered with the
|
|
94
|
+
// image that was built from the old one
|
|
95
|
+
async function writeSecrets(app, context, fingerprint) {
|
|
96
|
+
const env = {
|
|
97
|
+
id: `${app.name}-env-${fingerprint}`,
|
|
98
|
+
src: await context.host.write(`${app.name}.env`, context.env),
|
|
99
|
+
};
|
|
100
|
+
const files = await Promise.all(Object.entries(context.files).map(async ([path, contents], index) => ({
|
|
101
|
+
path,
|
|
102
|
+
id: `${app.name}-file-${index}-${fingerprint}`,
|
|
103
|
+
// Named by index, so a container path with slashes in it stays one file
|
|
104
|
+
src: await context.host.write(`${app.name}.file.${index}`, contents),
|
|
105
|
+
})));
|
|
106
|
+
return { env, files };
|
|
107
|
+
}
|
|
108
|
+
// BuildKit names the step it is on in its own progress output, which is a
|
|
109
|
+
// better line to show than anything this file could invent
|
|
110
|
+
const STEP = /^#\d+ \[[^\]]*\] (.+)$/;
|
|
111
|
+
function watch(detail, output) {
|
|
112
|
+
return (line) => {
|
|
113
|
+
output?.(line);
|
|
114
|
+
const step = STEP.exec(line)?.[1];
|
|
115
|
+
if (step)
|
|
116
|
+
detail(step);
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
// The commit is one input of several. The pipeline, the environment file and
|
|
120
|
+
// any credential baked in as a file all change the image without touching it
|
|
121
|
+
function fingerprintOf(app, context, release) {
|
|
122
|
+
return createHash("sha256")
|
|
123
|
+
.update(PIPELINE)
|
|
124
|
+
.update(release)
|
|
125
|
+
.update(app.dir ?? "")
|
|
126
|
+
.update(JSON.stringify(app.build))
|
|
127
|
+
.update(context.env)
|
|
128
|
+
.update(JSON.stringify(Object.entries(context.files).sort()))
|
|
129
|
+
.digest("hex")
|
|
130
|
+
.slice(0, 12);
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=build.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build.js","sourceRoot":"","sources":["../src/build.ts"],"names":[],"mappings":"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"}
|
package/dist/checks.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checks.d.ts","sourceRoot":"","sources":["../src/checks.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAapE,wBAAsB,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAajF;AA8BD,wBAAgB,eAAe,CAAC,IAAI,EAAE,IAAI,QAOzC"}
|
package/dist/checks.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { appRoot } from "./layout.js";
|
|
2
|
+
import { quote } from "./shell.js";
|
|
3
|
+
import { attachment, builderOf } from "./steps.js";
|
|
4
|
+
// What redkite's verify step runs. An app declares the commands that decide
|
|
5
|
+
// whether its build works, and this is the whole of putting them somewhere they
|
|
6
|
+
// can reach the services the deployment brought up.
|
|
7
|
+
//
|
|
8
|
+
// The image is the builder rather than the runtime one. The runtime image holds
|
|
9
|
+
// the compiled output and nothing that compiled it, so the test runner is not
|
|
10
|
+
// in there, and installing one at check time would test a different tree.
|
|
11
|
+
export async function runChecks(input, context) {
|
|
12
|
+
const checked = [];
|
|
13
|
+
for (const app of context.config.apps) {
|
|
14
|
+
if (!app.verify)
|
|
15
|
+
continue;
|
|
16
|
+
await checkApp(app, app.verify, input, context);
|
|
17
|
+
checked.push(app.name);
|
|
18
|
+
}
|
|
19
|
+
// Anything that got here passed: a failing command throws. The lists a swap
|
|
20
|
+
// fills stay empty, because a verify run moves no addresses
|
|
21
|
+
return { ...input, ok: true, released: [], reverted: [], checked };
|
|
22
|
+
}
|
|
23
|
+
async function checkApp(app, spec, input, context) {
|
|
24
|
+
const flags = [
|
|
25
|
+
"run --rm",
|
|
26
|
+
...attachment(spec.network ?? "deployment", context.topology),
|
|
27
|
+
`--workdir ${appRoot(app.dir)}`,
|
|
28
|
+
...settings({ ...app.environment, ...spec.environment }),
|
|
29
|
+
builderOf(input, app.name),
|
|
30
|
+
];
|
|
31
|
+
// In order and one at a time. The first is usually what brings the database
|
|
32
|
+
// to the schema the rest expect, so running them together would race
|
|
33
|
+
for (const command of spec.steps) {
|
|
34
|
+
context.task.detail(`${app.name}: ${command}`);
|
|
35
|
+
await context.docker.runOrThrow([...flags, "sh -c", quote(command)].join(" "), `${app.name} failed ${command}`, context.task.line);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function settings(environment) {
|
|
39
|
+
return Object.entries(environment).map(([name, value]) => `-e ${name}=${quote(value)}`);
|
|
40
|
+
}
|
|
41
|
+
// Checked before the run starts, so asking for a verify that would check
|
|
42
|
+
// nothing fails without having created a network or built an image
|
|
43
|
+
export function assertCheckable(plan) {
|
|
44
|
+
if (plan.config.apps.some((app) => app.verify))
|
|
45
|
+
return;
|
|
46
|
+
throw new Error("No app declares verify, so this run would check nothing. " +
|
|
47
|
+
"An app is verified by giving it verify: { steps: [...] }");
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=checks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checks.js","sourceRoot":"","sources":["../src/checks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAEtC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAGnD,4EAA4E;AAC5E,gFAAgF;AAChF,oDAAoD;AACpD,EAAE;AACF,gFAAgF;AAChF,8EAA8E;AAC9E,0EAA0E;AAE1E,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,KAAY,EAAE,OAAgB;IAC5D,MAAM,OAAO,GAAa,EAAE,CAAC;IAE7B,KAAK,MAAM,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QACtC,IAAI,CAAC,GAAG,CAAC,MAAM;YAAE,SAAS;QAE1B,MAAM,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;QAChD,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC;IAED,4EAA4E;IAC5E,4DAA4D;IAC5D,OAAO,EAAE,GAAG,KAAK,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC;AACrE,CAAC;AAED,KAAK,UAAU,QAAQ,CAAC,GAAY,EAAE,IAAgB,EAAE,KAAY,EAAE,OAAgB;IACpF,MAAM,KAAK,GAAG;QACZ,UAAU;QACV,GAAG,UAAU,CAAC,IAAI,CAAC,OAAO,IAAI,YAAY,EAAE,OAAO,CAAC,QAAQ,CAAC;QAC7D,aAAa,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;QAC/B,GAAG,QAAQ,CAAC,EAAE,GAAG,GAAG,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;QACxD,SAAS,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,CAAC;KAC3B,CAAC;IAEF,4EAA4E;IAC5E,qEAAqE;IACrE,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QACjC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC,CAAC;QAE/C,MAAM,OAAO,CAAC,MAAM,CAAC,UAAU,CAC7B,CAAC,GAAG,KAAK,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAC7C,GAAG,GAAG,CAAC,IAAI,WAAW,OAAO,EAAE,EAC/B,OAAO,CAAC,IAAI,CAAC,IAAI,CAClB,CAAC;IACJ,CAAC;AACH,CAAC;AAED,SAAS,QAAQ,CAAC,WAAmC;IACnD,OAAO,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;AAC1F,CAAC;AAED,yEAAyE;AACzE,mEAAmE;AACnE,MAAM,UAAU,eAAe,CAAC,IAAU;IACxC,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC;QAAE,OAAO;IAEvD,MAAM,IAAI,KAAK,CACb,2DAA2D;QACzD,0DAA0D,CAC7D,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/cli/agent.ts"],"names":[],"mappings":"AAQA,wBAAgB,YAAY,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,UAmB3D"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { execFileSync } from "node:child_process";
|
|
2
|
+
// Cloning private repositories and opening the tunnel both go through the
|
|
3
|
+
// agent, so a deploy without one fails halfway rather than at the start
|
|
4
|
+
// A plain writer rather than a Log, because this runs before the view opens:
|
|
5
|
+
// ssh-add may ask for a passphrase, and it cannot ask through a screen
|
|
6
|
+
// something else is drawing
|
|
7
|
+
export function requireAgent(warn) {
|
|
8
|
+
const existing = process.env["SSH_AUTH_SOCK"];
|
|
9
|
+
if (existing)
|
|
10
|
+
return existing;
|
|
11
|
+
warn("No SSH agent, starting one");
|
|
12
|
+
const output = execFileSync("ssh-agent", ["-s"], { encoding: "utf8" });
|
|
13
|
+
const socket = output.match(/SSH_AUTH_SOCK=([^;]+);/)?.[1];
|
|
14
|
+
const pid = output.match(/SSH_AGENT_PID=([^;]+);/)?.[1];
|
|
15
|
+
if (!socket)
|
|
16
|
+
throw new Error("ssh-agent did not report a socket");
|
|
17
|
+
process.env["SSH_AUTH_SOCK"] = socket;
|
|
18
|
+
if (pid)
|
|
19
|
+
process.env["SSH_AGENT_PID"] = pid;
|
|
20
|
+
// Inherits stdio so a passphrase prompt reaches the person running this
|
|
21
|
+
execFileSync("ssh-add", [], { stdio: "inherit" });
|
|
22
|
+
return socket;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=agent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent.js","sourceRoot":"","sources":["../../src/cli/agent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,0EAA0E;AAC1E,wEAAwE;AAExE,6EAA6E;AAC7E,uEAAuE;AACvE,4BAA4B;AAC5B,MAAM,UAAU,YAAY,CAAC,IAA+B;IAC1D,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;IAC9C,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAE9B,IAAI,CAAC,4BAA4B,CAAC,CAAC;IAEnC,MAAM,MAAM,GAAG,YAAY,CAAC,WAAW,EAAE,CAAC,IAAI,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;IACvE,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,wBAAwB,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC3D,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,wBAAwB,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAExD,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;IAElE,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,GAAG,MAAM,CAAC;IACtC,IAAI,GAAG;QAAE,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,GAAG,GAAG,CAAC;IAE5C,wEAAwE;IACxE,YAAY,CAAC,SAAS,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;IAElD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Deployment, Environment } from "../types.js";
|
|
2
|
+
export declare function loadConfig(explicit?: string): Promise<Deployment>;
|
|
3
|
+
export declare function discover(from: string): string;
|
|
4
|
+
export declare function loadEnvironments(directory: string): Promise<Record<string, Environment>>;
|
|
5
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/cli/config.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AA2B3D,wBAAsB,UAAU,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAiBvE;AA0CD,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAwB7C;AAGD,wBAAsB,gBAAgB,CAAC,SAAS,EAAE,MAAM,wCAmBvD"}
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import { dirname, join, resolve } from "node:path";
|
|
4
|
+
import { pathToFileURL } from "node:url";
|
|
5
|
+
// Found by convention rather than named on the command line. A repository has
|
|
6
|
+
// one deployment, and requiring the path is a flag nobody ever varies.
|
|
7
|
+
//
|
|
8
|
+
// The environments live beside it, one file each, so the thing that differs
|
|
9
|
+
// between staging and production is a file rather than a key several levels
|
|
10
|
+
// down a literal.
|
|
11
|
+
const EXTENSIONS = ["ts", "mts", "js", "mjs"];
|
|
12
|
+
const CANDIDATES = EXTENSIONS.map((extension) => `redkite.config.${extension}`);
|
|
13
|
+
// redkite.<environment>.config.<extension>, beside the deployment it belongs to
|
|
14
|
+
const PER_ENVIRONMENT = /^redkite\.([a-z0-9-]+)\.config\.(ts|mts|js|mjs)$/;
|
|
15
|
+
// Node strips types itself from 22.18 on, which is what lets redkite ship with
|
|
16
|
+
// no dependencies. These are the ways that can fail on a config it cannot read.
|
|
17
|
+
// A SyntaxError is the same class of failure: a package without "type":
|
|
18
|
+
// "module" makes a .ts file CommonJS, where an import statement is not legal
|
|
19
|
+
const LOADER = new Set([
|
|
20
|
+
"ERR_UNKNOWN_FILE_EXTENSION",
|
|
21
|
+
"ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX",
|
|
22
|
+
"ERR_MODULE_NOT_FOUND",
|
|
23
|
+
"ERR_INVALID_MODULE_SPECIFIER",
|
|
24
|
+
]);
|
|
25
|
+
export async function loadConfig(explicit) {
|
|
26
|
+
const path = explicit ? resolve(explicit) : discover(process.cwd());
|
|
27
|
+
const config = defaultOf(await load(path), path);
|
|
28
|
+
const beside = await loadEnvironments(dirname(path));
|
|
29
|
+
const named = await loadNamed(manifestOf(explicit ? dirname(path) : process.cwd()));
|
|
30
|
+
for (const name of Object.keys(named)) {
|
|
31
|
+
if (!beside[name])
|
|
32
|
+
continue;
|
|
33
|
+
throw new Error(`${name} is named by package.json and also sits beside the deployment. ` +
|
|
34
|
+
"An environment comes from one place or the other");
|
|
35
|
+
}
|
|
36
|
+
return { ...rooted(config, dirname(path)), environments: { ...beside, ...named } };
|
|
37
|
+
}
|
|
38
|
+
// A source path belongs to the file that named it, not to wherever the command
|
|
39
|
+
// was run. Resolving it here is what lets a deploy from a workspace and one
|
|
40
|
+
// from the root build the same tree
|
|
41
|
+
function rooted(config, directory) {
|
|
42
|
+
if (!config.apps.some((app) => app.path))
|
|
43
|
+
return config;
|
|
44
|
+
return {
|
|
45
|
+
...config,
|
|
46
|
+
apps: config.apps.map((app) => app.path ? { ...app, path: resolve(directory, app.path) } : app),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
// package.json may name the file each environment lives in, for a repository
|
|
50
|
+
// that keeps them somewhere the naming convention would not find them
|
|
51
|
+
async function loadNamed(manifest) {
|
|
52
|
+
const declared = manifest?.redkite.environments;
|
|
53
|
+
if (!manifest || !declared)
|
|
54
|
+
return {};
|
|
55
|
+
const environments = {};
|
|
56
|
+
for (const [name, where] of Object.entries(declared)) {
|
|
57
|
+
if (typeof where !== "string") {
|
|
58
|
+
throw new Error(`package.json names ${name} as something other than a path`);
|
|
59
|
+
}
|
|
60
|
+
const path = resolve(manifest.root, where);
|
|
61
|
+
if (!existsSync(path)) {
|
|
62
|
+
throw new Error(`package.json points ${name} at ${path}, which is not there`);
|
|
63
|
+
}
|
|
64
|
+
environments[name] = defaultOf(await load(path), path);
|
|
65
|
+
}
|
|
66
|
+
return environments;
|
|
67
|
+
}
|
|
68
|
+
// A deployment is one file at the root of the project, and a deploy is as
|
|
69
|
+
// likely to be run from a workspace inside it as from there
|
|
70
|
+
export function discover(from) {
|
|
71
|
+
let directory = from;
|
|
72
|
+
for (;;) {
|
|
73
|
+
const declared = directoryFrom(directory);
|
|
74
|
+
// Saying where the files are and not putting them there is a mistake worth
|
|
75
|
+
// stopping for, rather than a reason to keep looking further up
|
|
76
|
+
if (declared)
|
|
77
|
+
return found(declared) ?? missing(declared, directory);
|
|
78
|
+
const here = found(directory);
|
|
79
|
+
if (here)
|
|
80
|
+
return here;
|
|
81
|
+
const parent = dirname(directory);
|
|
82
|
+
if (parent === directory)
|
|
83
|
+
break;
|
|
84
|
+
directory = parent;
|
|
85
|
+
}
|
|
86
|
+
throw new Error(`No redkite.config.ts found in ${from} or any directory above it. A deployment ` +
|
|
87
|
+
'is one file at the root of the project, or wherever package.json\'s ' +
|
|
88
|
+
'"redkite": { "directory": … } says it is');
|
|
89
|
+
}
|
|
90
|
+
// Every environment that lives in a file of its own, keyed by the name in it
|
|
91
|
+
export async function loadEnvironments(directory) {
|
|
92
|
+
const environments = {};
|
|
93
|
+
const seen = {};
|
|
94
|
+
for (const entry of readdirSync(directory).sort()) {
|
|
95
|
+
const name = PER_ENVIRONMENT.exec(entry)?.[1];
|
|
96
|
+
if (!name)
|
|
97
|
+
continue;
|
|
98
|
+
const first = seen[name];
|
|
99
|
+
if (first) {
|
|
100
|
+
throw new Error(`${name} is defined by both ${first} and ${entry}`);
|
|
101
|
+
}
|
|
102
|
+
seen[name] = entry;
|
|
103
|
+
const path = join(directory, entry);
|
|
104
|
+
environments[name] = defaultOf(await load(path), path);
|
|
105
|
+
}
|
|
106
|
+
return environments;
|
|
107
|
+
}
|
|
108
|
+
function found(directory) {
|
|
109
|
+
for (const candidate of CANDIDATES) {
|
|
110
|
+
const path = join(directory, candidate);
|
|
111
|
+
if (existsSync(path))
|
|
112
|
+
return path;
|
|
113
|
+
}
|
|
114
|
+
return undefined;
|
|
115
|
+
}
|
|
116
|
+
function missing(declared, from) {
|
|
117
|
+
throw new Error(`${join(from, "package.json")} points redkite at ${declared}, which holds no ` +
|
|
118
|
+
`redkite.config.${EXTENSIONS.join(", redkite.config.")}`);
|
|
119
|
+
}
|
|
120
|
+
function manifestAt(directory) {
|
|
121
|
+
const path = join(directory, "package.json");
|
|
122
|
+
if (!existsSync(path))
|
|
123
|
+
return undefined;
|
|
124
|
+
try {
|
|
125
|
+
const parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
126
|
+
return parsed.redkite ? { root: directory, redkite: parsed.redkite } : undefined;
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
// A package.json that does not parse is not this tool's to complain about
|
|
130
|
+
return undefined;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
// The nearest one above wherever this was run, which is the same walk the
|
|
134
|
+
// config itself is found by
|
|
135
|
+
function manifestOf(from) {
|
|
136
|
+
let directory = from;
|
|
137
|
+
for (;;) {
|
|
138
|
+
const found = manifestAt(directory);
|
|
139
|
+
if (found)
|
|
140
|
+
return found;
|
|
141
|
+
const parent = dirname(directory);
|
|
142
|
+
if (parent === directory)
|
|
143
|
+
return undefined;
|
|
144
|
+
directory = parent;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
// package.json says where the deployment files live, for a repository that
|
|
148
|
+
// would rather not keep them at its root
|
|
149
|
+
function directoryFrom(directory) {
|
|
150
|
+
const declared = manifestAt(directory)?.redkite.directory;
|
|
151
|
+
return typeof declared === "string" ? resolve(directory, declared) : undefined;
|
|
152
|
+
}
|
|
153
|
+
function defaultOf(module, path) {
|
|
154
|
+
const found = module;
|
|
155
|
+
// A config inside a CommonJS package transpiles to CommonJS, and Node hands
|
|
156
|
+
// back the whole module.exports as the default, wrapping the real one
|
|
157
|
+
const config = found.default?.default ?? found.default;
|
|
158
|
+
if (config)
|
|
159
|
+
return config;
|
|
160
|
+
throw new Error(`${path} has no default export`);
|
|
161
|
+
}
|
|
162
|
+
async function load(path) {
|
|
163
|
+
const url = pathToFileURL(path).href;
|
|
164
|
+
try {
|
|
165
|
+
return await import(url);
|
|
166
|
+
}
|
|
167
|
+
catch (error) {
|
|
168
|
+
if (!unreadable(error))
|
|
169
|
+
throw error;
|
|
170
|
+
// tsx resolves what Node will not: a path mapped by tsconfig, and the
|
|
171
|
+
// ./thing.js specifier TypeScript writes for a sibling ./thing.ts
|
|
172
|
+
const register = await tsxFrom(dirname(path));
|
|
173
|
+
if (!register)
|
|
174
|
+
throw cannotRead(path, error);
|
|
175
|
+
const unregister = register();
|
|
176
|
+
try {
|
|
177
|
+
return await import(url);
|
|
178
|
+
}
|
|
179
|
+
finally {
|
|
180
|
+
await unregister();
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
// Resolved from the project being deployed rather than depended on, so redkite
|
|
185
|
+
// installs as one package and still reads a config that needs more
|
|
186
|
+
async function tsxFrom(directory) {
|
|
187
|
+
try {
|
|
188
|
+
const require = createRequire(join(directory, "redkite.js"));
|
|
189
|
+
const api = (await import(pathToFileURL(require.resolve("tsx/esm/api")).href));
|
|
190
|
+
return api.register;
|
|
191
|
+
}
|
|
192
|
+
catch {
|
|
193
|
+
return undefined;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
function unreadable(error) {
|
|
197
|
+
if (!(error instanceof Error))
|
|
198
|
+
return false;
|
|
199
|
+
if (error instanceof SyntaxError)
|
|
200
|
+
return true;
|
|
201
|
+
return "code" in error && typeof error.code === "string" && LOADER.has(error.code);
|
|
202
|
+
}
|
|
203
|
+
// Node reads TypeScript itself, within limits a config can run into. Each of
|
|
204
|
+
// them has a one line fix, and none of them is obvious from what Node throws
|
|
205
|
+
function cannotRead(path, error) {
|
|
206
|
+
const remedies = [
|
|
207
|
+
' · A package without "type": "module" makes a .ts file CommonJS, where',
|
|
208
|
+
" an import statement is not legal. Name it redkite.config.mts instead",
|
|
209
|
+
" · Node resolves a relative import by the file it names, so a sibling is",
|
|
210
|
+
" ./thing.ts rather than ./thing.js",
|
|
211
|
+
" · Node reads TypeScript from 22.18 on, and this is " + process.version,
|
|
212
|
+
" · Anything else: add tsx to this project and redkite will read the config",
|
|
213
|
+
" through it",
|
|
214
|
+
];
|
|
215
|
+
return new Error(`Could not read ${path}\n\n${error.message}\n\n${remedies.join("\n")}`, { cause: error });
|
|
216
|
+
}
|
|
217
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/cli/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Deployment } from "../types.js";
|
|
2
|
+
export declare function positional(argv: string[]): string[];
|
|
3
|
+
export declare function main(argv: string[]): Promise<boolean | void>;
|
|
4
|
+
export declare function stopper(on: {
|
|
5
|
+
abort: () => void;
|
|
6
|
+
say: (message: string) => void;
|
|
7
|
+
signal: (name: "TERM" | "KILL") => void;
|
|
8
|
+
leave: () => void;
|
|
9
|
+
}): () => void;
|
|
10
|
+
export declare function buildingHere(config: Deployment, environment: string): Deployment;
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,UAAU,EAAc,MAAM,aAAa,CAAC;AA2F1D,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,YAgBxC;AAED,wBAAsB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,2BASxC;AAkLD,wBAAgB,OAAO,CAAC,EAAE,EAAE;IAC1B,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,GAAG,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,KAAK,IAAI,CAAC;IACxC,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB,cAwBA;AAkCD,wBAAgB,YAAY,CAAC,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,GAAG,UAAU,CAehF"}
|