@fjall/deploy-core 0.89.5 → 0.89.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 +50 -21
- package/README.md +25 -0
- package/dist/.minified +1 -0
- package/dist/src/__test-utils__/awsMockHelpers.d.ts +20 -0
- package/dist/src/__test-utils__/awsMockHelpers.js +1 -0
- package/dist/src/__test-utils__/index.d.ts +1 -0
- package/dist/src/__test-utils__/index.js +1 -0
- package/dist/src/aws/AwsProvider.js +0 -1
- package/dist/src/aws/SimpleAwsProvider.js +1 -70
- package/dist/src/aws/index.d.ts +4 -2
- package/dist/src/aws/index.js +1 -3
- package/dist/src/aws/organisations/accounts.js +10 -10
- package/dist/src/aws/organisations/backup.js +4 -2
- package/dist/src/aws/organisations/costAllocation.js +4 -2
- package/dist/src/aws/organisations/delegatedAdmin.d.ts +9 -0
- package/dist/src/aws/organisations/delegatedAdmin.js +43 -0
- package/dist/src/aws/organisations/identityCentre.d.ts +1 -1
- package/dist/src/aws/organisations/identityCentre.js +6 -2
- package/dist/src/aws/organisations/index.d.ts +4 -3
- package/dist/src/aws/organisations/index.js +1 -12
- package/dist/src/aws/organisations/ipam.js +4 -2
- package/dist/src/aws/organisations/organisation.js +27 -18
- package/dist/src/aws/organisations/organisationalUnits.d.ts +26 -6
- package/dist/src/aws/organisations/organisationalUnits.js +149 -35
- package/dist/src/aws/organisations/policies.js +4 -3
- package/dist/src/aws/organisations/ram.js +6 -2
- package/dist/src/aws/organisations/serviceAccess.js +12 -6
- package/dist/src/aws/organisations/trustedAccess.js +6 -2
- package/dist/src/aws/organisations/types.d.ts +23 -1
- package/dist/src/aws/organisations/types.js +1 -16
- package/dist/src/aws/utils/__tests__/cloudformationTestHelpers.d.ts +6 -0
- package/dist/src/aws/utils/__tests__/cloudformationTestHelpers.js +1 -0
- package/dist/src/aws/utils/cloudformationEventHelpers.d.ts +48 -0
- package/dist/src/aws/utils/cloudformationEventHelpers.js +1 -0
- package/dist/src/aws/utils/cloudformationEventTypes.d.ts +45 -0
- package/dist/src/aws/utils/cloudformationEventTypes.js +1 -0
- package/dist/src/aws/utils/cloudformationEvents.d.ts +8 -54
- package/dist/src/aws/utils/cloudformationEvents.js +1 -596
- package/dist/src/aws/utils/index.d.ts +5 -0
- package/dist/src/aws/utils/index.js +1 -0
- package/dist/src/aws/utils/stackStatus.js +1 -90
- package/dist/src/events/index.d.ts +13 -0
- package/dist/src/events/index.js +1 -0
- package/dist/src/index.d.ts +34 -17
- package/dist/src/index.js +41 -21
- package/dist/src/orchestration/__tests__/cascadeTestHelpers.d.ts +12 -0
- package/dist/src/orchestration/__tests__/cascadeTestHelpers.js +78 -0
- package/dist/src/orchestration/activeDeploymentGuard.d.ts +10 -0
- package/dist/src/orchestration/activeDeploymentGuard.js +39 -0
- package/dist/src/orchestration/applicationDeploy.js +46 -229
- package/dist/src/orchestration/applicationDeployHelpers.d.ts +39 -0
- package/dist/src/orchestration/applicationDeployHelpers.js +223 -0
- package/dist/src/orchestration/applicationDestroy.d.ts +14 -0
- package/dist/src/orchestration/applicationDestroy.js +131 -0
- package/dist/src/orchestration/builders/dockerBuilder.d.ts +17 -0
- package/dist/src/orchestration/builders/dockerBuilder.js +98 -0
- package/dist/src/orchestration/builders/frameworkRegistry.d.ts +23 -0
- package/dist/src/orchestration/builders/frameworkRegistry.js +1 -0
- package/dist/src/orchestration/builders/index.d.ts +4 -0
- package/dist/src/orchestration/builders/index.js +1 -0
- package/dist/src/orchestration/builders/openNextBuilder.d.ts +21 -0
- package/dist/src/orchestration/builders/openNextBuilder.js +144 -0
- package/dist/src/orchestration/cascadeDestroyHelpers.d.ts +30 -0
- package/dist/src/orchestration/cascadeDestroyHelpers.js +1 -0
- package/dist/src/orchestration/cascadeHelpers.d.ts +46 -0
- package/dist/src/orchestration/cascadeHelpers.js +160 -0
- package/dist/src/orchestration/contextHelpers.d.ts +46 -2
- package/dist/src/orchestration/contextHelpers.js +93 -1
- package/dist/src/orchestration/destroy.d.ts +13 -0
- package/dist/src/orchestration/destroy.js +67 -0
- package/dist/src/orchestration/detectionPipeline.d.ts +2 -11
- package/dist/src/orchestration/detectionPipeline.js +29 -10
- package/dist/src/orchestration/dockerBuildHelper.d.ts +10 -0
- package/dist/src/orchestration/dockerBuildHelper.js +49 -0
- package/dist/src/orchestration/dockerInterface.d.ts +4 -2
- package/dist/src/orchestration/index.d.ts +8 -1
- package/dist/src/orchestration/index.js +1 -3
- package/dist/src/orchestration/manifestSecretParser.d.ts +11 -0
- package/dist/src/orchestration/manifestSecretParser.js +1 -0
- package/dist/src/orchestration/openNextBuild.d.ts +28 -0
- package/dist/src/orchestration/openNextBuild.js +243 -0
- package/dist/src/orchestration/organisationDeploy.js +110 -233
- package/dist/src/orchestration/organisationDestroy.d.ts +24 -0
- package/dist/src/orchestration/organisationDestroy.js +189 -0
- package/dist/src/orchestration/organisationSetup.d.ts +6 -4
- package/dist/src/orchestration/organisationSetup.js +28 -8
- package/dist/src/orchestration/resolveOperation.js +68 -6
- package/dist/src/orchestration/serviceFactory.d.ts +4 -0
- package/dist/src/orchestration/serviceFactory.js +1 -16
- package/dist/src/orchestration/spawnHelpers.d.ts +47 -0
- package/dist/src/orchestration/spawnHelpers.js +1 -0
- package/dist/src/orchestration/stackCleanup.d.ts +39 -0
- package/dist/src/orchestration/stackCleanup.js +1 -0
- package/dist/src/orchestration/welcomeImageHelper.d.ts +15 -0
- package/dist/src/orchestration/welcomeImageHelper.js +64 -0
- package/dist/src/services/application/ApplicationStackService.d.ts +21 -30
- package/dist/src/services/application/ApplicationStackService.js +16 -234
- package/dist/src/services/application/applicationStackHelpers.d.ts +46 -0
- package/dist/src/services/application/applicationStackHelpers.js +248 -0
- package/dist/src/services/application/index.d.ts +1 -0
- package/dist/src/services/application/index.js +1 -1
- package/dist/src/services/index.d.ts +6 -0
- package/dist/src/services/index.js +1 -0
- package/dist/src/services/infrastructure/CdkArgumentBuilder.js +1 -67
- package/dist/src/services/infrastructure/CdkCommandRunner.d.ts +10 -2
- package/dist/src/services/infrastructure/CdkCommandRunner.js +18 -15
- package/dist/src/services/infrastructure/CdkErrorFormatter.js +16 -194
- package/dist/src/services/infrastructure/CdkEventMonitoring.js +1 -41
- package/dist/src/services/infrastructure/CdkOutputAnalyser.js +1 -1
- package/dist/src/services/infrastructure/CdkOutputParser.js +2 -33
- package/dist/src/services/infrastructure/CdkProcessManager.d.ts +5 -0
- package/dist/src/services/infrastructure/CdkProcessManager.js +81 -47
- package/dist/src/services/infrastructure/CdkService.d.ts +7 -53
- package/dist/src/services/infrastructure/CdkService.js +41 -83
- package/dist/src/services/infrastructure/CdkServiceTypes.d.ts +50 -0
- package/dist/src/services/infrastructure/CdkServiceTypes.js +0 -0
- package/dist/src/services/infrastructure/CloudFormationService.js +9 -10
- package/dist/src/services/infrastructure/ICdkProcessManager.d.ts +27 -0
- package/dist/src/services/infrastructure/ICdkProcessManager.js +1 -0
- package/dist/src/services/infrastructure/__tests__/cloudFormationTestHelpers.d.ts +9 -0
- package/dist/src/services/infrastructure/__tests__/cloudFormationTestHelpers.js +1 -0
- package/dist/src/services/infrastructure/cdkServiceHelpers.d.ts +9 -0
- package/dist/src/services/infrastructure/cdkServiceHelpers.js +1 -0
- package/dist/src/services/infrastructure/constructMapEnrichment.d.ts +7 -0
- package/dist/src/services/infrastructure/constructMapEnrichment.js +1 -0
- package/dist/src/services/infrastructure/index.d.ts +3 -1
- package/dist/src/services/infrastructure/index.js +1 -7
- package/dist/src/services/supporting/TemplateHashService.js +1 -1
- package/dist/src/services/supporting/helpers.js +1 -81
- package/dist/src/services/supporting/index.js +1 -3
- package/dist/src/steps/index.d.ts +1 -0
- package/dist/src/steps/index.js +1 -0
- package/dist/src/steps/stepRegistry.d.ts +71 -0
- package/dist/src/steps/stepRegistry.js +505 -0
- package/dist/src/types/FjallState.js +1 -118
- package/dist/src/types/ProgressEvent.js +1 -48
- package/dist/src/types/application/ApplicationServiceTypes.js +1 -30
- package/dist/src/types/application/index.js +1 -1
- package/dist/src/types/callbacks.d.ts +76 -4
- package/dist/src/types/callbacks.js +0 -1
- package/dist/src/types/constants.d.ts +2 -0
- package/dist/src/types/constants.js +1 -6
- package/dist/src/types/credentials.js +0 -1
- package/dist/src/types/deployment/DeploymentServiceTypes.d.ts +5 -2
- package/dist/src/types/deployment/DeploymentServiceTypes.js +1 -1
- package/dist/src/types/deployment/DeploymentTypes.js +0 -1
- package/dist/src/types/deployment/cloudformation.js +0 -1
- package/dist/src/types/deployment/index.d.ts +3 -1
- package/dist/src/types/deployment/index.js +1 -1
- package/dist/src/types/deployment/parallel.js +1 -10
- package/dist/src/types/deploymentEventSchema.d.ts +158 -0
- package/dist/src/types/deploymentEventSchema.js +1 -0
- package/dist/src/types/detection.d.ts +22 -0
- package/dist/src/types/detection.js +1 -0
- package/dist/src/types/entitlements.d.ts +31 -0
- package/dist/src/types/entitlements.js +0 -0
- package/dist/src/types/errors/CdkError.js +1 -20
- package/dist/src/types/errors/ServiceError.d.ts +2 -1
- package/dist/src/types/errors/ServiceError.js +1 -119
- package/dist/src/types/errors/index.d.ts +2 -0
- package/dist/src/types/errors/index.js +1 -0
- package/dist/src/types/events.d.ts +3 -9
- package/dist/src/types/events.js +0 -5
- package/dist/src/types/frameworkBuilder.d.ts +96 -0
- package/dist/src/types/frameworkBuilder.js +8 -0
- package/dist/src/types/index.d.ts +19 -4
- package/dist/src/types/index.js +1 -9
- package/dist/src/types/operations.d.ts +3 -2
- package/dist/src/types/operations.js +1 -285
- package/dist/src/types/orgConfig.d.ts +2 -10
- package/dist/src/types/orgConfig.js +0 -11
- package/dist/src/types/params.d.ts +60 -1
- package/dist/src/types/patternDetection.d.ts +14 -16
- package/dist/src/types/patternDetection.js +14 -18
- package/dist/src/types/patternTypes.d.ts +19 -0
- package/dist/src/types/patternTypes.js +1 -0
- package/dist/src/types/stepDefinitions.d.ts +163 -0
- package/dist/src/types/stepDefinitions.js +98 -0
- package/dist/src/types/validation.js +0 -1
- package/dist/src/util/dockerfileDetection.d.ts +5 -0
- package/dist/src/util/dockerfileDetection.js +1 -0
- package/dist/src/util/index.d.ts +4 -3
- package/dist/src/util/index.js +1 -3
- package/dist/src/util/sequencedCallbacks.d.ts +44 -0
- package/dist/src/util/sequencedCallbacks.js +1 -0
- package/package.json +49 -8
- package/dist/src/aws/utils/CloudFormationFailureAnalyser.d.ts +0 -32
- package/dist/src/aws/utils/CloudFormationFailureAnalyser.js +0 -228
- package/dist/src/aws/utils/errors.d.ts +0 -26
- package/dist/src/aws/utils/errors.js +0 -59
- package/dist/src/util/fsHelpers.d.ts +0 -4
- package/dist/src/util/fsHelpers.js +0 -16
- package/dist/src/util/securityHelpers.d.ts +0 -31
- package/dist/src/util/securityHelpers.js +0 -124
- package/dist/src/util/singleton.d.ts +0 -2
- package/dist/src/util/singleton.js +0 -9
- package/dist/src/util/sleep.d.ts +0 -4
- package/dist/src/util/sleep.js +0 -4
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { success, failure } from "@fjall/generator";
|
|
2
|
+
import { logger } from "@fjall/util/logger";
|
|
3
|
+
import { getApplicationDestroyOrder, getApplicationStepName, getApplicationStepId } from "../types/operations.js";
|
|
4
|
+
import { stubCallerIdentity } from "../types/deployment/index.js";
|
|
5
|
+
import { deriveResourcesFromManifestStacks } from "../types/patternDetection.js";
|
|
6
|
+
import { CdkContextBuilder } from "../services/supporting/CdkContextBuilder.js";
|
|
7
|
+
import { buildParamsContext } from "./contextHelpers.js";
|
|
8
|
+
import { deleteStateFile, readStateFile } from "../types/FjallState.js";
|
|
9
|
+
/**
|
|
10
|
+
* Core application destruction orchestration.
|
|
11
|
+
*
|
|
12
|
+
* Detects application pattern, determines destroy order (reverse of deploy),
|
|
13
|
+
* then destroys stacks sequentially or in parallel groups. Delegates all
|
|
14
|
+
* CDK operations to the ApplicationStackService.destroyAllStacks() method,
|
|
15
|
+
* which handles "stack doesn't exist" → success conversion and parallel
|
|
16
|
+
* phase orchestration for OpenNext patterns.
|
|
17
|
+
*/
|
|
18
|
+
export async function destroyApplication(params, services, operation) {
|
|
19
|
+
const { callbacks } = params;
|
|
20
|
+
const startTime = Date.now();
|
|
21
|
+
// 1. Detect pattern for correct destroy order
|
|
22
|
+
const resolved = services.frameworkRegistry.resolve({
|
|
23
|
+
appPath: operation.path
|
|
24
|
+
});
|
|
25
|
+
const pattern = resolved?.detection.pattern ?? null;
|
|
26
|
+
// Derive resources from state file (if available from prior deploy)
|
|
27
|
+
let destroyResources;
|
|
28
|
+
try {
|
|
29
|
+
const stateFile = await readStateFile(operation.path);
|
|
30
|
+
if (stateFile !== null) {
|
|
31
|
+
const stackNames = Object.keys(stateFile.templateHashes);
|
|
32
|
+
if (stackNames.length > 0) {
|
|
33
|
+
destroyResources = deriveResourcesFromManifestStacks(stackNames);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
logger.debug("applicationDestroy", "Could not read state file for resource detection", { error: err instanceof Error ? err.message : String(err) });
|
|
39
|
+
callbacks.onLog?.("Could not read state file for resource detection — falling back to pattern detection", "warn");
|
|
40
|
+
}
|
|
41
|
+
// 2. Build deployment context
|
|
42
|
+
const context = CdkContextBuilder.buildDeploymentContext({
|
|
43
|
+
deployType: "application",
|
|
44
|
+
target: operation.appName,
|
|
45
|
+
path: operation.path,
|
|
46
|
+
region: services.awsProvider.getRegion(),
|
|
47
|
+
callerIdentity: stubCallerIdentity(services.awsProvider.getAccountId()),
|
|
48
|
+
...buildParamsContext({
|
|
49
|
+
orgConfig: params.orgConfig,
|
|
50
|
+
identity: params.identity
|
|
51
|
+
})
|
|
52
|
+
}, {
|
|
53
|
+
verbose: params.options?.verbose
|
|
54
|
+
}, params.orgConfig);
|
|
55
|
+
// 3. Determine destroy order
|
|
56
|
+
const destroyOrder = getApplicationDestroyOrder({
|
|
57
|
+
pattern,
|
|
58
|
+
resources: destroyResources
|
|
59
|
+
});
|
|
60
|
+
const totalSteps = destroyOrder.length;
|
|
61
|
+
callbacks.onLog?.(`Destroying ${operation.appName} (${totalSteps} stacks, ${pattern ?? "standard"} pattern)`, "info");
|
|
62
|
+
// 4. Destroy stacks via ApplicationStackService
|
|
63
|
+
const stacksDestroyed = [];
|
|
64
|
+
const skippedStacks = [];
|
|
65
|
+
const destroyResult = await services.stackService.destroyAllStacks(context, {
|
|
66
|
+
onOutput: (chunk) => {
|
|
67
|
+
callbacks.onOutput?.(chunk);
|
|
68
|
+
},
|
|
69
|
+
onResourceProgress: (event, stackId) => {
|
|
70
|
+
callbacks.onResourceProgress?.(event);
|
|
71
|
+
if (stackId) {
|
|
72
|
+
callbacks.onParallelStackResourceProgress?.(stackId, event);
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
onStackStart: (stackType, _stackName) => {
|
|
76
|
+
const stepId = getApplicationStepId(stackType, "destroy");
|
|
77
|
+
const stepName = getApplicationStepName(stackType, "destroy");
|
|
78
|
+
const stepIndex = destroyOrder.indexOf(stackType);
|
|
79
|
+
callbacks.onStepStart?.(stepId, stepName, stepIndex, totalSteps);
|
|
80
|
+
},
|
|
81
|
+
onStackComplete: async (stackType, result) => {
|
|
82
|
+
const stepId = getApplicationStepId(stackType, "destroy");
|
|
83
|
+
const stepName = getApplicationStepName(stackType, "destroy");
|
|
84
|
+
const stepIndex = destroyOrder.indexOf(stackType);
|
|
85
|
+
if (result.success) {
|
|
86
|
+
if (result.data?.skipped) {
|
|
87
|
+
skippedStacks.push(result.data.stackName || stackType);
|
|
88
|
+
callbacks.onStepComplete?.(stepId, stepName, "skipped", stepIndex, totalSteps);
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
stacksDestroyed.push(result.data?.stackName || stackType);
|
|
92
|
+
callbacks.onStepComplete?.(stepId, stepName, "completed", stepIndex, totalSteps);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
callbacks.onStepComplete?.(stepId, stepName, "error", stepIndex, totalSteps);
|
|
97
|
+
callbacks.onError?.(result.error);
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
onParallelPhaseStart: (stacks, description) => {
|
|
101
|
+
callbacks.onLog?.(`Parallel phase: ${description}`, "info");
|
|
102
|
+
callbacks.onParallelPhaseStart?.(stacks, description);
|
|
103
|
+
},
|
|
104
|
+
onParallelPhaseComplete: (results) => {
|
|
105
|
+
const failed = results.filter((r) => !r.success);
|
|
106
|
+
if (failed.length > 0) {
|
|
107
|
+
callbacks.onLog?.(`Parallel phase completed with ${failed.length} failure(s)`, "warn");
|
|
108
|
+
}
|
|
109
|
+
callbacks.onParallelPhaseComplete?.(results);
|
|
110
|
+
}
|
|
111
|
+
}, destroyResources);
|
|
112
|
+
if (!destroyResult.success) {
|
|
113
|
+
callbacks.onError?.(destroyResult.error);
|
|
114
|
+
return failure(destroyResult.error);
|
|
115
|
+
}
|
|
116
|
+
// 5. Clean up state file after successful destroy
|
|
117
|
+
try {
|
|
118
|
+
await deleteStateFile(operation.path);
|
|
119
|
+
}
|
|
120
|
+
catch (err) {
|
|
121
|
+
logger.debug("applicationDestroy", "Failed to delete state file (non-critical)", { error: err instanceof Error ? err.message : String(err) });
|
|
122
|
+
callbacks.onLog?.("Failed to delete state file (non-critical)", "warn");
|
|
123
|
+
}
|
|
124
|
+
return success({
|
|
125
|
+
target: operation.appName,
|
|
126
|
+
deploymentType: "application",
|
|
127
|
+
stacksDestroyed,
|
|
128
|
+
skippedStacks,
|
|
129
|
+
durationMs: Date.now() - startTime
|
|
130
|
+
});
|
|
131
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DockerBuilder — FrameworkBuilder implementation for standard Docker apps.
|
|
3
|
+
*
|
|
4
|
+
* Fallback builder (priority 100) that detects any Fjall app with an
|
|
5
|
+
* infrastructure.ts file. Docker builds are NOT handled here — they are
|
|
6
|
+
* handled by DockerProvider in the orchestration layer. This builder only
|
|
7
|
+
* produces the deployment plan and resource detection.
|
|
8
|
+
*/
|
|
9
|
+
import type { FrameworkBuilder } from "../../types/frameworkBuilder.js";
|
|
10
|
+
/**
|
|
11
|
+
* Docker FrameworkBuilder for standard containerised applications.
|
|
12
|
+
*
|
|
13
|
+
* Priority 100 — checked last as the fallback builder. Any Fjall app with
|
|
14
|
+
* an infrastructure.ts file is a valid Docker app unless a higher-priority
|
|
15
|
+
* builder (e.g. OpenNext) claims it first.
|
|
16
|
+
*/
|
|
17
|
+
export declare const dockerBuilder: FrameworkBuilder;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DockerBuilder — FrameworkBuilder implementation for standard Docker apps.
|
|
3
|
+
*
|
|
4
|
+
* Fallback builder (priority 100) that detects any Fjall app with an
|
|
5
|
+
* infrastructure.ts file. Docker builds are NOT handled here — they are
|
|
6
|
+
* handled by DockerProvider in the orchestration layer. This builder only
|
|
7
|
+
* produces the deployment plan and resource detection.
|
|
8
|
+
*/
|
|
9
|
+
import { existsSync, readFileSync } from "fs";
|
|
10
|
+
import { join } from "path";
|
|
11
|
+
import { success } from "@fjall/generator";
|
|
12
|
+
import { logger } from "@fjall/util/logger";
|
|
13
|
+
import { getErrorMessage } from "@fjall/util";
|
|
14
|
+
import { hasDockerfile } from "../../util/dockerfileDetection.js";
|
|
15
|
+
import { INFRASTRUCTURE_FILENAME } from "../../types/constants.js";
|
|
16
|
+
import { getApplicationDeployOrder, getApplicationDestroyOrder } from "../../types/operations.js";
|
|
17
|
+
/** Default resources when infrastructure.ts cannot be parsed */
|
|
18
|
+
const DEFAULT_RESOURCES = {
|
|
19
|
+
hasNetwork: true,
|
|
20
|
+
hasCompute: true,
|
|
21
|
+
hasDatabase: false,
|
|
22
|
+
hasStorage: false,
|
|
23
|
+
hasMessaging: false,
|
|
24
|
+
hasCdn: false
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Read infrastructure.ts and derive resource flags from its content.
|
|
28
|
+
*/
|
|
29
|
+
function detectResources(appPath) {
|
|
30
|
+
try {
|
|
31
|
+
const filePath = join(appPath, INFRASTRUCTURE_FILENAME);
|
|
32
|
+
if (!existsSync(filePath))
|
|
33
|
+
return { exists: false, hasDatabase: false };
|
|
34
|
+
const content = readFileSync(filePath, "utf-8");
|
|
35
|
+
const hasDatabase = content.includes("DatabaseFactory.build(");
|
|
36
|
+
return { exists: true, hasDatabase };
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
logger.debug("dockerBuilder", "Failed to read infrastructure file", {
|
|
40
|
+
appPath,
|
|
41
|
+
error: getErrorMessage(error)
|
|
42
|
+
});
|
|
43
|
+
return { exists: false, hasDatabase: false };
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Docker FrameworkBuilder for standard containerised applications.
|
|
48
|
+
*
|
|
49
|
+
* Priority 100 — checked last as the fallback builder. Any Fjall app with
|
|
50
|
+
* an infrastructure.ts file is a valid Docker app unless a higher-priority
|
|
51
|
+
* builder (e.g. OpenNext) claims it first.
|
|
52
|
+
*/
|
|
53
|
+
export const dockerBuilder = {
|
|
54
|
+
name: "docker",
|
|
55
|
+
priority: 100,
|
|
56
|
+
detect(context) {
|
|
57
|
+
const { exists, hasDatabase } = detectResources(context.appPath);
|
|
58
|
+
if (!exists) {
|
|
59
|
+
return {
|
|
60
|
+
detected: false,
|
|
61
|
+
pattern: null,
|
|
62
|
+
reason: "No infrastructure.ts found",
|
|
63
|
+
resources: DEFAULT_RESOURCES,
|
|
64
|
+
hasDatabase: false,
|
|
65
|
+
hasDockerfile: false
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
const dockerfile = hasDockerfile(context.appPath);
|
|
69
|
+
return {
|
|
70
|
+
detected: true,
|
|
71
|
+
pattern: null,
|
|
72
|
+
reason: dockerfile
|
|
73
|
+
? "infrastructure.ts found with Dockerfile"
|
|
74
|
+
: "infrastructure.ts found (no Dockerfile)",
|
|
75
|
+
resources: { ...DEFAULT_RESOURCES, hasDatabase },
|
|
76
|
+
hasDatabase,
|
|
77
|
+
hasDockerfile: dockerfile
|
|
78
|
+
};
|
|
79
|
+
},
|
|
80
|
+
plan(_context, detection) {
|
|
81
|
+
const resources = detection.resources;
|
|
82
|
+
return {
|
|
83
|
+
builderName: "docker",
|
|
84
|
+
deployOrder: getApplicationDeployOrder({ resources }),
|
|
85
|
+
destroyOrder: getApplicationDestroyOrder({ resources }),
|
|
86
|
+
parallelDestroy: false,
|
|
87
|
+
preBuildCommands: [],
|
|
88
|
+
buildCommand: null,
|
|
89
|
+
requiresDockerBuild: detection.hasDockerfile,
|
|
90
|
+
resources
|
|
91
|
+
};
|
|
92
|
+
},
|
|
93
|
+
async build(_appPath, _plan, _callbacks, _options) {
|
|
94
|
+
// Docker builds are handled by DockerProvider in the orchestration layer,
|
|
95
|
+
// not by the builder. This is the correct separation of concerns.
|
|
96
|
+
return success(undefined);
|
|
97
|
+
}
|
|
98
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FrameworkRegistry — resolves which FrameworkBuilder handles an application.
|
|
3
|
+
*
|
|
4
|
+
* Builders are registered with a priority (lower = higher precedence) and
|
|
5
|
+
* checked in order. The first builder whose `detect()` returns `detected: true`
|
|
6
|
+
* wins. A config override bypasses detection and forces selection by name.
|
|
7
|
+
*/
|
|
8
|
+
import type { FrameworkBuilder, FrameworkDetection, DetectionContext } from "../../types/frameworkBuilder.js";
|
|
9
|
+
/** Result of resolving a builder for an application */
|
|
10
|
+
export interface ResolvedBuilder {
|
|
11
|
+
readonly builder: FrameworkBuilder;
|
|
12
|
+
readonly detection: FrameworkDetection;
|
|
13
|
+
}
|
|
14
|
+
export declare class FrameworkRegistry {
|
|
15
|
+
private readonly builders;
|
|
16
|
+
private constructor();
|
|
17
|
+
/** Resolve which builder handles this app */
|
|
18
|
+
resolve(context: DetectionContext, configOverride?: string): ResolvedBuilder | null;
|
|
19
|
+
/** Create a registry with all built-in builders */
|
|
20
|
+
static createDefault(): FrameworkRegistry;
|
|
21
|
+
/** Create with custom builders (for testing) */
|
|
22
|
+
static create(builders: FrameworkBuilder[]): FrameworkRegistry;
|
|
23
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{openNextBuilder as u}from"./openNextBuilder.js";import{dockerBuilder as d}from"./dockerBuilder.js";class n{builders;constructor(e){this.builders=[...e].sort((r,t)=>r.priority-t.priority)}resolve(e,r){if(r){const t=this.builders.find(o=>o.name===r);if(!t)return null;const i=t.detect(e);return{builder:t,detection:{...i,detected:!0}}}for(const t of this.builders){const i=t.detect(e);if(i.detected)return{builder:t,detection:i}}return null}static createDefault(){return new n([u,d])}static create(e){return new n(e)}}export{n as FrameworkRegistry};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{dockerBuilder as o}from"./dockerBuilder.js";import{openNextBuilder as m}from"./openNextBuilder.js";import{FrameworkRegistry as x}from"./frameworkRegistry.js";export{x as FrameworkRegistry,o as dockerBuilder,m as openNextBuilder};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenNextBuilder — FrameworkBuilder implementation for Next.js and Payload apps.
|
|
3
|
+
*
|
|
4
|
+
* Detects OpenNext patterns from infrastructure.ts, produces a build plan with
|
|
5
|
+
* the correct stack ordering, and delegates build execution to `runOpenNextBuild()`.
|
|
6
|
+
*
|
|
7
|
+
* BUILD ORDERING NOTE: The OpenNext build runs BEFORE the detection pipeline
|
|
8
|
+
* because CDK synth needs the `.open-next/` directory to exist. This builder's
|
|
9
|
+
* `build()` method is called early in the deployment flow, not after detection.
|
|
10
|
+
* The plan's `buildCommand` is declarative — actual execution goes through
|
|
11
|
+
* `runOpenNextBuild()` which handles binary resolution, timeouts, and cleanup.
|
|
12
|
+
*/
|
|
13
|
+
import type { FrameworkBuilder } from "../../types/frameworkBuilder.js";
|
|
14
|
+
/**
|
|
15
|
+
* OpenNext FrameworkBuilder for Next.js and Payload applications.
|
|
16
|
+
*
|
|
17
|
+
* Priority 10 — checked before Docker (priority 50) since OpenNext is more
|
|
18
|
+
* specific. Apps matching an OpenNext pattern use Lambda-based deployment
|
|
19
|
+
* with S3, DynamoDB, SQS, and CloudFront stacks.
|
|
20
|
+
*/
|
|
21
|
+
export declare const openNextBuilder: FrameworkBuilder;
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenNextBuilder — FrameworkBuilder implementation for Next.js and Payload apps.
|
|
3
|
+
*
|
|
4
|
+
* Detects OpenNext patterns from infrastructure.ts, produces a build plan with
|
|
5
|
+
* the correct stack ordering, and delegates build execution to `runOpenNextBuild()`.
|
|
6
|
+
*
|
|
7
|
+
* BUILD ORDERING NOTE: The OpenNext build runs BEFORE the detection pipeline
|
|
8
|
+
* because CDK synth needs the `.open-next/` directory to exist. This builder's
|
|
9
|
+
* `build()` method is called early in the deployment flow, not after detection.
|
|
10
|
+
* The plan's `buildCommand` is declarative — actual execution goes through
|
|
11
|
+
* `runOpenNextBuild()` which handles binary resolution, timeouts, and cleanup.
|
|
12
|
+
*/
|
|
13
|
+
import { basename } from "path";
|
|
14
|
+
import { success } from "@fjall/generator";
|
|
15
|
+
import { logger } from "@fjall/util/logger";
|
|
16
|
+
import { OPENNEXT_DEPLOY_ORDER, OPENNEXT_DESTROY_ORDER } from "../../types/operations.js";
|
|
17
|
+
import { readInfrastructureContent } from "../../types/patternDetection.js";
|
|
18
|
+
import { runOpenNextBuild, BUILD_TIMEOUT_MS, IMPORT_MAP_TIMEOUT_MS } from "../openNextBuild.js";
|
|
19
|
+
/** Resource flags for all OpenNext apps (hasDatabase is dynamic) */
|
|
20
|
+
function openNextResources(hasDatabase) {
|
|
21
|
+
return {
|
|
22
|
+
hasNetwork: true,
|
|
23
|
+
hasCompute: true,
|
|
24
|
+
hasDatabase,
|
|
25
|
+
hasStorage: true,
|
|
26
|
+
hasMessaging: true,
|
|
27
|
+
hasCdn: true
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* OpenNext FrameworkBuilder for Next.js and Payload applications.
|
|
32
|
+
*
|
|
33
|
+
* Priority 10 — checked before Docker (priority 50) since OpenNext is more
|
|
34
|
+
* specific. Apps matching an OpenNext pattern use Lambda-based deployment
|
|
35
|
+
* with S3, DynamoDB, SQS, and CloudFront stacks.
|
|
36
|
+
*/
|
|
37
|
+
export const openNextBuilder = {
|
|
38
|
+
name: "opennext",
|
|
39
|
+
priority: 10,
|
|
40
|
+
detect(context) {
|
|
41
|
+
const notDetected = {
|
|
42
|
+
detected: false,
|
|
43
|
+
pattern: null,
|
|
44
|
+
reason: "No OpenNext pattern found",
|
|
45
|
+
resources: openNextResources(false),
|
|
46
|
+
hasDatabase: false,
|
|
47
|
+
hasDockerfile: false
|
|
48
|
+
};
|
|
49
|
+
const content = readInfrastructureContent(context.appPath);
|
|
50
|
+
if (!content) {
|
|
51
|
+
return {
|
|
52
|
+
...notDetected,
|
|
53
|
+
reason: "No infrastructure.ts found"
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
if (!content.includes("PatternFactory")) {
|
|
57
|
+
return {
|
|
58
|
+
...notDetected,
|
|
59
|
+
reason: "No PatternFactory reference in infrastructure.ts"
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
if (content.includes('type: "payload"')) {
|
|
63
|
+
return {
|
|
64
|
+
detected: true,
|
|
65
|
+
pattern: "payload",
|
|
66
|
+
reason: 'PatternFactory with type: "payload" detected',
|
|
67
|
+
resources: openNextResources(true),
|
|
68
|
+
hasDatabase: true,
|
|
69
|
+
hasDockerfile: false
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
if (content.includes('type: "nextjs"')) {
|
|
73
|
+
// Next.js database detection is dynamic — check for explicit database usage
|
|
74
|
+
const hasDatabase = content.includes("DatabaseFactory.build(") ||
|
|
75
|
+
content.includes("database:");
|
|
76
|
+
return {
|
|
77
|
+
detected: true,
|
|
78
|
+
pattern: "nextjs",
|
|
79
|
+
reason: 'PatternFactory with type: "nextjs" detected',
|
|
80
|
+
resources: openNextResources(hasDatabase),
|
|
81
|
+
hasDatabase,
|
|
82
|
+
hasDockerfile: false
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
...notDetected,
|
|
87
|
+
reason: "PatternFactory found but no recognised pattern type"
|
|
88
|
+
};
|
|
89
|
+
},
|
|
90
|
+
plan(_context, detection) {
|
|
91
|
+
const preBuildCommands = detection.pattern === "payload"
|
|
92
|
+
? [
|
|
93
|
+
{
|
|
94
|
+
name: "payload-import-map",
|
|
95
|
+
binary: "npx",
|
|
96
|
+
args: ["payload", "generate:importmap"],
|
|
97
|
+
timeoutMs: IMPORT_MAP_TIMEOUT_MS
|
|
98
|
+
}
|
|
99
|
+
]
|
|
100
|
+
: [];
|
|
101
|
+
return {
|
|
102
|
+
builderName: "opennext",
|
|
103
|
+
deployOrder: OPENNEXT_DEPLOY_ORDER,
|
|
104
|
+
destroyOrder: OPENNEXT_DESTROY_ORDER,
|
|
105
|
+
parallelDestroy: true,
|
|
106
|
+
preBuildCommands,
|
|
107
|
+
buildCommand: {
|
|
108
|
+
name: "open-next-build",
|
|
109
|
+
binary: "open-next",
|
|
110
|
+
args: ["build"],
|
|
111
|
+
timeoutMs: BUILD_TIMEOUT_MS
|
|
112
|
+
},
|
|
113
|
+
requiresDockerBuild: false,
|
|
114
|
+
resources: detection.resources
|
|
115
|
+
};
|
|
116
|
+
},
|
|
117
|
+
async build(appPath, plan, callbacks, options) {
|
|
118
|
+
if (options?.skipBuild || options?.infraOnly) {
|
|
119
|
+
logger.debug("openNextBuilder", "Build skipped", {
|
|
120
|
+
skipBuild: options.skipBuild,
|
|
121
|
+
infraOnly: options.infraOnly
|
|
122
|
+
});
|
|
123
|
+
return success(undefined);
|
|
124
|
+
}
|
|
125
|
+
// Delegate to existing runOpenNextBuild which handles binary resolution,
|
|
126
|
+
// import map generation, timeouts, stream cleanup, and artefact validation.
|
|
127
|
+
// We build an ApplicationOperation and map BuildCallbacks to DeployCallbacks.
|
|
128
|
+
const operation = {
|
|
129
|
+
kind: "application",
|
|
130
|
+
appName: basename(appPath) || "app",
|
|
131
|
+
path: appPath
|
|
132
|
+
};
|
|
133
|
+
// Determine pattern from the plan's pre-build commands
|
|
134
|
+
const isPayload = plan.preBuildCommands.some((cmd) => cmd.name === "payload-import-map");
|
|
135
|
+
const pattern = isPayload ? "payload" : "nextjs";
|
|
136
|
+
const result = await runOpenNextBuild(operation, pattern, {
|
|
137
|
+
onOpenNextBuildStart: () => callbacks.onBuildStart?.("opennext"),
|
|
138
|
+
onOpenNextProgress: (message) => callbacks.onBuildProgress?.("opennext", message),
|
|
139
|
+
onOpenNextBuildComplete: () => callbacks.onBuildComplete?.("opennext"),
|
|
140
|
+
onOpenNextBuildError: (error) => callbacks.onBuildError?.("opennext", error)
|
|
141
|
+
});
|
|
142
|
+
return result;
|
|
143
|
+
}
|
|
144
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Multi-region destroy helpers for organisation cascade destruction.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors the deployCascadeAccount() pattern from cascadeHelpers.ts but
|
|
5
|
+
* for destroy operations. No bootstrap step (unlike deploy).
|
|
6
|
+
*/
|
|
7
|
+
import type { DestroyParams } from "../types/params.js";
|
|
8
|
+
import type { DeployCallbacks } from "../types/callbacks.js";
|
|
9
|
+
import type { OrganisationOperation } from "../types/operations.js";
|
|
10
|
+
import type { DeployServices } from "./serviceFactory.js";
|
|
11
|
+
export interface CascadeDestroyAccountResult {
|
|
12
|
+
accountName: string;
|
|
13
|
+
accountId: string;
|
|
14
|
+
region: string;
|
|
15
|
+
success: boolean;
|
|
16
|
+
duration: number;
|
|
17
|
+
error?: string;
|
|
18
|
+
skipped?: boolean;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Destroy a single cascade account (platform or member) in a specific region.
|
|
22
|
+
*
|
|
23
|
+
* Flow: assume role -> synth -> CDK destroy -> failed-state cleanup if needed.
|
|
24
|
+
* No bootstrap step (unlike deploy).
|
|
25
|
+
*/
|
|
26
|
+
export declare function destroyCascadeAccount(params: DestroyParams, services: DeployServices, operation: OrganisationOperation, account: {
|
|
27
|
+
id: string;
|
|
28
|
+
name: string;
|
|
29
|
+
environment: string;
|
|
30
|
+
}, deployType: "platform" | "account", region: string, callbacks: DeployCallbacks): Promise<CascadeDestroyAccountResult>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{logger as S}from"@fjall/util/logger";import{maskSensitiveOutput as c,getErrorMessage as A}from"@fjall/util";import{stubCallerIdentity as P}from"../types/deployment/index.js";import{CloudFormationClient as $,DescribeStacksCommand as R}from"@aws-sdk/client-cloudformation";import{NodeHttpHandler as O}from"@smithy/node-http-handler";import{ORGANISATION_TYPES as h,getOrganisationStackName as _}from"../types/operations.js";import{CdkContextBuilder as k}from"../services/supporting/CdkContextBuilder.js";import{buildParamsContext as F,assumeCascadeRole as x,forwardOutput as I}from"./contextHelpers.js";import{cleanupFailedStack as L}from"./stackCleanup.js";import{STACK_NOT_FOUND_PATTERN as K,STACK_FAILED_STATE_PATTERN as M}from"../types/constants.js";async function V(n,u,i,t,m,e,r){const o=Date.now(),a=`${t.name} (${e})`;r.onCascadeAccountStart?.(a,t.id,e,m);const f=await x(u.awsProvider,t.id,e,`fjall-cascade-destroy-${t.name}`);if(!f.success)return r.onCascadeAccountComplete?.(a,!1,c(f.error.message),e),{accountName:t.name,accountId:t.id,region:e,success:!1,duration:Date.now()-o,error:`AssumeRole failed: ${c(f.error.message)}`,skipped:!0};const{provider:v,credentials:l}=f.data,w=k.buildDeploymentContext({deployType:m,target:i.target,path:i.path,region:e,accountName:t.name,callerIdentity:P(t.id),...F({orgConfig:n.orgConfig,identity:n.identity})},{verbose:n.options?.verbose},n.orgConfig);r.onCascadeAccountPhaseChange?.(a,"synth",e);const y=await u.cdkService.runCdkSynth(w,I(r));if(!y.success){const s=c(`Synth failed: ${y.error}`);return r.onCascadeAccountComplete?.(a,!1,s,e),{accountName:t.name,accountId:t.id,region:e,success:!1,duration:Date.now()-o,error:s}}r.onCascadeAccountPhaseChange?.(a,"destroy",e);const d=_(m==="platform"?h.PLATFORM:h.ACCOUNT),D=await u.cdkService.runCdkDestroy(w,d,I(r),s=>r.onCascadeAccountResourceProgress?.(a,s,e),v,!0,l);if(!D.success){const s=D.error;if(s.includes(M)){S.warn("cascadeDestroy",`CDK destroy failed on ${d} in failed state, retrying via CloudFormation API`,{region:e,account:t.name});try{await L(d,e,l,void 0,r)}catch(C){const E=`cleanupFailedStack threw for ${d}: ${A(C)}`;S.warn("cascadeDestroy",E),r.onLog?.(E,"warn")}const p=await H(d,e,l);if(p.deleted)return r.onCascadeAccountComplete?.(a,!0,void 0,e),{accountName:t.name,accountId:t.id,region:e,success:!0,duration:Date.now()-o};if(p.error){const C=c(p.error);return r.onCascadeAccountComplete?.(a,!1,C,e),{accountName:t.name,accountId:t.id,region:e,success:!1,duration:Date.now()-o,error:C}}const T=c(`Stack ${d} cleanup attempted but stack still exists in ${e}`);return r.onCascadeAccountComplete?.(a,!1,T,e),{accountName:t.name,accountId:t.id,region:e,success:!1,duration:Date.now()-o,error:T}}const N=c(s);return r.onCascadeAccountComplete?.(a,!1,N,e),{accountName:t.name,accountId:t.id,region:e,success:!1,duration:Date.now()-o,error:N}}return r.onCascadeAccountComplete?.(a,!0,void 0,e),{accountName:t.name,accountId:t.id,region:e,success:!0,duration:Date.now()-o}}async function H(n,u,i){try{const e=(await new $({region:u,credentials:i,requestHandler:new O({requestTimeout:15e3})}).send(new R({StackName:n}))).Stacks?.[0]?.StackStatus;return!e||e==="DELETE_COMPLETE"?{deleted:!0}:{deleted:!1,error:`Stack still in ${e} after cleanup attempt`}}catch(t){return t instanceof Error&&t.message?.includes(K)?{deleted:!0}:(S.debug("cascadeDestroy","Stack verification failed",{error:A(t)}),{deleted:!1,error:`Stack verification failed: ${A(t)}`})}}export{V as destroyCascadeAccount};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { type Result } from "@fjall/generator";
|
|
2
|
+
import type { DeployParams } from "../types/params.js";
|
|
3
|
+
import type { DeployCallbacks } from "../types/callbacks.js";
|
|
4
|
+
import type { OrganisationOperation } from "../types/operations.js";
|
|
5
|
+
import type { DeployServices } from "./serviceFactory.js";
|
|
6
|
+
import type { DomainDeployProvider } from "./domainInterface.js";
|
|
7
|
+
import type { ProviderAccount } from "@fjall/util/config";
|
|
8
|
+
/**
|
|
9
|
+
* Partition provider accounts into platform and member accounts.
|
|
10
|
+
* Used by both deploy and destroy orchestration.
|
|
11
|
+
*/
|
|
12
|
+
export declare function partitionAccounts(providerAccounts: ProviderAccount[]): {
|
|
13
|
+
platformAccount: ProviderAccount | undefined;
|
|
14
|
+
memberAccounts: ProviderAccount[];
|
|
15
|
+
};
|
|
16
|
+
export { buildCascadeRoleArn } from "./contextHelpers.js";
|
|
17
|
+
/**
|
|
18
|
+
* Deploy a single cascade account (platform or member).
|
|
19
|
+
* Assumes the target account's role, sets env credentials, and deploys.
|
|
20
|
+
*/
|
|
21
|
+
export interface CascadeAccountResult {
|
|
22
|
+
outputs?: Record<string, string>;
|
|
23
|
+
}
|
|
24
|
+
export declare function deployCascadeAccount(params: DeployParams, services: DeployServices, operation: OrganisationOperation, account: {
|
|
25
|
+
id: string;
|
|
26
|
+
name: string;
|
|
27
|
+
environment: string;
|
|
28
|
+
}, deployType: "platform" | "account", callbacks: DeployCallbacks, ipamPoolId?: string): Promise<Result<CascadeAccountResult>>;
|
|
29
|
+
/**
|
|
30
|
+
* Read Platform stack outputs to extract IPAM pool IDs for member accounts.
|
|
31
|
+
* Output keys follow the pattern `IpamPoolId{12-digit-accountId}{regionSuffix}`.
|
|
32
|
+
* Returns a map keyed by `{accountId}-{regionSuffix}` → pool ID.
|
|
33
|
+
* Non-fatal: returns empty map on any error.
|
|
34
|
+
*/
|
|
35
|
+
export declare function readPlatformIpamPoolIds(services: DeployServices, platformAccount: {
|
|
36
|
+
id: string;
|
|
37
|
+
name: string;
|
|
38
|
+
}, callbacks: DeployCallbacks): Promise<Map<string, string>>;
|
|
39
|
+
/**
|
|
40
|
+
* Deploy configured domains: apex domains sequentially, then delegated
|
|
41
|
+
* domains in parallel. Delegates to the caller-provided DomainDeployProvider.
|
|
42
|
+
*/
|
|
43
|
+
export declare function deployDomains(provider: DomainDeployProvider, callbacks: DeployCallbacks): Promise<{
|
|
44
|
+
domainsDeployed: number;
|
|
45
|
+
errors: string[];
|
|
46
|
+
}>;
|