@ethlete/cli 2.0.1-next.2 → 2.1.0-next.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/README.md +82 -6
- package/package.json +1 -1
- package/src/index.d.ts +1 -1
- package/src/index.js +27 -10
- package/src/index.js.map +1 -1
- package/src/lib/api/api-command.d.ts +4 -0
- package/src/lib/api/api-command.js +27 -0
- package/src/lib/api/api-command.js.map +1 -0
- package/src/lib/api/compose.d.ts +17 -0
- package/src/lib/api/compose.js +58 -0
- package/src/lib/api/compose.js.map +1 -0
- package/src/lib/api/definition.d.ts +28 -0
- package/src/lib/api/definition.js +7 -0
- package/src/lib/api/definition.js.map +1 -0
- package/src/lib/api/index.d.ts +5 -0
- package/src/lib/api/index.js +9 -0
- package/src/lib/api/index.js.map +1 -0
- package/src/lib/api/load-definitions.d.ts +16 -0
- package/src/lib/api/load-definitions.js +22 -0
- package/src/lib/api/load-definitions.js.map +1 -0
- package/src/lib/api/run.d.ts +10 -0
- package/src/lib/api/run.js +119 -0
- package/src/lib/api/run.js.map +1 -0
- package/src/lib/config/index.d.ts +1 -0
- package/src/lib/config/index.js +5 -0
- package/src/lib/config/index.js.map +1 -0
- package/src/lib/config/local-config.d.ts +31 -0
- package/src/lib/config/local-config.js +45 -0
- package/src/lib/config/local-config.js.map +1 -0
- package/src/lib/index.d.ts +2 -0
- package/src/lib/index.js +2 -0
- package/src/lib/index.js.map +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# @ethlete/cli
|
|
2
2
|
|
|
3
|
+
## 2.1.0-next.4
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [`b6fe4be`](https://github.com/ethlete-io/ethdk/commit/b6fe4beae010aaa2e0e367d636f6759442983395) Thanks [@TomTomB](https://github.com/TomTomB)! - Add `et api` to run an app's backend from a local checkout, declared in `ethlete.apis.js`. The new
|
|
8
|
+
`ethlete.config.local.json` says where the sibling checkouts on this machine live.
|
|
9
|
+
|
|
10
|
+
## 2.1.0-next.3
|
|
11
|
+
|
|
12
|
+
### Minor Changes
|
|
13
|
+
|
|
14
|
+
- [`edea44b`](https://github.com/ethlete-io/ethdk/commit/edea44bf1c494420f02b545202f4b24db9a6395c) Thanks [@TomTomB](https://github.com/TomTomB)! - Update to angular 22
|
|
15
|
+
|
|
3
16
|
## 2.0.1-next.2
|
|
4
17
|
|
|
5
18
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -1,11 +1,87 @@
|
|
|
1
|
-
# cli
|
|
1
|
+
# @ethlete/cli
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Repo tooling - installs the `et` binary.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Installation
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
```bash
|
|
8
|
+
yarn add --dev @ethlete/cli
|
|
9
|
+
```
|
|
8
10
|
|
|
9
|
-
##
|
|
11
|
+
## `et release`
|
|
10
12
|
|
|
11
|
-
|
|
13
|
+
```bash
|
|
14
|
+
yarn et release
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Turns pending changesets into a tagged, pushed release commit (version → tag → commit → push).
|
|
18
|
+
|
|
19
|
+
## `et api`
|
|
20
|
+
|
|
21
|
+
Runs the API an app in this repo talks to, from a checkout on your own machine.
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
yarn et api up hub # start the containers
|
|
25
|
+
yarn et api down hub # stop them
|
|
26
|
+
yarn et api logs hub # follow the API's log
|
|
27
|
+
yarn et api shell hub # a shell in the API container
|
|
28
|
+
yarn et api install hub # an entry from that API's own "exec" map
|
|
29
|
+
yarn et api up hub --host # also print the address other devices can reach
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
The first container tool that answers is used, in this order: `docker compose`,
|
|
33
|
+
`container compose`, `podman-compose`, `podman compose`.
|
|
34
|
+
|
|
35
|
+
### Declaring the APIs
|
|
36
|
+
|
|
37
|
+
`ethlete.apis.js` at the repo root describes each API's compose setup. It is a module rather
|
|
38
|
+
than JSON because `env` is a function:
|
|
39
|
+
|
|
40
|
+
```js
|
|
41
|
+
const { sshKeyPath } = require('@ethlete/cli');
|
|
42
|
+
|
|
43
|
+
module.exports = {
|
|
44
|
+
hub: {
|
|
45
|
+
composeDir: 'development',
|
|
46
|
+
services: ['app', 'database', 'mailhog'],
|
|
47
|
+
execService: 'app',
|
|
48
|
+
port: 8040,
|
|
49
|
+
envFile: '.env',
|
|
50
|
+
setupCommand: 'make setup',
|
|
51
|
+
network: 'shared-fut',
|
|
52
|
+
envKey: 'hubApiEnv',
|
|
53
|
+
examplePath: '../fut-hub-backend',
|
|
54
|
+
env: () => ({ SSH_PRIVATE_KEY: sshKeyPath() }),
|
|
55
|
+
exec: {
|
|
56
|
+
install: ['composer', 'install'],
|
|
57
|
+
'reset-db': ['make', 'reset-db-with-dev-fixtures'],
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Adding an API is an entry in this map. Nothing else changes.
|
|
64
|
+
|
|
65
|
+
### Where the checkouts live
|
|
66
|
+
|
|
67
|
+
The paths differ per machine, so they live in a gitignored `ethlete.config.local.json` at the
|
|
68
|
+
repo root. `@ethlete/agent-rules` reads the same file, so its skills and `et` agree on where a
|
|
69
|
+
checkout is:
|
|
70
|
+
|
|
71
|
+
```json
|
|
72
|
+
{
|
|
73
|
+
"sdkSourcePath": "/absolute/path/to/ethlete-sdk",
|
|
74
|
+
"apiRepoPaths": { "hub": "../fut-hub-backend", "*": "../shared-backend" },
|
|
75
|
+
"apiRepoBranches": { "hub": "develop", "*": "main" }
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Matching is exact; `"*"` is an explicit shared fallback. A relative path resolves from the repo
|
|
80
|
+
root. These keys used to live in `ethlete-agents.config.local.json`, which is still read as a
|
|
81
|
+
fallback with a warning. Add `ethlete.config.local.json` to your `.gitignore`.
|
|
82
|
+
|
|
83
|
+
## Documentation
|
|
84
|
+
|
|
85
|
+
Full command reference on the docs site:
|
|
86
|
+
|
|
87
|
+
- [Overview & usage](https://ethlete-sdk-docs.web.app/cli/)
|
package/package.json
CHANGED
package/src/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export
|
|
1
|
+
export * from './lib';
|
package/src/index.js
CHANGED
|
@@ -2,19 +2,36 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
4
|
const lib_1 = require("./lib");
|
|
5
|
+
const USAGE = `et — Ethlete repo tooling
|
|
6
|
+
|
|
7
|
+
et release Turn pending changesets into a tagged, pushed release commit
|
|
8
|
+
et api <cmd> <api> Run an API from this repo's ethlete.apis.js locally
|
|
9
|
+
(up, down, logs, shell, plus that API's own exec entries)
|
|
10
|
+
`;
|
|
5
11
|
const cli = (args) => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
|
|
6
|
-
|
|
7
|
-
switch (cliFunctionArg) {
|
|
12
|
+
switch (args[0]) {
|
|
8
13
|
case 'release':
|
|
9
|
-
|
|
10
|
-
|
|
14
|
+
// `release` reads its flags from a list that was split on "=" before this switch existed.
|
|
15
|
+
// Keep that shape here so its own parsing is untouched.
|
|
16
|
+
yield (0, lib_1.release)(args.join('=').split('='));
|
|
17
|
+
return 0;
|
|
18
|
+
case 'api':
|
|
19
|
+
return (0, lib_1.apiCommand)({ root: process.cwd(), argv: args.slice(1) });
|
|
11
20
|
default:
|
|
12
|
-
console.log(
|
|
13
|
-
|
|
21
|
+
console.log(USAGE);
|
|
22
|
+
return args[0] === undefined || args[0] === '--help' || args[0] === '-h' ? 0 : 1;
|
|
14
23
|
}
|
|
15
24
|
});
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
25
|
+
tslib_1.__exportStar(require("./lib"), exports);
|
|
26
|
+
// Guarded so the package can also be imported as a library without running the CLI.
|
|
27
|
+
if (require.main === module) {
|
|
28
|
+
cli(process.argv.slice(2))
|
|
29
|
+
.then((code) => {
|
|
30
|
+
process.exitCode = code;
|
|
31
|
+
})
|
|
32
|
+
.catch((error) => {
|
|
33
|
+
console.error(error instanceof Error ? error.message : error);
|
|
34
|
+
process.exitCode = 1;
|
|
35
|
+
});
|
|
36
|
+
}
|
|
20
37
|
//# sourceMappingURL=index.js.map
|
package/src/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../libs/cli/src/index.ts"],"names":[],"mappings":";;;AAAA,+
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../libs/cli/src/index.ts"],"names":[],"mappings":";;;AAAA,+BAA4C;AAE5C,MAAM,KAAK,GAAG;;;;;CAKb,CAAC;AAEF,MAAM,GAAG,GAAG,CAAO,IAAc,EAAmB,EAAE;IACpD,QAAQ,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QAChB,KAAK,SAAS;YACZ,0FAA0F;YAC1F,wDAAwD;YACxD,MAAM,IAAA,aAAO,EAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;YAEzC,OAAO,CAAC,CAAC;QAEX,KAAK,KAAK;YACR,OAAO,IAAA,gBAAU,EAAC,EAAE,IAAI,EAAE,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAElE;YACE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YAEnB,OAAO,IAAI,CAAC,CAAC,CAAC,KAAK,SAAS,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,QAAQ,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACrF,CAAC;AACH,CAAC,CAAA,CAAC;AAEF,gDAAsB;AAEtB,oFAAoF;AACpF,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;IAC5B,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;SACvB,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE;QACb,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;IAC1B,CAAC,CAAC;SACD,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;QACxB,OAAO,CAAC,KAAK,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QAC9D,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;IACvB,CAAC,CAAC,CAAC;AACP,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.apiCommand = void 0;
|
|
4
|
+
const load_definitions_1 = require("./load-definitions");
|
|
5
|
+
const run_1 = require("./run");
|
|
6
|
+
const apiCommand = ({ root, argv }) => {
|
|
7
|
+
const { found, apis } = (0, load_definitions_1.loadApiDefinitions)(root);
|
|
8
|
+
if (!found) {
|
|
9
|
+
console.error(`No API definitions found. Create ${load_definitions_1.API_DEFINITIONS_FILE_NAMES[0]} in the repo root:\n\n` +
|
|
10
|
+
` const { sshKeyPath } = require('@ethlete/cli');\n\n` +
|
|
11
|
+
` module.exports = {\n` +
|
|
12
|
+
` hub: {\n` +
|
|
13
|
+
` composeDir: 'development',\n` +
|
|
14
|
+
` services: ['app', 'database'],\n` +
|
|
15
|
+
` execService: 'app',\n` +
|
|
16
|
+
` port: 8040,\n` +
|
|
17
|
+
` envFile: '.env',\n` +
|
|
18
|
+
` setupCommand: 'make setup',\n` +
|
|
19
|
+
` exec: { install: ['composer', 'install'] },\n` +
|
|
20
|
+
` },\n` +
|
|
21
|
+
` };`);
|
|
22
|
+
return 1;
|
|
23
|
+
}
|
|
24
|
+
return (0, run_1.runApiCommand)({ apis, argv, root });
|
|
25
|
+
};
|
|
26
|
+
exports.apiCommand = apiCommand;
|
|
27
|
+
//# sourceMappingURL=api-command.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-command.js","sourceRoot":"","sources":["../../../../../../libs/cli/src/lib/api/api-command.ts"],"names":[],"mappings":";;;AAAA,yDAAoF;AACpF,+BAAsC;AAE/B,MAAM,UAAU,GAAG,CAAC,EAAE,IAAI,EAAE,IAAI,EAAoC,EAAE,EAAE;IAC7E,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,IAAA,qCAAkB,EAAC,IAAI,CAAC,CAAC;IAEjD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,CAAC,KAAK,CACX,oCAAoC,6CAA0B,CAAC,CAAC,CAAC,wBAAwB;YACvF,uDAAuD;YACvD,wBAAwB;YACxB,cAAc;YACd,oCAAoC;YACpC,wCAAwC;YACxC,6BAA6B;YAC7B,qBAAqB;YACrB,0BAA0B;YAC1B,qCAAqC;YACrC,qDAAqD;YACrD,UAAU;YACV,MAAM,CACT,CAAC;QAEF,OAAO,CAAC,CAAC;IACX,CAAC;IAED,OAAO,IAAA,mBAAa,EAAC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;AAC7C,CAAC,CAAC;AAxBW,QAAA,UAAU,cAwBrB"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export type ComposeTool = {
|
|
2
|
+
engine: string;
|
|
3
|
+
/** The binary and its fixed arguments. Non-empty, so the first entry is always the binary. */
|
|
4
|
+
compose: [string, ...string[]];
|
|
5
|
+
};
|
|
6
|
+
export declare const composeBinary: (compose: string[]) => string[];
|
|
7
|
+
/** Finds the first container tool on this machine that answers `<compose> version`. */
|
|
8
|
+
export declare const resolveComposeTool: (tools?: ComposeTool[]) => ComposeTool | undefined;
|
|
9
|
+
export declare const composeToolNames: (tools?: ComposeTool[]) => string[];
|
|
10
|
+
export declare const engineEnv: (engine: string) => {
|
|
11
|
+
CONTAINERS_REGISTRIES_CONF: string;
|
|
12
|
+
} | {
|
|
13
|
+
CONTAINERS_REGISTRIES_CONF?: undefined;
|
|
14
|
+
};
|
|
15
|
+
export declare const lanAddress: () => string | undefined;
|
|
16
|
+
/** Path of this machine's SSH key, for a compose file that mounts one into the API container. */
|
|
17
|
+
export declare const sshKeyPath: () => string | undefined;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.sshKeyPath = exports.lanAddress = exports.engineEnv = exports.composeToolNames = exports.resolveComposeTool = exports.composeBinary = void 0;
|
|
4
|
+
const child_process_1 = require("child_process");
|
|
5
|
+
const fs_1 = require("fs");
|
|
6
|
+
const os_1 = require("os");
|
|
7
|
+
const path_1 = require("path");
|
|
8
|
+
/**
|
|
9
|
+
* SELinux denies a container read access to a bind mount that carries the host's own label, and API
|
|
10
|
+
* repos mount their checkout without the `:z` that would relabel it. Disabling the label from here
|
|
11
|
+
* keeps those checkouts untouched.
|
|
12
|
+
*/
|
|
13
|
+
const PODMAN_COMPOSE_ARGS = ['--podman-run-args=--security-opt label=disable'];
|
|
14
|
+
const COMPOSE_TOOLS = [
|
|
15
|
+
{ engine: 'docker', compose: ['docker', 'compose'] },
|
|
16
|
+
{ engine: 'container', compose: ['container', 'compose'] },
|
|
17
|
+
{ engine: 'podman', compose: ['podman-compose', ...PODMAN_COMPOSE_ARGS] },
|
|
18
|
+
{ engine: 'podman', compose: ['podman', 'compose', ...PODMAN_COMPOSE_ARGS] },
|
|
19
|
+
];
|
|
20
|
+
/**
|
|
21
|
+
* Podman refuses to resolve a short image name such as `mysql:8.0` without a TTY prompt when several
|
|
22
|
+
* unqualified search registries are configured. API compose files use short names, so point podman
|
|
23
|
+
* at one registry and turn the prompt off.
|
|
24
|
+
*/
|
|
25
|
+
const PODMAN_REGISTRIES_CONF = `unqualified-search-registries = ["docker.io"]\nshort-name-mode = "disabled"\n`;
|
|
26
|
+
let podmanRegistriesConfPath;
|
|
27
|
+
const writePodmanRegistriesConf = () => {
|
|
28
|
+
podmanRegistriesConfPath !== null && podmanRegistriesConfPath !== void 0 ? podmanRegistriesConfPath : (podmanRegistriesConfPath = (0, path_1.join)((0, fs_1.mkdtempSync)((0, path_1.join)((0, os_1.tmpdir)(), 'ethlete-api-')), 'registries.conf'));
|
|
29
|
+
(0, fs_1.writeFileSync)(podmanRegistriesConfPath, PODMAN_REGISTRIES_CONF, 'utf8');
|
|
30
|
+
return podmanRegistriesConfPath;
|
|
31
|
+
};
|
|
32
|
+
const composeBinary = (compose) => compose.filter((part) => !part.startsWith('--'));
|
|
33
|
+
exports.composeBinary = composeBinary;
|
|
34
|
+
const canRun = (command, args) => {
|
|
35
|
+
const result = (0, child_process_1.spawnSync)(command, args, { stdio: 'ignore' });
|
|
36
|
+
return result.error === undefined && result.status === 0;
|
|
37
|
+
};
|
|
38
|
+
/** Finds the first container tool on this machine that answers `<compose> version`. */
|
|
39
|
+
const resolveComposeTool = (tools = COMPOSE_TOOLS) => tools.find(({ compose }) => {
|
|
40
|
+
const [binary, ...rest] = (0, exports.composeBinary)(compose);
|
|
41
|
+
return binary !== undefined && canRun(binary, [...rest, 'version']);
|
|
42
|
+
});
|
|
43
|
+
exports.resolveComposeTool = resolveComposeTool;
|
|
44
|
+
const composeToolNames = (tools = COMPOSE_TOOLS) => tools.map(({ compose }) => (0, exports.composeBinary)(compose).join(' '));
|
|
45
|
+
exports.composeToolNames = composeToolNames;
|
|
46
|
+
const engineEnv = (engine) => engine === 'podman' ? { CONTAINERS_REGISTRIES_CONF: writePodmanRegistriesConf() } : {};
|
|
47
|
+
exports.engineEnv = engineEnv;
|
|
48
|
+
const lanAddress = () => {
|
|
49
|
+
var _a;
|
|
50
|
+
return (_a = Object.values((0, os_1.networkInterfaces)())
|
|
51
|
+
.flat()
|
|
52
|
+
.find((networkInterface) => (networkInterface === null || networkInterface === void 0 ? void 0 : networkInterface.family) === 'IPv4' && !networkInterface.internal)) === null || _a === void 0 ? void 0 : _a.address;
|
|
53
|
+
};
|
|
54
|
+
exports.lanAddress = lanAddress;
|
|
55
|
+
/** Path of this machine's SSH key, for a compose file that mounts one into the API container. */
|
|
56
|
+
const sshKeyPath = () => [(0, path_1.join)((0, os_1.homedir)(), '.ssh/id_ed25519'), (0, path_1.join)((0, os_1.homedir)(), '.ssh/id_rsa')].find((path) => (0, fs_1.existsSync)(path));
|
|
57
|
+
exports.sshKeyPath = sshKeyPath;
|
|
58
|
+
//# sourceMappingURL=compose.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compose.js","sourceRoot":"","sources":["../../../../../../libs/cli/src/lib/api/compose.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/** One API this repo can run locally. Everything here describes the API's own compose setup. */
|
|
2
|
+
export type ApiDefinition = {
|
|
3
|
+
/** Directory inside the API checkout that holds the compose file, for example `development`. */
|
|
4
|
+
composeDir: string;
|
|
5
|
+
/** Compose services to start. Leave out a service the app does not need, such as a bundled frontend. */
|
|
6
|
+
services: string[];
|
|
7
|
+
/** Service that `shell`, `logs` and every `exec` entry run in. */
|
|
8
|
+
execService: string;
|
|
9
|
+
/** Published host port, not the port inside the container. Used for the printed url. */
|
|
10
|
+
port: number;
|
|
11
|
+
/** File that must exist in `composeDir` before the API can start, for example `.env`. */
|
|
12
|
+
envFile?: string;
|
|
13
|
+
/** Command that creates `envFile`. Named in the error when the file is missing. */
|
|
14
|
+
setupCommand?: string;
|
|
15
|
+
/** External container network to create before the first `up`. */
|
|
16
|
+
network?: string;
|
|
17
|
+
/** Example path shown in the error that asks the developer to configure this API's checkout. */
|
|
18
|
+
examplePath?: string;
|
|
19
|
+
/** localStorage key the app reads to pick its API. Printed by `--host`. */
|
|
20
|
+
envKey?: string;
|
|
21
|
+
/** Extra environment for every compose call. An undefined value is dropped rather than passed as "undefined". */
|
|
22
|
+
env?: () => Record<string, string | undefined>;
|
|
23
|
+
/** Named commands run in `execService`, for example `{ install: ['composer', 'install'] }`. */
|
|
24
|
+
exec?: Record<string, string[]>;
|
|
25
|
+
};
|
|
26
|
+
export type ApiDefinitions = Record<string, ApiDefinition>;
|
|
27
|
+
export declare const BUILT_IN_API_COMMANDS: readonly ["up", "down", "logs", "shell"];
|
|
28
|
+
export declare const apiCommandNames: (api: ApiDefinition) => string[];
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.apiCommandNames = exports.BUILT_IN_API_COMMANDS = void 0;
|
|
4
|
+
exports.BUILT_IN_API_COMMANDS = ['up', 'down', 'logs', 'shell'];
|
|
5
|
+
const apiCommandNames = (api) => { var _a; return [...exports.BUILT_IN_API_COMMANDS, ...Object.keys((_a = api.exec) !== null && _a !== void 0 ? _a : {})]; };
|
|
6
|
+
exports.apiCommandNames = apiCommandNames;
|
|
7
|
+
//# sourceMappingURL=definition.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"definition.js","sourceRoot":"","sources":["../../../../../../libs/cli/src/lib/api/definition.ts"],"names":[],"mappings":";;;AA4Ba,QAAA,qBAAqB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAU,CAAC;AAEvE,MAAM,eAAe,GAAG,CAAC,GAAkB,EAAE,EAAE,WAAC,OAAA,CAAC,GAAG,6BAAqB,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,MAAA,GAAG,CAAC,IAAI,mCAAI,EAAE,CAAC,CAAC,CAAA,EAAA,CAAC;AAArG,QAAA,eAAe,mBAAsF"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
tslib_1.__exportStar(require("./api-command"), exports);
|
|
5
|
+
tslib_1.__exportStar(require("./compose"), exports);
|
|
6
|
+
tslib_1.__exportStar(require("./definition"), exports);
|
|
7
|
+
tslib_1.__exportStar(require("./load-definitions"), exports);
|
|
8
|
+
tslib_1.__exportStar(require("./run"), exports);
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../libs/cli/src/lib/api/index.ts"],"names":[],"mappings":";;;AAAA,wDAA8B;AAC9B,oDAA0B;AAC1B,uDAA6B;AAC7B,6DAAmC;AACnC,gDAAsB"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { ApiDefinitions } from './definition';
|
|
2
|
+
export declare const API_DEFINITIONS_FILE_NAMES: string[];
|
|
3
|
+
export type LoadApiDefinitionsResult = {
|
|
4
|
+
found: true;
|
|
5
|
+
apis: ApiDefinitions;
|
|
6
|
+
fileName: string;
|
|
7
|
+
} | {
|
|
8
|
+
found: false;
|
|
9
|
+
apis?: undefined;
|
|
10
|
+
fileName?: undefined;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Loads the repo's API definitions from `ethlete.apis.js`. The file is a module rather than JSON
|
|
14
|
+
* because a definition's `env` is a function, which JSON cannot hold.
|
|
15
|
+
*/
|
|
16
|
+
export declare const loadApiDefinitions: (root: string) => LoadApiDefinitionsResult;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.loadApiDefinitions = exports.API_DEFINITIONS_FILE_NAMES = void 0;
|
|
4
|
+
const fs_1 = require("fs");
|
|
5
|
+
const module_1 = require("module");
|
|
6
|
+
const path_1 = require("path");
|
|
7
|
+
exports.API_DEFINITIONS_FILE_NAMES = ['ethlete.apis.js', 'ethlete.apis.cjs'];
|
|
8
|
+
/**
|
|
9
|
+
* Loads the repo's API definitions from `ethlete.apis.js`. The file is a module rather than JSON
|
|
10
|
+
* because a definition's `env` is a function, which JSON cannot hold.
|
|
11
|
+
*/
|
|
12
|
+
const loadApiDefinitions = (root) => {
|
|
13
|
+
var _a;
|
|
14
|
+
const fileName = exports.API_DEFINITIONS_FILE_NAMES.find((candidate) => (0, fs_1.existsSync)((0, path_1.join)(root, candidate)));
|
|
15
|
+
if (!fileName)
|
|
16
|
+
return { found: false };
|
|
17
|
+
const loaded = (0, module_1.createRequire)((0, path_1.join)(root, 'package.json'))((0, path_1.join)(root, fileName));
|
|
18
|
+
const apis = (_a = loaded.default) !== null && _a !== void 0 ? _a : loaded;
|
|
19
|
+
return { found: true, apis, fileName };
|
|
20
|
+
};
|
|
21
|
+
exports.loadApiDefinitions = loadApiDefinitions;
|
|
22
|
+
//# sourceMappingURL=load-definitions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load-definitions.js","sourceRoot":"","sources":["../../../../../../libs/cli/src/lib/api/load-definitions.ts"],"names":[],"mappings":";;;AAAA,2BAAgC;AAChC,mCAAuC;AACvC,+BAA4B;AAGf,QAAA,0BAA0B,GAAG,CAAC,iBAAiB,EAAE,kBAAkB,CAAC,CAAC;AAKlF;;;GAGG;AACI,MAAM,kBAAkB,GAAG,CAAC,IAAY,EAA4B,EAAE;;IAC3E,MAAM,QAAQ,GAAG,kCAA0B,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,IAAA,eAAU,EAAC,IAAA,WAAI,EAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC;IAEnG,IAAI,CAAC,QAAQ;QAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;IAEvC,MAAM,MAAM,GAAY,IAAA,sBAAa,EAAC,IAAA,WAAI,EAAC,IAAI,EAAE,cAAc,CAAC,CAAC,CAAC,IAAA,WAAI,EAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC;IACxF,MAAM,IAAI,GAAG,MAAC,MAAuC,CAAC,OAAO,mCAAK,MAAyB,CAAC;IAE5F,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;AACzC,CAAC,CAAC;AATW,QAAA,kBAAkB,sBAS7B"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ApiDefinitions } from './definition';
|
|
2
|
+
export type RunApiCommandOptions = {
|
|
3
|
+
apis: ApiDefinitions;
|
|
4
|
+
/** Arguments after the command name, for example `['up', 'hub', '--host']`. */
|
|
5
|
+
argv: string[];
|
|
6
|
+
root?: string;
|
|
7
|
+
/** How the caller is invoked, used in the usage line. */
|
|
8
|
+
invocation?: string;
|
|
9
|
+
};
|
|
10
|
+
export declare const runApiCommand: ({ apis, argv, root, invocation }: RunApiCommandOptions) => number;
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runApiCommand = void 0;
|
|
4
|
+
const child_process_1 = require("child_process");
|
|
5
|
+
const fs_1 = require("fs");
|
|
6
|
+
const path_1 = require("path");
|
|
7
|
+
const local_config_1 = require("../config/local-config");
|
|
8
|
+
const compose_1 = require("./compose");
|
|
9
|
+
const definition_1 = require("./definition");
|
|
10
|
+
const configHelp = ({ name, api, reason }) => {
|
|
11
|
+
var _a;
|
|
12
|
+
return `${reason}\n\nAdd the path of your ${name} API checkout to ${local_config_1.LOCAL_CONFIG_FILE_NAME} in the repo ` +
|
|
13
|
+
`root. The file is gitignored, so it changes nothing for anyone else:\n\n` +
|
|
14
|
+
` {\n "apiRepoPaths": {\n "${name}": "${(_a = api.examplePath) !== null && _a !== void 0 ? _a : `../${name}-api`}"\n }\n }`;
|
|
15
|
+
};
|
|
16
|
+
const definedEntries = (record) => Object.fromEntries(Object.entries(record).filter(([, value]) => value !== undefined));
|
|
17
|
+
const isDirectory = (path) => (0, fs_1.existsSync)(path) && (0, fs_1.statSync)(path).isDirectory();
|
|
18
|
+
const runApiCommand = ({ apis, argv, root = process.cwd(), invocation = 'et api' }) => {
|
|
19
|
+
var _a, _b, _c, _d;
|
|
20
|
+
const exposeOnLan = argv.includes('--host');
|
|
21
|
+
const [command, name] = argv.filter((arg) => !arg.startsWith('--'));
|
|
22
|
+
const api = name === undefined ? undefined : apis[name];
|
|
23
|
+
if (command === undefined || name === undefined || !api) {
|
|
24
|
+
console.error(`Usage: ${invocation} <command> <api> [--host]\n\nAPIs: ${Object.keys(apis).join(', ')}`);
|
|
25
|
+
return 1;
|
|
26
|
+
}
|
|
27
|
+
const commands = (0, definition_1.apiCommandNames)(api);
|
|
28
|
+
if (!commands.includes(command)) {
|
|
29
|
+
console.error(`Unknown command "${command}" for the ${name} API.\n\nCommands: ${commands.join(', ')}`);
|
|
30
|
+
return 1;
|
|
31
|
+
}
|
|
32
|
+
const { config, fileName, isLegacy } = (0, local_config_1.readLocalConfig)(root);
|
|
33
|
+
const configured = (0, local_config_1.configuredApiRepoPath)(config, name);
|
|
34
|
+
if (!configured) {
|
|
35
|
+
console.error(configHelp({
|
|
36
|
+
name,
|
|
37
|
+
api,
|
|
38
|
+
reason: fileName
|
|
39
|
+
? `${fileName} has no apiRepoPaths entry for "${name}".`
|
|
40
|
+
: `${local_config_1.LOCAL_CONFIG_FILE_NAME} does not exist.`,
|
|
41
|
+
}));
|
|
42
|
+
return 1;
|
|
43
|
+
}
|
|
44
|
+
if (isLegacy) {
|
|
45
|
+
console.warn(`${local_config_1.LEGACY_LOCAL_CONFIG_FILE_NAME} still holds "apiRepoPaths". Move it to ${local_config_1.LOCAL_CONFIG_FILE_NAME}.\n`);
|
|
46
|
+
}
|
|
47
|
+
const repoPath = (0, local_config_1.resolveConfiguredPath)(root, configured);
|
|
48
|
+
if (!isDirectory(repoPath)) {
|
|
49
|
+
console.error(`apiRepoPaths.${name} points at ${repoPath}, which is not a directory that exists.`);
|
|
50
|
+
return 1;
|
|
51
|
+
}
|
|
52
|
+
const cwd = (0, path_1.join)(repoPath, api.composeDir);
|
|
53
|
+
if (!isDirectory(cwd)) {
|
|
54
|
+
console.error(`${repoPath} has no ${api.composeDir} directory. Is apiRepoPaths.${name} the right checkout?`);
|
|
55
|
+
return 1;
|
|
56
|
+
}
|
|
57
|
+
if (api.envFile && !(0, fs_1.existsSync)((0, path_1.join)(cwd, api.envFile))) {
|
|
58
|
+
console.error(`Missing ${api.envFile} in ${cwd}.${api.setupCommand ? ` Run "${api.setupCommand}" there first.` : ''}`);
|
|
59
|
+
return 1;
|
|
60
|
+
}
|
|
61
|
+
const tool = (0, compose_1.resolveComposeTool)();
|
|
62
|
+
if (!tool) {
|
|
63
|
+
console.error(`No compose tool found. Tried: ${(0, compose_1.composeToolNames)().join(', ')}.`);
|
|
64
|
+
return 1;
|
|
65
|
+
}
|
|
66
|
+
const { engine, compose } = tool;
|
|
67
|
+
const [binary, ...composePrefix] = compose;
|
|
68
|
+
const env = Object.assign(Object.assign(Object.assign({}, (0, compose_1.engineEnv)(engine)), process.env), definedEntries((_b = (_a = api.env) === null || _a === void 0 ? void 0 : _a.call(api)) !== null && _b !== void 0 ? _b : {}));
|
|
69
|
+
let exitCode = 0;
|
|
70
|
+
const runCompose = (...composeArgs) => {
|
|
71
|
+
var _a;
|
|
72
|
+
const result = (0, child_process_1.spawnSync)(binary, [...composePrefix, ...composeArgs], { cwd, env, stdio: 'inherit' });
|
|
73
|
+
if (result.error) {
|
|
74
|
+
console.error(result.error.message);
|
|
75
|
+
exitCode = 1;
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
exitCode = (_a = result.status) !== null && _a !== void 0 ? _a : 1;
|
|
79
|
+
};
|
|
80
|
+
if (command === 'up') {
|
|
81
|
+
if (api.network) {
|
|
82
|
+
(0, child_process_1.spawnSync)(engine, ['network', 'create', api.network], { stdio: 'ignore' });
|
|
83
|
+
}
|
|
84
|
+
runCompose('up', '-d', ...api.services);
|
|
85
|
+
// podman-compose exits 0 even when it fails to build or pull an image, so the state has to be
|
|
86
|
+
// read back rather than inferred from the exit code.
|
|
87
|
+
console.log(`\n${name} API at http://localhost:${api.port}. State:\n`);
|
|
88
|
+
runCompose('ps');
|
|
89
|
+
if (exposeOnLan) {
|
|
90
|
+
const address = (0, compose_1.lanAddress)();
|
|
91
|
+
if (!address) {
|
|
92
|
+
console.error('\nThis machine has no external IPv4 address, so the API cannot be reached over the network.');
|
|
93
|
+
return 1;
|
|
94
|
+
}
|
|
95
|
+
const envKeyStep = api.envKey
|
|
96
|
+
? `\n 2. Run localStorage.setItem('${api.envKey}', 'http://${address}:${api.port}') on that device.`
|
|
97
|
+
: '';
|
|
98
|
+
console.log(`\nThe published ports already listen on every interface, so the API also answers on\n` +
|
|
99
|
+
`http://${address}:${api.port}. Two more steps make another device use it:\n\n` +
|
|
100
|
+
` 1. Serve the app with a host binding of 0.0.0.0.${envKeyStep}\n\n` +
|
|
101
|
+
`A host firewall can still block port ${api.port}.`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
else if (command === 'down') {
|
|
105
|
+
runCompose('down');
|
|
106
|
+
}
|
|
107
|
+
else if (command === 'logs') {
|
|
108
|
+
runCompose('logs', '-f', api.execService);
|
|
109
|
+
}
|
|
110
|
+
else if (command === 'shell') {
|
|
111
|
+
runCompose('exec', api.execService, 'bash');
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
runCompose('exec', api.execService, ...((_d = (_c = api.exec) === null || _c === void 0 ? void 0 : _c[command]) !== null && _d !== void 0 ? _d : []));
|
|
115
|
+
}
|
|
116
|
+
return exitCode;
|
|
117
|
+
};
|
|
118
|
+
exports.runApiCommand = runApiCommand;
|
|
119
|
+
//# sourceMappingURL=run.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.js","sourceRoot":"","sources":["../../../../../../libs/cli/src/lib/api/run.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './local-config';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../libs/cli/src/lib/config/index.ts"],"names":[],"mappings":";;;AAAA,yDAA+B"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export declare const LOCAL_CONFIG_FILE_NAME = "ethlete.config.local.json";
|
|
2
|
+
/**
|
|
3
|
+
* The file these keys lived in before they moved to `ethlete.config.local.json`. Still read as a
|
|
4
|
+
* fallback so an existing checkout keeps working, and reported so the developer can move them.
|
|
5
|
+
*/
|
|
6
|
+
export declare const LEGACY_LOCAL_CONFIG_FILE_NAME = "ethlete-agents.config.local.json";
|
|
7
|
+
/**
|
|
8
|
+
* Machine-local repo topology: where the sibling checkouts this repo works with live. The file is
|
|
9
|
+
* gitignored, so every value is per-machine and never changes what anyone else sees.
|
|
10
|
+
*/
|
|
11
|
+
export type LocalConfig = {
|
|
12
|
+
/** Path to a local `ethlete-sdk` checkout, for reading its source or building it into this repo. */
|
|
13
|
+
sdkSourcePath?: string;
|
|
14
|
+
/** Path to the checkout of the API an app talks to, keyed by app name. `"*"` matches any app. */
|
|
15
|
+
apiRepoPaths?: Record<string, string>;
|
|
16
|
+
/** Branch that represents each API's deployed state, keyed by app name. `"*"` matches any app. */
|
|
17
|
+
apiRepoBranches?: Record<string, string>;
|
|
18
|
+
};
|
|
19
|
+
export type LocalConfigSource = {
|
|
20
|
+
config: LocalConfig;
|
|
21
|
+
/** The file the values came from, or `undefined` when neither file exists. */
|
|
22
|
+
fileName?: string;
|
|
23
|
+
/** True when the values came from `LEGACY_LOCAL_CONFIG_FILE_NAME`. */
|
|
24
|
+
isLegacy: boolean;
|
|
25
|
+
};
|
|
26
|
+
/** Reads the local config, falling back to the file the keys used to live in. */
|
|
27
|
+
export declare const readLocalConfig: (root: string) => LocalConfigSource;
|
|
28
|
+
export declare const configuredApiRepoPath: (config: LocalConfig, api: string) => string | undefined;
|
|
29
|
+
export declare const configuredApiRepoBranch: (config: LocalConfig, api: string) => string | undefined;
|
|
30
|
+
/** Resolves a configured path against the repo root, so a relative path in the file works. */
|
|
31
|
+
export declare const resolveConfiguredPath: (root: string, configured: string) => string;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveConfiguredPath = exports.configuredApiRepoBranch = exports.configuredApiRepoPath = exports.readLocalConfig = exports.LEGACY_LOCAL_CONFIG_FILE_NAME = exports.LOCAL_CONFIG_FILE_NAME = void 0;
|
|
4
|
+
const fs_1 = require("fs");
|
|
5
|
+
const path_1 = require("path");
|
|
6
|
+
exports.LOCAL_CONFIG_FILE_NAME = 'ethlete.config.local.json';
|
|
7
|
+
/**
|
|
8
|
+
* The file these keys lived in before they moved to `ethlete.config.local.json`. Still read as a
|
|
9
|
+
* fallback so an existing checkout keeps working, and reported so the developer can move them.
|
|
10
|
+
*/
|
|
11
|
+
exports.LEGACY_LOCAL_CONFIG_FILE_NAME = 'ethlete-agents.config.local.json';
|
|
12
|
+
const readJsonObject = (path) => {
|
|
13
|
+
if (!(0, fs_1.existsSync)(path))
|
|
14
|
+
return undefined;
|
|
15
|
+
let parsed;
|
|
16
|
+
try {
|
|
17
|
+
parsed = JSON.parse((0, fs_1.readFileSync)(path, 'utf8'));
|
|
18
|
+
}
|
|
19
|
+
catch (_a) {
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed))
|
|
23
|
+
return undefined;
|
|
24
|
+
return parsed;
|
|
25
|
+
};
|
|
26
|
+
/** Reads the local config, falling back to the file the keys used to live in. */
|
|
27
|
+
const readLocalConfig = (root) => {
|
|
28
|
+
const current = readJsonObject((0, path_1.join)(root, exports.LOCAL_CONFIG_FILE_NAME));
|
|
29
|
+
if (current)
|
|
30
|
+
return { config: current, fileName: exports.LOCAL_CONFIG_FILE_NAME, isLegacy: false };
|
|
31
|
+
const legacy = readJsonObject((0, path_1.join)(root, exports.LEGACY_LOCAL_CONFIG_FILE_NAME));
|
|
32
|
+
if (legacy)
|
|
33
|
+
return { config: legacy, fileName: exports.LEGACY_LOCAL_CONFIG_FILE_NAME, isLegacy: true };
|
|
34
|
+
return { config: {}, isLegacy: false };
|
|
35
|
+
};
|
|
36
|
+
exports.readLocalConfig = readLocalConfig;
|
|
37
|
+
const entryFor = (record, key) => { var _a; return (_a = record === null || record === void 0 ? void 0 : record[key]) !== null && _a !== void 0 ? _a : record === null || record === void 0 ? void 0 : record['*']; };
|
|
38
|
+
const configuredApiRepoPath = (config, api) => entryFor(config.apiRepoPaths, api);
|
|
39
|
+
exports.configuredApiRepoPath = configuredApiRepoPath;
|
|
40
|
+
const configuredApiRepoBranch = (config, api) => entryFor(config.apiRepoBranches, api);
|
|
41
|
+
exports.configuredApiRepoBranch = configuredApiRepoBranch;
|
|
42
|
+
/** Resolves a configured path against the repo root, so a relative path in the file works. */
|
|
43
|
+
const resolveConfiguredPath = (root, configured) => (0, path_1.isAbsolute)(configured) ? configured : (0, path_1.resolve)(root, configured);
|
|
44
|
+
exports.resolveConfiguredPath = resolveConfiguredPath;
|
|
45
|
+
//# sourceMappingURL=local-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-config.js","sourceRoot":"","sources":["../../../../../../libs/cli/src/lib/config/local-config.ts"],"names":[],"mappings":";;;AAAA,2BAA8C;AAC9C,+BAAiD;AAEpC,QAAA,sBAAsB,GAAG,2BAA2B,CAAC;AAElE;;;GAGG;AACU,QAAA,6BAA6B,GAAG,kCAAkC,CAAC;AAuBhF,MAAM,cAAc,GAAG,CAAC,IAAY,EAA2B,EAAE;IAC/D,IAAI,CAAC,IAAA,eAAU,EAAC,IAAI,CAAC;QAAE,OAAO,SAAS,CAAC;IAExC,IAAI,MAAe,CAAC;IAEpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAA,iBAAY,EAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;IAClD,CAAC;IAAC,WAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;QAAE,OAAO,SAAS,CAAC;IAE7F,OAAO,MAAqB,CAAC;AAC/B,CAAC,CAAC;AAEF,iFAAiF;AAC1E,MAAM,eAAe,GAAG,CAAC,IAAY,EAAqB,EAAE;IACjE,MAAM,OAAO,GAAG,cAAc,CAAC,IAAA,WAAI,EAAC,IAAI,EAAE,8BAAsB,CAAC,CAAC,CAAC;IAEnE,IAAI,OAAO;QAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,8BAAsB,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;IAE3F,MAAM,MAAM,GAAG,cAAc,CAAC,IAAA,WAAI,EAAC,IAAI,EAAE,qCAA6B,CAAC,CAAC,CAAC;IAEzE,IAAI,MAAM;QAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,qCAA6B,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAE/F,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;AACzC,CAAC,CAAC;AAVW,QAAA,eAAe,mBAU1B;AAEF,MAAM,QAAQ,GAAG,CAAC,MAA0C,EAAE,GAAW,EAAE,EAAE,WAAC,OAAA,MAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAG,GAAG,CAAC,mCAAI,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAG,GAAG,CAAC,CAAA,EAAA,CAAC;AAEtG,MAAM,qBAAqB,GAAG,CAAC,MAAmB,EAAE,GAAW,EAAE,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC;AAAjG,QAAA,qBAAqB,yBAA4E;AAEvG,MAAM,uBAAuB,GAAG,CAAC,MAAmB,EAAE,GAAW,EAAE,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,eAAe,EAAE,GAAG,CAAC,CAAC;AAAtG,QAAA,uBAAuB,2BAA+E;AAEnH,8FAA8F;AACvF,MAAM,qBAAqB,GAAG,CAAC,IAAY,EAAE,UAAkB,EAAE,EAAE,CACxE,IAAA,iBAAU,EAAC,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAA,cAAO,EAAC,IAAI,EAAE,UAAU,CAAC,CAAC;AADrD,QAAA,qBAAqB,yBACgC"}
|
package/src/lib/index.d.ts
CHANGED
package/src/lib/index.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
|
+
tslib_1.__exportStar(require("./api"), exports);
|
|
5
|
+
tslib_1.__exportStar(require("./config"), exports);
|
|
4
6
|
tslib_1.__exportStar(require("./release"), exports);
|
|
5
7
|
//# sourceMappingURL=index.js.map
|
package/src/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../libs/cli/src/lib/index.ts"],"names":[],"mappings":";;;AAAA,oDAA0B"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../libs/cli/src/lib/index.ts"],"names":[],"mappings":";;;AAAA,gDAAsB;AACtB,mDAAyB;AACzB,oDAA0B"}
|