@fjall/util 2.32.0 → 2.34.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/.minified CHANGED
@@ -1 +1 @@
1
- 86 files minified at 2026-07-16T21:23:58.809Z
1
+ 87 files minified at 2026-07-17T22:47:13.831Z
@@ -20,7 +20,7 @@
20
20
  */
21
21
  import { type BuildxBuildArgs, type BuildxBuildResult, type DockerCliError } from "./dockerCliSchemas.js";
22
22
  import { type BuildxProgressEvent, type DockerCliState, type ImagetoolsInspect, type Result } from "./DockerCli.js";
23
- export declare function _buildxBuild(state: DockerCliState, args: BuildxBuildArgs, onProgress: (event: BuildxProgressEvent) => void): Promise<Result<BuildxBuildResult, DockerCliError>>;
23
+ export declare function _buildxBuild(state: DockerCliState, args: BuildxBuildArgs, onProgress: (event: BuildxProgressEvent) => void, abortSignal?: AbortSignal): Promise<Result<BuildxBuildResult, DockerCliError>>;
24
24
  /**
25
25
  * Create one or more manifest-list tags pointing at an existing image
26
26
  * digest without re-uploading layers.
@@ -1 +1 @@
1
- import{rm as C}from"node:fs/promises";import{buildxArgvBuilder as D}from"./buildxArgvBuilder.js";import{BuildxBuildArgsSchema as k}from"./dockerCliSchemas.js";import{DEFAULT_BUILD_TIMEOUT_MS as $,DEFAULT_INSPECT_TIMEOUT_MS as w,DOCKER_CLI_BUILDX_LOG_CATEGORY as T}from"./dockerCliConstants.js";import{parseMetadataFile as B}from"./metadataFileParser.js";import{parseRawjsonLine as M}from"./rawjsonParser.js";import{rawjsonToVertexEvent as S}from"./rawjsonToVertexEvent.js";import{maskSensitiveOutput as x}from"../securityHelpers.js";import{failure as i,makeError as s,maskOutput as b,runDocker as _,spawnFailureToError as F,streamDocker as I,success as v}from"./DockerCli.js";function h(o){return o instanceof Error?o.message:String(o)}async function H(o,u,t){const r=k.safeParse(u);if(!r.success){const a=x(r.error.message);return i(s("validation",`Invalid BuildxBuildArgs: ${a}`,{issues:r.error.issues}))}const l=D(r.data);let n=0,g=0;const d=new Set,f=a=>{const m=M(a);if(m===null){a.trim()!==""&&o.logger.debug(T,"Skipping malformed rawjson line",{line:x(a)});return}const c=S(m);if(c!==null){for(const e of c.vertexes)e.completed!==void 0&&!d.has(e.digest)&&(d.add(e.digest),e.cached===!0?n++:g++),t({type:"vertex",message:b(e.name),vertex:e.digest});for(const e of c.logs)t({type:"log",message:b(e.data),vertex:e.vertex});for(const e of c.statuses)t({type:"status",message:b(`${e.name} ${e.current}`),vertex:e.vertex});for(const e of c.warnings)t({type:"warning",message:b(e.short),vertex:e.vertex})}};let p;try{p=r.data.metadataFile;const a=await I(o,{args:l,timeoutMs:$},f);if(a.spawnError!==void 0)return i(s("daemon_unreachable",`Docker CLI is not available: ${a.spawnError}`,{stderrTail:a.stderrTail}));if(a.aborted||a.exitCode===null)return i(s("abort","docker buildx build was aborted",{stderrTail:a.stderrTail}));if(a.exitCode!==0)return i(s("build_failed",`docker buildx build failed (exit ${a.exitCode})`,{stderrTail:a.stderrTail}));const m=await B(r.data.metadataFile);if(!m.success)return m;const c=m.data,e=c["containerimage.digest"];if(typeof e!="string"||e==="")return i(s("metadata_missing_digest","Buildx metadata file does not contain containerimage.digest",{metadataFile:r.data.metadataFile}));const y={};for(const E of r.data.tags)y[E]=e;return v({digest:e,imageDigests:y,metadata:c,platforms:r.data.platforms,cacheHits:n,cacheMisses:g})}finally{p!==void 0&&await C(p,{force:!0}).catch(a=>{o.logger.warn(T,"Failed to clean up buildx metadata file",{path:p,error:x(h(a))})})}}async function K(o,u,t,r){if(u.trim()==="")return i(s("validation","tagByDigest: sourceImage must be non-empty"));if(!t.startsWith("sha256:"))return i(s("validation",`tagByDigest: expected sha256:... digest, got ${t.slice(0,32)}`));if(r.length===0)return i(s("validation","tagByDigest: tags must be a non-empty list"));for(const f of r)if(typeof f!="string"||f.trim()==="")return i(s("validation","tagByDigest: every tag must be non-empty"));const l=`${u}@${t}`,n=[];for(const f of r)n.push("--tag",f);const g=["buildx","imagetools","create",...n,l],d=await _(o,{args:g,timeoutMs:w});return d.spawnError!==void 0?i(F(d)):d.exitCode===null?i(s("abort",`docker buildx imagetools create for ${l} was aborted`,{stderrTail:d.stderrTail})):d.exitCode!==0?i(s("tag_failed",`docker buildx imagetools create for ${l} failed (exit ${d.exitCode})`,{stderrTail:d.stderrTail})):v(void 0)}async function V(o,u){const t=await _(o,{args:["buildx","imagetools","inspect",u,"--raw"],timeoutMs:w});if(t.spawnError!==void 0)return i(s("daemon_unreachable",`Docker CLI is not available: ${t.spawnError}`,{stderrTail:t.stderrTail}));if(t.exitCode===null)return i(s("abort",`docker buildx imagetools inspect ${u} was aborted`,{stderrTail:t.stderrTail}));if(t.exitCode!==0)return i(s("inspect_failed",`docker buildx imagetools inspect ${u} failed (exit ${t.exitCode})`,{stderrTail:t.stderrTail}));let r,l;try{const n=JSON.parse(t.stdout);typeof n.mediaType=="string"&&(r=n.mediaType),typeof n.digest=="string"&&(l=n.digest)}catch(n){o.logger.debug(T,"imagetools inspect output is not JSON; preserving raw",{error:x(h(n))})}return v({raw:t.stdout,...r!==void 0&&{mediaType:r},...l!==void 0&&{digest:l}})}export{H as _buildxBuild,V as _imagetoolsInspect,K as _tagByDigest};
1
+ import{rm as L}from"node:fs/promises";import{buildxArgvBuilder as A}from"./buildxArgvBuilder.js";import{BuildxBuildArgsSchema as R}from"./dockerCliSchemas.js";import{DEFAULT_INSPECT_TIMEOUT_MS as S,DOCKER_CLI_BUILDX_LOG_CATEGORY as B}from"./dockerCliConstants.js";import{BuildxBuildMonitor as j,buildPhaseTimeoutMessage as N,publishStallTimeoutMessage as U,resolveBuildxBudgets as G}from"./buildxBuildMonitor.js";import{parseMetadataFile as J}from"./metadataFileParser.js";import{parseRawjsonLine as P}from"./rawjsonParser.js";import{rawjsonToVertexEvent as H}from"./rawjsonToVertexEvent.js";import{maskSensitiveOutput as x}from"../securityHelpers.js";import{failure as t,makeError as a,maskOutput as b,runDocker as M,spawnFailureToError as K,streamDocker as V,success as C}from"./DockerCli.js";function F(s){return s instanceof Error?s.message:String(s)}async function ae(s,c,e,l){const r=R.safeParse(c);if(!r.success){const n=x(r.error.message);return t(a("validation",`Invalid BuildxBuildArgs: ${n}`,{issues:r.error.issues}))}const o=G(s.env);if(!o.success)return t(a("validation",x(o.error.message)));const g=o.data,u=A(r.data);let f=0,_=0;const k=new Set;let w,T;try{const n=new j(g);w=n,T=r.data.metadataFile;const O=p=>{const D=P(p);if(D===null){p.trim()!==""&&s.logger.debug(B,"Skipping malformed rawjson line",{line:x(p)});return}const m=H(D);if(m===null)return;const y=n.observe(m);y!==void 0&&e({type:"status",message:b(y.message),...y.percentage!==void 0&&{percentage:y.percentage}});for(const i of m.vertexes)i.completed!==void 0&&!k.has(i.digest)&&(k.add(i.digest),i.cached===!0?f++:_++),e({type:"vertex",message:b(i.name),vertex:i.digest});for(const i of m.logs)e({type:"log",message:b(i.data),vertex:i.vertex});for(const i of m.statuses)e({type:"status",message:b(`${i.name} ${i.current}`),vertex:i.vertex});for(const i of m.warnings)e({type:"warning",message:b(i.short),vertex:i.vertex})},I=l!==void 0?AbortSignal.any([n.signal,l]):n.signal,d=await V(s,{args:u,abortSignal:I},O);if(d.spawnError!==void 0)return t(a("daemon_unreachable",`Docker CLI is not available: ${d.spawnError}`,{stderrTail:d.stderrTail}));if(d.aborted||d.exitCode===null)return n.timedOutPhase==="build"?t(a("timeout",N(g),{stderrTail:d.stderrTail})):n.timedOutPhase==="publish"?t(a("timeout",U(g,n.progressSummary()),{stderrTail:d.stderrTail})):t(a("abort","docker buildx build was aborted",{stderrTail:d.stderrTail}));if(d.exitCode!==0)return t(a("build_failed",`docker buildx build failed (exit ${d.exitCode})`,{stderrTail:d.stderrTail}));const h=await J(r.data.metadataFile);if(!h.success)return h;const E=h.data,v=E["containerimage.digest"];if(typeof v!="string"||v==="")return t(a("metadata_missing_digest","Buildx metadata file does not contain containerimage.digest",{metadataFile:r.data.metadataFile}));const $={};for(const p of r.data.tags)$[p]=v;return C({digest:v,imageDigests:$,metadata:E,platforms:r.data.platforms,cacheHits:f,cacheMisses:_})}finally{w!==void 0&&w.dispose(),T!==void 0&&await L(T,{force:!0}).catch(n=>{s.logger.warn(B,"Failed to clean up buildx metadata file",{path:T,error:x(F(n))})})}}async function ie(s,c,e,l){if(c.trim()==="")return t(a("validation","tagByDigest: sourceImage must be non-empty"));if(!e.startsWith("sha256:"))return t(a("validation",`tagByDigest: expected sha256:... digest, got ${e.slice(0,32)}`));if(l.length===0)return t(a("validation","tagByDigest: tags must be a non-empty list"));for(const f of l)if(typeof f!="string"||f.trim()==="")return t(a("validation","tagByDigest: every tag must be non-empty"));const r=`${c}@${e}`,o=[];for(const f of l)o.push("--tag",f);const g=["buildx","imagetools","create",...o,r],u=await M(s,{args:g,timeoutMs:S});return u.spawnError!==void 0?t(K(u)):u.exitCode===null?t(a("abort",`docker buildx imagetools create for ${r} was aborted`,{stderrTail:u.stderrTail})):u.exitCode!==0?t(a("tag_failed",`docker buildx imagetools create for ${r} failed (exit ${u.exitCode})`,{stderrTail:u.stderrTail})):C(void 0)}async function se(s,c){const e=await M(s,{args:["buildx","imagetools","inspect",c,"--raw"],timeoutMs:S});if(e.spawnError!==void 0)return t(a("daemon_unreachable",`Docker CLI is not available: ${e.spawnError}`,{stderrTail:e.stderrTail}));if(e.exitCode===null)return t(a("abort",`docker buildx imagetools inspect ${c} was aborted`,{stderrTail:e.stderrTail}));if(e.exitCode!==0)return t(a("inspect_failed",`docker buildx imagetools inspect ${c} failed (exit ${e.exitCode})`,{stderrTail:e.stderrTail}));let l,r;try{const o=JSON.parse(e.stdout);typeof o.mediaType=="string"&&(l=o.mediaType),typeof o.digest=="string"&&(r=o.digest)}catch(o){s.logger.debug(B,"imagetools inspect output is not JSON; preserving raw",{error:x(F(o))})}return C({raw:e.stdout,...l!==void 0&&{mediaType:l},...r!==void 0&&{digest:r}})}export{ae as _buildxBuild,se as _imagetoolsInspect,ie as _tagByDigest};
@@ -52,6 +52,9 @@ export interface BuildxProgressEvent {
52
52
  readonly type: "vertex" | "log" | "status" | "warning";
53
53
  readonly message: string;
54
54
  readonly vertex?: string;
55
+ /** Aggregate publish-phase completion (0–100); only on the synthetic
56
+ * push-progress events emitted by the buildx monitor. */
57
+ readonly percentage?: number;
55
58
  }
