hereya-cli 0.90.1 → 0.92.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 +90 -75
- package/dist/backend/cloud/cloud-backend/executor-broker.d.ts +25 -0
- package/dist/backend/cloud/cloud-backend/executor-broker.js +38 -0
- package/dist/backend/cloud/cloud-backend.d.ts +3 -0
- package/dist/backend/cloud/cloud-backend.js +7 -0
- package/dist/backend/common.d.ts +2 -2
- package/dist/commands/executor/start/index.d.ts +3 -0
- package/dist/commands/executor/start/index.js +115 -32
- package/dist/commands/workspace/executor/install/index.d.ts +3 -0
- package/dist/commands/workspace/executor/install/index.js +176 -76
- package/dist/commands/workspace/executor/uninstall/index.d.ts +1 -0
- package/dist/commands/workspace/executor/uninstall/index.js +29 -4
- package/dist/executor/local.d.ts +0 -1
- package/dist/executor/local.js +10 -62
- package/dist/executor/resolve-env.d.ts +88 -0
- package/dist/executor/resolve-env.js +77 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +7 -0
- package/dist/infrastructure/index.d.ts +12 -16
- package/dist/infrastructure/index.js +18 -25
- package/dist/infrastructure/registry.d.ts +38 -0
- package/dist/infrastructure/registry.js +61 -0
- package/dist/lib/package/index.d.ts +22 -22
- package/oclif.manifest.json +102 -62
- package/package.json +1 -1
|
@@ -5,11 +5,20 @@ import { getBackend } from '../../../../backend/index.js';
|
|
|
5
5
|
import { getExecutor } from '../../../../executor/index.js';
|
|
6
6
|
import { getLogger, getLogPath, isDebug, setDebug } from '../../../../lib/log.js';
|
|
7
7
|
import { delay } from '../../../../lib/shell.js';
|
|
8
|
-
const
|
|
8
|
+
const EXECUTOR_PACKAGE = 'hereya/remote-executor-aws';
|
|
9
9
|
export default class WorkspaceExecutorUninstall extends Command {
|
|
10
|
-
static description =
|
|
10
|
+
static description = `Uninstall the remote executor from a workspace.
|
|
11
|
+
|
|
12
|
+
Both modes (always-on and ephemeral) are backed by the same package
|
|
13
|
+
(hereya/remote-executor-aws). The --mode flag is informational only and
|
|
14
|
+
controls log output.`;
|
|
11
15
|
static flags = {
|
|
12
16
|
debug: Flags.boolean({ default: false, description: 'enable debug mode' }),
|
|
17
|
+
mode: Flags.string({
|
|
18
|
+
default: 'always-on',
|
|
19
|
+
description: 'executor mode used at install time (informational only)',
|
|
20
|
+
options: ['ephemeral', 'always-on'],
|
|
21
|
+
}),
|
|
13
22
|
workspace: Flags.string({
|
|
14
23
|
char: 'w',
|
|
15
24
|
description: 'name of the workspace',
|
|
@@ -56,7 +65,7 @@ export default class WorkspaceExecutorUninstall extends Command {
|
|
|
56
65
|
const { executor } = executor$;
|
|
57
66
|
const destroyOutput = await executor.destroy({
|
|
58
67
|
logger: getLogger(task),
|
|
59
|
-
package:
|
|
68
|
+
package: EXECUTOR_PACKAGE,
|
|
60
69
|
skipDeploy: true,
|
|
61
70
|
workspace: flags.workspace,
|
|
62
71
|
});
|
|
@@ -76,6 +85,22 @@ export default class WorkspaceExecutorUninstall extends Command {
|
|
|
76
85
|
},
|
|
77
86
|
title: 'Revoking executor token',
|
|
78
87
|
},
|
|
88
|
+
{
|
|
89
|
+
async task() {
|
|
90
|
+
const backend = await getBackend();
|
|
91
|
+
// Always attempt to unregister the broker. The endpoint
|
|
92
|
+
// gracefully no-ops on 404, so this is safe for always-on
|
|
93
|
+
// installs that never registered a broker.
|
|
94
|
+
const result = await backend.unregisterExecutorBroker({
|
|
95
|
+
workspace: flags.workspace,
|
|
96
|
+
});
|
|
97
|
+
if (!result.success) {
|
|
98
|
+
throw new Error(`Failed to unregister executor broker: ${result.reason}`);
|
|
99
|
+
}
|
|
100
|
+
await delay(500);
|
|
101
|
+
},
|
|
102
|
+
title: 'Unregistering executor broker',
|
|
103
|
+
},
|
|
79
104
|
{
|
|
80
105
|
async task() {
|
|
81
106
|
const backend = await getBackend();
|
|
@@ -89,7 +114,7 @@ export default class WorkspaceExecutorUninstall extends Command {
|
|
|
89
114
|
},
|
|
90
115
|
], { concurrent: false, rendererOptions: { collapseSubtasks: !isDebug() } });
|
|
91
116
|
},
|
|
92
|
-
title: `Uninstalling executor from workspace ${flags.workspace}`,
|
|
117
|
+
title: `Uninstalling executor from workspace ${flags.workspace} (mode: ${flags.mode})`,
|
|
93
118
|
},
|
|
94
119
|
], { concurrent: false });
|
|
95
120
|
try {
|
package/dist/executor/local.d.ts
CHANGED
|
@@ -7,5 +7,4 @@ export declare class LocalExecutor implements Executor {
|
|
|
7
7
|
setEnvVar(input: ExecutorSetEnvVarInput): Promise<ExecutorSetEnvVarOutput>;
|
|
8
8
|
unsetEnvVar(input: ExecutorUnsetEnvVarInput): Promise<ExecutorUnsetEnvVarOutput>;
|
|
9
9
|
private getWorkspaceEnv;
|
|
10
|
-
private resolveGithubAppMarkers;
|
|
11
10
|
}
|
package/dist/executor/local.js
CHANGED
|
@@ -2,6 +2,7 @@ import { getBackend } from '../backend/index.js';
|
|
|
2
2
|
import { destroyPackage, getInfrastructure, getProvisioningLogicalId, provisionPackage, resolveEnvValues as resolveEnvValuesSimple } from '../infrastructure/index.js';
|
|
3
3
|
import { mintInstallationToken } from '../lib/github-app.js';
|
|
4
4
|
import { resolvePackage } from '../lib/package/index.js';
|
|
5
|
+
import { resolveEnvValues as resolveEnvValuesPure } from './resolve-env.js';
|
|
5
6
|
export class LocalExecutor {
|
|
6
7
|
async destroy(input) {
|
|
7
8
|
// For apps, we use `app` as the project-name source for workspace env resolution
|
|
@@ -70,28 +71,15 @@ export class LocalExecutor {
|
|
|
70
71
|
});
|
|
71
72
|
}
|
|
72
73
|
async resolveEnvValues(input) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
if (!infra$.supported) {
|
|
83
|
-
// Unknown infra type - treat as plain value, return as-is
|
|
84
|
-
return [key, value];
|
|
85
|
-
}
|
|
86
|
-
const { infrastructure } = infra$;
|
|
87
|
-
const valueWithoutInfra = value.slice(colonIndex + 1);
|
|
88
|
-
const { isSecret, value: resolvedValue } = await infrastructure.resolveEnv({
|
|
89
|
-
value: valueWithoutInfra,
|
|
90
|
-
});
|
|
91
|
-
const finalValue = input.markSecret && isSecret ? `secret://${resolvedValue}` : resolvedValue;
|
|
92
|
-
return [key, finalValue];
|
|
93
|
-
})));
|
|
94
|
-
return this.resolveGithubAppMarkers(resolved, input);
|
|
74
|
+
return resolveEnvValuesPure(input, {
|
|
75
|
+
getInfrastructure,
|
|
76
|
+
async getWorkspaceEnv(args) {
|
|
77
|
+
const backend = await getBackend();
|
|
78
|
+
return backend.getWorkspaceEnv(args);
|
|
79
|
+
},
|
|
80
|
+
mintInstallationToken,
|
|
81
|
+
resolveSimpleEnv: resolveEnvValuesSimple,
|
|
82
|
+
});
|
|
95
83
|
}
|
|
96
84
|
async setEnvVar(input) {
|
|
97
85
|
const backend = await getBackend();
|
|
@@ -187,44 +175,4 @@ export class LocalExecutor {
|
|
|
187
175
|
success: true,
|
|
188
176
|
};
|
|
189
177
|
}
|
|
190
|
-
async resolveGithubAppMarkers(resolved, input) {
|
|
191
|
-
const needsToken = Object.values(resolved).some((v) => typeof v === 'string' && v.startsWith('github-app:'));
|
|
192
|
-
if (!needsToken)
|
|
193
|
-
return resolved;
|
|
194
|
-
if (!input.workspace || !input.project)
|
|
195
|
-
return resolved;
|
|
196
|
-
const backend = await getBackend();
|
|
197
|
-
const wsEnv$ = await backend.getWorkspaceEnv({
|
|
198
|
-
project: input.project,
|
|
199
|
-
workspace: input.workspace,
|
|
200
|
-
});
|
|
201
|
-
if (!wsEnv$.success)
|
|
202
|
-
return resolved;
|
|
203
|
-
// Use the simple infrastructure resolver - resolves aws: prefixes only and
|
|
204
|
-
// does NOT recurse into github-app: markers, so no circularity.
|
|
205
|
-
const wsResolved = await resolveEnvValuesSimple(wsEnv$.env);
|
|
206
|
-
const appId = wsResolved.hereyaGithubAppId;
|
|
207
|
-
const installationIdFromEnv = wsResolved.hereyaGithubAppInstallationId;
|
|
208
|
-
const privateKey = wsResolved.hereyaGithubAppPrivateKey;
|
|
209
|
-
if (!appId || !privateKey) {
|
|
210
|
-
console.warn('hereya: github-app marker present but workspace env missing hereyaGithubAppId / hereyaGithubAppPrivateKey; leaving marker unresolved');
|
|
211
|
-
return resolved;
|
|
212
|
-
}
|
|
213
|
-
const out = { ...resolved };
|
|
214
|
-
for (const [k, v] of Object.entries(resolved)) {
|
|
215
|
-
if (typeof v !== 'string' || !v.startsWith('github-app:'))
|
|
216
|
-
continue;
|
|
217
|
-
const installationId = v.slice('github-app:'.length) || installationIdFromEnv;
|
|
218
|
-
if (!installationId)
|
|
219
|
-
continue;
|
|
220
|
-
try {
|
|
221
|
-
// eslint-disable-next-line no-await-in-loop
|
|
222
|
-
out[k] = await mintInstallationToken({ appId, installationId, privateKey });
|
|
223
|
-
}
|
|
224
|
-
catch (error) {
|
|
225
|
-
console.warn(`hereya: failed to mint github-app installation token: ${error.message}`);
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
return out;
|
|
229
|
-
}
|
|
230
178
|
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type { GetInfrastructureOutput } from '../infrastructure/registry.js';
|
|
2
|
+
/**
|
|
3
|
+
* Pure-function env-value resolver, factored out of `LocalExecutor.resolveEnvValues`.
|
|
4
|
+
*
|
|
5
|
+
* The functions in this module are deliberately free of any class state
|
|
6
|
+
* (`this`) or hard-coded global lookups so they can be invoked from contexts
|
|
7
|
+
* that do not include the full CLI runtime — e.g. the broker Lambda that
|
|
8
|
+
* imports `hereya-cli` as a published npm dependency.
|
|
9
|
+
*
|
|
10
|
+
* Dependencies that the resolver needs (the infrastructure-provider lookup,
|
|
11
|
+
* the workspace-env lookup, and the GitHub-app installation-token minter) are
|
|
12
|
+
* all injected via the `providers` argument so callers can supply only the
|
|
13
|
+
* pieces they have available.
|
|
14
|
+
*/
|
|
15
|
+
import { InfrastructureType } from '../infrastructure/common.js';
|
|
16
|
+
export type ResolveEnvValuesInput = {
|
|
17
|
+
env: {
|
|
18
|
+
[key: string]: string;
|
|
19
|
+
};
|
|
20
|
+
markSecret?: boolean;
|
|
21
|
+
project?: string;
|
|
22
|
+
workspace?: string;
|
|
23
|
+
};
|
|
24
|
+
export type ResolveEnvValuesOutput = {
|
|
25
|
+
[key: string]: string;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Look up an infrastructure provider by type. The Lambda passes a thin wrapper
|
|
29
|
+
* over its registered `aws` provider; the CLI passes the full registry.
|
|
30
|
+
*/
|
|
31
|
+
export type GetInfrastructureFn = (input: {
|
|
32
|
+
type: InfrastructureType;
|
|
33
|
+
}) => GetInfrastructureOutput;
|
|
34
|
+
/**
|
|
35
|
+
* Fetch a workspace's stored env values (used to find the GitHub-app
|
|
36
|
+
* configuration when resolving `github-app:` markers).
|
|
37
|
+
*/
|
|
38
|
+
export type GetWorkspaceEnvFn = (input: {
|
|
39
|
+
project: string;
|
|
40
|
+
workspace: string;
|
|
41
|
+
}) => Promise<{
|
|
42
|
+
env: {
|
|
43
|
+
[key: string]: string;
|
|
44
|
+
};
|
|
45
|
+
success: true;
|
|
46
|
+
} | {
|
|
47
|
+
reason: string;
|
|
48
|
+
success: false;
|
|
49
|
+
}>;
|
|
50
|
+
/**
|
|
51
|
+
* Resolve a workspace env map without recursing into github-app markers.
|
|
52
|
+
* Used to dereference the `aws:` (or other infra) values for the GitHub-app
|
|
53
|
+
* config keys.
|
|
54
|
+
*/
|
|
55
|
+
export type ResolveSimpleEnvFn = (env: Record<string, string>) => Promise<Record<string, string>>;
|
|
56
|
+
/**
|
|
57
|
+
* Mint a GitHub-app installation token.
|
|
58
|
+
*/
|
|
59
|
+
export type MintInstallationTokenFn = (input: {
|
|
60
|
+
appId: string;
|
|
61
|
+
installationId: string;
|
|
62
|
+
privateKey: string;
|
|
63
|
+
}) => Promise<string>;
|
|
64
|
+
export interface ResolveEnvProviders {
|
|
65
|
+
/** Infrastructure-provider lookup — required. */
|
|
66
|
+
getInfrastructure: GetInfrastructureFn;
|
|
67
|
+
/**
|
|
68
|
+
* Optional GitHub-app dependencies. If any of them is missing, `github-app:`
|
|
69
|
+
* markers are left unresolved (the Lambda path can choose not to wire
|
|
70
|
+
* GitHub-app support at all).
|
|
71
|
+
*/
|
|
72
|
+
getWorkspaceEnv?: GetWorkspaceEnvFn;
|
|
73
|
+
mintInstallationToken?: MintInstallationTokenFn;
|
|
74
|
+
resolveSimpleEnv?: ResolveSimpleEnvFn;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Resolve `infra:` prefixes and `github-app:` markers in an env map. Pure
|
|
78
|
+
* function — no module-level state, no `this`, side effects are limited to
|
|
79
|
+
* what the injected providers do.
|
|
80
|
+
*/
|
|
81
|
+
export declare function resolveEnvValues(input: ResolveEnvValuesInput, providers: ResolveEnvProviders): Promise<ResolveEnvValuesOutput>;
|
|
82
|
+
/**
|
|
83
|
+
* Walk the resolved env, replace any `github-app:<installationId?>` marker
|
|
84
|
+
* with a freshly-minted installation token. Reads the GitHub-app config from
|
|
85
|
+
* the workspace env (`hereyaGithubAppId`, `hereyaGithubAppPrivateKey`,
|
|
86
|
+
* optional `hereyaGithubAppInstallationId`).
|
|
87
|
+
*/
|
|
88
|
+
export declare function resolveGithubAppMarkers(resolved: Record<string, string>, input: ResolveEnvValuesInput, providers: ResolveEnvProviders): Promise<Record<string, string>>;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve `infra:` prefixes and `github-app:` markers in an env map. Pure
|
|
3
|
+
* function — no module-level state, no `this`, side effects are limited to
|
|
4
|
+
* what the injected providers do.
|
|
5
|
+
*/
|
|
6
|
+
export async function resolveEnvValues(input, providers) {
|
|
7
|
+
const resolved = Object.fromEntries(await Promise.all(Object.entries(input.env).map(async ([key, value]) => {
|
|
8
|
+
// Check if value has infra prefix (contains ':' and first part is valid infra)
|
|
9
|
+
const colonIndex = value.indexOf(':');
|
|
10
|
+
if (colonIndex === -1) {
|
|
11
|
+
// No colon - plain value, return as-is
|
|
12
|
+
return [key, value];
|
|
13
|
+
}
|
|
14
|
+
const infraType = value.slice(0, colonIndex);
|
|
15
|
+
const infra$ = providers.getInfrastructure({ type: infraType });
|
|
16
|
+
if (!infra$.supported) {
|
|
17
|
+
// Unknown infra type - treat as plain value, return as-is
|
|
18
|
+
return [key, value];
|
|
19
|
+
}
|
|
20
|
+
const { infrastructure } = infra$;
|
|
21
|
+
const valueWithoutInfra = value.slice(colonIndex + 1);
|
|
22
|
+
const { isSecret, value: resolvedValue } = await infrastructure.resolveEnv({
|
|
23
|
+
value: valueWithoutInfra,
|
|
24
|
+
});
|
|
25
|
+
const finalValue = input.markSecret && isSecret ? `secret://${resolvedValue}` : resolvedValue;
|
|
26
|
+
return [key, finalValue];
|
|
27
|
+
})));
|
|
28
|
+
return resolveGithubAppMarkers(resolved, input, providers);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Walk the resolved env, replace any `github-app:<installationId?>` marker
|
|
32
|
+
* with a freshly-minted installation token. Reads the GitHub-app config from
|
|
33
|
+
* the workspace env (`hereyaGithubAppId`, `hereyaGithubAppPrivateKey`,
|
|
34
|
+
* optional `hereyaGithubAppInstallationId`).
|
|
35
|
+
*/
|
|
36
|
+
export async function resolveGithubAppMarkers(resolved, input, providers) {
|
|
37
|
+
const needsToken = Object.values(resolved).some((v) => typeof v === 'string' && v.startsWith('github-app:'));
|
|
38
|
+
if (!needsToken)
|
|
39
|
+
return resolved;
|
|
40
|
+
if (!input.workspace || !input.project)
|
|
41
|
+
return resolved;
|
|
42
|
+
const { getWorkspaceEnv, mintInstallationToken, resolveSimpleEnv } = providers;
|
|
43
|
+
if (!getWorkspaceEnv || !mintInstallationToken || !resolveSimpleEnv)
|
|
44
|
+
return resolved;
|
|
45
|
+
const wsEnv$ = await getWorkspaceEnv({
|
|
46
|
+
project: input.project,
|
|
47
|
+
workspace: input.workspace,
|
|
48
|
+
});
|
|
49
|
+
if (!wsEnv$.success)
|
|
50
|
+
return resolved;
|
|
51
|
+
// Use the simple infrastructure resolver - resolves aws: prefixes only and
|
|
52
|
+
// does NOT recurse into github-app: markers, so no circularity.
|
|
53
|
+
const wsResolved = await resolveSimpleEnv(wsEnv$.env);
|
|
54
|
+
const appId = wsResolved.hereyaGithubAppId;
|
|
55
|
+
const installationIdFromEnv = wsResolved.hereyaGithubAppInstallationId;
|
|
56
|
+
const privateKey = wsResolved.hereyaGithubAppPrivateKey;
|
|
57
|
+
if (!appId || !privateKey) {
|
|
58
|
+
console.warn('hereya: github-app marker present but workspace env missing hereyaGithubAppId / hereyaGithubAppPrivateKey; leaving marker unresolved');
|
|
59
|
+
return resolved;
|
|
60
|
+
}
|
|
61
|
+
const out = { ...resolved };
|
|
62
|
+
for (const [k, v] of Object.entries(resolved)) {
|
|
63
|
+
if (typeof v !== 'string' || !v.startsWith('github-app:'))
|
|
64
|
+
continue;
|
|
65
|
+
const installationId = v.slice('github-app:'.length) || installationIdFromEnv;
|
|
66
|
+
if (!installationId)
|
|
67
|
+
continue;
|
|
68
|
+
try {
|
|
69
|
+
// eslint-disable-next-line no-await-in-loop
|
|
70
|
+
out[k] = await mintInstallationToken({ appId, installationId, privateKey });
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
console.warn(`hereya: failed to mint github-app installation token: ${error.message}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return out;
|
|
77
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1 +1,4 @@
|
|
|
1
|
+
export { type GetInfrastructureFn, type GetWorkspaceEnvFn, type MintInstallationTokenFn, type ResolveEnvProviders, resolveEnvValues, type ResolveEnvValuesInput, type ResolveEnvValuesOutput, resolveGithubAppMarkers, type ResolveSimpleEnvFn, } from './executor/resolve-env.js';
|
|
2
|
+
export { InfrastructureType } from './infrastructure/common.js';
|
|
3
|
+
export { awsProviderFactory, getInfrastructure, type GetInfrastructureInput, type GetInfrastructureOutput, type InfrastructureProviderFactory, registerInfrastructureProvider, resetInfrastructureProviders, } from './infrastructure/registry.js';
|
|
1
4
|
export { run } from '@oclif/core';
|
package/dist/index.js
CHANGED
|
@@ -1 +1,8 @@
|
|
|
1
|
+
// Public API for external consumers (e.g. the broker Lambda) that import
|
|
2
|
+
// `hereya-cli` as a published npm dependency. None of these re-exports pull
|
|
3
|
+
// in the `local` infrastructure provider or the rest of the CLI runtime — the
|
|
4
|
+
// Lambda bundle stays slim.
|
|
5
|
+
export { resolveEnvValues, resolveGithubAppMarkers, } from './executor/resolve-env.js';
|
|
6
|
+
export { InfrastructureType } from './infrastructure/common.js';
|
|
7
|
+
export { awsProviderFactory, getInfrastructure, registerInfrastructureProvider, resetInfrastructureProviders, } from './infrastructure/registry.js';
|
|
1
8
|
export { run } from '@oclif/core';
|
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { Logger } from '../lib/log.js';
|
|
3
3
|
import { PackageMetadata } from '../lib/package/index.js';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
import { Infrastructure } from './common.js';
|
|
5
|
+
import { type InfrastructureProviderFactory } from './registry.js';
|
|
6
|
+
export { awsProviderFactory, getInfrastructure, type GetInfrastructureInput, type GetInfrastructureOutput, type InfrastructureProviderFactory, registerInfrastructureProvider, resetInfrastructureProviders, } from './registry.js';
|
|
7
|
+
/**
|
|
8
|
+
* Default factory for the local-filesystem provider. Registered eagerly when
|
|
9
|
+
* this module is imported (the CLI's standard entry point). The broker
|
|
10
|
+
* Lambda never imports this module, so `LocalInfrastructure` and its
|
|
11
|
+
* filesystem deps are tree-shaken out of the Lambda bundle.
|
|
12
|
+
*/
|
|
13
|
+
export declare const localProviderFactory: InfrastructureProviderFactory;
|
|
14
|
+
export declare const awsInfrastructure: Infrastructure;
|
|
15
|
+
export declare const localInfrastructure: Infrastructure;
|
|
9
16
|
export declare function resolveEnvValues(env: Record<string, string>): Promise<Record<string, string>>;
|
|
10
|
-
export declare function getInfrastructure(input: GetInfrastructureInput): GetInfrastructureOutput;
|
|
11
17
|
export declare function destroyPackage(input: DestroyPackageInput): Promise<DestroyPackageOutput>;
|
|
12
18
|
export declare function provisionPackage(input: ProvisionPackageInput): Promise<ProvisionPackageOutput>;
|
|
13
19
|
export declare function getProvisioningLogicalId({ app, pkg, project, workspace }: {
|
|
@@ -49,14 +55,4 @@ export type ProvisionPackageOutput = {
|
|
|
49
55
|
reason: string;
|
|
50
56
|
success: false;
|
|
51
57
|
};
|
|
52
|
-
export type GetInfrastructureInput = {
|
|
53
|
-
type: InfrastructureType;
|
|
54
|
-
};
|
|
55
|
-
export type GetInfrastructureOutput = {
|
|
56
|
-
infrastructure: Infrastructure;
|
|
57
|
-
supported: true;
|
|
58
|
-
} | {
|
|
59
|
-
reason: string;
|
|
60
|
-
supported: false;
|
|
61
|
-
};
|
|
62
58
|
export type PackageMetadata = z.infer<typeof PackageMetadata>;
|
|
@@ -1,11 +1,26 @@
|
|
|
1
1
|
import { getBackend } from '../backend/index.js';
|
|
2
2
|
import { stripOrgPrefix } from '../lib/org-utils.js';
|
|
3
3
|
import { resolvePackage } from '../lib/package/index.js';
|
|
4
|
-
import { AwsInfrastructure } from './aws.js';
|
|
5
4
|
import { InfrastructureType } from './common.js';
|
|
6
5
|
import { LocalInfrastructure } from './local.js';
|
|
7
|
-
|
|
8
|
-
export
|
|
6
|
+
import { getInfrastructure, getOrCreateProvider, registerInfrastructureProvider, } from './registry.js';
|
|
7
|
+
// Re-export the registry surface so existing imports
|
|
8
|
+
// (`from '../infrastructure/index.js'`) keep working.
|
|
9
|
+
export { awsProviderFactory, getInfrastructure, registerInfrastructureProvider, resetInfrastructureProviders, } from './registry.js';
|
|
10
|
+
/**
|
|
11
|
+
* Default factory for the local-filesystem provider. Registered eagerly when
|
|
12
|
+
* this module is imported (the CLI's standard entry point). The broker
|
|
13
|
+
* Lambda never imports this module, so `LocalInfrastructure` and its
|
|
14
|
+
* filesystem deps are tree-shaken out of the Lambda bundle.
|
|
15
|
+
*/
|
|
16
|
+
export const localProviderFactory = () => new LocalInfrastructure();
|
|
17
|
+
registerInfrastructureProvider(InfrastructureType.local, localProviderFactory);
|
|
18
|
+
// Backwards-compatible singleton exports. These remain stable references
|
|
19
|
+
// (`sinon.stub(awsInfrastructure, 'foo')` continues to work) because the
|
|
20
|
+
// default registrations above run at import time and the cached instances
|
|
21
|
+
// never change identity for the lifetime of the CLI process.
|
|
22
|
+
export const awsInfrastructure = getOrCreateProvider(InfrastructureType.aws);
|
|
23
|
+
export const localInfrastructure = getOrCreateProvider(InfrastructureType.local);
|
|
9
24
|
export async function resolveEnvValues(env) {
|
|
10
25
|
return Object.fromEntries(await Promise.all(Object.entries(env).map(async ([key, value]) => {
|
|
11
26
|
const colonIndex = value.indexOf(':');
|
|
@@ -21,28 +36,6 @@ export async function resolveEnvValues(env) {
|
|
|
21
36
|
return [key, resolvedValue];
|
|
22
37
|
})));
|
|
23
38
|
}
|
|
24
|
-
export function getInfrastructure(input) {
|
|
25
|
-
switch (input.type) {
|
|
26
|
-
case InfrastructureType.aws: {
|
|
27
|
-
return {
|
|
28
|
-
infrastructure: awsInfrastructure,
|
|
29
|
-
supported: true,
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
case InfrastructureType.local: {
|
|
33
|
-
return {
|
|
34
|
-
infrastructure: localInfrastructure,
|
|
35
|
-
supported: true,
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
default: {
|
|
39
|
-
return {
|
|
40
|
-
reason: `Invalid infrastructure type: ${input.type}. Valid options are: aws, local`,
|
|
41
|
-
supported: false,
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
39
|
/**
|
|
47
40
|
* When `input.app` is set, scope the provisioning row by `app` (workspace-scoped).
|
|
48
41
|
* Otherwise, scope by `project`. Apps and projects are mutually exclusive scopes
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Infrastructure, InfrastructureType } from './common.js';
|
|
2
|
+
/**
|
|
3
|
+
* A factory that lazily constructs an `Infrastructure` provider singleton.
|
|
4
|
+
* Registered factories are invoked at most once per type — the resulting
|
|
5
|
+
* instance is cached so external consumers (and tests that stub methods on
|
|
6
|
+
* `awsInfrastructure` / `localInfrastructure`) see the same reference every
|
|
7
|
+
* time.
|
|
8
|
+
*/
|
|
9
|
+
export type InfrastructureProviderFactory = () => Infrastructure;
|
|
10
|
+
/**
|
|
11
|
+
* Default factory for the AWS provider. Both the CLI and the broker Lambda
|
|
12
|
+
* register this; it is the only factory the Lambda bundle pulls in.
|
|
13
|
+
*/
|
|
14
|
+
export declare const awsProviderFactory: InfrastructureProviderFactory;
|
|
15
|
+
/**
|
|
16
|
+
* Register (or replace) the factory for a given infrastructure type. Resets
|
|
17
|
+
* any cached instance for that type so the next `getInfrastructure` call
|
|
18
|
+
* rebuilds it from the new factory.
|
|
19
|
+
*/
|
|
20
|
+
export declare function registerInfrastructureProvider(type: InfrastructureType, factory: InfrastructureProviderFactory): void;
|
|
21
|
+
/**
|
|
22
|
+
* Clear all registered providers and cached instances. Primarily useful for
|
|
23
|
+
* tests and for the Lambda bundle that wants to start with a clean slate
|
|
24
|
+
* before registering only `aws`.
|
|
25
|
+
*/
|
|
26
|
+
export declare function resetInfrastructureProviders(): void;
|
|
27
|
+
export declare function getOrCreateProvider(type: InfrastructureType): Infrastructure;
|
|
28
|
+
export declare function getInfrastructure(input: GetInfrastructureInput): GetInfrastructureOutput;
|
|
29
|
+
export type GetInfrastructureInput = {
|
|
30
|
+
type: InfrastructureType;
|
|
31
|
+
};
|
|
32
|
+
export type GetInfrastructureOutput = {
|
|
33
|
+
infrastructure: Infrastructure;
|
|
34
|
+
supported: true;
|
|
35
|
+
} | {
|
|
36
|
+
reason: string;
|
|
37
|
+
supported: false;
|
|
38
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Infrastructure provider registry. This module is the slim, Lambda-friendly
|
|
3
|
+
* entry point: it never imports the local-filesystem provider. The CLI's
|
|
4
|
+
* `./index.ts` extends this registry with `LocalInfrastructure`; the broker
|
|
5
|
+
* Lambda imports only this registry (via the `hereya-cli` package root) and
|
|
6
|
+
* registers `aws` only.
|
|
7
|
+
*/
|
|
8
|
+
import { AwsInfrastructure } from './aws.js';
|
|
9
|
+
import { InfrastructureType } from './common.js';
|
|
10
|
+
/**
|
|
11
|
+
* Default factory for the AWS provider. Both the CLI and the broker Lambda
|
|
12
|
+
* register this; it is the only factory the Lambda bundle pulls in.
|
|
13
|
+
*/
|
|
14
|
+
export const awsProviderFactory = () => new AwsInfrastructure();
|
|
15
|
+
const factories = new Map();
|
|
16
|
+
const instances = new Map();
|
|
17
|
+
/**
|
|
18
|
+
* Register (or replace) the factory for a given infrastructure type. Resets
|
|
19
|
+
* any cached instance for that type so the next `getInfrastructure` call
|
|
20
|
+
* rebuilds it from the new factory.
|
|
21
|
+
*/
|
|
22
|
+
export function registerInfrastructureProvider(type, factory) {
|
|
23
|
+
factories.set(type, factory);
|
|
24
|
+
instances.delete(type);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Clear all registered providers and cached instances. Primarily useful for
|
|
28
|
+
* tests and for the Lambda bundle that wants to start with a clean slate
|
|
29
|
+
* before registering only `aws`.
|
|
30
|
+
*/
|
|
31
|
+
export function resetInfrastructureProviders() {
|
|
32
|
+
factories.clear();
|
|
33
|
+
instances.clear();
|
|
34
|
+
}
|
|
35
|
+
export function getOrCreateProvider(type) {
|
|
36
|
+
const cached = instances.get(type);
|
|
37
|
+
if (cached)
|
|
38
|
+
return cached;
|
|
39
|
+
const factory = factories.get(type);
|
|
40
|
+
if (!factory) {
|
|
41
|
+
throw new Error(`Infrastructure provider not registered: ${type}. Call registerInfrastructureProvider(${type}, factory) first.`);
|
|
42
|
+
}
|
|
43
|
+
const instance = factory();
|
|
44
|
+
instances.set(type, instance);
|
|
45
|
+
return instance;
|
|
46
|
+
}
|
|
47
|
+
export function getInfrastructure(input) {
|
|
48
|
+
if (!factories.has(input.type)) {
|
|
49
|
+
return {
|
|
50
|
+
reason: `Invalid infrastructure type: ${input.type}. Valid options are: ${[...factories.keys()].join(', ') || '<none registered>'}`,
|
|
51
|
+
supported: false,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
infrastructure: getOrCreateProvider(input.type),
|
|
56
|
+
supported: true,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
// Register the AWS provider eagerly. The CLI's `infrastructure/index.ts`
|
|
60
|
+
// additionally registers the `local` provider; the broker Lambda does not.
|
|
61
|
+
registerInfrastructureProvider(InfrastructureType.aws, awsProviderFactory);
|
|
@@ -37,20 +37,20 @@ export declare const ParameterSpec: z.ZodEffects<z.ZodObject<{
|
|
|
37
37
|
description: z.ZodOptional<z.ZodString>;
|
|
38
38
|
mandatory: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
|
|
39
39
|
}, "strip", z.ZodTypeAny, {
|
|
40
|
-
description?: string | undefined;
|
|
41
40
|
default?: string | undefined;
|
|
41
|
+
description?: string | undefined;
|
|
42
42
|
mandatory?: boolean | undefined;
|
|
43
43
|
}, {
|
|
44
|
-
description?: string | undefined;
|
|
45
44
|
default?: string | undefined;
|
|
45
|
+
description?: string | undefined;
|
|
46
46
|
mandatory?: boolean | undefined;
|
|
47
47
|
}>, {
|
|
48
|
-
description?: string | undefined;
|
|
49
48
|
default?: string | undefined;
|
|
49
|
+
description?: string | undefined;
|
|
50
50
|
mandatory?: boolean | undefined;
|
|
51
51
|
}, {
|
|
52
|
-
description?: string | undefined;
|
|
53
52
|
default?: string | undefined;
|
|
53
|
+
description?: string | undefined;
|
|
54
54
|
mandatory?: boolean | undefined;
|
|
55
55
|
}>;
|
|
56
56
|
export type IParameterSpec = z.infer<typeof ParameterSpec>;
|
|
@@ -79,42 +79,37 @@ export declare const PackageMetadata: z.ZodObject<{
|
|
|
79
79
|
description: z.ZodOptional<z.ZodString>;
|
|
80
80
|
mandatory: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
|
|
81
81
|
}, "strip", z.ZodTypeAny, {
|
|
82
|
-
description?: string | undefined;
|
|
83
82
|
default?: string | undefined;
|
|
83
|
+
description?: string | undefined;
|
|
84
84
|
mandatory?: boolean | undefined;
|
|
85
85
|
}, {
|
|
86
|
-
description?: string | undefined;
|
|
87
86
|
default?: string | undefined;
|
|
87
|
+
description?: string | undefined;
|
|
88
88
|
mandatory?: boolean | undefined;
|
|
89
89
|
}>, {
|
|
90
|
-
description?: string | undefined;
|
|
91
90
|
default?: string | undefined;
|
|
91
|
+
description?: string | undefined;
|
|
92
92
|
mandatory?: boolean | undefined;
|
|
93
93
|
}, {
|
|
94
|
-
description?: string | undefined;
|
|
95
94
|
default?: string | undefined;
|
|
95
|
+
description?: string | undefined;
|
|
96
96
|
mandatory?: boolean | undefined;
|
|
97
97
|
}>>>, Record<string, {
|
|
98
|
-
description?: string | undefined;
|
|
99
98
|
default?: string | undefined;
|
|
99
|
+
description?: string | undefined;
|
|
100
100
|
mandatory?: boolean | undefined;
|
|
101
101
|
}> | undefined, Record<string, {
|
|
102
|
-
description?: string | undefined;
|
|
103
102
|
default?: string | undefined;
|
|
103
|
+
description?: string | undefined;
|
|
104
104
|
mandatory?: boolean | undefined;
|
|
105
105
|
}> | undefined>;
|
|
106
106
|
snakeCase: z.ZodOptional<z.ZodBoolean>;
|
|
107
107
|
}, "strip", z.ZodTypeAny, {
|
|
108
108
|
iac: IacType;
|
|
109
109
|
infra: InfrastructureType;
|
|
110
|
-
dependencies?: Record<string, string> | undefined;
|
|
111
110
|
kind?: "app" | "package" | undefined;
|
|
112
|
-
parameters?: Record<string, {
|
|
113
|
-
description?: string | undefined;
|
|
114
|
-
default?: string | undefined;
|
|
115
|
-
mandatory?: boolean | undefined;
|
|
116
|
-
}> | undefined;
|
|
117
111
|
deploy?: boolean | undefined;
|
|
112
|
+
dependencies?: Record<string, string> | undefined;
|
|
118
113
|
devDeploy?: boolean | undefined;
|
|
119
114
|
inputs?: Record<string, z.objectOutputType<{}, z.ZodTypeAny, "passthrough">> | undefined;
|
|
120
115
|
onDeploy?: {
|
|
@@ -123,18 +118,18 @@ export declare const PackageMetadata: z.ZodObject<{
|
|
|
123
118
|
} | undefined;
|
|
124
119
|
originalInfra?: InfrastructureType | undefined;
|
|
125
120
|
outputs?: Record<string, z.objectOutputType<{}, z.ZodTypeAny, "passthrough">> | undefined;
|
|
121
|
+
parameters?: Record<string, {
|
|
122
|
+
default?: string | undefined;
|
|
123
|
+
description?: string | undefined;
|
|
124
|
+
mandatory?: boolean | undefined;
|
|
125
|
+
}> | undefined;
|
|
126
126
|
snakeCase?: boolean | undefined;
|
|
127
127
|
}, {
|
|
128
128
|
iac: IacType;
|
|
129
129
|
infra: InfrastructureType;
|
|
130
|
-
dependencies?: Record<string, string> | undefined;
|
|
131
130
|
kind?: "app" | "package" | undefined;
|
|
132
|
-
parameters?: Record<string, {
|
|
133
|
-
description?: string | undefined;
|
|
134
|
-
default?: string | undefined;
|
|
135
|
-
mandatory?: boolean | undefined;
|
|
136
|
-
}> | undefined;
|
|
137
131
|
deploy?: boolean | undefined;
|
|
132
|
+
dependencies?: Record<string, string> | undefined;
|
|
138
133
|
devDeploy?: boolean | undefined;
|
|
139
134
|
inputs?: Record<string, z.objectInputType<{}, z.ZodTypeAny, "passthrough">> | undefined;
|
|
140
135
|
onDeploy?: {
|
|
@@ -143,6 +138,11 @@ export declare const PackageMetadata: z.ZodObject<{
|
|
|
143
138
|
} | undefined;
|
|
144
139
|
originalInfra?: InfrastructureType | undefined;
|
|
145
140
|
outputs?: Record<string, z.objectInputType<{}, z.ZodTypeAny, "passthrough">> | undefined;
|
|
141
|
+
parameters?: Record<string, {
|
|
142
|
+
default?: string | undefined;
|
|
143
|
+
description?: string | undefined;
|
|
144
|
+
mandatory?: boolean | undefined;
|
|
145
|
+
}> | undefined;
|
|
146
146
|
snakeCase?: boolean | undefined;
|
|
147
147
|
}>;
|
|
148
148
|
export type IPackageMetadata = z.infer<typeof PackageMetadata>;
|