@fjall/deploy-core 2.29.0 → 2.30.3
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/dist/.minified +1 -1
- package/dist/src/index.d.ts +4 -2
- package/dist/src/index.js +1 -1
- package/dist/src/orchestration/application/applicationDeploy.js +1 -1
- package/dist/src/orchestration/application/applicationDeployHelpers.d.ts +18 -0
- package/dist/src/orchestration/application/applicationDeployHelpers.js +3 -3
- package/dist/src/orchestration/application/artefactCollection.d.ts +8 -1
- package/dist/src/orchestration/application/artefactCollection.js +1 -1
- package/dist/src/orchestration/application/codeOnlyDeploy.d.ts +32 -1
- package/dist/src/orchestration/application/codeOnlyDeploy.js +1 -1
- package/dist/src/orchestration/application/dockerBuildHelper.d.ts +1 -0
- package/dist/src/orchestration/application/dockerBuildHelper.js +1 -1
- package/dist/src/orchestration/application/lambdaCodeOnlyRollout.d.ts +58 -0
- package/dist/src/orchestration/application/lambdaCodeOnlyRollout.js +1 -0
- package/dist/src/orchestration/application/openNextBuild.d.ts +1 -1
- package/dist/src/orchestration/application/openNextBuild.js +3 -3
- package/dist/src/orchestration/builders/frameworkRegistry.js +1 -1
- package/dist/src/orchestration/builders/index.d.ts +1 -0
- package/dist/src/orchestration/builders/index.js +1 -1
- package/dist/src/orchestration/builders/openNextBuilder.js +1 -1
- package/dist/src/orchestration/builders/staticSiteBuilder.d.ts +27 -0
- package/dist/src/orchestration/builders/staticSiteBuilder.js +2 -0
- package/dist/src/orchestration/serviceFactory.d.ts +2 -0
- package/dist/src/orchestration/serviceFactory.js +1 -1
- package/dist/src/orchestration/spawnHelpers.d.ts +9 -0
- package/dist/src/orchestration/spawnHelpers.js +1 -1
- package/dist/src/services/infrastructure/LambdaService.d.ts +45 -0
- package/dist/src/services/infrastructure/LambdaService.js +1 -0
- package/dist/src/types/deployEvent.d.ts +10 -3
- package/dist/src/types/deployEvent.js +1 -1
- package/dist/src/types/detection/patternTypes.d.ts +9 -4
- package/dist/src/types/detection/patternTypes.js +1 -1
- package/dist/src/types/frameworkBuilder.d.ts +14 -0
- package/dist/src/types/index.d.ts +36 -2
- package/dist/src/types/index.js +1 -1
- package/dist/src/types/operations.d.ts +2 -1
- package/package.json +6 -4
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{createRequire as
|
|
2
|
-
${m}`))}return c.debug("openNextBuild","Payload import map generated",{appPath:s}),n.onOpenNextProgress?.(
|
|
3
|
-
${
|
|
1
|
+
import{createRequire as $}from"module";import{existsSync as O,statSync as v,rmSync as S}from"fs";import{join as f}from"path";import{success as l,failure as o}from"@fjall/generator";import{filterDangerousEnvVars as E,maskSensitiveOutput as u,parseShellArgs as b}from"@fjall/util";import{logger as c}from"@fjall/util/logger";import{isOpenNextPattern as T}from"../../types/detection/patternDetection.js";import{spawnWithTimeout as P}from"../spawnHelpers.js";const x="@opennextjs/aws",w=6e5,M=3e4;function D(s){const n=$(f(s,"package.json"));let e;try{e=n.resolve.paths(x)}catch(r){return o(new Error(`Cannot determine module search paths for ${x}. Ensure it is installed in your project. (${r instanceof Error?r.message:String(r)})`))}if(!e||e.length===0)return o(new Error(`Cannot determine module search paths for ${x}. Ensure it is installed in your project.`));for(const r of e){const p=f(r,"@opennextjs","aws");try{if(v(p).isDirectory()){const t=f(r,".bin","open-next");if(!O(t)){c.debug("openNextBuild","Package found but binary missing",{nodeModulesPath:r,binPath:t});continue}return c.debug("openNextBuild","Resolved OpenNext binary",{binPath:t}),l(t)}}catch(i){c.debug("openNextBuild","Package not at location",{nodeModulesPath:r,error:String(i)})}}return o(new Error(`Cannot find ${x} package. Ensure it is installed in your project: npm install ${x}`))}function N(s){const n=f(s,".open-next");if(O(n))try{S(n,{recursive:!0,force:!0}),c.debug("openNextBuild","Cleaned up stale .open-next directory",{path:n})}catch(e){c.debug("openNextBuild","Failed to clean up .open-next",{error:String(e)})}}function B(s,n,e,r){switch(s.type){case"timeout":return e?.(),r?.(n.timeoutMsg),o(new Error(n.timeoutMsg));case"aborted":return e?.(),r?.(n.abortedMsg),o(new Error(n.abortedMsg));case"enoent":return e?.(),r?.(n.enoentMsg),o(new Error(n.enoentMsg));case"spawn_error":{const p=`${n.spawnErrorPrefix}: ${s.error.message}`;return e?.(),r?.(p),o(new Error(p))}default:return}}async function j(s,n,e){n.onOpenNextProgress?.(u("Generating Payload import map..."));const[r,...p]=b("npx payload generate:importmap"),i=E(globalThis.process.env),t=await P({command:r,args:p,cwd:s,env:{...i,FORCE_COLOR:"0"},timeout:M,...e!==void 0&&{abortSignal:e},onStdoutData:m=>{n.onOpenNextProgress?.(u(m.trim()))}}),g=B(t,{timeoutMsg:`Payload import map generation timed out after ${M/1e3} seconds`,abortedMsg:"Payload import map generation cancelled",enoentMsg:"Payload CLI not found. Ensure payload is installed: npm install payload",spawnErrorPrefix:"Failed to generate Payload import map"});if(g)return g;if(t.type!=="success")return o(new Error("Unexpected spawn result"));if(t.code!==0){const m=u(t.stderr||t.stdout);return o(new Error(`Payload import map generation failed (exit code ${t.code}):
|
|
2
|
+
${m}`))}return c.debug("openNextBuild","Payload import map generated",{appPath:s}),n.onOpenNextProgress?.(u("Payload import map generated")),l(void 0)}async function q(s,n,e,r,p){if(!T(n))return l(void 0);if(r?.skipBuild||r?.infraOnly)return c.debug("openNextBuild","Build skipped",{skipBuild:r?.skipBuild,infraOnly:r?.infraOnly}),e.onLog?.(r?.infraOnly?"Infrastructure-only mode \u2014 skipping OpenNext build":"Build skipped (--skip-build)","info"),l(void 0);const i=s.path;if(n==="payload"){const d=await j(i,e,p);if(!d.success)return e.onOpenNextBuildError?.(u(d.error.message)),N(i),o(d.error)}const t=D(i);if(!t.success)return e.onOpenNextBuildError?.(u(t.error.message)),o(t.error);const g=t.data;e.onOpenNextBuildStart?.(),e.onOpenNextProgress?.(u("Starting OpenNext build..."));const m=E(globalThis.process.env),h=f(i,"node_modules"),a=await P({command:g,args:["build"],cwd:i,env:{...m,FORCE_COLOR:"0",NODE_PATH:h,npm_config_loglevel:"error",PNPM_HOME:m.PNPM_HOME||""},timeout:w,...p!==void 0&&{abortSignal:p},onStdoutData:d=>{e.onOpenNextProgress?.(u(d.trim()))},onStderrData:d=>{e.onOpenNextProgress?.(u(d.trim()))}}),y=B(a,{timeoutMsg:`OpenNext build timed out after ${w/1e3} seconds`,abortedMsg:"OpenNext build cancelled",enoentMsg:"OpenNext binary not found. Ensure Node.js is installed and in PATH.",spawnErrorPrefix:"Failed to spawn OpenNext build"},()=>N(i),d=>e.onOpenNextBuildError?.(d));if(y)return y;if(a.type!=="success")return o(new Error("Unexpected spawn result"));if(a.code!==0){N(i);const d=u(a.stderr||a.stdout);return e.onOpenNextBuildError?.(`OpenNext build failed (exit code ${a.code})`),o(new Error(`OpenNext build failed (exit code ${a.code}):
|
|
3
|
+
${d}`))}const _=f(i,".open-next");return O(_)?(e.onOpenNextBuildComplete?.(),e.onOpenNextProgress?.(u("OpenNext build completed successfully")),l(void 0)):(e.onOpenNextBuildError?.("OpenNext build completed but .open-next directory not found"),o(new Error("OpenNext build completed but .open-next directory not found")))}export{w as BUILD_TIMEOUT_MS,M as IMPORT_MAP_TIMEOUT_MS,q as runOpenNextBuild};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{openNextBuilder as
|
|
1
|
+
import{openNextBuilder as d}from"./openNextBuilder.js";import{staticSiteBuilder as n}from"./staticSiteBuilder.js";import{dockerBuilder as c}from"./dockerBuilder.js";class o{builders;constructor(e){this.builders=[...e].sort((r,t)=>r.priority-t.priority)}resolve(e,r){if(r){const t=this.builders.find(u=>u.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 o([d,n,c])}static create(e){return new o(e)}}export{o as FrameworkRegistry};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { dockerBuilder } from "./dockerBuilder.js";
|
|
2
2
|
export { openNextBuilder } from "./openNextBuilder.js";
|
|
3
|
+
export { staticSiteBuilder } from "./staticSiteBuilder.js";
|
|
3
4
|
export { FrameworkRegistry } from "./frameworkRegistry.js";
|
|
4
5
|
export type { ResolvedBuilder } from "./frameworkRegistry.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{dockerBuilder as o}from"./dockerBuilder.js";import{openNextBuilder as
|
|
1
|
+
import{dockerBuilder as o}from"./dockerBuilder.js";import{openNextBuilder as i}from"./openNextBuilder.js";import{staticSiteBuilder as p}from"./staticSiteBuilder.js";import{FrameworkRegistry as d}from"./frameworkRegistry.js";export{d as FrameworkRegistry,o as dockerBuilder,i as openNextBuilder,p as staticSiteBuilder};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{basename as
|
|
1
|
+
import{basename as d}from"path";import{success as i,parseInfrastructure as l,isOpenNextPatternType as c}from"@fjall/generator";import{logger as f}from"@fjall/util/logger";import{OPENNEXT_DEPLOY_ORDER as m,OPENNEXT_DESTROY_ORDER as y}from"../../types/operations.js";import{readInfrastructureContent as x}from"../../types/detection/patternDetection.js";import{runOpenNextBuild as N,BUILD_TIMEOUT_MS as O,IMPORT_MAP_TIMEOUT_MS as B}from"../application/openNextBuild.js";function p(r){return{hasNetwork:!0,hasCompute:!0,hasDatabase:r,hasStorage:!0,hasMessaging:!0,hasCdn:!0}}const M={name:"opennext",priority:10,detect(r){const t={detected:!1,pattern:null,reason:"No OpenNext pattern found",resources:p(!1),hasDatabase:!1,hasDockerfile:!1},e=x(r.appPath);if(e===null||e==="")return{...t,reason:"No infrastructure.ts found"};const a=l(e).patternResources.find(o=>c(o.type));if(a===void 0)return{...t,reason:'No PatternFactory with type: "payload" or "nextjs" in infrastructure.ts'};if(a.type==="payload")return{detected:!0,pattern:"payload",reason:'PatternFactory with type: "payload" detected',resources:p(!0),hasDatabase:!0,hasDockerfile:!1};if(a.type==="nextjs"){const o=a.config.database!==void 0;return{detected:!0,pattern:"nextjs",reason:'PatternFactory with type: "nextjs" detected',resources:p(o),hasDatabase:o,hasDockerfile:!1}}return{...t,reason:"PatternFactory found but no recognised pattern type"}},plan(r,t){const e=t.pattern==="payload"?[{name:"payload-import-map",binary:"npx",args:["payload","generate:importmap"],timeoutMs:B}]:[];return{builderName:"opennext",deployOrder:m,destroyOrder:y,parallelDestroy:!0,preBuildCommands:e,buildCommand:{name:"open-next-build",binary:"open-next",args:["build"],timeoutMs:O},requiresDockerBuild:!1,resources:t.resources}},async build(r,t,e,n){if(n?.skipBuild||n?.infraOnly)return f.debug("openNextBuilder","Build skipped",{skipBuild:n.skipBuild,infraOnly:n.infraOnly}),i(void 0);const a={kind:"application",appName:d(r)||"app",path:r},u=t.preBuildCommands.some(s=>s.name==="payload-import-map")?"payload":"nextjs";return await N(a,u,{onOpenNextBuildStart:()=>e.onBuildStart?.("opennext"),onOpenNextProgress:s=>e.onBuildProgress?.("opennext",s),onOpenNextBuildComplete:()=>e.onBuildComplete?.("opennext"),onOpenNextBuildError:s=>e.onBuildError?.("opennext",s)},void 0,n?.abortSignal)}};export{M as openNextBuilder};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* StaticSiteBuilder — FrameworkBuilder implementation for static-site apps.
|
|
3
|
+
*
|
|
4
|
+
* Detects a `type: "staticsite"` PatternFactory call in infrastructure.ts,
|
|
5
|
+
* produces a single-stack (Cdn) build plan, and runs the app's own build
|
|
6
|
+
* command to produce the static artefacts that CDK's BucketDeployment then
|
|
7
|
+
* uploads to S3.
|
|
8
|
+
*
|
|
9
|
+
* Priority 50 — strictly between OpenNext (10) and Docker (100). This is
|
|
10
|
+
* load-bearing: without it the Docker catch-all (priority 100) would claim
|
|
11
|
+
* the static site and emit a container deployment plan.
|
|
12
|
+
*
|
|
13
|
+
* Unlike OpenNext, the build command and its working directory are not
|
|
14
|
+
* hardcoded — they are the app's own, read out of infrastructure.ts with the
|
|
15
|
+
* generator's AST parser (`@fjall/generator` is already a dependency, and its
|
|
16
|
+
* barrel already pulls the parser in, so this costs nothing over a regex).
|
|
17
|
+
*/
|
|
18
|
+
import type { FrameworkBuilder } from "../../types/frameworkBuilder.js";
|
|
19
|
+
/** Default static-site build timeout: 10 minutes (mirrors the OpenNext budget) */
|
|
20
|
+
export declare const STATIC_BUILD_TIMEOUT_MS = 600000;
|
|
21
|
+
/**
|
|
22
|
+
* Static-site FrameworkBuilder.
|
|
23
|
+
*
|
|
24
|
+
* Priority 50 — checked after OpenNext (more specific) and before Docker
|
|
25
|
+
* (the fallback catch-all).
|
|
26
|
+
*/
|
|
27
|
+
export declare const staticSiteBuilder: FrameworkBuilder;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{existsSync as y}from"fs";import{resolve as f}from"path";import{success as m,failure as u,parseInfrastructure as p}from"@fjall/generator";import{filterDangerousEnvVars as b,maskSensitiveOutput as d,parseShellArgs as B}from"@fjall/util";import{logger as D}from"@fjall/util/logger";import{getApplicationDeployOrder as E,getApplicationDestroyOrder as h}from"../../types/operations.js";import{readInfrastructureContent as g}from"../../types/detection/patternDetection.js";import{spawnWithTimeout as w}from"../spawnHelpers.js";const O=6e5,S={hasNetwork:!1,hasCompute:!1,hasDatabase:!1,hasStorage:!1,hasMessaging:!1,hasCdn:!0};function C(o){return p(o).patternResources.some(r=>r.type==="staticsite")}function P(o){const r=g(o);if(r===null||r==="")return;const t=p(r).patternResources.find(n=>n.type==="staticsite");if(t===void 0||t.type!=="staticsite")return;const{source:i,build:s}=t.config,a=s?.command,c=s?.outputDir;if(!(i===void 0||i===""||a===void 0||a===""||c===void 0||c===""))return{source:i,command:a,outputDir:c}}const R={name:"staticsite",priority:50,detect(o){const r={detected:!1,pattern:null,reason:"No static-site pattern found",resources:S,hasDatabase:!1,hasDockerfile:!1},t=g(o.appPath);return t===null||t===""?{...r,reason:"No infrastructure.ts found"}:C(t)?{detected:!0,pattern:"staticsite",reason:'PatternFactory with type: "staticsite" detected',resources:S,hasDatabase:!1,hasDockerfile:!1}:{...r,reason:'No PatternFactory with type: "staticsite"'}},plan(o,r){const t=P(o.appPath);let i=null;if(t!==void 0){const[s,...a]=B(t.command);s!==void 0&&(i={name:"static-site-build",binary:s,args:a,timeoutMs:O,cwd:t.source})}return{builderName:"staticsite",deployOrder:E({resources:r.resources}),destroyOrder:h({resources:r.resources}),parallelDestroy:!1,preBuildCommands:[],buildCommand:i,requiresDockerBuild:!1,artefactDir:t?.outputDir,resources:r.resources}},async build(o,r,t,i){if(i?.skipBuild||i?.infraOnly)return D.debug("staticSiteBuilder","Build skipped",{skipBuild:i.skipBuild,infraOnly:i.infraOnly}),m(void 0);const{buildCommand:s}=r;if(s===null){const e='Static-site build command could not be read from infrastructure.ts. The pattern needs an inline build block \u2014 build: { command: "npm run build", outputDir: "out" } \u2014 with literal strings, not variables or expressions.';return t.onBuildError?.("staticsite",e),u(new Error(e))}const a=f(o,s.cwd??"."),c=b(globalThis.process.env);t.onBuildStart?.("staticsite"),t.onBuildProgress?.("staticsite",d("Starting static-site build..."));const n=await w({command:s.binary,args:[...s.args],cwd:a,env:{...c,FORCE_COLOR:"0"},timeout:s.timeoutMs,...i?.abortSignal!==void 0&&{abortSignal:i.abortSignal},onStdoutData:e=>t.onBuildProgress?.("staticsite",d(e.trim())),onStderrData:e=>t.onBuildProgress?.("staticsite",d(e.trim()))});if(n.type==="timeout"){const e=`Static-site build timed out after ${s.timeoutMs/1e3} seconds`;return t.onBuildError?.("staticsite",e),u(new Error(e))}if(n.type==="aborted"){const e="Static-site build cancelled";return t.onBuildError?.("staticsite",e),u(new Error(e))}if(n.type==="enoent"){const e=`Static-site build command not found: ${s.binary}. Ensure it is installed and in PATH.`;return t.onBuildError?.("staticsite",e),u(new Error(e))}if(n.type==="spawn_error"){const e=d(`Failed to spawn static-site build: ${n.error.message}`);return t.onBuildError?.("staticsite",e),u(new Error(e))}if(n.code!==0){const e=d(n.stderr||n.stdout);return t.onBuildError?.("staticsite",`Static-site build failed (exit code ${n.code})`),u(new Error(`Static-site build failed (exit code ${n.code}):
|
|
2
|
+
${e}`))}if(r.artefactDir!==void 0){const e=f(a,r.artefactDir);if(!y(e)){const l=`Static-site build completed but output directory '${r.artefactDir}' was not found`;return t.onBuildError?.("staticsite",l),u(new Error(l))}}return t.onBuildComplete?.("staticsite"),t.onBuildProgress?.("staticsite",d("Static-site build completed successfully")),m(void 0)}};export{O as STATIC_BUILD_TIMEOUT_MS,R as staticSiteBuilder};
|
|
@@ -3,6 +3,7 @@ import { CdkService } from "../services/infrastructure/CdkService.js";
|
|
|
3
3
|
import { CloudFormationService } from "../services/infrastructure/CloudFormationService.js";
|
|
4
4
|
import { EcsService } from "../services/infrastructure/EcsService.js";
|
|
5
5
|
import { EcsServiceResolver } from "../services/infrastructure/EcsServiceResolver.js";
|
|
6
|
+
import { LambdaService } from "../services/infrastructure/LambdaService.js";
|
|
6
7
|
import { EcrImageInspectorService } from "../services/infrastructure/EcrImageInspectorService.js";
|
|
7
8
|
import { ApplicationStackService } from "../services/application/ApplicationStackService.js";
|
|
8
9
|
import { TemplateHashService } from "../services/supporting/TemplateHashService.js";
|
|
@@ -14,6 +15,7 @@ export interface DeployServices {
|
|
|
14
15
|
cfnService: CloudFormationService;
|
|
15
16
|
ecsService: EcsService;
|
|
16
17
|
ecsResolver: EcsServiceResolver;
|
|
18
|
+
lambdaService: LambdaService;
|
|
17
19
|
ecrImageInspector: EcrImageInspectorService;
|
|
18
20
|
stackService: ApplicationStackService;
|
|
19
21
|
hashService: TemplateHashService;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{SimpleAwsProvider as
|
|
1
|
+
import{SimpleAwsProvider as v}from"../aws/SimpleAwsProvider.js";import{CdkService as f}from"../services/infrastructure/CdkService.js";import{CdkArgumentBuilder as p}from"../services/infrastructure/CdkArgumentBuilder.js";import{CdkProcessManager as w}from"../services/infrastructure/CdkProcessManager.js";import{CloudFormationService as g}from"../services/infrastructure/CloudFormationService.js";import{EcsService as u}from"../services/infrastructure/EcsService.js";import{EcsServiceResolver as b}from"../services/infrastructure/EcsServiceResolver.js";import{LambdaService as k}from"../services/infrastructure/LambdaService.js";import{EcrImageInspectorService as y}from"../services/infrastructure/EcrImageInspectorService.js";import{ApplicationStackService as A}from"../services/application/ApplicationStackService.js";import{TemplateHashService as C}from"../services/supporting/TemplateHashService.js";import{FrameworkRegistry as F}from"./builders/frameworkRegistry.js";function j(e){const r=new v(e.awsCredentials,e.mintScopedBuildSecretSession);r.exportToEnv();const c=new p,i=new w(c,e.abortSignal),n=new f({processManager:i,...e.abortSignal!==void 0?{abortSignal:e.abortSignal}:{},...e.callbacks.onFailureAnalysis!==void 0?{onFailureAnalysis:e.callbacks.onFailureAnalysis}:{}}),o=new g(r),t=new u(r),s=new b(o),a=new k(r),l=new y(r),m=new A(n,o,r),S=new C,d=F.createDefault();return{awsProvider:r,cdkService:n,cfnService:o,ecsService:t,ecsResolver:s,lambdaService:a,ecrImageInspector:l,stackService:m,hashService:S,frameworkRegistry:d,...e.abortSignal!==void 0?{abortSignal:e.abortSignal}:{},dispose(){i.dispose()}}}export{j as createDeployServices};
|
|
@@ -18,6 +18,10 @@ export type SpawnResult = {
|
|
|
18
18
|
type: "timeout";
|
|
19
19
|
stdout: string;
|
|
20
20
|
stderr: string;
|
|
21
|
+
} | {
|
|
22
|
+
type: "aborted";
|
|
23
|
+
stdout: string;
|
|
24
|
+
stderr: string;
|
|
21
25
|
} | {
|
|
22
26
|
type: "enoent";
|
|
23
27
|
error: Error;
|
|
@@ -35,6 +39,10 @@ export declare function destroyProcessStreams(childProcess: ReturnType<typeof sp
|
|
|
35
39
|
export declare function isEnoentError(err: unknown): err is NodeJS.ErrnoException;
|
|
36
40
|
/**
|
|
37
41
|
* Spawn a child process with timeout handling and stream collection.
|
|
42
|
+
*
|
|
43
|
+
* `abortSignal` is the caller's cancellation signal (`DeployParams.abortSignal`
|
|
44
|
+
* — Ctrl-C, or `fjall deployments cancel`). Without it a cancelled deploy still
|
|
45
|
+
* waits out the full build timeout, because nothing else can reach the child.
|
|
38
46
|
*/
|
|
39
47
|
export declare function spawnWithTimeout(options: {
|
|
40
48
|
command: string;
|
|
@@ -42,6 +50,7 @@ export declare function spawnWithTimeout(options: {
|
|
|
42
50
|
cwd: string;
|
|
43
51
|
env: Record<string, string | undefined>;
|
|
44
52
|
timeout: number;
|
|
53
|
+
abortSignal?: AbortSignal;
|
|
45
54
|
onStdoutData?: (data: string) => void;
|
|
46
55
|
onStderrData?: (data: string) => void;
|
|
47
56
|
}): Promise<SpawnResult>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{spawn as
|
|
1
|
+
import{spawn as j}from"child_process";import{logger as l}from"@fjall/util/logger";function m(e){try{e.stdout?.destroy()}catch(s){l.debug("spawnHelpers","stdout destroy failed",{error:String(s)})}try{e.stderr?.destroy()}catch(s){l.debug("spawnHelpers","stderr destroy failed",{error:String(s)})}}function v(e){return e instanceof Error&&"code"in e&&e.code==="ENOENT"}function x(e){const{command:s,args:f,cwd:y,env:g,timeout:S,abortSignal:a,onStdoutData:b,onStderrData:E}=e;return new Promise(h=>{let c=!1;const r=t=>{c||(c=!0,h(t))};if(a?.aborted===!0){r({type:"aborted",stdout:"",stderr:""});return}const o=j(s,f,{cwd:y,shell:!1,stdio:["ignore","pipe","pipe"],env:g}),d=[],i=[];o.stdout?.on("data",t=>{const n=t.toString();d.push(n),b?.(n)}),o.stderr?.on("data",t=>{const n=t.toString();i.push(n),E?.(n)});const w=setTimeout(()=>{m(o),o.kill("SIGTERM"),u(),r({type:"timeout",stdout:d.join(""),stderr:i.join("")})},S),p=()=>{m(o),o.kill("SIGTERM"),u(),r({type:"aborted",stdout:d.join(""),stderr:i.join("")})},u=()=>{clearTimeout(w),a?.removeEventListener("abort",p)};a?.addEventListener("abort",p,{once:!0}),o.on("close",t=>{u(),r({type:"success",code:t??1,stdout:d.join(""),stderr:i.join("")})}),o.on("error",t=>{u(),v(t)?r({type:"enoent",error:t}):r({type:"spawn_error",error:t})})})}export{m as destroyProcessStreams,v as isEnoentError,x as spawnWithTimeout};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { AwsProvider } from "../../aws/AwsProvider.js";
|
|
2
|
+
import { type Result } from "@fjall/generator";
|
|
3
|
+
import { BaseServiceError } from "../../types/errors/ServiceError.js";
|
|
4
|
+
export declare class LambdaError extends BaseServiceError {
|
|
5
|
+
readonly functionName: string;
|
|
6
|
+
readonly operation: "publish_version" | "update_function_code";
|
|
7
|
+
constructor(message: string, functionName: string, operation: "publish_version" | "update_function_code", details?: unknown);
|
|
8
|
+
}
|
|
9
|
+
export interface PublishedLambdaVersion {
|
|
10
|
+
functionArn: string;
|
|
11
|
+
version: string;
|
|
12
|
+
}
|
|
13
|
+
export interface UpdatedLambdaFunctionCode {
|
|
14
|
+
functionArn: string;
|
|
15
|
+
version: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Lambda service using the AwsProvider interface. Constructor-injected
|
|
19
|
+
* provider matches the `EcsService`/`CloudFormationService` pattern.
|
|
20
|
+
*/
|
|
21
|
+
export declare class LambdaService {
|
|
22
|
+
private aws;
|
|
23
|
+
constructor(aws: AwsProvider);
|
|
24
|
+
private getClient;
|
|
25
|
+
/**
|
|
26
|
+
* Publish a new immutable version of a Lambda function pointing at
|
|
27
|
+
* whatever is currently deployed as `$LATEST`. Used right after a
|
|
28
|
+
* container-image Lambda's `cdk deploy` succeeds — CDK's `.currentVersion`
|
|
29
|
+
* can't be trusted to do this itself when the image reference is a
|
|
30
|
+
* `CfnParameter` (its logical-id hash is computed from synth-time template
|
|
31
|
+
* shape, not the parameter's deploy-time resolved value, so the hash
|
|
32
|
+
* doesn't change between deploys even though the underlying image does).
|
|
33
|
+
*/
|
|
34
|
+
publishVersion(functionName: string): Promise<Result<PublishedLambdaVersion, LambdaError>>;
|
|
35
|
+
/**
|
|
36
|
+
* Update a container-image Lambda function's code directly — the Lambda
|
|
37
|
+
* equivalent of ECS's `UpdateService`/`RegisterTaskDefinition` for a
|
|
38
|
+
* code-only deploy, bypassing CloudFormation entirely. Publishes a new
|
|
39
|
+
* version in the same call (`Publish: true`) since we own this API call
|
|
40
|
+
* directly here — unlike the full-deploy path, where CloudFormation
|
|
41
|
+
* performs the code update and `publishVersion` has to run as a separate
|
|
42
|
+
* step afterward.
|
|
43
|
+
*/
|
|
44
|
+
updateFunctionCode(functionName: string, imageUri: string): Promise<Result<UpdatedLambdaFunctionCode, LambdaError>>;
|
|
45
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{LambdaClient as h,PublishVersionCommand as $,UpdateFunctionCodeCommand as f}from"@aws-sdk/client-lambda";import{success as l,failure as a}from"@fjall/generator";import{BaseServiceError as g}from"../../types/errors/ServiceError.js";import{logger as d}from"@fjall/util/logger";import{maskSensitiveOutput as p}from"@fjall/util";import{getAwsErrorDetails as m}from"../../aws/utils/awsErrorHandler.js";class c extends g{functionName;operation;constructor(e,t,r,o){super(`LAMBDA_${r.toUpperCase()}_FAILED`,e,o,!1),this.functionName=t,this.operation=r}}class V{aws;constructor(e){this.aws=e}getClient(){return this.aws.getClient(h)}async publishVersion(e){try{const r=await this.getClient().send(new $({FunctionName:e}));return!r.FunctionArn||!r.Version?a(new c("PublishVersion returned no function ARN or version",e,"publish_version",r)):(d.debug("LambdaService",`Published version ${r.Version} for ${e}`),l({functionArn:r.FunctionArn,version:r.Version}))}catch(t){const{message:r,name:o,httpCode:n}=m(t),s=p(r);d.error("LambdaService",`PublishVersion failed for ${e}: ${o} - ${s}`,{functionName:e,httpCode:n,error:t});let i=`Failed to publish Lambda version for '${e}': ${s}`;return n&&(i+=` (HTTP ${n})`),a(new c(i,e,"publish_version",{error:t,httpCode:n,errorName:o}))}}async updateFunctionCode(e,t){try{const o=await this.getClient().send(new f({FunctionName:e,ImageUri:t,Publish:!0}));return!o.FunctionArn||!o.Version?a(new c("UpdateFunctionCode returned no function ARN or version",e,"update_function_code",o)):(d.debug("LambdaService",`Updated ${e} to ${t}, published version ${o.Version}`),l({functionArn:o.FunctionArn,version:o.Version}))}catch(r){const{message:o,name:n,httpCode:s}=m(r),i=p(o);d.error("LambdaService",`UpdateFunctionCode failed for ${e}: ${n} - ${i}`,{functionName:e,imageUri:t,httpCode:s,error:r});let u=`Failed to update Lambda function code for '${e}': ${i}`;return s&&(u+=` (HTTP ${s})`),a(new c(u,e,"update_function_code",{error:r,httpCode:s,errorName:n}))}}}export{c as LambdaError,V as LambdaService};
|
|
@@ -13,8 +13,12 @@
|
|
|
13
13
|
* `deploymentEventSchema.ts`, superseded in a later phase). They coexist during
|
|
14
14
|
* the migration; do not conflate them.
|
|
15
15
|
*
|
|
16
|
-
* Browser-safe:
|
|
17
|
-
* `@fjall/util/config`
|
|
16
|
+
* Browser-safe: imports only Zod, pure constant tuples, and the static const
|
|
17
|
+
* `TRAIL_LIFECYCLE_STATES` from `@fjall/util/config`. `config.js` DOES carry
|
|
18
|
+
* `import * as fs`/`import * as path`, but they are used only inside functions
|
|
19
|
+
* (never at module-eval), so importing this module accesses no Node builtin —
|
|
20
|
+
* see the eval-safety invariant in `./index.ts`. Keep the import to that static
|
|
21
|
+
* const; do not pull a config.js helper that touches fs/path into eval scope.
|
|
18
22
|
*/
|
|
19
23
|
import { z } from "zod";
|
|
20
24
|
/** The contract marker stamped on every event this build emits. */
|
|
@@ -64,7 +68,7 @@ export declare const DETECTION_PHASES: readonly ["detect", "synth", "hash", "val
|
|
|
64
68
|
/** started/completed — reused across the phase-boundary events in this contract. */
|
|
65
69
|
export declare const PHASE_STATUSES: readonly ["started", "completed"];
|
|
66
70
|
/** Build-pipeline kinds carried by the `build.*` events. */
|
|
67
|
-
export declare const BUILDERS: readonly ["docker", "buildpush", "opennext"];
|
|
71
|
+
export declare const BUILDERS: readonly ["docker", "buildpush", "opennext", "staticsite"];
|
|
68
72
|
/**
|
|
69
73
|
* Cascade per-target outcome. Mirrors the engine-side `CascadeOutcomeResult`
|
|
70
74
|
* (orchestration/organisation/cascadeSummary.ts); the wire ledger owns its own
|
|
@@ -314,6 +318,7 @@ export declare const DeployEventSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
314
318
|
progressKind: z.ZodLiteral<"build.started">;
|
|
315
319
|
builder: z.ZodEnum<{
|
|
316
320
|
docker: "docker";
|
|
321
|
+
staticsite: "staticsite";
|
|
317
322
|
buildpush: "buildpush";
|
|
318
323
|
opennext: "opennext";
|
|
319
324
|
}>;
|
|
@@ -331,6 +336,7 @@ export declare const DeployEventSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
331
336
|
progressKind: z.ZodLiteral<"build.progress">;
|
|
332
337
|
builder: z.ZodEnum<{
|
|
333
338
|
docker: "docker";
|
|
339
|
+
staticsite: "staticsite";
|
|
334
340
|
buildpush: "buildpush";
|
|
335
341
|
opennext: "opennext";
|
|
336
342
|
}>;
|
|
@@ -350,6 +356,7 @@ export declare const DeployEventSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
350
356
|
progressKind: z.ZodLiteral<"build.completed">;
|
|
351
357
|
builder: z.ZodEnum<{
|
|
352
358
|
docker: "docker";
|
|
359
|
+
staticsite: "staticsite";
|
|
353
360
|
buildpush: "buildpush";
|
|
354
361
|
opennext: "opennext";
|
|
355
362
|
}>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{z as e}from"zod";import{CASCADE_PHASES as h,DEPLOYMENT_EVENT_RESOURCE_CATEGORIES as E}from"./deploymentEventSchema.js";import{TRAIL_MIGRATION_PHASES as A,TRAIL_MIGRATION_STATUSES as C}from"./events.js";import{TRAIL_LIFECYCLE_STATES as p}from"@fjall/util/config";const Ue="fjall.deploy/1.1",Ve=1,Ye=1,_=["fjall.deploy/1.0","fjall.deploy/1.1"],a=256,o=256,s=2048,i=2048,n=4096,j=2048,m=8192,r=2048,g=4096,T=["completed","skipped","error","cancelled"],y=["info","debug","warn"],D=["emptying-bucket","deleting-stack","waiting","complete","error","quarantine-suspected","retained-buckets"],v=["bootstrap","synth","deploy","destroy"],P=["success","failure","cancelled","no-changes","rejected"],R=["detect","synth","hash","validate"],c=["started","completed"],l=["docker","buildpush","opennext"],d=["succeeded","skipped","failed"],N=["create","update","replace","delete","read","no-op"],K=["will","may","conditional","none"],O=["destructive","cost","policy"],f=["approved","rejected","expired","superseded"],u=e.object({create:e.number().int().nonnegative(),update:e.number().int().nonnegative(),replace:e.number().int().nonnegative(),delete:e.number().int().nonnegative(),read:e.number().int().nonnegative(),"no-op":e.number().int().nonnegative()}).strict(),L={create:!0,update:!0,replace:!0,delete:!0,read:!0,"no-op":!0},t={contract:e.enum(_),deploymentId:e.string().min(1).max(a),seq:e.number().int().nonnegative(),time:e.string().datetime()},x=e.object({index:e.number().int().nonnegative(),total:e.number().int().positive()}).strict(),b=e.object({id:e.string().max(a),name:e.string().max(o)}).strict(),k=e.object({logicalId:e.string().max(a),resourceType:e.string().max(a),status:e.string().max(64),displayName:e.string().max(o).optional(),category:e.enum(E).optional(),group:e.string().max(128).optional(),constructPath:e.string().max(512).optional(),statusReason:e.string().max(i).optional(),physicalId:e.string().max(r).optional(),expectedDurationSeconds:e.number().nonnegative().optional()}).strict(),M=e.object({pattern:e.string().max(128).nullable(),hasDockerfile:e.boolean(),hasDifferences:e.boolean(),resources:e.object({hasNetwork:e.boolean(),hasCompute:e.boolean(),hasDatabase:e.boolean(),hasStorage:e.boolean(),hasMessaging:e.boolean(),hasCdn:e.boolean()}).strict(),requiredSecrets:e.array(e.string().max(512)).max(100).optional()}).strict(),I=e.object({path:e.string().max(512),forcesReplacement:e.boolean()}).strict(),U=e.object({address:e.string().max(512),resourceType:e.string().max(a),action:e.enum(N),stack:e.string().max(a).optional(),replacementMode:e.enum(K).optional(),dataLoss:e.boolean().optional(),propertyChanges:e.array(I).max(100).optional()}).strict(),S=e.object({accountId:e.string().max(a),error:e.string().max(n)}).strict(),V=e.object({platformDeployed:e.boolean(),platformSkipped:e.boolean(),platformFailed:e.boolean(),domainsDeployed:e.boolean(),accountsDeployed:e.number().int().nonnegative(),accountsSkipped:e.number().int().nonnegative(),accountsFailed:e.number().int().nonnegative(),errors:e.array(S).max(1e3)}).strict(),Y=e.object({accountId:e.string().max(a),accountName:e.string().max(o),region:e.string().max(a),result:e.enum(d),durationMs:e.number().nonnegative(),error:e.string().max(n).optional()}).strict(),B=e.object({accountId:e.string().max(a),result:e.enum(d),durationMs:e.number().nonnegative(),error:e.string().max(n).optional()}).strict(),G=e.object({members:e.array(Y).max(1e3),platform:B.optional(),domainsDeployed:e.boolean(),errors:e.array(S).max(1e3),totalDurationMs:e.number().nonnegative()}).strict(),X=e.object({bucketName:e.string().max(o),accountId:e.string().max(a).optional()}).strict(),w=e.object({retainedBuckets:e.array(e.string().max(o)).max(1e3),message:e.string().max(s)}).strict(),H=e.union([X,w]),q=e.object({stack:e.string().max(a),success:e.boolean(),error:e.string().max(n).optional()}).strict(),F=e.object({accountId:e.string().max(a),region:e.string().max(a),profileName:e.string().max(o).optional()}).strict(),z=e.object({...t,progressKind:e.literal("step.started"),step:b,progress:x.optional()}).strict(),J=e.object({...t,progressKind:e.literal("step.completed"),step:b,status:e.enum(T),progress:x.optional(),errorMessage:e.string().max(n).optional()}).strict(),Q=e.object({...t,progressKind:e.literal("log"),level:e.enum(y),message:e.string().max(s)}).strict(),W=e.object({...t,progressKind:e.literal("output"),chunk:e.string().max(m)}).strict(),Z=e.object({...t,progressKind:e.literal("resource"),resource:k,scope:e.object({stack:e.string().max(a).optional(),operationKey:e.string().max(a).optional(),region:e.string().max(a).optional()}).strict().optional()}).strict(),$=e.object({...t,progressKind:e.literal("phase.parallel"),status:e.enum(c),stacks:e.array(e.string().max(a)).max(50),description:e.string().max(o).optional(),results:e.array(q).max(50).optional()}).strict(),ee=e.object({...t,progressKind:e.literal("build.started"),builder:e.enum(l),serviceName:e.string().max(o).optional(),imageTag:e.string().max(o).optional(),ecrRepositoryUri:e.string().max(r).optional()}).strict(),te=e.object({...t,progressKind:e.literal("build.progress"),builder:e.enum(l),message:e.string().max(s),serviceName:e.string().max(o).optional(),percentage:e.number().optional(),layerId:e.string().max(a).optional(),status:e.string().max(64).optional()}).strict(),ae=e.object({...t,progressKind:e.literal("build.completed"),builder:e.enum(l),success:e.boolean(),serviceName:e.string().max(o).optional(),imageTag:e.string().max(o).optional(),imageDigest:e.string().max(a).optional(),imageUri:e.string().max(g).optional(),ecrRepositoryArn:e.string().max(r).optional(),durationMs:e.number().nonnegative().optional(),error:e.string().max(n).optional()}).strict(),oe=e.object({...t,progressKind:e.literal("taskdef.registered"),serviceName:e.string().max(o),taskDefinitionArn:e.string().max(r),previousTaskDefinitionArn:e.string().max(r),revision:e.number().int().nonnegative(),family:e.string().max(o),imageDigest:e.string().max(a).optional()}).strict(),re=e.object({...t,progressKind:e.literal("ecs.update"),status:e.string().max(64),service:e.string().max(o).optional()}).strict(),se=e.object({...t,progressKind:e.literal("ecs.progress"),message:e.string().max(s),percentage:e.number().optional()}).strict(),ne=e.object({...t,progressKind:e.literal("ecs.completed"),serviceName:e.string().max(o),serviceArn:e.string().max(r),success:e.boolean(),taskDefinitionArn:e.string().max(r),durationMs:e.number().nonnegative(),reason:e.string().max(i).optional(),finalRunningCount:e.number().int().nonnegative().optional(),finalDesiredCount:e.number().int().nonnegative().optional()}).strict(),ie=e.object({...t,progressKind:e.literal("migrations.started"),family:e.string().max(o),taskDefinitionArn:e.string().max(r),imageDigest:e.string().max(a)}).strict(),ce=e.object({...t,progressKind:e.literal("migrations.completed"),family:e.string().max(o),taskDefinitionArn:e.string().max(r),success:e.boolean(),durationMs:e.number().nonnegative(),exitCode:e.number().int().optional(),reason:e.string().max(i).optional()}).strict(),le=e.object({...t,progressKind:e.literal("cdk.bootstrap"),status:e.string().max(s)}).strict(),pe=e.object({...t,progressKind:e.literal("cdk.output"),outputType:e.enum(["synth","diff"]),output:e.string().max(m)}).strict(),me=e.object({...t,progressKind:e.literal("detection.completed"),detection:M}).strict(),ge=e.object({...t,progressKind:e.literal("detection.phase"),phase:e.enum(R),status:e.enum(c)}).strict(),de=e.object({...t,progressKind:e.literal("cascade.started")}).strict(),ue=e.object({...t,progressKind:e.literal("cascade.accountsReconciled"),hasPlatformAccount:e.boolean(),hasMemberAccounts:e.boolean()}).strict(),xe=e.object({...t,progressKind:e.literal("cascade.orgChanges"),hasOrgChanges:e.boolean()}).strict(),be=e.object({...t,progressKind:e.literal("cascade.missingAccounts"),accountNames:e.array(e.string().max(o)).max(256)}).strict(),Se=e.object({...t,progressKind:e.literal("cascade.phase"),phase:e.enum(h),status:e.enum(c)}).strict(),he=e.object({...t,progressKind:e.literal("cascade.account.started"),operationKey:e.string().max(a),accountId:e.string().max(a),region:e.string().max(a),deployType:e.string().max(64).optional()}).strict(),Ee=e.object({...t,progressKind:e.literal("cascade.account.phase"),operationKey:e.string().max(a),phase:e.enum(v),region:e.string().max(a).optional()}).strict(),Ae=e.object({...t,progressKind:e.literal("cascade.account.completed"),operationKey:e.string().max(a),success:e.boolean(),error:e.string().max(n).optional(),region:e.string().max(a).optional(),outputs:e.record(e.string().max(o),e.string().max(i)).optional(),skipped:e.boolean().optional()}).strict(),Ce=e.object({...t,progressKind:e.literal("cascade.completed"),result:V}).strict(),_e=e.object({...t,progressKind:e.literal("cascade.ledger"),ledger:G}).strict(),je=e.object({...t,progressKind:e.literal("trail.phase"),accountId:e.string().max(a),accountName:e.string().max(o),phase:e.enum(A),status:e.enum(C),detail:e.string().max(j).optional()}).strict(),Te=e.object({...t,progressKind:e.literal("trail.lifecycle"),accountId:e.string().max(a),to:e.enum(p),from:e.enum(p).optional()}).strict(),ye=e.object({...t,progressKind:e.literal("cleanup.progress"),stackName:e.string().max(a),phase:e.enum(D),detail:H.optional()}).strict(),De=e.object({...t,progressKind:e.literal("auth.ssoUrl"),url:e.string().max(g).nullable()}).strict(),ve=e.object({...t,progressKind:e.literal("auth.completed"),result:F.nullable()}).strict(),Pe=e.object({...t,progressKind:e.literal("error"),message:e.string().max(n),name:e.string().max(o).optional()}).strict(),Re=e.object({...t,progressKind:e.literal("deploy.completed"),result:e.enum(P),ok:e.boolean(),errorType:e.string().max(128).optional(),message:e.string().max(s)}).strict(),Ne=e.object({...t,progressKind:e.literal("plan.available"),plan:e.object({summary:e.string().max(s),changeCount:e.number().int().nonnegative(),hasDestructiveChanges:e.boolean(),changes:e.array(U).max(1e3).optional(),diffRef:e.string().max(512).optional(),iamBroadening:e.boolean().optional(),securityGroupBroadening:e.boolean().optional(),changeCountsByAction:u.optional()}).strict()}).strict(),Ke=e.object({...t,progressKind:e.literal("approval.awaiting"),approval:e.object({token:e.string().max(512),kind:e.enum(O),reason:e.string().max(s),expiresAt:e.string().datetime(),assemblyDigest:e.string().max(128).optional(),changeCounts:u.optional(),approvalClass:e.string().max(64).optional(),requiredApprovers:e.array(e.string().max(256)).max(50).optional()}).strict()}).strict(),Oe=e.object({...t,progressKind:e.literal("approval.resolved"),approval:e.object({token:e.string().max(512),decision:e.enum(f),actor:e.string().max(o).optional()}).strict()}).strict(),Be=e.discriminatedUnion("progressKind",[z,J,Q,W,Z,$,ee,te,ae,oe,re,se,ne,ie,ce,le,pe,me,ge,de,ue,xe,be,Se,he,Ee,Ae,Ce,_e,je,Te,ye,De,ve,Pe,Re,Ne,Ke,Oe]),fe={"step.started":!0,"step.completed":!0,log:!0,output:!0,resource:!0,"phase.parallel":!0,"build.started":!0,"build.progress":!0,"build.completed":!0,"taskdef.registered":!0,"ecs.update":!0,"ecs.progress":!0,"ecs.completed":!0,"migrations.started":!0,"migrations.completed":!0,"cdk.bootstrap":!0,"cdk.output":!0,"detection.completed":!0,"detection.phase":!0,"cascade.started":!0,"cascade.accountsReconciled":!0,"cascade.orgChanges":!0,"cascade.missingAccounts":!0,"cascade.phase":!0,"cascade.account.started":!0,"cascade.account.phase":!0,"cascade.account.completed":!0,"cascade.completed":!0,"cascade.ledger":!0,"trail.phase":!0,"trail.lifecycle":!0,"cleanup.progress":!0,"auth.ssoUrl":!0,"auth.completed":!0,error:!0,"deploy.completed":!0,"plan.available":!0,"approval.awaiting":!0,"approval.resolved":!0},Ge=Object.keys(fe);export{Ge as ALL_PROGRESS_KINDS,f as APPROVAL_DECISIONS,O as APPROVAL_KINDS,l as BUILDERS,v as CASCADE_ACCOUNT_PHASES,d as CASCADE_OUTCOME_RESULTS,u as ChangeCountsSchema,r as DEPLOY_EVENT_ARN_MAX,Ue as DEPLOY_EVENT_CONTRACT,Ve as DEPLOY_EVENT_CONTRACT_MAJOR,Ye as DEPLOY_EVENT_CONTRACT_MINOR,n as DEPLOY_EVENT_ERROR_MESSAGE_MAX,a as DEPLOY_EVENT_ID_MAX,s as DEPLOY_EVENT_MESSAGE_MAX,o as DEPLOY_EVENT_NAME_MAX,m as DEPLOY_EVENT_OUTPUT_MAX,i as DEPLOY_EVENT_STATUS_REASON_MAX,j as DEPLOY_EVENT_TRAIL_DETAIL_MAX,g as DEPLOY_EVENT_URL_MAX,P as DEPLOY_RESULTS,R as DETECTION_PHASES,Be as DeployEventSchema,k as DeployResourceSchema,y as LOG_LEVELS,c as PHASE_STATUSES,N as PLAN_ACTIONS,U as PlanChangeSchema,I as PlanPropertyChangeSchema,K as REPLACEMENT_MODES,D as STACK_CLEANUP_PHASES,T as STEP_COMPLETE_STATUSES,_ as SUPPORTED_CONTRACT_MARKERS,x as StepProgressSchema};
|
|
1
|
+
import{z as e}from"zod";import{CASCADE_PHASES as h,DEPLOYMENT_EVENT_RESOURCE_CATEGORIES as E}from"./deploymentEventSchema.js";import{TRAIL_MIGRATION_PHASES as A,TRAIL_MIGRATION_STATUSES as C}from"./events.js";import{TRAIL_LIFECYCLE_STATES as p}from"@fjall/util/config";const Ue="fjall.deploy/1.1",Ve=1,Ye=1,_=["fjall.deploy/1.0","fjall.deploy/1.1"],a=256,o=256,s=2048,i=2048,n=4096,j=2048,m=8192,r=2048,g=4096,T=["completed","skipped","error","cancelled"],y=["info","debug","warn"],D=["emptying-bucket","deleting-stack","waiting","complete","error","quarantine-suspected","retained-buckets"],v=["bootstrap","synth","deploy","destroy"],P=["success","failure","cancelled","no-changes","rejected"],R=["detect","synth","hash","validate"],c=["started","completed"],l=["docker","buildpush","opennext","staticsite"],d=["succeeded","skipped","failed"],N=["create","update","replace","delete","read","no-op"],K=["will","may","conditional","none"],O=["destructive","cost","policy"],f=["approved","rejected","expired","superseded"],u=e.object({create:e.number().int().nonnegative(),update:e.number().int().nonnegative(),replace:e.number().int().nonnegative(),delete:e.number().int().nonnegative(),read:e.number().int().nonnegative(),"no-op":e.number().int().nonnegative()}).strict(),L={create:!0,update:!0,replace:!0,delete:!0,read:!0,"no-op":!0},t={contract:e.enum(_),deploymentId:e.string().min(1).max(a),seq:e.number().int().nonnegative(),time:e.string().datetime()},x=e.object({index:e.number().int().nonnegative(),total:e.number().int().positive()}).strict(),b=e.object({id:e.string().max(a),name:e.string().max(o)}).strict(),k=e.object({logicalId:e.string().max(a),resourceType:e.string().max(a),status:e.string().max(64),displayName:e.string().max(o).optional(),category:e.enum(E).optional(),group:e.string().max(128).optional(),constructPath:e.string().max(512).optional(),statusReason:e.string().max(i).optional(),physicalId:e.string().max(r).optional(),expectedDurationSeconds:e.number().nonnegative().optional()}).strict(),M=e.object({pattern:e.string().max(128).nullable(),hasDockerfile:e.boolean(),hasDifferences:e.boolean(),resources:e.object({hasNetwork:e.boolean(),hasCompute:e.boolean(),hasDatabase:e.boolean(),hasStorage:e.boolean(),hasMessaging:e.boolean(),hasCdn:e.boolean()}).strict(),requiredSecrets:e.array(e.string().max(512)).max(100).optional()}).strict(),I=e.object({path:e.string().max(512),forcesReplacement:e.boolean()}).strict(),U=e.object({address:e.string().max(512),resourceType:e.string().max(a),action:e.enum(N),stack:e.string().max(a).optional(),replacementMode:e.enum(K).optional(),dataLoss:e.boolean().optional(),propertyChanges:e.array(I).max(100).optional()}).strict(),S=e.object({accountId:e.string().max(a),error:e.string().max(n)}).strict(),V=e.object({platformDeployed:e.boolean(),platformSkipped:e.boolean(),platformFailed:e.boolean(),domainsDeployed:e.boolean(),accountsDeployed:e.number().int().nonnegative(),accountsSkipped:e.number().int().nonnegative(),accountsFailed:e.number().int().nonnegative(),errors:e.array(S).max(1e3)}).strict(),Y=e.object({accountId:e.string().max(a),accountName:e.string().max(o),region:e.string().max(a),result:e.enum(d),durationMs:e.number().nonnegative(),error:e.string().max(n).optional()}).strict(),B=e.object({accountId:e.string().max(a),result:e.enum(d),durationMs:e.number().nonnegative(),error:e.string().max(n).optional()}).strict(),G=e.object({members:e.array(Y).max(1e3),platform:B.optional(),domainsDeployed:e.boolean(),errors:e.array(S).max(1e3),totalDurationMs:e.number().nonnegative()}).strict(),X=e.object({bucketName:e.string().max(o),accountId:e.string().max(a).optional()}).strict(),w=e.object({retainedBuckets:e.array(e.string().max(o)).max(1e3),message:e.string().max(s)}).strict(),H=e.union([X,w]),q=e.object({stack:e.string().max(a),success:e.boolean(),error:e.string().max(n).optional()}).strict(),F=e.object({accountId:e.string().max(a),region:e.string().max(a),profileName:e.string().max(o).optional()}).strict(),z=e.object({...t,progressKind:e.literal("step.started"),step:b,progress:x.optional()}).strict(),J=e.object({...t,progressKind:e.literal("step.completed"),step:b,status:e.enum(T),progress:x.optional(),errorMessage:e.string().max(n).optional()}).strict(),Q=e.object({...t,progressKind:e.literal("log"),level:e.enum(y),message:e.string().max(s)}).strict(),W=e.object({...t,progressKind:e.literal("output"),chunk:e.string().max(m)}).strict(),Z=e.object({...t,progressKind:e.literal("resource"),resource:k,scope:e.object({stack:e.string().max(a).optional(),operationKey:e.string().max(a).optional(),region:e.string().max(a).optional()}).strict().optional()}).strict(),$=e.object({...t,progressKind:e.literal("phase.parallel"),status:e.enum(c),stacks:e.array(e.string().max(a)).max(50),description:e.string().max(o).optional(),results:e.array(q).max(50).optional()}).strict(),ee=e.object({...t,progressKind:e.literal("build.started"),builder:e.enum(l),serviceName:e.string().max(o).optional(),imageTag:e.string().max(o).optional(),ecrRepositoryUri:e.string().max(r).optional()}).strict(),te=e.object({...t,progressKind:e.literal("build.progress"),builder:e.enum(l),message:e.string().max(s),serviceName:e.string().max(o).optional(),percentage:e.number().optional(),layerId:e.string().max(a).optional(),status:e.string().max(64).optional()}).strict(),ae=e.object({...t,progressKind:e.literal("build.completed"),builder:e.enum(l),success:e.boolean(),serviceName:e.string().max(o).optional(),imageTag:e.string().max(o).optional(),imageDigest:e.string().max(a).optional(),imageUri:e.string().max(g).optional(),ecrRepositoryArn:e.string().max(r).optional(),durationMs:e.number().nonnegative().optional(),error:e.string().max(n).optional()}).strict(),oe=e.object({...t,progressKind:e.literal("taskdef.registered"),serviceName:e.string().max(o),taskDefinitionArn:e.string().max(r),previousTaskDefinitionArn:e.string().max(r),revision:e.number().int().nonnegative(),family:e.string().max(o),imageDigest:e.string().max(a).optional()}).strict(),re=e.object({...t,progressKind:e.literal("ecs.update"),status:e.string().max(64),service:e.string().max(o).optional()}).strict(),se=e.object({...t,progressKind:e.literal("ecs.progress"),message:e.string().max(s),percentage:e.number().optional()}).strict(),ne=e.object({...t,progressKind:e.literal("ecs.completed"),serviceName:e.string().max(o),serviceArn:e.string().max(r),success:e.boolean(),taskDefinitionArn:e.string().max(r),durationMs:e.number().nonnegative(),reason:e.string().max(i).optional(),finalRunningCount:e.number().int().nonnegative().optional(),finalDesiredCount:e.number().int().nonnegative().optional()}).strict(),ie=e.object({...t,progressKind:e.literal("migrations.started"),family:e.string().max(o),taskDefinitionArn:e.string().max(r),imageDigest:e.string().max(a)}).strict(),ce=e.object({...t,progressKind:e.literal("migrations.completed"),family:e.string().max(o),taskDefinitionArn:e.string().max(r),success:e.boolean(),durationMs:e.number().nonnegative(),exitCode:e.number().int().optional(),reason:e.string().max(i).optional()}).strict(),le=e.object({...t,progressKind:e.literal("cdk.bootstrap"),status:e.string().max(s)}).strict(),pe=e.object({...t,progressKind:e.literal("cdk.output"),outputType:e.enum(["synth","diff"]),output:e.string().max(m)}).strict(),me=e.object({...t,progressKind:e.literal("detection.completed"),detection:M}).strict(),ge=e.object({...t,progressKind:e.literal("detection.phase"),phase:e.enum(R),status:e.enum(c)}).strict(),de=e.object({...t,progressKind:e.literal("cascade.started")}).strict(),ue=e.object({...t,progressKind:e.literal("cascade.accountsReconciled"),hasPlatformAccount:e.boolean(),hasMemberAccounts:e.boolean()}).strict(),xe=e.object({...t,progressKind:e.literal("cascade.orgChanges"),hasOrgChanges:e.boolean()}).strict(),be=e.object({...t,progressKind:e.literal("cascade.missingAccounts"),accountNames:e.array(e.string().max(o)).max(256)}).strict(),Se=e.object({...t,progressKind:e.literal("cascade.phase"),phase:e.enum(h),status:e.enum(c)}).strict(),he=e.object({...t,progressKind:e.literal("cascade.account.started"),operationKey:e.string().max(a),accountId:e.string().max(a),region:e.string().max(a),deployType:e.string().max(64).optional()}).strict(),Ee=e.object({...t,progressKind:e.literal("cascade.account.phase"),operationKey:e.string().max(a),phase:e.enum(v),region:e.string().max(a).optional()}).strict(),Ae=e.object({...t,progressKind:e.literal("cascade.account.completed"),operationKey:e.string().max(a),success:e.boolean(),error:e.string().max(n).optional(),region:e.string().max(a).optional(),outputs:e.record(e.string().max(o),e.string().max(i)).optional(),skipped:e.boolean().optional()}).strict(),Ce=e.object({...t,progressKind:e.literal("cascade.completed"),result:V}).strict(),_e=e.object({...t,progressKind:e.literal("cascade.ledger"),ledger:G}).strict(),je=e.object({...t,progressKind:e.literal("trail.phase"),accountId:e.string().max(a),accountName:e.string().max(o),phase:e.enum(A),status:e.enum(C),detail:e.string().max(j).optional()}).strict(),Te=e.object({...t,progressKind:e.literal("trail.lifecycle"),accountId:e.string().max(a),to:e.enum(p),from:e.enum(p).optional()}).strict(),ye=e.object({...t,progressKind:e.literal("cleanup.progress"),stackName:e.string().max(a),phase:e.enum(D),detail:H.optional()}).strict(),De=e.object({...t,progressKind:e.literal("auth.ssoUrl"),url:e.string().max(g).nullable()}).strict(),ve=e.object({...t,progressKind:e.literal("auth.completed"),result:F.nullable()}).strict(),Pe=e.object({...t,progressKind:e.literal("error"),message:e.string().max(n),name:e.string().max(o).optional()}).strict(),Re=e.object({...t,progressKind:e.literal("deploy.completed"),result:e.enum(P),ok:e.boolean(),errorType:e.string().max(128).optional(),message:e.string().max(s)}).strict(),Ne=e.object({...t,progressKind:e.literal("plan.available"),plan:e.object({summary:e.string().max(s),changeCount:e.number().int().nonnegative(),hasDestructiveChanges:e.boolean(),changes:e.array(U).max(1e3).optional(),diffRef:e.string().max(512).optional(),iamBroadening:e.boolean().optional(),securityGroupBroadening:e.boolean().optional(),changeCountsByAction:u.optional()}).strict()}).strict(),Ke=e.object({...t,progressKind:e.literal("approval.awaiting"),approval:e.object({token:e.string().max(512),kind:e.enum(O),reason:e.string().max(s),expiresAt:e.string().datetime(),assemblyDigest:e.string().max(128).optional(),changeCounts:u.optional(),approvalClass:e.string().max(64).optional(),requiredApprovers:e.array(e.string().max(256)).max(50).optional()}).strict()}).strict(),Oe=e.object({...t,progressKind:e.literal("approval.resolved"),approval:e.object({token:e.string().max(512),decision:e.enum(f),actor:e.string().max(o).optional()}).strict()}).strict(),Be=e.discriminatedUnion("progressKind",[z,J,Q,W,Z,$,ee,te,ae,oe,re,se,ne,ie,ce,le,pe,me,ge,de,ue,xe,be,Se,he,Ee,Ae,Ce,_e,je,Te,ye,De,ve,Pe,Re,Ne,Ke,Oe]),fe={"step.started":!0,"step.completed":!0,log:!0,output:!0,resource:!0,"phase.parallel":!0,"build.started":!0,"build.progress":!0,"build.completed":!0,"taskdef.registered":!0,"ecs.update":!0,"ecs.progress":!0,"ecs.completed":!0,"migrations.started":!0,"migrations.completed":!0,"cdk.bootstrap":!0,"cdk.output":!0,"detection.completed":!0,"detection.phase":!0,"cascade.started":!0,"cascade.accountsReconciled":!0,"cascade.orgChanges":!0,"cascade.missingAccounts":!0,"cascade.phase":!0,"cascade.account.started":!0,"cascade.account.phase":!0,"cascade.account.completed":!0,"cascade.completed":!0,"cascade.ledger":!0,"trail.phase":!0,"trail.lifecycle":!0,"cleanup.progress":!0,"auth.ssoUrl":!0,"auth.completed":!0,error:!0,"deploy.completed":!0,"plan.available":!0,"approval.awaiting":!0,"approval.resolved":!0},Ge=Object.keys(fe);export{Ge as ALL_PROGRESS_KINDS,f as APPROVAL_DECISIONS,O as APPROVAL_KINDS,l as BUILDERS,v as CASCADE_ACCOUNT_PHASES,d as CASCADE_OUTCOME_RESULTS,u as ChangeCountsSchema,r as DEPLOY_EVENT_ARN_MAX,Ue as DEPLOY_EVENT_CONTRACT,Ve as DEPLOY_EVENT_CONTRACT_MAJOR,Ye as DEPLOY_EVENT_CONTRACT_MINOR,n as DEPLOY_EVENT_ERROR_MESSAGE_MAX,a as DEPLOY_EVENT_ID_MAX,s as DEPLOY_EVENT_MESSAGE_MAX,o as DEPLOY_EVENT_NAME_MAX,m as DEPLOY_EVENT_OUTPUT_MAX,i as DEPLOY_EVENT_STATUS_REASON_MAX,j as DEPLOY_EVENT_TRAIL_DETAIL_MAX,g as DEPLOY_EVENT_URL_MAX,P as DEPLOY_RESULTS,R as DETECTION_PHASES,Be as DeployEventSchema,k as DeployResourceSchema,y as LOG_LEVELS,c as PHASE_STATUSES,N as PLAN_ACTIONS,U as PlanChangeSchema,I as PlanPropertyChangeSchema,K as REPLACEMENT_MODES,D as STACK_CLEANUP_PHASES,T as STEP_COMPLETE_STATUSES,_ as SUPPORTED_CONTRACT_MARKERS,x as StepProgressSchema};
|
|
@@ -4,10 +4,16 @@
|
|
|
4
4
|
* These are safe for browser bundles. Filesystem-based detection functions
|
|
5
5
|
* remain in patternDetection.ts.
|
|
6
6
|
*/
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
import { isOpenNextPatternType, type OpenNextPatternType } from "@fjall/util/patterns";
|
|
8
|
+
/**
|
|
9
|
+
* The OpenNext accept-set is derived from `PATTERN_REGISTRY` in `@fjall/util`:
|
|
10
|
+
* a pattern is OpenNext-shaped iff its declared artefact is an OpenNext Lambda
|
|
11
|
+
* bundle. Re-listing the members here is how `staticsite` would silently join
|
|
12
|
+
* the OpenNext build path.
|
|
13
|
+
*/
|
|
14
|
+
export type OpenNextPattern = OpenNextPatternType;
|
|
9
15
|
export declare const OPENNEXT_PATTERNS: ReadonlySet<string>;
|
|
10
|
-
export declare
|
|
16
|
+
export declare const isOpenNextPattern: typeof isOpenNextPatternType;
|
|
11
17
|
export interface AppResourceFlags {
|
|
12
18
|
hasNetwork: boolean;
|
|
13
19
|
hasCompute: boolean;
|
|
@@ -16,4 +22,3 @@ export interface AppResourceFlags {
|
|
|
16
22
|
hasMessaging: boolean;
|
|
17
23
|
hasCdn: boolean;
|
|
18
24
|
}
|
|
19
|
-
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
import{OPENNEXT_PATTERN_TYPES as t,isOpenNextPatternType as e}from"@fjall/util/patterns";const T=new Set(t),n=e;export{T as OPENNEXT_PATTERNS,n as isOpenNextPattern};
|
|
@@ -40,6 +40,13 @@ export interface BuildPlan {
|
|
|
40
40
|
readonly buildCommand: BuildCommand | null;
|
|
41
41
|
/** Whether this plan requires a Docker build (standard apps with Dockerfile) */
|
|
42
42
|
readonly requiresDockerBuild: boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Directory the build must produce, relative to the build command's `cwd`.
|
|
45
|
+
* Verified to exist after `build()` completes. Set by builders whose artefacts
|
|
46
|
+
* are uploaded to a bucket rather than containerised (static sites); the
|
|
47
|
+
* Docker/OpenNext builders leave it undefined.
|
|
48
|
+
*/
|
|
49
|
+
readonly artefactDir?: string;
|
|
43
50
|
/** Infrastructure requirements */
|
|
44
51
|
readonly resources: AppResourceFlags;
|
|
45
52
|
}
|
|
@@ -71,6 +78,13 @@ export interface BuildOptions {
|
|
|
71
78
|
readonly skipBuild?: boolean;
|
|
72
79
|
/** Only deploy infrastructure, skip application build */
|
|
73
80
|
readonly infraOnly?: boolean;
|
|
81
|
+
/**
|
|
82
|
+
* The deploy's cancellation signal (`DeployParams.abortSignal` — Ctrl-C, or
|
|
83
|
+
* `fjall deployments cancel`). A build can run for minutes; without the
|
|
84
|
+
* signal a cancelled deploy has no way to reach the child process and waits
|
|
85
|
+
* out the full build timeout before noticing.
|
|
86
|
+
*/
|
|
87
|
+
readonly abortSignal?: AbortSignal;
|
|
74
88
|
}
|
|
75
89
|
/** The FrameworkBuilder interface — detect/plan/build lifecycle */
|
|
76
90
|
export interface FrameworkBuilder {
|
|
@@ -1,3 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@fjall/deploy-core/types` — the BROWSER-SAFE type/schema barrel.
|
|
3
|
+
*
|
|
4
|
+
* INVARIANT: nothing re-exported here may ACCESS a Node builtin at MODULE-EVAL.
|
|
5
|
+
* The webapp imports this subpath from CLIENT-reachable modules (e.g.
|
|
6
|
+
* `app/types/approval-plan.ts`, `app/types/destruction-consent.ts`); Vite's dev
|
|
7
|
+
* esbuild bundles the whole barrel without tree-shaking and stubs each Node
|
|
8
|
+
* builtin with a shim that THROWS ON ACCESS, killing React hydration app-wide in
|
|
9
|
+
* dev — while prod Rollup tree-shakes the unused module out, so CI stays green
|
|
10
|
+
* and the breakage is invisible to CI (the 2026-07-07 incident). Two shapes trip
|
|
11
|
+
* the eval-time access: a NAMED builtin import (`import { readFileSync } from
|
|
12
|
+
* "fs"`) binds to the throwing shim at link time, and a top-level builtin call
|
|
13
|
+
* (`readFileSync(...)` at module scope) calls it immediately. A bare NAMESPACE
|
|
14
|
+
* import (`import * as fs from "fs"`) used only inside functions does NOT trip it
|
|
15
|
+
* — the shim is never accessed at eval.
|
|
16
|
+
*
|
|
17
|
+
* deploy-core's OWN re-exported modules are kept fully Node-builtin-free: the
|
|
18
|
+
* fs-based helpers (`deriveResourcesFromManifestStacks` with its named `fs`
|
|
19
|
+
* import; the FjallState IO functions with named `fs`/`crypto`) — the two
|
|
20
|
+
* modules that tripped the 2026-07-07 incident — are NOT re-exported here. Their
|
|
21
|
+
* server-only consumers import them straight from the LEAF modules
|
|
22
|
+
* (`./detection/patternDetection.js`, `./config/FjallState.js`) and the ROOT
|
|
23
|
+
* barrel (`../index.js`) re-exports them — never from here.
|
|
24
|
+
*
|
|
25
|
+
* One TOLERATED cross-package builtin edge: `deployEvent.js` imports the static
|
|
26
|
+
* const `TRAIL_LIFECYCLE_STATES` from `@fjall/util/config`, which carries
|
|
27
|
+
* `import * as fs`/`import * as path` used ONLY inside functions. That is
|
|
28
|
+
* import-safe (verified: esbuild-bundle this barrel for the browser with a
|
|
29
|
+
* throw-on-access builtin stub → importing it does not throw). FRAGILE: if
|
|
30
|
+
* `config.js` ever adds a top-level fs/path call or a named builtin import, this
|
|
31
|
+
* barrel breaks — `TRAIL_LIFECYCLE_STATES` should then move to a genuinely
|
|
32
|
+
* builtin-free `@fjall/util` module. Before adding a re-export here, prefer a
|
|
33
|
+
* Node-builtin-free module; if it transitively pulls a builtin, that builtin
|
|
34
|
+
* MUST be a namespace import never accessed at eval (`import type` is always
|
|
35
|
+
* fine — it is erased).
|
|
36
|
+
*/
|
|
1
37
|
export { DeploymentEventSchema, DEPLOYMENT_EVENT_TYPES, DEPLOYMENT_EVENT_RESOURCE_CATEGORIES, DEPLOYMENT_EVENT_STATUS_REASON_MAX, DEPLOYMENT_EVENT_ERROR_MESSAGE_MAX, DEPLOYMENT_EVENT_TRAIL_DETAIL_MAX, CASCADE_PHASES, CASCADE_ACCOUNT_STATUSES, toCascadePhase } from "./deploymentEventSchema.js";
|
|
2
38
|
export type { DeploymentEvent, DeploymentEventType, DeploymentEventResourceCategory, DeploymentEventCascadePhase, DeploymentEventCascadeAccountStatus } from "./deploymentEventSchema.js";
|
|
3
39
|
export type { AwsCredentials, DeployIdentity, ScopedBuildSecretSessionMinter } from "./credentials.js";
|
|
@@ -32,11 +68,9 @@ export type { ParallelDeploymentResult, ParallelDeployGroup, ParallelOperation,
|
|
|
32
68
|
export { PARALLEL_OPERATION_TYPES } from "./deployment/index.js";
|
|
33
69
|
export type { OpenNextPattern, AppResourceFlags } from "./detection/patternTypes.js";
|
|
34
70
|
export { isOpenNextPattern, OPENNEXT_PATTERNS } from "./detection/patternTypes.js";
|
|
35
|
-
export { deriveResourcesFromManifestStacks } from "./detection/patternDetection.js";
|
|
36
71
|
export { STACK_NOT_FOUND_PATTERN, STACK_FAILED_STATE_PATTERN, CDK_NO_STACKS_MATCH, INFRASTRUCTURE_FILENAME } from "./constants.js";
|
|
37
72
|
export { ApplicationError, wrapApplicationError, type ApplicationErrorType, type StackDeploymentData, type StackDeploymentOptions, type ApplicationDeploymentData, type ApplicationDestructionData } from "./application/index.js";
|
|
38
73
|
export type { FjallStateFile, TemplateHashEntry } from "./config/FjallState.js";
|
|
39
|
-
export { FjallStateFileSchema, readStateFile, writeStateFile, createEmptyState, deleteStateFile, updateTemplateHash, getStateFilePath, regionSuffix } from "./config/FjallState.js";
|
|
40
74
|
export type { FrameworkBuilder, FrameworkDetection, BuildPlan, BuildCommand, BuildCallbacks, DetectionContext, BuildOptions } from "./frameworkBuilder.js";
|
|
41
75
|
export { STEP_IDS, STEP_NAMES, INFRASTRUCTURE_STEP_NAMES, INFRA_STEP_NAME } from "./stepDefinitions.js";
|
|
42
76
|
export type { StepId, InfrastructureStepName, StepDefinition, StepDeploymentType, Operation, StepContext } from "./stepDefinitions.js";
|
package/dist/src/types/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{DeploymentEventSchema as S,DEPLOYMENT_EVENT_TYPES as
|
|
1
|
+
import{DeploymentEventSchema as S,DEPLOYMENT_EVENT_TYPES as _,DEPLOYMENT_EVENT_RESOURCE_CATEGORIES as T,DEPLOYMENT_EVENT_STATUS_REASON_MAX as A,DEPLOYMENT_EVENT_ERROR_MESSAGE_MAX as t,DEPLOYMENT_EVENT_TRAIL_DETAIL_MAX as r,CASCADE_PHASES as o,CASCADE_ACCOUNT_STATUSES as a,toCascadePhase as R}from"./deploymentEventSchema.js";import{isQuarantineDetail as P,isRetainedBucketsDetail as N}from"./callbacks.js";import{DeployEventSchema as D,StepProgressSchema as c,DeployResourceSchema as L,PlanChangeSchema as p,PlanPropertyChangeSchema as C,ChangeCountsSchema as n,DEPLOY_EVENT_CONTRACT as m,DEPLOY_EVENT_CONTRACT_MAJOR as I,DEPLOY_EVENT_CONTRACT_MINOR as s,SUPPORTED_CONTRACT_MARKERS as l,DEPLOY_EVENT_ID_MAX as M,DEPLOY_EVENT_NAME_MAX as h,DEPLOY_EVENT_MESSAGE_MAX as V,DEPLOY_EVENT_STATUS_REASON_MAX as U,DEPLOY_EVENT_ERROR_MESSAGE_MAX as Y,DEPLOY_EVENT_TRAIL_DETAIL_MAX as d,DEPLOY_EVENT_OUTPUT_MAX as f,DEPLOY_EVENT_ARN_MAX as g,DEPLOY_EVENT_URL_MAX as u,STEP_COMPLETE_STATUSES as x,LOG_LEVELS as G,STACK_CLEANUP_PHASES as X,CASCADE_ACCOUNT_PHASES as y,DEPLOY_RESULTS as F,DETECTION_PHASES as K,PHASE_STATUSES as k,BUILDERS as H,CASCADE_OUTCOME_RESULTS as b,PLAN_ACTIONS as v,REPLACEMENT_MODES as B,APPROVAL_KINDS as J,APPROVAL_DECISIONS as w,ALL_PROGRESS_KINDS as Q}from"./deployEvent.js";import{createDeployEmitter as j}from"./deployEmitter.js";import{parseDeployEvent as z,parseDeployContractVersion as Z}from"./deployEventParse.js";import{TRAIL_MIGRATION_PHASES as EE,TRAIL_MIGRATION_STATUSES as eE}from"./events.js";import{RemediationVerbSchema as _E,REMEDIATION_VERB_GLOSS as TE,DestructionFindingSchema as AE,DestructionTicketResourceSchema as tE,DestructionTicketSchema as rE,DestructionConsentSchema as oE,DestructionOutcomeSchema as aE,DESTRUCTION_FINDINGS as RE,CONSENT_VERDICTS as OE,TICKET_VERDICT_SOURCES as PE,TicketVerdictSourceSchema as NE}from"./destruction.js";import{DRIFT_VERDICTS as DE,DriftVerdictSchema as cE,DriftSuspectSchema as LE,DriftFindingSchema as pE,DriftJournalRecordSchema as CE,verbsForDriftVerdict as nE}from"./drift.js";import{REMEDIATION_PHASES as IE,RemediationPhaseSchema as sE,RemediationTargetSchema as lE,RemediationFlipProofSchema as ME,RemediationJournalRecordSchema as hE,RemediationVerbWithSurgerySchema as VE,remediationPhaseRank as UE,remediationPlaceholderPhysicalId as YE,isRemediationPlaceholderPhysicalId as dE}from"./remediation.js";import{stubCallerIdentity as gE}from"./deployment/index.js";import{ProgressReporter as xE}from"./ProgressEvent.js";import{APPLICATION_STACKS as XE,ORGANISATION_TYPES as yE,APPLICATION_DEPLOY_ORDER as FE,APPLICATION_DESTROY_ORDER as KE,OPENNEXT_DEPLOY_ORDER as kE,OPENNEXT_DESTROY_ORDER as HE,PARALLEL_DEPLOY_GROUPS as bE,PARALLEL_DESTROY_GROUPS as vE,OPENNEXT_PARALLEL_GROUPS as BE,isApplicationOperation as JE,isOrganisationOperation as wE,getParallelDeployGroups as QE,getParallelDestroyGroups as WE,getApplicationDeployOrder as jE,getApplicationDestroyOrder as qE,getApplicationStackName as zE,getOrganisationStackName as ZE,isApplicationStack as $E,getApplicationStepName as Ee,getApplicationStepId as ee,toPascalCase as Se}from"./operations.js";import{PARALLEL_OPERATION_TYPES as Te}from"./deployment/index.js";import{isOpenNextPattern as te,OPENNEXT_PATTERNS as re}from"./detection/patternTypes.js";import{STACK_NOT_FOUND_PATTERN as ae,STACK_FAILED_STATE_PATTERN as Re,CDK_NO_STACKS_MATCH as Oe,INFRASTRUCTURE_FILENAME as Pe}from"./constants.js";import{ApplicationError as ie,wrapApplicationError as De}from"./application/index.js";import{STEP_IDS as Le,STEP_NAMES as pe,INFRASTRUCTURE_STEP_NAMES as Ce,INFRA_STEP_NAME as ne}from"./stepDefinitions.js";export{Q as ALL_PROGRESS_KINDS,FE as APPLICATION_DEPLOY_ORDER,KE as APPLICATION_DESTROY_ORDER,XE as APPLICATION_STACKS,w as APPROVAL_DECISIONS,J as APPROVAL_KINDS,ie as ApplicationError,H as BUILDERS,y as CASCADE_ACCOUNT_PHASES,a as CASCADE_ACCOUNT_STATUSES,b as CASCADE_OUTCOME_RESULTS,o as CASCADE_PHASES,Oe as CDK_NO_STACKS_MATCH,OE as CONSENT_VERDICTS,n as ChangeCountsSchema,t as DEPLOYMENT_EVENT_ERROR_MESSAGE_MAX,T as DEPLOYMENT_EVENT_RESOURCE_CATEGORIES,A as DEPLOYMENT_EVENT_STATUS_REASON_MAX,r as DEPLOYMENT_EVENT_TRAIL_DETAIL_MAX,_ as DEPLOYMENT_EVENT_TYPES,g as DEPLOY_EVENT_ARN_MAX,m as DEPLOY_EVENT_CONTRACT,I as DEPLOY_EVENT_CONTRACT_MAJOR,s as DEPLOY_EVENT_CONTRACT_MINOR,Y as DEPLOY_EVENT_ERROR_MESSAGE_MAX,M as DEPLOY_EVENT_ID_MAX,V as DEPLOY_EVENT_MESSAGE_MAX,h as DEPLOY_EVENT_NAME_MAX,f as DEPLOY_EVENT_OUTPUT_MAX,U as DEPLOY_EVENT_STATUS_REASON_MAX,d as DEPLOY_EVENT_TRAIL_DETAIL_MAX,u as DEPLOY_EVENT_URL_MAX,F as DEPLOY_RESULTS,RE as DESTRUCTION_FINDINGS,K as DETECTION_PHASES,DE as DRIFT_VERDICTS,D as DeployEventSchema,L as DeployResourceSchema,S as DeploymentEventSchema,oE as DestructionConsentSchema,AE as DestructionFindingSchema,aE as DestructionOutcomeSchema,tE as DestructionTicketResourceSchema,rE as DestructionTicketSchema,pE as DriftFindingSchema,CE as DriftJournalRecordSchema,LE as DriftSuspectSchema,cE as DriftVerdictSchema,Pe as INFRASTRUCTURE_FILENAME,Ce as INFRASTRUCTURE_STEP_NAMES,ne as INFRA_STEP_NAME,G as LOG_LEVELS,kE as OPENNEXT_DEPLOY_ORDER,HE as OPENNEXT_DESTROY_ORDER,BE as OPENNEXT_PARALLEL_GROUPS,re as OPENNEXT_PATTERNS,yE as ORGANISATION_TYPES,bE as PARALLEL_DEPLOY_GROUPS,vE as PARALLEL_DESTROY_GROUPS,Te as PARALLEL_OPERATION_TYPES,k as PHASE_STATUSES,v as PLAN_ACTIONS,p as PlanChangeSchema,C as PlanPropertyChangeSchema,xE as ProgressReporter,IE as REMEDIATION_PHASES,TE as REMEDIATION_VERB_GLOSS,B as REPLACEMENT_MODES,ME as RemediationFlipProofSchema,hE as RemediationJournalRecordSchema,sE as RemediationPhaseSchema,lE as RemediationTargetSchema,_E as RemediationVerbSchema,VE as RemediationVerbWithSurgerySchema,X as STACK_CLEANUP_PHASES,Re as STACK_FAILED_STATE_PATTERN,ae as STACK_NOT_FOUND_PATTERN,x as STEP_COMPLETE_STATUSES,Le as STEP_IDS,pe as STEP_NAMES,l as SUPPORTED_CONTRACT_MARKERS,c as StepProgressSchema,PE as TICKET_VERDICT_SOURCES,EE as TRAIL_MIGRATION_PHASES,eE as TRAIL_MIGRATION_STATUSES,NE as TicketVerdictSourceSchema,j as createDeployEmitter,jE as getApplicationDeployOrder,qE as getApplicationDestroyOrder,zE as getApplicationStackName,ee as getApplicationStepId,Ee as getApplicationStepName,ZE as getOrganisationStackName,QE as getParallelDeployGroups,WE as getParallelDestroyGroups,JE as isApplicationOperation,$E as isApplicationStack,te as isOpenNextPattern,wE as isOrganisationOperation,P as isQuarantineDetail,dE as isRemediationPlaceholderPhysicalId,N as isRetainedBucketsDetail,Z as parseDeployContractVersion,z as parseDeployEvent,UE as remediationPhaseRank,YE as remediationPlaceholderPhysicalId,gE as stubCallerIdentity,R as toCascadePhase,Se as toPascalCase,nE as verbsForDriftVerdict,De as wrapApplicationError};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type AppResourceFlags } from "./detection/patternTypes.js";
|
|
2
2
|
import { type StepId } from "./stepDefinitions.js";
|
|
3
3
|
import { toPascalCase } from "@fjall/util";
|
|
4
|
+
import type { PatternType } from "@fjall/generator";
|
|
4
5
|
/**
|
|
5
6
|
* Application infrastructure stacks
|
|
6
7
|
*/
|
|
@@ -157,7 +158,7 @@ export declare function getParallelDestroyGroups(): ReadonlyArray<(typeof PARALL
|
|
|
157
158
|
* Options for determining deployment order
|
|
158
159
|
*/
|
|
159
160
|
export interface DeployOrderOptions {
|
|
160
|
-
pattern?:
|
|
161
|
+
pattern?: PatternType | null;
|
|
161
162
|
resources?: AppResourceFlags;
|
|
162
163
|
}
|
|
163
164
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fjall/deploy-core",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.30.3",
|
|
4
4
|
"description": "Shared deployment engine for Fjall — used by CLI and webapp worker",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/src/index.js",
|
|
@@ -48,6 +48,7 @@
|
|
|
48
48
|
"scripts": {
|
|
49
49
|
"clean": "rm -rf ./dist ./sourcemaps",
|
|
50
50
|
"build": "npm run clean && tsc && node ../scripts/minify-dist.mjs dist",
|
|
51
|
+
"prepack": "node ../scripts/check-dist-freshness.mjs",
|
|
51
52
|
"watch": "npm run build && tsc --watch --preserveWatchOutput",
|
|
52
53
|
"watch:only": "tsc --watch --preserveWatchOutput",
|
|
53
54
|
"typecheck": "tsc --noEmit",
|
|
@@ -74,6 +75,7 @@
|
|
|
74
75
|
"@aws-sdk/client-iam": "^3.1038.0",
|
|
75
76
|
"@aws-sdk/client-identitystore": "^3.1079.0",
|
|
76
77
|
"@aws-sdk/client-kms": "^3.1065.0",
|
|
78
|
+
"@aws-sdk/client-lambda": "^3.1038.0",
|
|
77
79
|
"@aws-sdk/client-organizations": "^3.1038.0",
|
|
78
80
|
"@aws-sdk/client-ram": "^3.1038.0",
|
|
79
81
|
"@aws-sdk/client-rds": "^3.1038.0",
|
|
@@ -83,8 +85,8 @@
|
|
|
83
85
|
"@aws-sdk/client-ssm": "^3.1038.0",
|
|
84
86
|
"@aws-sdk/client-sso-admin": "^3.1038.0",
|
|
85
87
|
"@aws-sdk/client-sts": "^3.1038.0",
|
|
86
|
-
"@fjall/generator": "^2.
|
|
87
|
-
"@fjall/util": "^2.
|
|
88
|
+
"@fjall/generator": "^2.30.3",
|
|
89
|
+
"@fjall/util": "^2.30.3",
|
|
88
90
|
"@smithy/node-http-handler": "^4.6.1",
|
|
89
91
|
"aws-cdk": "^2.1128.1",
|
|
90
92
|
"tsx": "^4.21.0",
|
|
@@ -95,5 +97,5 @@
|
|
|
95
97
|
"typescript": "^6.0.3",
|
|
96
98
|
"vitest": "^4.1.5"
|
|
97
99
|
},
|
|
98
|
-
"gitHead": "
|
|
100
|
+
"gitHead": "d398edc0c0edf661d7ab6e5a47623529f68dfd2a"
|
|
99
101
|
}
|