56
59
  export interface PushProgressEvent {
57
60
  readonly id: string;
@@ -91,7 +94,7 @@ export interface DaemonInfo {
91
94
  export declare class DockerCli {
92
95
  private readonly state;
93
96
  constructor(opts: DockerCliOptions);
94
- buildxBuild(args: BuildxBuildArgs, onProgress: (event: BuildxProgressEvent) => void): Promise<Result<BuildxBuildResult, DockerCliError>>;
97
+ buildxBuild(args: BuildxBuildArgs, onProgress: (event: BuildxProgressEvent) => void, abortSignal?: AbortSignal): Promise<Result<BuildxBuildResult, DockerCliError>>;
95
98
  tag(source: string, target: string): Promise<Result<void, DockerCliError>>;
96
99
  /**
97
100
  * Create one or more manifest-list tags pointing at a previously pushed
@@ -141,6 +144,9 @@ export interface SpawnDockerOptions {
141
144
  readonly args: readonly string[];
142
145
  readonly stdin?: string;
143
146
  readonly timeoutMs?: number;
147
+ /** Extra caller-owned signal (e.g. a phase watchdog), composed with the
148
+ * instance signal and `timeoutMs`. */
149
+ readonly abortSignal?: AbortSignal;
144
150
  }
145
151
  export interface SpawnDockerResult {
146
152
  readonly exitCode: number | null;
@@ -1 +1 @@
1
- import{spawn as h}from"node:child_process";import{filterDangerousEnvVars as k,maskSensitiveOutput as E}from"../securityHelpers.js";import{abortChildProcess as b}from"./abortHelpers.js";import{DEFAULT_DOCKER_BIN as A,DOCKER_CLI_LOG_CATEGORY as x,STDERR_TAIL_LINE_MAX_CHARS as y,STDERR_TAIL_LINES as S}from"./dockerCliConstants.js";import{_buildxBuild as D,_imagetoolsInspect as C,_tagByDigest as I}from"./DockerCli.build.js";import{_assertBuildxAvailable as L,_detectDaemon as R,_ensureBuilder as O}from"./DockerCli.daemon.js";import{_imageInspect as P,_loginEcr as N,_pull as F,_push as G,_tag as K}from"./DockerCli.registry.js";import{failure as v,success as j}from"./result.js";class Q{state;constructor(e){const r=e.dockerBin!==void 0&&e.dockerBin!==""?e.dockerBin:A,n=k(e.env??process.env);this.state={logger:e.logger,dockerBin:r,env:n,abortSignal:e.abortSignal,ecrSession:void 0}}async buildxBuild(e,r){return D(this.state,e,r)}async tag(e,r){return K(this.state,e,r)}async tagByDigest(e,r,n){return I(this.state,e,r,n)}async push(e,r){return G(this.state,e,r)}async pull(e,r,n){return F(this.state,e,r,n)}async imageInspect(e){return P(this.state,e)}async imagetoolsInspect(e){return C(this.state,e)}async loginEcr(e){return N(this.state,e)}async logoutEcr(){const e=this.state.ecrSession;this.state.ecrSession=void 0,e!==void 0&&await e.dispose()}async withEcrSession(e,r,n){const o=await this.loginEcr(e);if(!o.success)return v(n(o.error));try{return await r()}finally{await this.logoutEcr().catch(()=>{})}}async ensureBuilder(e){return O(this.state,e)}async assertBuildxAvailable(){return L(this.state)}async detectDaemon(){return R(this.state)}}function H(t){const e=E(t);return e.length>y?e.slice(0,y)+"\u2026":e}function U(t,e,r){let n,o=r;if(r!==void 0&&Array.isArray(r.stderrTail)&&r.stderrTail.every(a=>typeof a=="string")){n=r.stderrTail.map(H);const{stderrTail:a,...s}=r;o=Object.keys(s).length>0?s:void 0}return{kind:t,message:e,...n!==void 0&&{stderrTail:n},...o!==void 0&&{details:o}}}function W(t){return U("daemon_unreachable",`Docker CLI is not available: ${t.spawnError??"unknown spawn failure"}`,{stderrTail:t.stderrTail})}function _(t,e){if(t==="")return[];const r=t.split(/\r?\n/);for(;r.length>0&&r[r.length-1]==="";)r.pop();return r.slice(-e)}function Z(t){return E(t)}function T(t){return t.ecrSession!==void 0?{...t.env,...t.ecrSession.env}:t.env}function ee(t,e){return new Promise(r=>{let n=!1,o=!1;const a=w(t.abortSignal,e.timeoutMs);let s;try{s=h(t.dockerBin,e.args,{shell:!1,env:T(t)})}catch(i){const d=i instanceof Error?i.message:String(i);r({exitCode:null,stdout:"",stderr:d,stderrTail:[d],aborted:!1,spawnError:d});return}let c="",l="";s.stdout?.on("data",i=>{c+=i.toString()}),s.stderr?.on("data",i=>{l+=i.toString()}),e.stdin!==void 0&&(s.stdin?.on("error",i=>{t.logger.debug(x,"stdin write error (typically EPIPE on early child exit)",{error:i.message})}),s.stdin?.write(e.stdin),s.stdin?.end());const g=()=>{n=!0,b(s)};a!==void 0&&(a.aborted?g():a.addEventListener("abort",g,{once:!0})),s.once("error",i=>{if(o)return;o=!0,a!==void 0&&a.removeEventListener("abort",g);const d=i instanceof Error?i.message:String(i);r({exitCode:null,stdout:c,stderr:d,stderrTail:[d],aborted:n,spawnError:d})}),s.once("close",i=>{o||(o=!0,a!==void 0&&a.removeEventListener("abort",g),r({exitCode:i,stdout:c,stderr:l,stderrTail:_(l,S),aborted:n}))})})}function re(t,e,r,n){return new Promise(o=>{let a=!1,s=!1;const c=w(t.abortSignal,e.timeoutMs);let l;try{l=h(t.dockerBin,e.args,{shell:!1,env:T(t)})}catch(u){const f=u instanceof Error?u.message:String(u);o({exitCode:null,stderrTail:[f],aborted:!1,spawnError:f,child:null});return}let g="",i="",d="";l.stdout?.on("data",u=>{g+=u.toString();const f=g.split(/\r?\n/);g=f.pop()??"";for(const p of f)r(p)}),l.stderr?.on("data",u=>{const f=u.toString();if(i+=f,n!==void 0){d+=f;const p=d.split(/\r?\n/);d=p.pop()??"";for(const B of p)n(B)}});const m=()=>{a=!0,b(l)};c!==void 0&&(c.aborted?m():c.addEventListener("abort",m,{once:!0})),l.once("error",u=>{if(s)return;s=!0,c!==void 0&&c.removeEventListener("abort",m);const f=u instanceof Error?u.message:String(u);o({exitCode:null,stderrTail:[f],aborted:a,spawnError:f,child:l})}),l.once("close",u=>{s||(s=!0,g!==""&&r(g),n!==void 0&&d!==""&&n(d),c!==void 0&&c.removeEventListener("abort",m),o({exitCode:u,stderrTail:_(i,S),aborted:a,child:l}))})})}function w(t,e){if(!(t===void 0&&e===void 0))return t===void 0?AbortSignal.timeout(e):e===void 0?t:AbortSignal.any([t,AbortSignal.timeout(e)])}export{Q as DockerCli,v as failure,U as makeError,Z as maskOutput,ee as runDocker,W as spawnFailureToError,re as streamDocker,j as success,_ as tailLines};
1
+ import{spawn as h}from"node:child_process";import{filterDangerousEnvVars as k,maskSensitiveOutput as E}from"../securityHelpers.js";import{abortChildProcess as b}from"./abortHelpers.js";import{DEFAULT_DOCKER_BIN as x,DOCKER_CLI_LOG_CATEGORY as A,STDERR_TAIL_LINE_MAX_CHARS as y,STDERR_TAIL_LINES as S}from"./dockerCliConstants.js";import{_buildxBuild as D,_imagetoolsInspect as C,_tagByDigest as I}from"./DockerCli.build.js";import{_assertBuildxAvailable as L,_detectDaemon as R,_ensureBuilder as O}from"./DockerCli.daemon.js";import{_imageInspect as P,_loginEcr as N,_pull as F,_push as G,_tag as K}from"./DockerCli.registry.js";import{failure as v,success as M}from"./result.js";class Q{state;constructor(e){const r=e.dockerBin!==void 0&&e.dockerBin!==""?e.dockerBin:x,t=k(e.env??process.env);this.state={logger:e.logger,dockerBin:r,env:t,abortSignal:e.abortSignal,ecrSession:void 0}}async buildxBuild(e,r,t){return D(this.state,e,r,t)}async tag(e,r){return K(this.state,e,r)}async tagByDigest(e,r,t){return I(this.state,e,r,t)}async push(e,r){return G(this.state,e,r)}async pull(e,r,t){return F(this.state,e,r,t)}async imageInspect(e){return P(this.state,e)}async imagetoolsInspect(e){return C(this.state,e)}async loginEcr(e){return N(this.state,e)}async logoutEcr(){const e=this.state.ecrSession;this.state.ecrSession=void 0,e!==void 0&&await e.dispose()}async withEcrSession(e,r,t){const o=await this.loginEcr(e);if(!o.success)return v(t(o.error));try{return await r()}finally{await this.logoutEcr().catch(()=>{})}}async ensureBuilder(e){return O(this.state,e)}async assertBuildxAvailable(){return L(this.state)}async detectDaemon(){return R(this.state)}}function j(n){const e=E(n);return e.length>y?e.slice(0,y)+"\u2026":e}function H(n,e,r){let t,o=r;if(r!==void 0&&Array.isArray(r.stderrTail)&&r.stderrTail.every(a=>typeof a=="string")){t=r.stderrTail.map(j);const{stderrTail:a,...i}=r;o=Object.keys(i).length>0?i:void 0}return{kind:n,message:e,...t!==void 0&&{stderrTail:t},...o!==void 0&&{details:o}}}function W(n){return H("daemon_unreachable",`Docker CLI is not available: ${n.spawnError??"unknown spawn failure"}`,{stderrTail:n.stderrTail})}function _(n,e){if(n==="")return[];const r=n.split(/\r?\n/);for(;r.length>0&&r[r.length-1]==="";)r.pop();return r.slice(-e)}function Z(n){return E(n)}function T(n){return n.ecrSession!==void 0?{...n.env,...n.ecrSession.env}:n.env}function ee(n,e){return new Promise(r=>{let t=!1,o=!1;const a=w(n.abortSignal,e.timeoutMs,e.abortSignal);let i;try{i=h(n.dockerBin,e.args,{shell:!1,env:T(n)})}catch(s){const d=s instanceof Error?s.message:String(s);r({exitCode:null,stdout:"",stderr:d,stderrTail:[d],aborted:!1,spawnError:d});return}let c="",l="";i.stdout?.on("data",s=>{c+=s.toString()}),i.stderr?.on("data",s=>{l+=s.toString()}),e.stdin!==void 0&&(i.stdin?.on("error",s=>{n.logger.debug(A,"stdin write error (typically EPIPE on early child exit)",{error:s.message})}),i.stdin?.write(e.stdin),i.stdin?.end());const g=()=>{t=!0,b(i)};a!==void 0&&(a.aborted?g():a.addEventListener("abort",g,{once:!0})),i.once("error",s=>{if(o)return;o=!0,a!==void 0&&a.removeEventListener("abort",g);const d=s instanceof Error?s.message:String(s);r({exitCode:null,stdout:c,stderr:d,stderrTail:[d],aborted:t,spawnError:d})}),i.once("close",s=>{o||(o=!0,a!==void 0&&a.removeEventListener("abort",g),r({exitCode:s,stdout:c,stderr:l,stderrTail:_(l,S),aborted:t}))})})}function re(n,e,r,t){return new Promise(o=>{let a=!1,i=!1;const c=w(n.abortSignal,e.timeoutMs,e.abortSignal);let l;try{l=h(n.dockerBin,e.args,{shell:!1,env:T(n)})}catch(u){const f=u instanceof Error?u.message:String(u);o({exitCode:null,stderrTail:[f],aborted:!1,spawnError:f,child:null});return}let g="",s="",d="";l.stdout?.on("data",u=>{g+=u.toString();const f=g.split(/\r?\n/);g=f.pop()??"";for(const p of f)r(p)}),l.stderr?.on("data",u=>{const f=u.toString();if(s+=f,t!==void 0){d+=f;const p=d.split(/\r?\n/);d=p.pop()??"";for(const B of p)t(B)}});const m=()=>{a=!0,b(l)};c!==void 0&&(c.aborted?m():c.addEventListener("abort",m,{once:!0})),l.once("error",u=>{if(i)return;i=!0,c!==void 0&&c.removeEventListener("abort",m);const f=u instanceof Error?u.message:String(u);o({exitCode:null,stderrTail:[f],aborted:a,spawnError:f,child:l})}),l.once("close",u=>{i||(i=!0,g!==""&&r(g),t!==void 0&&d!==""&&t(d),c!==void 0&&c.removeEventListener("abort",m),o({exitCode:u,stderrTail:_(s,S),aborted:a,child:l}))})})}function w(n,e,r){const t=[];if(n!==void 0&&t.push(n),r!==void 0&&t.push(r),e!==void 0&&t.push(AbortSignal.timeout(e)),t.length!==0)return t.length===1?t[0]:AbortSignal.any(t)}export{Q as DockerCli,v as failure,H as makeError,Z as maskOutput,ee as runDocker,W as spawnFailureToError,re as streamDocker,M as success,_ as tailLines};
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Phase-aware watchdog + push-progress aggregator for one buildx invocation.
3
+ *
4
+ * A single fixed timeout over the whole `docker buildx build --push` run
5
+ * conflates two phases with opposite failure profiles: the compile phase
6
+ * (bounded work, a hang means a broken toolchain) and the publish phase
7
+ * (image push + registry cache export, whose duration scales with layer
8
+ * size and uplink speed — a dep-bump build re-uploads multi-GB layers and
9
+ * legitimately pushes for 25+ minutes). Three incidents (2026-07-06,
10
+ * 2026-07-16 ×2) killed healthy deploys mid-push at the old whole-run cap.
11
+ *
12
+ * Split budgets:
13
+ * - Compile phase: absolute budget (`FJALL_BUILD_TIMEOUT_MS`, default
14
+ * `DEFAULT_BUILD_TIMEOUT_MS`). Runs from spawn until the exporter
15
+ * starts. SBOM/provenance generation is deliberately part of this
16
+ * phase — it is compute, not upload.
17
+ * - Publish phase: reset-on-progress stall budget
18
+ * (`FJALL_PUSH_STALL_TIMEOUT_MS`, default
19
+ * `DEFAULT_PUSH_STALL_TIMEOUT_MS`). A push that keeps making progress
20
+ * is never killed, however long it takes; a genuinely hung push
21
+ * (dead network, wedged registry) goes quiet and trips the budget.
22
+ *
23
+ * "Progress" means a CHANGE in the rawjson stream — a status whose
24
+ * current/total/completed moved, a vertex that started/completed, a log
25
+ * or warning line. A re-emitted status with identical numbers does not
26
+ * reset the stall budget, so a heartbeating-but-stuck buildkit still
27
+ * times out.
28
+ */
29
+ import type { RawjsonVertexEvent } from "./rawjsonToVertexEvent.js";
30
+ import { type Result } from "./result.js";
31
+ export declare const BUILD_TIMEOUT_ENV_VAR = "FJALL_BUILD_TIMEOUT_MS";
32
+ export declare const PUSH_STALL_TIMEOUT_ENV_VAR = "FJALL_PUSH_STALL_TIMEOUT_MS";
33
+ export interface BuildxBudgets {
34
+ readonly compilePhaseTimeoutMs: number;
35
+ readonly publishStallTimeoutMs: number;
36
+ }
37
+ export type BuildxTimeoutPhase = "build" | "publish";
38
+ export interface SyntheticBuildxProgress {
39
+ readonly message: string;
40
+ readonly percentage?: number;
41
+ }
42
+ /**
43
+ * Resolve the two buildx budgets from the environment. Fails (rather than
44
+ * falling back) on an empty or malformed override.
45
+ */
46
+ export declare function resolveBuildxBudgets(env: NodeJS.ProcessEnv): Result<BuildxBudgets, Error>;
47
+ export declare class BuildxBuildMonitor {
48
+ private readonly budgets;
49
+ private readonly controller;
50
+ private readonly now;
51
+ private compileTimer;
52
+ private stallTimer;
53
+ private lastActivityAt;
54
+ private lastEmitAt;
55
+ private lastEmitMessage;
56
+ private pendingPhaseFlipMessage;
57
+ private publishStartedFlag;
58
+ private disposed;
59
+ private timedOutPhaseValue;
60
+ /** Last-seen numbers per status, keyed `vertex|id` — change detection. */
61
+ private readonly statusMemos;
62
+ /** Last-seen start/complete/error stamp per vertex digest. */
63
+ private readonly vertexStamps;
64
+ /** Transfer statuses only (push + cache write) — progress aggregation. */
65
+ private readonly transfers;
66
+ constructor(budgets: BuildxBudgets, opts?: {
67
+ readonly now?: () => number;
68
+ });
69
+ get signal(): AbortSignal;
70
+ get timedOutPhase(): BuildxTimeoutPhase | undefined;
71
+ get publishStarted(): boolean;
72
+ /**
73
+ * Feed one normalised rawjson event. Returns a throttled synthetic
74
+ * progress message for the publish phase (or the one-off phase-flip
75
+ * message), when one is due. No-op after `dispose()` (including a
76
+ * watchdog trip) — a late-flushed line must not re-arm a timer that
77
+ * nothing will clear.
78
+ */
79
+ observe(event: RawjsonVertexEvent): SyntheticBuildxProgress | undefined;
80
+ /**
81
+ * Human-readable snapshot of how far the publish got — for the stall
82
+ * error message. Undefined until a transfer status has been observed.
83
+ */
84
+ progressSummary(): string | undefined;
85
+ dispose(): void;
86
+ private aggregateTransfers;
87
+ private maybeSyntheticProgress;
88
+ private beginPublishPhase;
89
+ private armStallTimer;
90
+ private clearStallTimer;
91
+ private trip;
92
+ }
93
+ export declare function buildPhaseTimeoutMessage(budgets: BuildxBudgets): string;
94
+ export declare function publishStallTimeoutMessage(budgets: BuildxBudgets, summary: string | undefined): string;
@@ -0,0 +1 @@
1
+ import{DEFAULT_BUILD_TIMEOUT_MS as g,DEFAULT_PUSH_STALL_TIMEOUT_MS as T}from"./dockerCliConstants.js";import{failure as h,success as u}from"./result.js";const d="FJALL_BUILD_TIMEOUT_MS",m="FJALL_PUSH_STALL_TIMEOUT_MS",c=2147483647,M=2e3;function f(r,e,t){const i=r[e];if(i===void 0)return u(t);if(!/^\d+$/.test(i)||parseInt(i,10)<=0)return h(new Error(`${e} must be a positive integer number of milliseconds (got ${JSON.stringify(i)}) \u2014 fix or unset it (default ${t} ms)`));const s=parseInt(i,10);return s>c?h(new Error(`${e} must be at most ${c} ms (got ${s})`)):u(s)}function w(r){const e=f(r,d,g);if(!e.success)return e;const t=f(r,m,T);return t.success?u({compilePhaseTimeoutMs:e.data,publishStallTimeoutMs:t.data}):t}function b(r){const e=r.toLowerCase();return e.startsWith("exporting")||e.startsWith("pushing")}function y(r){const e=r.toLowerCase();return e.startsWith("pushing")||e.startsWith("writing layer")}function l(r){const e=["B","kB","MB","GB","TB"];let t=r,i=0;for(;t>=1e3&&i<e.length-1;)t/=1e3,i+=1;return`${t.toFixed(t<10&&i>0?1:0)} ${e[i]}`}class _{budgets;controller=new AbortController;now;compileTimer;stallTimer;lastActivityAt;lastEmitAt;lastEmitMessage;pendingPhaseFlipMessage;publishStartedFlag=!1;disposed=!1;timedOutPhaseValue;statusMemos=new Map;vertexStamps=new Map;transfers=new Map;constructor(e,t){this.budgets=e,this.now=t?.now??Date.now,this.lastActivityAt=this.now(),this.compileTimer=setTimeout(()=>{this.trip("build")},e.compilePhaseTimeoutMs)}get signal(){return this.controller.signal}get timedOutPhase(){return this.timedOutPhaseValue}get publishStarted(){return this.publishStartedFlag}observe(e){if(this.disposed)return;let t=!1,i=!1;for(const s of e.vertexes){const n=`${s.started??""}|${s.completed??""}|${s.error??""}`;this.vertexStamps.get(s.digest)!==n&&(this.vertexStamps.set(s.digest,n),t=!0),s.started!==void 0&&b(s.name)&&(i=!0)}for(const s of e.statuses){const n=`${s.vertex}|${s.id}`,a=this.statusMemos.get(n),o={current:s.current,total:s.total,completed:s.completed!==void 0};(a===void 0||a.current!==o.current||a.total!==o.total||a.completed!==o.completed)&&(this.statusMemos.set(n,o),t=!0),y(s.name)&&(i=!0,this.transfers.set(n,o))}return(e.logs.length>0||e.warnings.length>0)&&(t=!0),i&&!this.publishStartedFlag&&this.beginPublishPhase(),t&&(this.lastActivityAt=this.now()),this.maybeSyntheticProgress()}progressSummary(){if(this.transfers.size===0)return;const e=this.aggregateTransfers(),t=`${e.completedTransfers}/${e.knownTransfers} layers complete`;if(e.totalBytes>0){const i=Math.min(100,Math.round(e.currentBytes/e.totalBytes*100));return`${l(e.currentBytes)} of ${l(e.totalBytes)} pushed (${i}%), ${t}`}return`${l(e.currentBytes)} pushed, ${t}`}dispose(){this.disposed=!0,this.compileTimer!==void 0&&(clearTimeout(this.compileTimer),this.compileTimer=void 0),this.clearStallTimer()}aggregateTransfers(){let e=0,t=0,i=0;for(const s of this.transfers.values())s.total!==void 0&&s.total>0?(t+=s.total,e+=Math.min(s.current,s.total)):e+=s.current,s.completed&&(i+=1);return{currentBytes:e,totalBytes:t,completedTransfers:i,knownTransfers:this.transfers.size}}maybeSyntheticProgress(){if(this.pendingPhaseFlipMessage!==void 0){const a=this.pendingPhaseFlipMessage;return this.pendingPhaseFlipMessage=void 0,this.lastEmitAt=this.now(),{message:a}}if(!this.publishStartedFlag||this.transfers.size===0)return;const e=this.now();if(this.lastEmitAt!==void 0&&e-this.lastEmitAt<M)return;const t=this.aggregateTransfers(),i=`${t.completedTransfers}/${t.knownTransfers} layers`;let s,n;if(t.totalBytes>0?(n=Math.min(100,Math.round(t.currentBytes/t.totalBytes*100)),s=`Pushing to registry: ${l(t.currentBytes)} of ${l(t.totalBytes)} \u2014 ${i}`):s=`Pushing to registry: ${l(t.currentBytes)} transferred \u2014 ${i}`,s!==this.lastEmitMessage)return this.lastEmitAt=e,this.lastEmitMessage=s,{message:s,...n!==void 0&&{percentage:n}}}beginPublishPhase(){this.publishStartedFlag=!0,this.compileTimer!==void 0&&(clearTimeout(this.compileTimer),this.compileTimer=void 0),this.lastActivityAt=this.now(),this.armStallTimer(this.budgets.publishStallTimeoutMs),this.pendingPhaseFlipMessage="Image build complete \u2014 pushing image and exporting build cache to the registry\u2026"}armStallTimer(e){this.clearStallTimer(),this.stallTimer=setTimeout(()=>{this.stallTimer=void 0;const t=this.now()-this.lastActivityAt;t>=this.budgets.publishStallTimeoutMs?this.trip("publish"):this.armStallTimer(this.budgets.publishStallTimeoutMs-t)},e)}clearStallTimer(){this.stallTimer!==void 0&&(clearTimeout(this.stallTimer),this.stallTimer=void 0)}trip(e){this.timedOutPhaseValue===void 0&&(this.timedOutPhaseValue=e,this.dispose(),this.controller.abort())}}function p(r){const e=r/6e4;return`${Number.isInteger(e)?e:e.toFixed(1)} minute${e===1?"":"s"}`}function P(r){return`docker buildx build exceeded the ${p(r.compilePhaseTimeoutMs)} build budget before the image finished compiling \u2014 nothing was pushed. If this build legitimately needs longer, set ${d} to a higher millisecond value.`}function A(r,e){const t=e!==void 0?`Progress before the stall: ${e}.`:"No upload progress was observed.";return`docker buildx push stalled \u2014 no upload progress for ${p(r.publishStallTimeoutMs)} while pushing the image and exporting the build cache. ${t} The image compiled successfully, so retrying is cheap: layers already pushed are deduplicated by the registry and the build cache is warm. If your connection is slow with long quiet spells, set ${m} to a higher millisecond value.`}export{d as BUILD_TIMEOUT_ENV_VAR,_ as BuildxBuildMonitor,m as PUSH_STALL_TIMEOUT_ENV_VAR,P as buildPhaseTimeoutMessage,A as publishStallTimeoutMessage,w as resolveBuildxBudgets};
@@ -8,8 +8,57 @@
8
8
  * resource (see code-quality.md § "Runtime resource names must match the CDK
9
9
  * construct's derivation" — same rule, orchestrator↔orchestrator seam).
10
10
  */
11
+ import { type Result } from "./result.js";
11
12
  /** `<repositoryName>-cache`; `repositoryName` is the kebab-case app repo name. */
12
13
  export declare function buildCacheRepositoryName(repositoryName: string): string;
14
+ export declare const BUILD_CACHE_MODE_ENV_VAR = "FJALL_BUILD_CACHE_MODE";
15
+ export declare const BUILD_CACHE_MODES: readonly ["max", "min", "off"];
16
+ export type BuildCacheMode = (typeof BUILD_CACHE_MODES)[number];
17
+ /**
18
+ * Resolve the registry cache-export mode from the environment. `max`
19
+ * (default) exports every intermediate layer — the cross-machine win for
20
+ * multi-stage npm Dockerfiles, whose valuable cache entries are the
21
+ * dependency-stage layers that `min` would drop. `min` exports final-stage
22
+ * layers only; `off` skips `--cache-to` entirely (`--cache-from` still
23
+ * reads any existing cache). Escape hatch for slow uplinks where the
24
+ * dep-bump double upload (image push + mode=max export) is not worth the
25
+ * cross-machine reuse — trade-off recorded in
26
+ * aiDocs/decisions/2026-07-17-buildx-cache-export-mode.md.
27
+ *
28
+ * Fails (rather than falling back) on an empty or unrecognised value.
29
+ */
30
+ export declare function resolveBuildCacheMode(env: NodeJS.ProcessEnv): Result<BuildCacheMode, Error>;
31
+ export interface RegistryCacheRefsInput {
32
+ /**
33
+ * Full URI of the app's `<repo>-cache` sibling ECR repository, or undefined
34
+ * when the caller has no cache repo provisioned (refs are skipped entirely).
35
+ */
36
+ readonly cacheRepoUri: string | undefined;
37
+ readonly appName: string;
38
+ /** Per-service cache tag within a shared app cache repo, when building one service of many. */
39
+ readonly serviceName?: string | undefined;
40
+ readonly mode: BuildCacheMode;
41
+ }
42
+ export interface RegistryCacheRefs {
43
+ readonly cacheFrom: string[];
44
+ readonly cacheTo?: string[];
45
+ }
46
+ /**
47
+ * Build the buildx `--cache-from`/`--cache-to` registry refs for an app
48
+ * service. The CLI provider (`@fjall/cli` CliDockerProvider) and the deploy
49
+ * worker (webapp `workerDockerProvider`) build against the SAME physical
50
+ * cache repo and tags — a cache exported by one machine must be importable
51
+ * by the other, so the tag derivation and ref syntax are a cross-repo
52
+ * coupled value (code-quality.md § "Coupled values") and live here only.
53
+ *
54
+ * The tag is `(serviceName ?? appName).toLowerCase()` — existing cache tags
55
+ * are already in this form, so changing the derivation would orphan every
56
+ * cache pushed to date.
57
+ *
58
+ * `off` drops `--cache-to` but keeps `--cache-from`: reading an existing
59
+ * cache costs nothing and only speeds the build up.
60
+ */
61
+ export declare function buildRegistryCacheRefs(input: RegistryCacheRefsInput): RegistryCacheRefs | undefined;
13
62
  /**
14
63
  * Days before untagged cache layers expire. Buildx registry-cache writes leave
15
64
  * untagged image layers behind on every push; both provisioners apply the same
@@ -1 +1 @@
1
- function t(e){return`${e}-cache`}const n=14;function i(e){return JSON.stringify({rules:[{rulePriority:1,description:`Expire untagged images after ${e} days`,selection:{tagStatus:"untagged",countType:"sinceImagePushed",countUnit:"days",countNumber:e},action:{type:"expire"}}]})}export{n as CACHE_REPO_UNTAGGED_RETENTION_DAYS,t as buildCacheRepositoryName,i as untaggedLifecyclePolicyText};
1
+ import{failure as i,success as o}from"./result.js";function u(e){return`${e}-cache`}const n="FJALL_BUILD_CACHE_MODE",c=["max","min","off"],s=new Set(c);function f(e){const r=e[n];return r===void 0?o("max"):s.has(r)?o(r):i(new Error(`${n} must be one of ${c.join(", ")} (got ${JSON.stringify(r)}) \u2014 fix or unset it`))}function d(e){if(e.cacheRepoUri===void 0)return;const r=(e.serviceName??e.appName).toLowerCase(),t=`type=registry,ref=${e.cacheRepoUri}:${r}`;return{cacheFrom:[t],...e.mode!=="off"&&{cacheTo:[`${t},mode=${e.mode}`]}}}const m=14;function E(e){return JSON.stringify({rules:[{rulePriority:1,description:`Expire untagged images after ${e} days`,selection:{tagStatus:"untagged",countType:"sinceImagePushed",countUnit:"days",countNumber:e},action:{type:"expire"}}]})}export{c as BUILD_CACHE_MODES,n as BUILD_CACHE_MODE_ENV_VAR,m as CACHE_REPO_UNTAGGED_RETENTION_DAYS,u as buildCacheRepositoryName,d as buildRegistryCacheRefs,f as resolveBuildCacheMode,E as untaggedLifecyclePolicyText};
@@ -9,6 +9,7 @@ export declare const SIGTERM_GRACE_MS = 5000;
9
9
  export declare const STDERR_TAIL_LINES = 50;
10
10
  export declare const STDERR_TAIL_LINE_MAX_CHARS = 2000;
11
11
  export declare const DEFAULT_BUILD_TIMEOUT_MS = 1800000;
12
+ export declare const DEFAULT_PUSH_STALL_TIMEOUT_MS = 300000;
12
13
  export declare const DEFAULT_PUSH_TIMEOUT_MS = 300000;
13
14
  export declare const DEFAULT_PULL_TIMEOUT_MS = 300000;
14
15
  export declare const DEFAULT_INSPECT_TIMEOUT_MS = 30000;
@@ -1 +1 @@
1
- const _="DockerCli",o="DockerCli.buildx",E="0.13.0",t="23.0.0",T=64,L="fjall",e="docker",I=5e3,r=50,O=2e3,D=18e5,c=3e5,s=3e5,R=3e4,U=1e4;export{E as BUILDX_VERSION_FLOOR,L as DEFAULT_BUILDER_NAME,D as DEFAULT_BUILD_TIMEOUT_MS,U as DEFAULT_DAEMON_PROBE_TIMEOUT_MS,e as DEFAULT_DOCKER_BIN,R as DEFAULT_INSPECT_TIMEOUT_MS,s as DEFAULT_PULL_TIMEOUT_MS,c as DEFAULT_PUSH_TIMEOUT_MS,o as DOCKER_CLI_BUILDX_LOG_CATEGORY,_ as DOCKER_CLI_LOG_CATEGORY,t as ENGINE_VERSION_FLOOR,T as PrerequisiteMissingExitCode,I as SIGTERM_GRACE_MS,r as STDERR_TAIL_LINES,O as STDERR_TAIL_LINE_MAX_CHARS};
1
+ const _="DockerCli",o="DockerCli.buildx",E="0.13.0",t="23.0.0",T=64,L="fjall",e="docker",I=5e3,r=50,O=2e3,U=18e5,D=3e5,c=3e5,s=3e5,x=3e4,A=1e4;export{E as BUILDX_VERSION_FLOOR,L as DEFAULT_BUILDER_NAME,U as DEFAULT_BUILD_TIMEOUT_MS,A as DEFAULT_DAEMON_PROBE_TIMEOUT_MS,e as DEFAULT_DOCKER_BIN,x as DEFAULT_INSPECT_TIMEOUT_MS,s as DEFAULT_PULL_TIMEOUT_MS,D as DEFAULT_PUSH_STALL_TIMEOUT_MS,c as DEFAULT_PUSH_TIMEOUT_MS,o as DOCKER_CLI_BUILDX_LOG_CATEGORY,_ as DOCKER_CLI_LOG_CATEGORY,t as ENGINE_VERSION_FLOOR,T as PrerequisiteMissingExitCode,I as SIGTERM_GRACE_MS,r as STDERR_TAIL_LINES,O as STDERR_TAIL_LINE_MAX_CHARS};
@@ -1,7 +1,8 @@
1
1
  export { type Result, isSuccess, isFailure, success, failure } from "./result.js";
2
- export { DOCKER_CLI_LOG_CATEGORY, DOCKER_CLI_BUILDX_LOG_CATEGORY, BUILDX_VERSION_FLOOR, ENGINE_VERSION_FLOOR, PrerequisiteMissingExitCode, DEFAULT_BUILDER_NAME, DEFAULT_DOCKER_BIN, SIGTERM_GRACE_MS, STDERR_TAIL_LINES, DEFAULT_BUILD_TIMEOUT_MS, DEFAULT_PUSH_TIMEOUT_MS, DEFAULT_PULL_TIMEOUT_MS, DEFAULT_INSPECT_TIMEOUT_MS, DEFAULT_DAEMON_PROBE_TIMEOUT_MS } from "./dockerCliConstants.js";
2
+ export { DOCKER_CLI_LOG_CATEGORY, DOCKER_CLI_BUILDX_LOG_CATEGORY, BUILDX_VERSION_FLOOR, ENGINE_VERSION_FLOOR, PrerequisiteMissingExitCode, DEFAULT_BUILDER_NAME, DEFAULT_DOCKER_BIN, SIGTERM_GRACE_MS, STDERR_TAIL_LINES, DEFAULT_BUILD_TIMEOUT_MS, DEFAULT_PUSH_STALL_TIMEOUT_MS, DEFAULT_PUSH_TIMEOUT_MS, DEFAULT_PULL_TIMEOUT_MS, DEFAULT_INSPECT_TIMEOUT_MS, DEFAULT_DAEMON_PROBE_TIMEOUT_MS } from "./dockerCliConstants.js";
3
3
  export { BuildxBuildArgsSchema, BuildxBuildResultSchema, DockerCliErrorKindSchema, DockerCliErrorSchema, isDockerCliErrorKind, type BuildxBuildArgs, type BuildxBuildResult, type DockerCliError, type DockerCliErrorKind } from "./dockerCliSchemas.js";
4
4
  export { buildxArgvBuilder } from "./buildxArgvBuilder.js";
5
+ export { BUILD_TIMEOUT_ENV_VAR, PUSH_STALL_TIMEOUT_ENV_VAR, BuildxBuildMonitor, buildPhaseTimeoutMessage, publishStallTimeoutMessage, resolveBuildxBudgets, type BuildxBudgets, type BuildxTimeoutPhase, type SyntheticBuildxProgress } from "./buildxBuildMonitor.js";
5
6
  export { evaluateBakeGuard, evaluateResolvedBuildArgValues, acknowledgedBuildArgKeys, createBakeWarningDeduper, BAKE_GUARD_EXPOSURE_CLAUSE, type BakeGuardFinding, type BakeGuardFindingReason, type BakeGuardWarning, type BakeGuardResult } from "./bakeGuard.js";
6
7
  export { PUBLIC_BUILD_ARG_PREFIXES, isPublicBuildVarName, inferPublicBuildArgKeys, type InferPublicBuildArgKeysInput } from "./buildArgInference.js";
7
8
  export { parseRawjsonLine, type RawjsonEnvelope, type RawjsonVertex, type RawjsonStatus, type RawjsonLog, type RawjsonWarning } from "./rawjsonParser.js";
@@ -11,4 +12,4 @@ export { projectBuildxResult, type DockerBuildResultLike, type ProjectBuildxResu
11
12
  export { abortChildProcess } from "./abortHelpers.js";
12
13
  export { DockerCli, type DockerCliLogger, type DockerCliOptions, type BuildxProgressEvent, type PushProgressEvent, type PushResult, type PullProgressEvent, type PullResult, type ImagetoolsInspect, type EcrLoginArgs, type BuildxCapabilities, type DaemonInfo } from "./DockerCli.js";
13
14
  export { createEcrAuthSession, type EcrAuthSession, type CreateEcrAuthSessionParams } from "./ecrCredentialStore.js";
14
- export { buildCacheRepositoryName, untaggedLifecyclePolicyText, CACHE_REPO_UNTAGGED_RETENTION_DAYS } from "./cacheRepository.js";
15
+ export { buildCacheRepositoryName, buildRegistryCacheRefs, resolveBuildCacheMode, untaggedLifecyclePolicyText, BUILD_CACHE_MODE_ENV_VAR, BUILD_CACHE_MODES, CACHE_REPO_UNTAGGED_RETENTION_DAYS, type BuildCacheMode, type RegistryCacheRefs, type RegistryCacheRefsInput } from "./cacheRepository.js";
@@ -1 +1 @@
1
- import{isSuccess as o,isFailure as E,success as _,failure as i}from"./result.js";import{DOCKER_CLI_LOG_CATEGORY as a,DOCKER_CLI_BUILDX_LOG_CATEGORY as l,BUILDX_VERSION_FLOOR as s,ENGINE_VERSION_FLOOR as u,PrerequisiteMissingExitCode as T,DEFAULT_BUILDER_NAME as A,DEFAULT_DOCKER_BIN as L,SIGTERM_GRACE_MS as R,STDERR_TAIL_LINES as D,DEFAULT_BUILD_TIMEOUT_MS as c,DEFAULT_PUSH_TIMEOUT_MS as U,DEFAULT_PULL_TIMEOUT_MS as d,DEFAULT_INSPECT_TIMEOUT_MS as I,DEFAULT_DAEMON_PROBE_TIMEOUT_MS as O}from"./dockerCliConstants.js";import{BuildxBuildArgsSchema as x,BuildxBuildResultSchema as B,DockerCliErrorKindSchema as m,DockerCliErrorSchema as C,isDockerCliErrorKind as p}from"./dockerCliSchemas.js";import{buildxArgvBuilder as M}from"./buildxArgvBuilder.js";import{evaluateBakeGuard as n,evaluateResolvedBuildArgValues as P,acknowledgedBuildArgKeys as F,createBakeWarningDeduper as G,BAKE_GUARD_EXPOSURE_CLAUSE as g}from"./bakeGuard.js";import{PUBLIC_BUILD_ARG_PREFIXES as h,isPublicBuildVarName as k,inferPublicBuildArgKeys as b}from"./buildArgInference.js";import{parseRawjsonLine as y}from"./rawjsonParser.js";import{rawjsonToVertexEvent as X}from"./rawjsonToVertexEvent.js";import{parseMetadataFile as w}from"./metadataFileParser.js";import{projectBuildxResult as H}from"./projectBuildxResult.js";import{abortChildProcess as W}from"./abortHelpers.js";import{DockerCli as J}from"./DockerCli.js";import{createEcrAuthSession as Z}from"./ecrCredentialStore.js";import{buildCacheRepositoryName as ee,untaggedLifecyclePolicyText as re,CACHE_REPO_UNTAGGED_RETENTION_DAYS as oe}from"./cacheRepository.js";export{g as BAKE_GUARD_EXPOSURE_CLAUSE,s as BUILDX_VERSION_FLOOR,x as BuildxBuildArgsSchema,B as BuildxBuildResultSchema,oe as CACHE_REPO_UNTAGGED_RETENTION_DAYS,A as DEFAULT_BUILDER_NAME,c as DEFAULT_BUILD_TIMEOUT_MS,O as DEFAULT_DAEMON_PROBE_TIMEOUT_MS,L as DEFAULT_DOCKER_BIN,I as DEFAULT_INSPECT_TIMEOUT_MS,d as DEFAULT_PULL_TIMEOUT_MS,U as DEFAULT_PUSH_TIMEOUT_MS,l as DOCKER_CLI_BUILDX_LOG_CATEGORY,a as DOCKER_CLI_LOG_CATEGORY,J as DockerCli,m as DockerCliErrorKindSchema,C as DockerCliErrorSchema,u as ENGINE_VERSION_FLOOR,h as PUBLIC_BUILD_ARG_PREFIXES,T as PrerequisiteMissingExitCode,R as SIGTERM_GRACE_MS,D as STDERR_TAIL_LINES,W as abortChildProcess,F as acknowledgedBuildArgKeys,ee as buildCacheRepositoryName,M as buildxArgvBuilder,G as createBakeWarningDeduper,Z as createEcrAuthSession,n as evaluateBakeGuard,P as evaluateResolvedBuildArgValues,i as failure,b as inferPublicBuildArgKeys,p as isDockerCliErrorKind,E as isFailure,k as isPublicBuildVarName,o as isSuccess,w as parseMetadataFile,y as parseRawjsonLine,H as projectBuildxResult,X as rawjsonToVertexEvent,_ as success,re as untaggedLifecyclePolicyText};
1
+ import{isSuccess as _,isFailure as E,success as o,failure as i}from"./result.js";import{DOCKER_CLI_LOG_CATEGORY as s,DOCKER_CLI_BUILDX_LOG_CATEGORY as t,BUILDX_VERSION_FLOOR as T,ENGINE_VERSION_FLOOR as u,PrerequisiteMissingExitCode as a,DEFAULT_BUILDER_NAME as A,DEFAULT_DOCKER_BIN as L,SIGTERM_GRACE_MS as U,STDERR_TAIL_LINES as d,DEFAULT_BUILD_TIMEOUT_MS as D,DEFAULT_PUSH_STALL_TIMEOUT_MS as R,DEFAULT_PUSH_TIMEOUT_MS as S,DEFAULT_PULL_TIMEOUT_MS as B,DEFAULT_INSPECT_TIMEOUT_MS as I,DEFAULT_DAEMON_PROBE_TIMEOUT_MS as O}from"./dockerCliConstants.js";import{BuildxBuildArgsSchema as C,BuildxBuildResultSchema as M,DockerCliErrorKindSchema as x,DockerCliErrorSchema as m,isDockerCliErrorKind as p}from"./dockerCliSchemas.js";import{buildxArgvBuilder as N}from"./buildxArgvBuilder.js";import{BUILD_TIMEOUT_ENV_VAR as g,PUSH_STALL_TIMEOUT_ENV_VAR as n,BuildxBuildMonitor as F,buildPhaseTimeoutMessage as G,publishStallTimeoutMessage as h,resolveBuildxBudgets as V}from"./buildxBuildMonitor.js";import{evaluateBakeGuard as K,evaluateResolvedBuildArgValues as k,acknowledgedBuildArgKeys as v,createBakeWarningDeduper as y,BAKE_GUARD_EXPOSURE_CLAUSE as H}from"./bakeGuard.js";import{PUBLIC_BUILD_ARG_PREFIXES as j,isPublicBuildVarName as w,inferPublicBuildArgKeys as Y}from"./buildArgInference.js";import{parseRawjsonLine as W}from"./rawjsonParser.js";import{rawjsonToVertexEvent as J}from"./rawjsonToVertexEvent.js";import{parseMetadataFile as Z}from"./metadataFileParser.js";import{projectBuildxResult as ee}from"./projectBuildxResult.js";import{abortChildProcess as _e}from"./abortHelpers.js";import{DockerCli as oe}from"./DockerCli.js";import{createEcrAuthSession as le}from"./ecrCredentialStore.js";import{buildCacheRepositoryName as te,buildRegistryCacheRefs as Te,resolveBuildCacheMode as ue,untaggedLifecyclePolicyText as ae,BUILD_CACHE_MODE_ENV_VAR as Ae,BUILD_CACHE_MODES as Le,CACHE_REPO_UNTAGGED_RETENTION_DAYS as Ue}from"./cacheRepository.js";export{H as BAKE_GUARD_EXPOSURE_CLAUSE,T as BUILDX_VERSION_FLOOR,Le as BUILD_CACHE_MODES,Ae as BUILD_CACHE_MODE_ENV_VAR,g as BUILD_TIMEOUT_ENV_VAR,C as BuildxBuildArgsSchema,F as BuildxBuildMonitor,M as BuildxBuildResultSchema,Ue as CACHE_REPO_UNTAGGED_RETENTION_DAYS,A as DEFAULT_BUILDER_NAME,D as DEFAULT_BUILD_TIMEOUT_MS,O as DEFAULT_DAEMON_PROBE_TIMEOUT_MS,L as DEFAULT_DOCKER_BIN,I as DEFAULT_INSPECT_TIMEOUT_MS,B as DEFAULT_PULL_TIMEOUT_MS,R as DEFAULT_PUSH_STALL_TIMEOUT_MS,S as DEFAULT_PUSH_TIMEOUT_MS,t as DOCKER_CLI_BUILDX_LOG_CATEGORY,s as DOCKER_CLI_LOG_CATEGORY,oe as DockerCli,x as DockerCliErrorKindSchema,m as DockerCliErrorSchema,u as ENGINE_VERSION_FLOOR,j as PUBLIC_BUILD_ARG_PREFIXES,n as PUSH_STALL_TIMEOUT_ENV_VAR,a as PrerequisiteMissingExitCode,U as SIGTERM_GRACE_MS,d as STDERR_TAIL_LINES,_e as abortChildProcess,v as acknowledgedBuildArgKeys,te as buildCacheRepositoryName,G as buildPhaseTimeoutMessage,Te as buildRegistryCacheRefs,N as buildxArgvBuilder,y as createBakeWarningDeduper,le as createEcrAuthSession,K as evaluateBakeGuard,k as evaluateResolvedBuildArgValues,i as failure,Y as inferPublicBuildArgKeys,p as isDockerCliErrorKind,E as isFailure,w as isPublicBuildVarName,_ as isSuccess,Z as parseMetadataFile,W as parseRawjsonLine,ee as projectBuildxResult,h as publishStallTimeoutMessage,J as rawjsonToVertexEvent,ue as resolveBuildCacheMode,V as resolveBuildxBudgets,o as success,ae as untaggedLifecyclePolicyText};
package/dist/index.d.ts CHANGED
@@ -27,7 +27,7 @@ export { deriveContentHashTag, CONTENT_HASH_TAG_PATTERN } from "./infra/deriveCo
27
27
  export { DEPLOY_MODES, DeployModeSchema, type DeployMode, IMAGE_TAG_PATTERN, ImageTagSchema, type ImageTag, ServiceArtefactSchema, type ServiceArtefact, ServiceArtefactsSchema, type ServiceArtefacts, ARTEFACT_OUTPUT_FIELDS, type ArtefactOutputField, artefactOutputKey } from "./infra/deployArtefacts.js";
28
28
  export { MIGRATION_SNAPSHOT_NAME_PREFIX, EXPECTED_SCHEMA_VERSION_ENV, EXPECTED_SCHEMA_VERSION_TOOL_ENV, EXPECTED_CH_SCHEMA_VERSION_ENV, SCHEMA_ADMIN_USER_ENV, SCHEMA_ADMIN_PASSWORD_ENV, PRISMA_MIGRATION_DIR_RE, CLICKHOUSE_MIGRATION_SKIP_RE } from "./migration/constants.js";
29
29
  export { PHYSICAL_NAME_FALLBACK_PROPERTIES } from "./cfn/physicalNameProperties.js";
30
- export { PATTERN_TYPE_VALUES, type PatternType, PATTERN_TYPES, isPatternType, type PatternArtefact, type PatternStackPlacement, type PatternDescriptor, PATTERN_REGISTRY, type OpenNextPatternType, OPENNEXT_PATTERN_TYPES, isOpenNextPatternType, STATIC_SITE_ROUTING_VALUES, type StaticSiteRouting } from "./patterns/patternTypes.js";
30
+ export { PATTERN_TYPE_VALUES, type PatternType, PATTERN_TYPES, isPatternType, type PatternArtefact, type PatternStackPlacement, type PatternDescriptor, PATTERN_REGISTRY, DEPLOYABLE_PATTERN_TYPES, type OpenNextPatternType, OPENNEXT_PATTERN_TYPES, isOpenNextPatternType, STATIC_SITE_ROUTING_VALUES, type StaticSiteRouting } from "./patterns/patternTypes.js";
31
31
  export { DEFAULT_FORMS_FROM_LOCAL_PART, defaultFormsFromAddress, defaultFormsCorsOrigin, isAddressAtDomain } from "./patterns/staticSiteForms.js";
32
32
  export { DEV_SUBSTRATE_PARAMS_SCHEMA_VERSION, DEV_SUBSTRATE_PARAMS_FILENAME, DevSubstrateSynthPropsSchema, type DevSubstrateSynthProps, DevSubstrateParamsSchema, type DevSubstrateParams } from "./devSubstrate/params.js";
33
33
  export { DEV_SUBSTRATE_ENTRYPOINT_SOURCE } from "./devSubstrate/entrypoint.js";
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{DNS_APEX as E,getDomainExportNames as o}from"./infra/domainExports.js";import{BACKUP_VAULT_NAME as S}from"./infra/backupVault.js";import{APPROVAL_TOKEN_OUTPUT_PREFIX as a,TOKEN_STDERR_PREFIX as A}from"./deploy/approvalTokenOutput.js";import{imageTagParameterName as R}from"./infra/imageTags.js";import{toPascalCase as i,toKebab as N,toValidDatabaseName as m,toScreamingSnake as s,capitalise as O,getSafeZoneName as P,accountConstructKey as C,hasAsciiStableConstructKey as p}from"./naming/caseConversion.js";import{findAccountNameCollision as c}from"./naming/accountNameCollision.js";import{defaultConnectedAccountName as g,suffixedAccountName as M,REGION_SHORT_CODES as D,findTrailingRegionShortCode as x,regionSuffixRejectionMessage as u}from"./naming/connectedAccountName.js";import{normaliseError as U,getErrorMessage as l,hasErrorCode as V,getErrorCode as L,getErrorStack as h,formatErrorString as F}from"./errorUtils.js";import{singleton as v}from"./async/singleton.js";import{DANGEROUS_ENV_VARS as b,filterDangerousEnvVars as X,maskSensitiveOutput as y,parseShellArgs as K,SCOPED_TOKEN_REGEX as Y}from"./securityHelpers.js";import{sleep as W}from"./async/sleep.js";import{mapSettledWithConcurrency as j}from"./async/concurrency.js";import{ACCOUNT_STAGES_WITH_ROOT as Z,STRUCTURAL_ENVIRONMENTS as q,ACCOUNT_STAGES as w,ACCOUNT_STAGE_LABELS as J,isAccountStage as Q,ACCOUNT_TIERS as $,AccountTierSchema as ee,isAccountTier as re,environmentToTier as Ee,stageFromWireEnvironment as oe,accountTier as te,getEnvironmentLabel as Se,ACCOUNT_ROLES as _e}from"./environments.js";import{RESOURCE_CATEGORIES as Ae,categoriseResource as Te,getExpectedDuration as Re,getFriendlyResourceType as ne}from"./resourceCategorisation.js";import{parseGitRemoteUrl as Ne}from"./repo/gitRemoteParser.js";import{abbreviateRegion as se,AWS_REGIONS_METADATA as Oe,DEFAULT_REGION as Pe,getRegionInfo as Ce,MAX_SECONDARY_REGIONS as pe,OPT_IN_REGION_CODES as fe,optInRegionWarning as ce,regions as Ie,suggestRegionForTimezone as ge}from"./infra/regions.js";import{SCOPE_VALUES as De,MACHINE_ONLY_SCOPES as xe,USER_GRANTABLE_SCOPES as ue}from"./infra/tokenScopes.js";import{SECRET_NAME_PATTERN as Ue,SECRET_NAME_ERROR as le,SSM_COMPONENT_PATTERN as Ve,SSM_COMPONENT_ERROR as Le,SSM_STANDARD_MAX_VALUE_BYTES as he,SecretNamespaceSchema as Fe,buildNamespaceParts as Ge,buildParameterPath as ve,parseParameterPath as He,isManageablePath as be,parseDotEnv as Xe,escapeDotEnvValue as ye}from"./secrets.js";import{ConnectionWireSchema as Ye,ConnectionsListResponseSchema as Be}from"./infra/connectionsWire.js";import{deriveRegionsFromOrgConfig as ke,deriveTargets as je,deriveAllTargets as ze,environmentOrTier as Ze,findTarget as qe,generateTargetName as we}from"./targets.js";import{buildAppConfigPath as Qe}from"./repo/appPath.js";import{findInfrastructurePaths as er,findBoundaryPath as rr,isInfrastructureFile as Er}from"./repo/findInfrastructurePaths.js";import{inferContainerFromCandidates as tr}from"./repo/inferContainerFromCandidates.js";import{RESERVED_APP_NAMES as _r,RESERVED_APP_NAME_MESSAGE as ar,isReservedAppName as Ar,RESERVED_APP_NAME_SUFFIX as Tr,RESERVED_APP_NAME_SUFFIX_MESSAGE as Rr,hasReservedAppNameSuffix as nr}from"./naming/reservedAppNames.js";import{deriveContentHashTag as Nr,CONTENT_HASH_TAG_PATTERN as mr}from"./infra/deriveContentHashTag.js";import{DEPLOY_MODES as Or,DeployModeSchema as Pr,IMAGE_TAG_PATTERN as Cr,ImageTagSchema as pr,ServiceArtefactSchema as fr,ServiceArtefactsSchema as cr,ARTEFACT_OUTPUT_FIELDS as Ir,artefactOutputKey as gr}from"./infra/deployArtefacts.js";import{MIGRATION_SNAPSHOT_NAME_PREFIX as Dr,EXPECTED_SCHEMA_VERSION_ENV as xr,EXPECTED_SCHEMA_VERSION_TOOL_ENV as ur,EXPECTED_CH_SCHEMA_VERSION_ENV as dr,SCHEMA_ADMIN_USER_ENV as Ur,SCHEMA_ADMIN_PASSWORD_ENV as lr,PRISMA_MIGRATION_DIR_RE as Vr,CLICKHOUSE_MIGRATION_SKIP_RE as Lr}from"./migration/constants.js";import{PHYSICAL_NAME_FALLBACK_PROPERTIES as Fr}from"./cfn/physicalNameProperties.js";import{PATTERN_TYPE_VALUES as vr,PATTERN_TYPES as Hr,isPatternType as br,PATTERN_REGISTRY as Xr,OPENNEXT_PATTERN_TYPES as yr,isOpenNextPatternType as Kr,STATIC_SITE_ROUTING_VALUES as Yr}from"./patterns/patternTypes.js";import{DEFAULT_FORMS_FROM_LOCAL_PART as Wr,defaultFormsFromAddress as kr,defaultFormsCorsOrigin as jr,isAddressAtDomain as zr}from"./patterns/staticSiteForms.js";import{DEV_SUBSTRATE_PARAMS_SCHEMA_VERSION as qr,DEV_SUBSTRATE_PARAMS_FILENAME as wr,DevSubstrateSynthPropsSchema as Jr,DevSubstrateParamsSchema as Qr}from"./devSubstrate/params.js";import{DEV_SUBSTRATE_ENTRYPOINT_SOURCE as eE}from"./devSubstrate/entrypoint.js";export{_e as ACCOUNT_ROLES,w as ACCOUNT_STAGES,Z as ACCOUNT_STAGES_WITH_ROOT,J as ACCOUNT_STAGE_LABELS,$ as ACCOUNT_TIERS,a as APPROVAL_TOKEN_OUTPUT_PREFIX,Ir as ARTEFACT_OUTPUT_FIELDS,Oe as AWS_REGIONS_METADATA,ee as AccountTierSchema,S as BACKUP_VAULT_NAME,Lr as CLICKHOUSE_MIGRATION_SKIP_RE,mr as CONTENT_HASH_TAG_PATTERN,Ye as ConnectionWireSchema,Be as ConnectionsListResponseSchema,b as DANGEROUS_ENV_VARS,Wr as DEFAULT_FORMS_FROM_LOCAL_PART,Pe as DEFAULT_REGION,Or as DEPLOY_MODES,eE as DEV_SUBSTRATE_ENTRYPOINT_SOURCE,wr as DEV_SUBSTRATE_PARAMS_FILENAME,qr as DEV_SUBSTRATE_PARAMS_SCHEMA_VERSION,E as DNS_APEX,Pr as DeployModeSchema,Qr as DevSubstrateParamsSchema,Jr as DevSubstrateSynthPropsSchema,dr as EXPECTED_CH_SCHEMA_VERSION_ENV,xr as EXPECTED_SCHEMA_VERSION_ENV,ur as EXPECTED_SCHEMA_VERSION_TOOL_ENV,Cr as IMAGE_TAG_PATTERN,pr as ImageTagSchema,xe as MACHINE_ONLY_SCOPES,pe as MAX_SECONDARY_REGIONS,Dr as MIGRATION_SNAPSHOT_NAME_PREFIX,yr as OPENNEXT_PATTERN_TYPES,fe as OPT_IN_REGION_CODES,Xr as PATTERN_REGISTRY,Hr as PATTERN_TYPES,vr as PATTERN_TYPE_VALUES,Fr as PHYSICAL_NAME_FALLBACK_PROPERTIES,Vr as PRISMA_MIGRATION_DIR_RE,D as REGION_SHORT_CODES,_r as RESERVED_APP_NAMES,ar as RESERVED_APP_NAME_MESSAGE,Tr as RESERVED_APP_NAME_SUFFIX,Rr as RESERVED_APP_NAME_SUFFIX_MESSAGE,Ae as RESOURCE_CATEGORIES,lr as SCHEMA_ADMIN_PASSWORD_ENV,Ur as SCHEMA_ADMIN_USER_ENV,Y as SCOPED_TOKEN_REGEX,De as SCOPE_VALUES,le as SECRET_NAME_ERROR,Ue as SECRET_NAME_PATTERN,Le as SSM_COMPONENT_ERROR,Ve as SSM_COMPONENT_PATTERN,he as SSM_STANDARD_MAX_VALUE_BYTES,Yr as STATIC_SITE_ROUTING_VALUES,q as STRUCTURAL_ENVIRONMENTS,Fe as SecretNamespaceSchema,fr as ServiceArtefactSchema,cr as ServiceArtefactsSchema,A as TOKEN_STDERR_PREFIX,ue as USER_GRANTABLE_SCOPES,se as abbreviateRegion,C as accountConstructKey,te as accountTier,gr as artefactOutputKey,Qe as buildAppConfigPath,Ge as buildNamespaceParts,ve as buildParameterPath,O as capitalise,Te as categoriseResource,g as defaultConnectedAccountName,jr as defaultFormsCorsOrigin,kr as defaultFormsFromAddress,ze as deriveAllTargets,Nr as deriveContentHashTag,ke as deriveRegionsFromOrgConfig,je as deriveTargets,Ze as environmentOrTier,Ee as environmentToTier,ye as escapeDotEnvValue,X as filterDangerousEnvVars,c as findAccountNameCollision,rr as findBoundaryPath,er as findInfrastructurePaths,qe as findTarget,x as findTrailingRegionShortCode,F as formatErrorString,we as generateTargetName,o as getDomainExportNames,Se as getEnvironmentLabel,L as getErrorCode,l as getErrorMessage,h as getErrorStack,Re as getExpectedDuration,ne as getFriendlyResourceType,Ce as getRegionInfo,P as getSafeZoneName,p as hasAsciiStableConstructKey,V as hasErrorCode,nr as hasReservedAppNameSuffix,R as imageTagParameterName,tr as inferContainerFromCandidates,Q as isAccountStage,re as isAccountTier,zr as isAddressAtDomain,Er as isInfrastructureFile,be as isManageablePath,Kr as isOpenNextPatternType,br as isPatternType,Ar as isReservedAppName,j as mapSettledWithConcurrency,y as maskSensitiveOutput,U as normaliseError,ce as optInRegionWarning,Xe as parseDotEnv,Ne as parseGitRemoteUrl,He as parseParameterPath,K as parseShellArgs,u as regionSuffixRejectionMessage,Ie as regions,v as singleton,W as sleep,oe as stageFromWireEnvironment,M as suffixedAccountName,ge as suggestRegionForTimezone,N as toKebab,i as toPascalCase,s as toScreamingSnake,m as toValidDatabaseName};
1
+ import{DNS_APEX as E,getDomainExportNames as o}from"./infra/domainExports.js";import{BACKUP_VAULT_NAME as _}from"./infra/backupVault.js";import{APPROVAL_TOKEN_OUTPUT_PREFIX as a,TOKEN_STDERR_PREFIX as A}from"./deploy/approvalTokenOutput.js";import{imageTagParameterName as R}from"./infra/imageTags.js";import{toPascalCase as i,toKebab as N,toValidDatabaseName as m,toScreamingSnake as s,capitalise as O,getSafeZoneName as P,accountConstructKey as C,hasAsciiStableConstructKey as p}from"./naming/caseConversion.js";import{findAccountNameCollision as c}from"./naming/accountNameCollision.js";import{defaultConnectedAccountName as g,suffixedAccountName as M,REGION_SHORT_CODES as D,findTrailingRegionShortCode as x,regionSuffixRejectionMessage as u}from"./naming/connectedAccountName.js";import{normaliseError as U,getErrorMessage as l,hasErrorCode as L,getErrorCode as V,getErrorStack as h,formatErrorString as F}from"./errorUtils.js";import{singleton as v}from"./async/singleton.js";import{DANGEROUS_ENV_VARS as b,filterDangerousEnvVars as X,maskSensitiveOutput as Y,parseShellArgs as y,SCOPED_TOKEN_REGEX as K}from"./securityHelpers.js";import{sleep as W}from"./async/sleep.js";import{mapSettledWithConcurrency as j}from"./async/concurrency.js";import{ACCOUNT_STAGES_WITH_ROOT as Z,STRUCTURAL_ENVIRONMENTS as q,ACCOUNT_STAGES as w,ACCOUNT_STAGE_LABELS as J,isAccountStage as Q,ACCOUNT_TIERS as $,AccountTierSchema as ee,isAccountTier as re,environmentToTier as Ee,stageFromWireEnvironment as oe,accountTier as te,getEnvironmentLabel as _e,ACCOUNT_ROLES as Se}from"./environments.js";import{RESOURCE_CATEGORIES as Ae,categoriseResource as Te,getExpectedDuration as Re,getFriendlyResourceType as ne}from"./resourceCategorisation.js";import{parseGitRemoteUrl as Ne}from"./repo/gitRemoteParser.js";import{abbreviateRegion as se,AWS_REGIONS_METADATA as Oe,DEFAULT_REGION as Pe,getRegionInfo as Ce,MAX_SECONDARY_REGIONS as pe,OPT_IN_REGION_CODES as fe,optInRegionWarning as ce,regions as Ie,suggestRegionForTimezone as ge}from"./infra/regions.js";import{SCOPE_VALUES as De,MACHINE_ONLY_SCOPES as xe,USER_GRANTABLE_SCOPES as ue}from"./infra/tokenScopes.js";import{SECRET_NAME_PATTERN as Ue,SECRET_NAME_ERROR as le,SSM_COMPONENT_PATTERN as Le,SSM_COMPONENT_ERROR as Ve,SSM_STANDARD_MAX_VALUE_BYTES as he,SecretNamespaceSchema as Fe,buildNamespaceParts as Ge,buildParameterPath as ve,parseParameterPath as He,isManageablePath as be,parseDotEnv as Xe,escapeDotEnvValue as Ye}from"./secrets.js";import{ConnectionWireSchema as Ke,ConnectionsListResponseSchema as Be}from"./infra/connectionsWire.js";import{deriveRegionsFromOrgConfig as ke,deriveTargets as je,deriveAllTargets as ze,environmentOrTier as Ze,findTarget as qe,generateTargetName as we}from"./targets.js";import{buildAppConfigPath as Qe}from"./repo/appPath.js";import{findInfrastructurePaths as er,findBoundaryPath as rr,isInfrastructureFile as Er}from"./repo/findInfrastructurePaths.js";import{inferContainerFromCandidates as tr}from"./repo/inferContainerFromCandidates.js";import{RESERVED_APP_NAMES as Sr,RESERVED_APP_NAME_MESSAGE as ar,isReservedAppName as Ar,RESERVED_APP_NAME_SUFFIX as Tr,RESERVED_APP_NAME_SUFFIX_MESSAGE as Rr,hasReservedAppNameSuffix as nr}from"./naming/reservedAppNames.js";import{deriveContentHashTag as Nr,CONTENT_HASH_TAG_PATTERN as mr}from"./infra/deriveContentHashTag.js";import{DEPLOY_MODES as Or,DeployModeSchema as Pr,IMAGE_TAG_PATTERN as Cr,ImageTagSchema as pr,ServiceArtefactSchema as fr,ServiceArtefactsSchema as cr,ARTEFACT_OUTPUT_FIELDS as Ir,artefactOutputKey as gr}from"./infra/deployArtefacts.js";import{MIGRATION_SNAPSHOT_NAME_PREFIX as Dr,EXPECTED_SCHEMA_VERSION_ENV as xr,EXPECTED_SCHEMA_VERSION_TOOL_ENV as ur,EXPECTED_CH_SCHEMA_VERSION_ENV as dr,SCHEMA_ADMIN_USER_ENV as Ur,SCHEMA_ADMIN_PASSWORD_ENV as lr,PRISMA_MIGRATION_DIR_RE as Lr,CLICKHOUSE_MIGRATION_SKIP_RE as Vr}from"./migration/constants.js";import{PHYSICAL_NAME_FALLBACK_PROPERTIES as Fr}from"./cfn/physicalNameProperties.js";import{PATTERN_TYPE_VALUES as vr,PATTERN_TYPES as Hr,isPatternType as br,PATTERN_REGISTRY as Xr,DEPLOYABLE_PATTERN_TYPES as Yr,OPENNEXT_PATTERN_TYPES as yr,isOpenNextPatternType as Kr,STATIC_SITE_ROUTING_VALUES as Br}from"./patterns/patternTypes.js";import{DEFAULT_FORMS_FROM_LOCAL_PART as kr,defaultFormsFromAddress as jr,defaultFormsCorsOrigin as zr,isAddressAtDomain as Zr}from"./patterns/staticSiteForms.js";import{DEV_SUBSTRATE_PARAMS_SCHEMA_VERSION as wr,DEV_SUBSTRATE_PARAMS_FILENAME as Jr,DevSubstrateSynthPropsSchema as Qr,DevSubstrateParamsSchema as $r}from"./devSubstrate/params.js";import{DEV_SUBSTRATE_ENTRYPOINT_SOURCE as rE}from"./devSubstrate/entrypoint.js";export{Se as ACCOUNT_ROLES,w as ACCOUNT_STAGES,Z as ACCOUNT_STAGES_WITH_ROOT,J as ACCOUNT_STAGE_LABELS,$ as ACCOUNT_TIERS,a as APPROVAL_TOKEN_OUTPUT_PREFIX,Ir as ARTEFACT_OUTPUT_FIELDS,Oe as AWS_REGIONS_METADATA,ee as AccountTierSchema,_ as BACKUP_VAULT_NAME,Vr as CLICKHOUSE_MIGRATION_SKIP_RE,mr as CONTENT_HASH_TAG_PATTERN,Ke as ConnectionWireSchema,Be as ConnectionsListResponseSchema,b as DANGEROUS_ENV_VARS,kr as DEFAULT_FORMS_FROM_LOCAL_PART,Pe as DEFAULT_REGION,Yr as DEPLOYABLE_PATTERN_TYPES,Or as DEPLOY_MODES,rE as DEV_SUBSTRATE_ENTRYPOINT_SOURCE,Jr as DEV_SUBSTRATE_PARAMS_FILENAME,wr as DEV_SUBSTRATE_PARAMS_SCHEMA_VERSION,E as DNS_APEX,Pr as DeployModeSchema,$r as DevSubstrateParamsSchema,Qr as DevSubstrateSynthPropsSchema,dr as EXPECTED_CH_SCHEMA_VERSION_ENV,xr as EXPECTED_SCHEMA_VERSION_ENV,ur as EXPECTED_SCHEMA_VERSION_TOOL_ENV,Cr as IMAGE_TAG_PATTERN,pr as ImageTagSchema,xe as MACHINE_ONLY_SCOPES,pe as MAX_SECONDARY_REGIONS,Dr as MIGRATION_SNAPSHOT_NAME_PREFIX,yr as OPENNEXT_PATTERN_TYPES,fe as OPT_IN_REGION_CODES,Xr as PATTERN_REGISTRY,Hr as PATTERN_TYPES,vr as PATTERN_TYPE_VALUES,Fr as PHYSICAL_NAME_FALLBACK_PROPERTIES,Lr as PRISMA_MIGRATION_DIR_RE,D as REGION_SHORT_CODES,Sr as RESERVED_APP_NAMES,ar as RESERVED_APP_NAME_MESSAGE,Tr as RESERVED_APP_NAME_SUFFIX,Rr as RESERVED_APP_NAME_SUFFIX_MESSAGE,Ae as RESOURCE_CATEGORIES,lr as SCHEMA_ADMIN_PASSWORD_ENV,Ur as SCHEMA_ADMIN_USER_ENV,K as SCOPED_TOKEN_REGEX,De as SCOPE_VALUES,le as SECRET_NAME_ERROR,Ue as SECRET_NAME_PATTERN,Ve as SSM_COMPONENT_ERROR,Le as SSM_COMPONENT_PATTERN,he as SSM_STANDARD_MAX_VALUE_BYTES,Br as STATIC_SITE_ROUTING_VALUES,q as STRUCTURAL_ENVIRONMENTS,Fe as SecretNamespaceSchema,fr as ServiceArtefactSchema,cr as ServiceArtefactsSchema,A as TOKEN_STDERR_PREFIX,ue as USER_GRANTABLE_SCOPES,se as abbreviateRegion,C as accountConstructKey,te as accountTier,gr as artefactOutputKey,Qe as buildAppConfigPath,Ge as buildNamespaceParts,ve as buildParameterPath,O as capitalise,Te as categoriseResource,g as defaultConnectedAccountName,zr as defaultFormsCorsOrigin,jr as defaultFormsFromAddress,ze as deriveAllTargets,Nr as deriveContentHashTag,ke as deriveRegionsFromOrgConfig,je as deriveTargets,Ze as environmentOrTier,Ee as environmentToTier,Ye as escapeDotEnvValue,X as filterDangerousEnvVars,c as findAccountNameCollision,rr as findBoundaryPath,er as findInfrastructurePaths,qe as findTarget,x as findTrailingRegionShortCode,F as formatErrorString,we as generateTargetName,o as getDomainExportNames,_e as getEnvironmentLabel,V as getErrorCode,l as getErrorMessage,h as getErrorStack,Re as getExpectedDuration,ne as getFriendlyResourceType,Ce as getRegionInfo,P as getSafeZoneName,p as hasAsciiStableConstructKey,L as hasErrorCode,nr as hasReservedAppNameSuffix,R as imageTagParameterName,tr as inferContainerFromCandidates,Q as isAccountStage,re as isAccountTier,Zr as isAddressAtDomain,Er as isInfrastructureFile,be as isManageablePath,Kr as isOpenNextPatternType,br as isPatternType,Ar as isReservedAppName,j as mapSettledWithConcurrency,Y as maskSensitiveOutput,U as normaliseError,ce as optInRegionWarning,Xe as parseDotEnv,Ne as parseGitRemoteUrl,He as parseParameterPath,y as parseShellArgs,u as regionSuffixRejectionMessage,Ie as regions,v as singleton,W as sleep,oe as stageFromWireEnvironment,M as suffixedAccountName,ge as suggestRegionForTimezone,N as toKebab,i as toPascalCase,s as toScreamingSnake,m as toValidDatabaseName};
@@ -41,6 +41,14 @@ export declare function readConstructMap(cdkOutPath: string): Promise<Map<string
41
41
  export interface ManifestDockerService {
42
42
  readonly name: string;
43
43
  readonly docker: DockerBuild;
44
+ /**
45
+ * True when this entry is a container-Lambda image (from `manifest.lambdas`)
46
+ * rather than an ECS service (from `manifest.services`). Build groups
47
+ * containing a Lambda entry must build without provenance/SBOM attestations
48
+ * — canonical rationale at `DockerBuildParams.targetsLambda`
49
+ * (`@fjall/deploy-core` dockerInterface.ts).
50
+ */
51
+ readonly isLambda?: boolean;
44
52
  }
45
53
  /**
46
54
  * Extract services with a Docker build configuration from the Fjall manifest.
@@ -78,10 +86,12 @@ export declare function parseDockerServicesFromManifest(cdkOutPath: string): Man
78
86
  *
79
87
  * Throws deliberately (not a `Result`) on divergent shared-`imageKey` docker
80
88
  * configs even though `Result`-returning callers sit above it: the throw is a
81
- * config error surfaced before any build starts, and both production
82
- * boundaries convert it — the CLI's `catch` in `runApplicationDeployment`
83
- * (`cli/src/services/deployment/applicationDeployment.ts`) and the webapp
84
- * worker's job-level `catch` in `deploymentJobHandler`. Sanctioned per the
89
+ * config error surfaced before any build starts, and every production
90
+ * boundary converts it — the CLI's `catch` in `runApplicationDeployment`
91
+ * (`cli/src/services/deployment/applicationDeployment.ts`), the webapp
92
+ * worker's job-level `catch` in `deploymentJobHandler`, and the `fjall build`
93
+ * orchestrator's call-site `catch` in `resolveLambdaBuildIdentityKeys`
94
+ * (`cli/src/services/container/EcrBuildOrchestrator.ts`). Sanctioned per the
85
95
  * 2026-07-16 docker-lambda review; do not re-litigate as a Pitfall-4 escape.
86
96
  */
87
97
  export declare function parseLambdaDockerServicesFromManifest(cdkOutPath: string): ManifestDockerService[];
@@ -1 +1 @@
1
- import{readFile as g,writeFile as y,unlink as M,rename as h,mkdir as F}from"fs/promises";import{readFileSync as b}from"fs";import{dirname as k,join as c}from"path";import{logger as o}from"../logger.js";import{fileExists as w}from"../fsHelpers.js";import{getErrorMessage as f}from"../errorUtils.js";import{recordToConstructMap as S}from"../constructMap.js";import{FjallManifestSchema as A,FJALL_MANIFEST_FILENAME as u,MANIFEST_SCHEMA_VERSION as x,normaliseDockerBuild as d}from"./schemas.js";function m(t){return c(t,u)}async function E(t){const r=m(t);if(!await w(r))return null;try{const n=await g(r,"utf-8"),e=JSON.parse(n),a=A.safeParse(e);return a.success||o.debug("FjallManifest","Manifest validation failed",{path:r,errors:a.error.issues.map(i=>`${i.path.join(".")}: ${i.message}`)}),a.success?a.data:null}catch(n){return o.debug("FjallManifest","Failed to read manifest file",{path:r,error:f(n)}),null}}async function K(t,r){const n=m(t),e=`${n}.${Date.now()}.tmp`;await F(k(n),{recursive:!0});try{await y(e,JSON.stringify(r,null,2),"utf-8"),await h(e,n)}catch(a){try{await M(e)}catch(i){o.debug("FjallManifest","Temp file cleanup failed (non-fatal)",{path:e,error:f(i)})}throw a}}function P(t){return{version:x,generatedAt:new Date().toISOString(),appName:t,services:[],lambdas:[],stacks:{}}}async function T(t){const r=await E(t);return r?.resourceMap?S(r.resourceMap):new Map}function s(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}function l(t,r){const n=c(t,u);let e;try{e=b(n,"utf-8")}catch{o.debug("FjallManifest",`Manifest file not readable \u2014 no ${r} extracted`,{path:n});return}let a;try{a=JSON.parse(e)}catch{o.debug("FjallManifest",`Manifest is not valid JSON \u2014 no ${r} extracted`,{path:n});return}return s(a)?a:void 0}function v(t){const r=l(t,"Docker services");if(r===void 0||!Array.isArray(r.services))return[];const n=[];for(const e of r.services){if(!s(e)||typeof e.name!="string")continue;const a=d(e.docker);a!==void 0&&n.push({name:e.name,docker:a})}return n}function _(t){const r=new Map;for(const{name:n,imageKey:e,docker:a}of p(t)){const i=r.get(e);if(i===void 0){r.set(e,{name:e,docker:a});continue}if(JSON.stringify(i.docker)!==JSON.stringify(a))throw new Error(`Lambda functions sharing image key "${e}" declare different \`docker\` configs \u2014 every Lambda function sharing an \`image\` must build from the identical Dockerfile/context/target/buildArgs (offending function: "${n}").`)}return Array.from(r.values())}function p(t){const r=l(t,"Lambda Docker entries");if(r===void 0||!Array.isArray(r.lambdas))return[];const n=[];for(const e of r.lambdas){if(!s(e)||typeof e.name!="string")continue;const a=d(e.docker);if(a===void 0)continue;const i=typeof e.imageKey=="string"&&e.imageKey.length>0?e.imageKey:e.name;n.push({name:e.name,imageKey:i,docker:a})}return n}function C(t){const r=v(t),n=p(t);return{ecsServices:r,lambdaEntries:n,declaresBuild:r.length>0||n.length>0}}export{P as createEmptyManifest,m as getManifestFilePath,C as parseDockerDeclarationsFromManifest,v as parseDockerServicesFromManifest,p as parseLambdaDockerEntriesFromManifest,_ as parseLambdaDockerServicesFromManifest,T as readConstructMap,E as readManifestFile,K as writeManifestFile};
1
+ import{readFile as g,writeFile as y,unlink as M,rename as h,mkdir as b}from"fs/promises";import{readFileSync as F}from"fs";import{dirname as k,join as c}from"path";import{logger as o}from"../logger.js";import{fileExists as w}from"../fsHelpers.js";import{getErrorMessage as f}from"../errorUtils.js";import{recordToConstructMap as S}from"../constructMap.js";import{FjallManifestSchema as A,FJALL_MANIFEST_FILENAME as u,MANIFEST_SCHEMA_VERSION as x,normaliseDockerBuild as d}from"./schemas.js";function m(t){return c(t,u)}async function E(t){const r=m(t);if(!await w(r))return null;try{const n=await g(r,"utf-8"),e=JSON.parse(n),a=A.safeParse(e);return a.success||o.debug("FjallManifest","Manifest validation failed",{path:r,errors:a.error.issues.map(i=>`${i.path.join(".")}: ${i.message}`)}),a.success?a.data:null}catch(n){return o.debug("FjallManifest","Failed to read manifest file",{path:r,error:f(n)}),null}}async function K(t,r){const n=m(t),e=`${n}.${Date.now()}.tmp`;await b(k(n),{recursive:!0});try{await y(e,JSON.stringify(r,null,2),"utf-8"),await h(e,n)}catch(a){try{await M(e)}catch(i){o.debug("FjallManifest","Temp file cleanup failed (non-fatal)",{path:e,error:f(i)})}throw a}}function P(t){return{version:x,generatedAt:new Date().toISOString(),appName:t,services:[],lambdas:[],stacks:{}}}async function T(t){const r=await E(t);return r?.resourceMap?S(r.resourceMap):new Map}function s(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}function l(t,r){const n=c(t,u);let e;try{e=F(n,"utf-8")}catch{o.debug("FjallManifest",`Manifest file not readable \u2014 no ${r} extracted`,{path:n});return}let a;try{a=JSON.parse(e)}catch{o.debug("FjallManifest",`Manifest is not valid JSON \u2014 no ${r} extracted`,{path:n});return}return s(a)?a:void 0}function v(t){const r=l(t,"Docker services");if(r===void 0||!Array.isArray(r.services))return[];const n=[];for(const e of r.services){if(!s(e)||typeof e.name!="string")continue;const a=d(e.docker);a!==void 0&&n.push({name:e.name,docker:a,isLambda:!1})}return n}function _(t){const r=new Map;for(const{name:n,imageKey:e,docker:a}of p(t)){const i=r.get(e);if(i===void 0){r.set(e,{name:e,docker:a,isLambda:!0});continue}if(JSON.stringify(i.docker)!==JSON.stringify(a))throw new Error(`Lambda functions sharing image key "${e}" declare different \`docker\` configs \u2014 every Lambda function sharing an \`image\` must build from the identical Dockerfile/context/target/buildArgs (offending function: "${n}").`)}return Array.from(r.values())}function p(t){const r=l(t,"Lambda Docker entries");if(r===void 0||!Array.isArray(r.lambdas))return[];const n=[];for(const e of r.lambdas){if(!s(e)||typeof e.name!="string")continue;const a=d(e.docker);if(a===void 0)continue;const i=typeof e.imageKey=="string"&&e.imageKey.length>0?e.imageKey:e.name;n.push({name:e.name,imageKey:i,docker:a})}return n}function C(t){const r=v(t),n=p(t);return{ecsServices:r,lambdaEntries:n,declaresBuild:r.length>0||n.length>0}}export{P as createEmptyManifest,m as getManifestFilePath,C as parseDockerDeclarationsFromManifest,v as parseDockerServicesFromManifest,p as parseLambdaDockerEntriesFromManifest,_ as parseLambdaDockerServicesFromManifest,T as readConstructMap,E as readManifestFile,K as writeManifestFile};
@@ -7,5 +7,5 @@
7
7
  * the webapp bundles) can take the vocabulary without depending on the root
8
8
  * barrel's contents staying pure.
9
9
  */
10
- export { PATTERN_TYPE_VALUES, type PatternType, PATTERN_TYPES, isPatternType, type PatternArtefact, type PatternStackPlacement, type PatternDescriptor, PATTERN_REGISTRY, type OpenNextPatternType, OPENNEXT_PATTERN_TYPES, isOpenNextPatternType, STATIC_SITE_ROUTING_VALUES, type StaticSiteRouting } from "./patternTypes.js";
10
+ export { PATTERN_TYPE_VALUES, type PatternType, PATTERN_TYPES, isPatternType, type PatternArtefact, type PatternStackPlacement, type PatternDescriptor, PATTERN_REGISTRY, DEPLOYABLE_PATTERN_TYPES, type OpenNextPatternType, OPENNEXT_PATTERN_TYPES, isOpenNextPatternType, STATIC_SITE_ROUTING_VALUES, type StaticSiteRouting } from "./patternTypes.js";
11
11
  export { DEFAULT_FORMS_FROM_LOCAL_PART, defaultFormsFromAddress, defaultFormsCorsOrigin, isAddressAtDomain } from "./staticSiteForms.js";
@@ -1 +1 @@
1
- import{PATTERN_TYPE_VALUES as r,PATTERN_TYPES as A,isPatternType as _,PATTERN_REGISTRY as e,OPENNEXT_PATTERN_TYPES as P,isOpenNextPatternType as s,STATIC_SITE_ROUTING_VALUES as t}from"./patternTypes.js";import{DEFAULT_FORMS_FROM_LOCAL_PART as o,defaultFormsFromAddress as N,defaultFormsCorsOrigin as S,isAddressAtDomain as O}from"./staticSiteForms.js";export{o as DEFAULT_FORMS_FROM_LOCAL_PART,P as OPENNEXT_PATTERN_TYPES,e as PATTERN_REGISTRY,A as PATTERN_TYPES,r as PATTERN_TYPE_VALUES,t as STATIC_SITE_ROUTING_VALUES,S as defaultFormsCorsOrigin,N as defaultFormsFromAddress,O as isAddressAtDomain,s as isOpenNextPatternType,_ as isPatternType};
1
+ import{PATTERN_TYPE_VALUES as A,PATTERN_TYPES as _,isPatternType as P,PATTERN_REGISTRY as r,DEPLOYABLE_PATTERN_TYPES as e,OPENNEXT_PATTERN_TYPES as R,isOpenNextPatternType as s,STATIC_SITE_ROUTING_VALUES as t}from"./patternTypes.js";import{DEFAULT_FORMS_FROM_LOCAL_PART as N,defaultFormsFromAddress as S,defaultFormsCorsOrigin as O,isAddressAtDomain as L}from"./staticSiteForms.js";export{N as DEFAULT_FORMS_FROM_LOCAL_PART,e as DEPLOYABLE_PATTERN_TYPES,R as OPENNEXT_PATTERN_TYPES,r as PATTERN_REGISTRY,_ as PATTERN_TYPES,A as PATTERN_TYPE_VALUES,t as STATIC_SITE_ROUTING_VALUES,O as defaultFormsCorsOrigin,S as defaultFormsFromAddress,L as isAddressAtDomain,s as isOpenNextPatternType,P as isPatternType};
@@ -22,7 +22,8 @@
22
22
  * - `nextjs` — a plain Next.js app on OpenNext (optional database). No CDK
23
23
  * construct exists yet: `IPatternProps` (components/infrastructure) omits it,
24
24
  * so a generated `nextjs` app fails to synthesise. Add the props + a
25
- * `PatternFactory.build` case to close the gap.
25
+ * `PatternFactory.build` case to close the gap, then flip its `deployable`
26
+ * flag so the CLI offers it again.
26
27
  * - `staticsite` — pre-built static assets on private S3 + CloudFront/OAC.
27
28
  */
28
29
  export declare const PATTERN_TYPE_VALUES: readonly ["payload", "nextjs", "staticsite"];
@@ -50,6 +51,14 @@ export interface PatternDescriptor {
50
51
  readonly artefact: PatternArtefact;
51
52
  /** Stack the pattern's constructs are placed into. */
52
53
  readonly stackPlacement: PatternStackPlacement;
54
+ /**
55
+ * Whether the pattern can deploy end-to-end. Runtime mirror of the
56
+ * compile-time gap in `IPatternProps` (components/infrastructure): the CLI
57
+ * cannot read that union, so it consults this flag to hide and refuse
58
+ * patterns that would scaffold an app that fails at synth. Flip alongside
59
+ * adding the construct.
60
+ */
61
+ readonly deployable: boolean;
53
62
  }
54
63
  export declare const PATTERN_REGISTRY: {
55
64
  readonly payload: {
@@ -57,20 +66,29 @@ export declare const PATTERN_REGISTRY: {
57
66
  readonly constructIdSuffix: "Payload";
58
67
  readonly artefact: "opennext-lambda";
59
68
  readonly stackPlacement: "compute";
69
+ readonly deployable: true;
60
70
  };
61
71
  readonly nextjs: {
62
72
  readonly label: "Next.js";
63
73
  readonly constructIdSuffix: "Nextjs";
64
74
  readonly artefact: "opennext-lambda";
65
75
  readonly stackPlacement: "compute";
76
+ readonly deployable: false;
66
77
  };
67
78
  readonly staticsite: {
68
79
  readonly label: "Static site";
69
80
  readonly constructIdSuffix: "StaticSite";
70
81
  readonly artefact: "static-assets";
71
82
  readonly stackPlacement: "cdn";
83
+ readonly deployable: true;
72
84
  };
73
85
  };
86
+ /**
87
+ * Patterns the toolchain may offer for creation, derived from the registry —
88
+ * pickers and validation reject the rest at create time instead of letting a
89
+ * scaffold fail at first deploy.
90
+ */
91
+ export declare const DEPLOYABLE_PATTERN_TYPES: readonly PatternType[];
74
92
  /**
75
93
  * The OpenNext-shaped patterns, derived from the registry at both the type and
76
94
  * the value level — a new OpenNext pattern joins this accept-set by declaring
@@ -1 +1 @@
1
- const e=["payload","nextjs","staticsite"],a=new Set(e);function o(t){return typeof t=="string"&&a.has(t)}const n={payload:{label:"Payload CMS",constructIdSuffix:"Payload",artefact:"opennext-lambda",stackPlacement:"compute"},nextjs:{label:"Next.js",constructIdSuffix:"Nextjs",artefact:"opennext-lambda",stackPlacement:"compute"},staticsite:{label:"Static site",constructIdSuffix:"StaticSite",artefact:"static-assets",stackPlacement:"cdn"}},c=e.filter(t=>n[t].artefact==="opennext-lambda"),s=new Set(c);function T(t){return t!=null&&s.has(t)}const r=["multipage","spa"];export{c as OPENNEXT_PATTERN_TYPES,n as PATTERN_REGISTRY,a as PATTERN_TYPES,e as PATTERN_TYPE_VALUES,r as STATIC_SITE_ROUTING_VALUES,T as isOpenNextPatternType,o as isPatternType};
1
+ const e=["payload","nextjs","staticsite"],n=new Set(e);function s(t){return typeof t=="string"&&n.has(t)}const a={payload:{label:"Payload CMS",constructIdSuffix:"Payload",artefact:"opennext-lambda",stackPlacement:"compute",deployable:!0},nextjs:{label:"Next.js",constructIdSuffix:"Nextjs",artefact:"opennext-lambda",stackPlacement:"compute",deployable:!1},staticsite:{label:"Static site",constructIdSuffix:"StaticSite",artefact:"static-assets",stackPlacement:"cdn",deployable:!0}},l=e.filter(t=>a[t].deployable),o=e.filter(t=>a[t].artefact==="opennext-lambda"),c=new Set(o);function T(t){return t!=null&&c.has(t)}const r=["multipage","spa"];export{l as DEPLOYABLE_PATTERN_TYPES,o as OPENNEXT_PATTERN_TYPES,a as PATTERN_REGISTRY,n as PATTERN_TYPES,e as PATTERN_TYPE_VALUES,r as STATIC_SITE_ROUTING_VALUES,T as isOpenNextPatternType,s as isPatternType};
@@ -36,8 +36,8 @@ export declare const SCOPED_TOKEN_REGEX: RegExp;
36
36
  * Patterns: postgres://user:pass@host, password=xxx, secret=xxx, apikey=xxx,
37
37
  * GitHub tokens (ghu_/ghs_/ghp_/gho_/github_pat_), bare AWS access-key IDs
38
38
  * (AKIA-prefixed and ASIA-prefixed), AWS secret keys (env, INI, and JSON key
39
- * spellings), session tokens, ARN account IDs, agent tokens (`fjall_ak_`
40
- * scoped, `fjall_dk_` deploy).
39
+ * spellings), session tokens, agent tokens (`fjall_ak_` scoped, `fjall_dk_`
40
+ * deploy).
41
41
  *
42
42
  * Single source of truth — consumer loggers (CLI, worker, webapp) MUST
43
43
  * NOT re-implement these patterns inline. See
@@ -1 +1 @@
1
- const A=new Set(["NODE_OPTIONS","NODE_PATH","NODE_EXTRA_CA_CERTS","NODE_DEBUG","NODE_PRESERVE_SYMLINKS","LD_PRELOAD","LD_LIBRARY_PATH","LD_AUDIT","LD_BIND_NOW","DYLD_INSERT_LIBRARIES","DYLD_LIBRARY_PATH","DYLD_FRAMEWORK_PATH","PYTHONPATH","PYTHONSTARTUP","PERL5LIB","PERL5OPT","RUBYLIB","RUBYOPT","HOME","XDG_CONFIG_HOME","AWS_SHARED_CREDENTIALS_FILE","AWS_CONFIG_FILE","SHELL","BASH_ENV","ENV","ZDOTDIR"]);function i(e){return Object.fromEntries(Object.entries(e).filter(([r])=>!A.has(r.toUpperCase())))}const l=/fjall_(?:ak|dk)_[A-Z2-7]{16}\.[A-Z2-7]{40}/,c=/(fjall_(?:ak|dk)_)[A-Z2-7]{16}\.[A-Z2-7]{40}/g;function o(e){return e.replace(/-----BEGIN [A-Z ]*PRIVATE KEY-----(?:[^"\\]|\\[\\nrt"])*?-----END [A-Z ]*PRIVATE KEY-----/g,"-----BEGIN [REDACTED] PRIVATE KEY-----...-----END [REDACTED] PRIVATE KEY-----").replace(/-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g,"-----BEGIN [REDACTED] PRIVATE KEY-----...-----END [REDACTED] PRIVATE KEY-----").replace(/(\w+:\/\/[^:]+:)[^@]+(@)/gi,"$1***$2").replace(/(?<![a-zA-Z])(password|passwd|secret|api[_-]?key|token|auth|credential)([=:])["']?[^\s"']+/gi,"$1$2***").replace(/\b(ghu_|ghs_|ghp_|gho_|github_pat_)[A-Za-z0-9_]+/g,"$1***").replace(/\b(sk|rk)_(live|test)_[A-Za-z0-9]{8,}/g,"$1_$2_***").replace(/\bwhsec_[A-Za-z0-9]{8,}/g,"whsec_***").replace(/(?<=Authorization:\s*Bearer\s+)[A-Za-z0-9._~+/=-]+/gi,"***").replace(/\b(AKIA|ASIA)[A-Z0-9]{12,}\b/g,"$1***").replace(/(?<=aws_secret_access_key\s*=\s*["']?|SecretAccessKey[=:]\s*|"(aws)?secretAccessKey":\s*"|"aws_secret_access_key":\s*")[A-Za-z0-9/+=]{40,}/gi,"***").replace(/(arn:aws[^:]*:[^:]*:[^:]*:)(\d{12})(:[^\s]*)/g,"$1***$3").replace(/(?<="(aws)?sessionToken":\s*"|"aws_session_token":\s*")[^"]+/gi,"***").replace(/(?<=aws_session_token\s*[=:]\s*["']?|SessionToken[=:]\s*["']?)[^\s"']+/gi,"***").replace(/(?<="(internal[Aa]piKey|fjallCallbackToken)":\s*")[^"]+/g,"***").replace(c,"$1***")}function D(e){const r=[];let s="",E=!1,t=!1,n=!1,_=!1;for(const a of e){if(n){s+=a,n=!1;continue}if(a==="\\"&&!E){n=!0;continue}if(a==="'"&&!t){E=!E,_=!0;continue}if(a==='"'&&!E){t=!t,_=!0;continue}if(a===" "&&!E&&!t){(s||_)&&(r.push(s),s="",_=!1);continue}s+=a}if(E||t)throw new Error(`Unbalanced ${E?"single":"double"} quote in command: ${e.slice(0,80)}`);if(n)throw new Error(`Trailing backslash in command: ${e.slice(0,80)}`);return(s||_)&&r.push(s),r}export{A as DANGEROUS_ENV_VARS,l as SCOPED_TOKEN_REGEX,i as filterDangerousEnvVars,o as maskSensitiveOutput,D as parseShellArgs};
1
+ const n=new Set(["NODE_OPTIONS","NODE_PATH","NODE_EXTRA_CA_CERTS","NODE_DEBUG","NODE_PRESERVE_SYMLINKS","LD_PRELOAD","LD_LIBRARY_PATH","LD_AUDIT","LD_BIND_NOW","DYLD_INSERT_LIBRARIES","DYLD_LIBRARY_PATH","DYLD_FRAMEWORK_PATH","PYTHONPATH","PYTHONSTARTUP","PERL5LIB","PERL5OPT","RUBYLIB","RUBYOPT","HOME","XDG_CONFIG_HOME","AWS_SHARED_CREDENTIALS_FILE","AWS_CONFIG_FILE","SHELL","BASH_ENV","ENV","ZDOTDIR"]);function i(e){return Object.fromEntries(Object.entries(e).filter(([r])=>!n.has(r.toUpperCase())))}const l=/fjall_(?:ak|dk)_[A-Z2-7]{16}\.[A-Z2-7]{40}/,c=/(fjall_(?:ak|dk)_)[A-Z2-7]{16}\.[A-Z2-7]{40}/g;function o(e){return e.replace(/-----BEGIN [A-Z ]*PRIVATE KEY-----(?:[^"\\]|\\[\\nrt"])*?-----END [A-Z ]*PRIVATE KEY-----/g,"-----BEGIN [REDACTED] PRIVATE KEY-----...-----END [REDACTED] PRIVATE KEY-----").replace(/-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g,"-----BEGIN [REDACTED] PRIVATE KEY-----...-----END [REDACTED] PRIVATE KEY-----").replace(/(\w+:\/\/[^:]+:)[^@]+(@)/gi,"$1***$2").replace(/(?<![a-zA-Z])(password|passwd|secret|api[_-]?key|token|auth|credential)([=:])["']?[^\s"']+/gi,"$1$2***").replace(/\b(ghu_|ghs_|ghp_|gho_|github_pat_)[A-Za-z0-9_]+/g,"$1***").replace(/\b(sk|rk)_(live|test)_[A-Za-z0-9]{8,}/g,"$1_$2_***").replace(/\bwhsec_[A-Za-z0-9]{8,}/g,"whsec_***").replace(/(?<=Authorization:\s*Bearer\s+)[A-Za-z0-9._~+/=-]+/gi,"***").replace(/\b(AKIA|ASIA)[A-Z0-9]{12,}\b/g,"$1***").replace(/(?<=aws_secret_access_key\s*=\s*["']?|SecretAccessKey[=:]\s*|"(aws)?secretAccessKey":\s*"|"aws_secret_access_key":\s*")[A-Za-z0-9/+=]{40,}/gi,"***").replace(/(?<="(aws)?sessionToken":\s*"|"aws_session_token":\s*")[^"]+/gi,"***").replace(/(?<=aws_session_token\s*[=:]\s*["']?|SessionToken[=:]\s*["']?)[^\s"']+/gi,"***").replace(/(?<="(internal[Aa]piKey|fjallCallbackToken)":\s*")[^"]+/g,"***").replace(c,"$1***")}function D(e){const r=[];let s="",E=!1,t=!1,A=!1,_=!1;for(const a of e){if(A){s+=a,A=!1;continue}if(a==="\\"&&!E){A=!0;continue}if(a==="'"&&!t){E=!E,_=!0;continue}if(a==='"'&&!E){t=!t,_=!0;continue}if(a===" "&&!E&&!t){(s||_)&&(r.push(s),s="",_=!1);continue}s+=a}if(E||t)throw new Error(`Unbalanced ${E?"single":"double"} quote in command: ${e.slice(0,80)}`);if(A)throw new Error(`Trailing backslash in command: ${e.slice(0,80)}`);return(s||_)&&r.push(s),r}export{n as DANGEROUS_ENV_VARS,l as SCOPED_TOKEN_REGEX,i as filterDangerousEnvVars,o as maskSensitiveOutput,D as parseShellArgs};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fjall/util",
3
- "version": "2.32.0",
3
+ "version": "2.34.0",
4
4
  "description": "Common utility methods",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -134,5 +134,5 @@
134
134
  "engines": {
135
135
  "node": ">=22.0.0"
136
136
  },
137
- "gitHead": "876a79a9ad0031a5919019c86867c28c1ab9dc92"
137
+ "gitHead": "8c553fca8f9737d445061ea75cf6c6c7db0d24c9"
138
138
  }