@fjall/util 2.30.0 → 2.31.1

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
- 84 files minified at 2026-07-15T07:08:25.279Z
1
+ 84 files minified at 2026-07-16T20:42:02.563Z
@@ -42,6 +42,14 @@ export type ImageTag = z.infer<typeof ImageTagSchema>;
42
42
  * neither may invent placeholder values. `previousTaskDefinitionArn` exists
43
43
  * only where an explicit RegisterTaskDefinition rollout captured it.
44
44
  * `ecrRepositoryArn` is absent for non-ECR registries.
45
+ *
46
+ * `functionArn`/`publishedVersion` are the Lambda analogue of
47
+ * `taskDefinitionArn`: present whenever a fresh version was published for a
48
+ * container-image Lambda — on a full deploy via the best-effort post-deploy
49
+ * `lambda:PublishVersion` step (a publish failure degrades the artefact, it
50
+ * never fails an already-succeeded deploy), and on code-only rollouts AND
51
+ * rollbacks via `UpdateFunctionCode`'s `Publish: true`, which publishes
52
+ * alongside the update itself.
45
53
  */
46
54
  export declare const ServiceArtefactSchema: z.ZodObject<{
47
55
  serviceName: z.ZodString;
@@ -51,6 +59,8 @@ export declare const ServiceArtefactSchema: z.ZodObject<{
51
59
  ecrRepositoryArn: z.ZodOptional<z.ZodString>;
52
60
  taskDefinitionArn: z.ZodOptional<z.ZodString>;
53
61
  previousTaskDefinitionArn: z.ZodOptional<z.ZodString>;
62
+ functionArn: z.ZodOptional<z.ZodString>;
63
+ publishedVersion: z.ZodOptional<z.ZodString>;
54
64
  }, z.core.$strict>;
55
65
  export type ServiceArtefact = z.infer<typeof ServiceArtefactSchema>;
56
66
  export declare const ServiceArtefactsSchema: z.ZodArray<z.ZodObject<{
@@ -61,6 +71,8 @@ export declare const ServiceArtefactsSchema: z.ZodArray<z.ZodObject<{
61
71
  ecrRepositoryArn: z.ZodOptional<z.ZodString>;
62
72
  taskDefinitionArn: z.ZodOptional<z.ZodString>;
63
73
  previousTaskDefinitionArn: z.ZodOptional<z.ZodString>;
74
+ functionArn: z.ZodOptional<z.ZodString>;
75
+ publishedVersion: z.ZodOptional<z.ZodString>;
64
76
  }, z.core.$strict>>;
65
77
  export type ServiceArtefacts = z.infer<typeof ServiceArtefactsSchema>;
66
78
  /**
@@ -1 +1 @@
1
- import{z as t}from"zod";const r=["full","code-only","rollback","restart"],c=t.enum(r),n=/^[a-zA-Z0-9._-]+$/,o=t.string().min(1).max(128).regex(n),a=t.object({serviceName:t.string().min(1),imageTag:o,imageDigest:t.string().min(1).optional(),imageUri:t.string().min(1),ecrRepositoryArn:t.string().min(1).optional(),taskDefinitionArn:t.string().min(1).optional(),previousTaskDefinitionArn:t.string().min(1).optional()}).strict(),m=t.array(a),g=["TaskDefinition","PreviousTaskDefinition","ImageTag","ImageUri","EcrRepositoryArn","ImageDigest"];function p(e,i){return`${e}${i}`}export{g as ARTEFACT_OUTPUT_FIELDS,r as DEPLOY_MODES,c as DeployModeSchema,n as IMAGE_TAG_PATTERN,o as ImageTagSchema,a as ServiceArtefactSchema,m as ServiceArtefactsSchema,p as artefactOutputKey};
1
+ import{z as i}from"zod";const n=["full","code-only","rollback","restart"],c=i.enum(n),o=/^[a-zA-Z0-9._-]+$/,r=i.string().min(1).max(128).regex(o),a=i.object({serviceName:i.string().min(1),imageTag:r,imageDigest:i.string().min(1).optional(),imageUri:i.string().min(1),ecrRepositoryArn:i.string().min(1).optional(),taskDefinitionArn:i.string().min(1).optional(),previousTaskDefinitionArn:i.string().min(1).optional(),functionArn:i.string().min(1).optional(),publishedVersion:i.string().min(1).optional()}).strict(),m=i.array(a),g=["TaskDefinition","PreviousTaskDefinition","ImageTag","ImageUri","EcrRepositoryArn","ImageDigest"];function p(t,e){return`${t}${e}`}export{g as ARTEFACT_OUTPUT_FIELDS,n as DEPLOY_MODES,c as DeployModeSchema,o as IMAGE_TAG_PATTERN,r as ImageTagSchema,a as ServiceArtefactSchema,m as ServiceArtefactsSchema,p as artefactOutputKey};
@@ -7,4 +7,4 @@
7
7
  * the barrel — the package.json `exports` map exposes both subpaths.
8
8
  */
9
9
  export { DockerBuildSchema, DockerBuildArgValueSchema, DockerBuildSecretRefSchema, DockerBuildPartialSchema, mergeDockerBuild, ManifestServiceSchema, ManifestPatternSchema, ManifestEcrSchema, ManifestLambdaSchema, ManifestStackHashSchema, ResourceMapEntrySchema, FjallManifestSchema, FJALL_MANIFEST_FILENAME, MANIFEST_SCHEMA_VERSION, BUILDKIT_SECRET_ID_PATTERN, type DockerBuild, type DockerBuildArgValue, type DockerBuildSecretRef, type DockerBuildPartial, type ManifestService, type ManifestPattern, type ManifestEcr, type ManifestLambda, type ManifestStackHash, type ResourceMapEntry, type FjallManifest } from "./schemas.js";
10
- export { getManifestFilePath, readManifestFile, writeManifestFile, createEmptyManifest, readConstructMap, parseDockerServicesFromManifest, type ManifestDockerService } from "./io.js";
10
+ export { getManifestFilePath, readManifestFile, writeManifestFile, createEmptyManifest, readConstructMap, parseDockerServicesFromManifest, parseLambdaDockerServicesFromManifest, parseLambdaDockerEntriesFromManifest, parseDockerDeclarationsFromManifest, type ManifestDockerService, type ManifestLambdaDockerEntry, type ManifestDockerDeclarations } from "./io.js";
@@ -1 +1 @@
1
- import{DockerBuildSchema as r,DockerBuildArgValueSchema as t,DockerBuildSecretRefSchema as c,DockerBuildPartialSchema as i,mergeDockerBuild as S,ManifestServiceSchema as m,ManifestPatternSchema as M,ManifestEcrSchema as s,ManifestLambdaSchema as f,ManifestStackHashSchema as n,ResourceMapEntrySchema as h,FjallManifestSchema as o,FJALL_MANIFEST_FILENAME as l,MANIFEST_SCHEMA_VERSION as E,BUILDKIT_SECRET_ID_PATTERN as F}from"./schemas.js";import{getManifestFilePath as u,readManifestFile as D,writeManifestFile as k,createEmptyManifest as A,readConstructMap as I,parseDockerServicesFromManifest as _}from"./io.js";export{F as BUILDKIT_SECRET_ID_PATTERN,t as DockerBuildArgValueSchema,i as DockerBuildPartialSchema,r as DockerBuildSchema,c as DockerBuildSecretRefSchema,l as FJALL_MANIFEST_FILENAME,o as FjallManifestSchema,E as MANIFEST_SCHEMA_VERSION,s as ManifestEcrSchema,f as ManifestLambdaSchema,M as ManifestPatternSchema,m as ManifestServiceSchema,n as ManifestStackHashSchema,h as ResourceMapEntrySchema,A as createEmptyManifest,u as getManifestFilePath,S as mergeDockerBuild,_ as parseDockerServicesFromManifest,I as readConstructMap,D as readManifestFile,k as writeManifestFile};
1
+ import{DockerBuildSchema as r,DockerBuildArgValueSchema as t,DockerBuildSecretRefSchema as c,DockerBuildPartialSchema as i,mergeDockerBuild as s,ManifestServiceSchema as m,ManifestPatternSchema as S,ManifestEcrSchema as o,ManifestLambdaSchema as M,ManifestStackHashSchema as n,ResourceMapEntrySchema as f,FjallManifestSchema as h,FJALL_MANIFEST_FILENAME as l,MANIFEST_SCHEMA_VERSION as E,BUILDKIT_SECRET_ID_PATTERN as D}from"./schemas.js";import{getManifestFilePath as d,readManifestFile as k,writeManifestFile as p,createEmptyManifest as u,readConstructMap as A,parseDockerServicesFromManifest as I,parseLambdaDockerServicesFromManifest as L,parseLambdaDockerEntriesFromManifest as _,parseDockerDeclarationsFromManifest as B}from"./io.js";export{D as BUILDKIT_SECRET_ID_PATTERN,t as DockerBuildArgValueSchema,i as DockerBuildPartialSchema,r as DockerBuildSchema,c as DockerBuildSecretRefSchema,l as FJALL_MANIFEST_FILENAME,h as FjallManifestSchema,E as MANIFEST_SCHEMA_VERSION,o as ManifestEcrSchema,M as ManifestLambdaSchema,S as ManifestPatternSchema,m as ManifestServiceSchema,n as ManifestStackHashSchema,f as ResourceMapEntrySchema,u as createEmptyManifest,d as getManifestFilePath,s as mergeDockerBuild,B as parseDockerDeclarationsFromManifest,I as parseDockerServicesFromManifest,_ as parseLambdaDockerEntriesFromManifest,L as parseLambdaDockerServicesFromManifest,A as readConstructMap,k as readManifestFile,p as writeManifestFile};
@@ -58,3 +58,80 @@ export interface ManifestDockerService {
58
58
  * the deploy phase.
59
59
  */
60
60
  export declare function parseDockerServicesFromManifest(cdkOutPath: string): ManifestDockerService[];
61
+ /**
62
+ * Extract Lambda container-image entries with a Docker build configuration
63
+ * from the Fjall manifest, projected into the same `{name, docker}` shape
64
+ * `parseDockerServicesFromManifest` returns for ECS services — this lets both
65
+ * lists feed the same downstream build/grouping/tagging pipeline unchanged.
66
+ *
67
+ * The projected `name` is the Lambda's `imageKey` (falling back to its own
68
+ * manifest `name` when absent): several Lambda functions may deliberately
69
+ * share one built image, so the build/tag identity is keyed by the shared
70
+ * image, not by each function's own name. Entries sharing one `imageKey` are
71
+ * deduped to a single build; a divergent `docker` config across entries
72
+ * sharing an `imageKey` is a real config mistake (ambiguous which build
73
+ * should win) and throws rather than silently picking one.
74
+ *
75
+ * Returns an empty array if the manifest does not exist, cannot be parsed, or
76
+ * contains no Lambda Docker entries. Lambdas without a `docker` block
77
+ * (bring-your-own-image) are skipped, not an error.
78
+ *
79
+ * Throws deliberately (not a `Result`) on divergent shared-`imageKey` docker
80
+ * 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
85
+ * 2026-07-16 docker-lambda review; do not re-litigate as a Pitfall-4 escape.
86
+ */
87
+ export declare function parseLambdaDockerServicesFromManifest(cdkOutPath: string): ManifestDockerService[];
88
+ /** A single container-Lambda manifest entry that declared a `docker` block. */
89
+ export interface ManifestLambdaDockerEntry {
90
+ /** The Lambda's own manifest/function name (NOT the shared image key). */
91
+ readonly name: string;
92
+ /** Shared build/tag key — `imageKey` if set, else `name`. */
93
+ readonly imageKey: string;
94
+ readonly docker: DockerBuild;
95
+ }
96
+ /**
97
+ * Extract every container-Lambda manifest entry that declared a `docker`
98
+ * block, WITHOUT deduping by `imageKey` — unlike
99
+ * `parseLambdaDockerServicesFromManifest`, this preserves each function's own
100
+ * `name`, needed to map a built image's shared `imageKey` back to the actual
101
+ * Lambda function name(s) that need a fresh published version after deploy
102
+ * (`lambda:PublishVersion` takes a function name, not an image key).
103
+ */
104
+ export declare function parseLambdaDockerEntriesFromManifest(cdkOutPath: string): ManifestLambdaDockerEntry[];
105
+ /**
106
+ * Every Docker build the post-synth manifest declares, across BOTH
107
+ * independent namespaces: ECS service `docker` configs (`manifest.services`)
108
+ * and container-Lambda `docker` blocks (`manifest.lambdas`).
109
+ */
110
+ export interface ManifestDockerDeclarations {
111
+ readonly ecsServices: ManifestDockerService[];
112
+ readonly lambdaEntries: ManifestLambdaDockerEntry[];
113
+ /**
114
+ * True when either namespace declares at least one build. This is the
115
+ * canonical "does this app need a Docker build?" presence gate — see
116
+ * `parseDockerDeclarationsFromManifest`.
117
+ */
118
+ readonly declaresBuild: boolean;
119
+ }
120
+ /**
121
+ * Aggregate view of every Docker build declared in the manifest. Presence
122
+ * gates ("should a Docker build run for this app?") MUST consume
123
+ * `declaresBuild` from here rather than composing the namespace parsers
124
+ * themselves: the namespaces are independent, and a gate that checks only one
125
+ * silently misses apps whose builds live entirely in the other — detection
126
+ * once checked only `manifest.services`, so a container-Lambda-only app never
127
+ * built and fell back to welcome-image seeding.
128
+ *
129
+ * When adding a new docker-carrying manifest namespace, extend this aggregate
130
+ * (fields + `declaresBuild`) in the same change as the build-group
131
+ * composition in deploy-core's `dockerBuildHelper` — the two must agree on
132
+ * emptiness, or presence and execution drift apart again.
133
+ *
134
+ * Never throws: both underlying parsers return `[]` on a missing or
135
+ * malformed manifest.
136
+ */
137
+ export declare function parseDockerDeclarationsFromManifest(cdkOutPath: string): ManifestDockerDeclarations;
@@ -1 +1 @@
1
- import{readFile as l,writeFile as m,unlink as g,rename as h,mkdir as y}from"fs/promises";import{readFileSync as M}from"fs";import{dirname as F,join as f}from"path";import{logger as o}from"../logger.js";import{fileExists as S}from"../fsHelpers.js";import{getErrorMessage as d}from"../errorUtils.js";import{recordToConstructMap as b}from"../constructMap.js";import{DockerBuildSchema as A,FjallManifestSchema as w,FJALL_MANIFEST_FILENAME as u,MANIFEST_SCHEMA_VERSION as x}from"./schemas.js";function p(e){return f(e,u)}async function k(e){const t=p(e);if(!await S(t))return null;try{const n=await l(t,"utf-8"),r=JSON.parse(n),i=w.safeParse(r);return i.success||o.debug("FjallManifest","Manifest validation failed",{path:t,errors:i.error.issues.map(a=>`${a.path.join(".")}: ${a.message}`)}),i.success?i.data:null}catch(n){return o.debug("FjallManifest","Failed to read manifest file",{path:t,error:d(n)}),null}}async function T(e,t){const n=p(e),r=`${n}.${Date.now()}.tmp`;await y(F(n),{recursive:!0});try{await m(r,JSON.stringify(t,null,2),"utf-8"),await h(r,n)}catch(i){try{await g(r)}catch(a){o.debug("FjallManifest","Temp file cleanup failed (non-fatal)",{path:r,error:d(a)})}throw i}}function _(e){return{version:x,generatedAt:new Date().toISOString(),appName:e,services:[],lambdas:[],stacks:{}}}async function $(e){const t=await k(e);return t?.resourceMap?b(t.resourceMap):new Map}function c(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function j(e){if(!c(e)||typeof e.path!="string"||e.path.length===0)return;const t=typeof e.context=="string"&&e.context.length>0?e.context:void 0,n=typeof e.target=="string"&&e.target.length>0?e.target:void 0,r=c(e.buildArgs)&&Object.keys(e.buildArgs).length>0?e.buildArgs:void 0,i=Array.isArray(e.buildSecrets)&&e.buildSecrets.length>0?e.buildSecrets:void 0,a={path:e.path,...t!==void 0&&{context:t},...n!==void 0&&{target:n},...r!==void 0&&{buildArgs:r},...i!==void 0&&{buildSecrets:i}},s=A.safeParse(a);return s.success?s.data:void 0}function L(e){const t=f(e,u);let n;try{n=M(t,"utf-8")}catch{return o.debug("FjallManifest","Manifest file not readable \u2014 no Docker services extracted",{path:t}),[]}let r;try{r=JSON.parse(n)}catch{return o.debug("FjallManifest","Manifest is not valid JSON \u2014 no Docker services extracted",{path:t}),[]}if(!c(r)||!Array.isArray(r.services))return[];const i=[];for(const a of r.services){if(!c(a)||typeof a.name!="string")continue;const s=j(a.docker);s!==void 0&&i.push({name:a.name,docker:s})}return i}export{_ as createEmptyManifest,p as getManifestFilePath,L as parseDockerServicesFromManifest,$ as readConstructMap,k as readManifestFile,T as writeManifestFile};
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};
@@ -176,6 +176,35 @@ export type DockerBuildPartial = z.infer<typeof DockerBuildPartialSchema>;
176
176
  * invoke this when they have a service-side `docker` to merge against.
177
177
  */
178
178
  export declare function mergeDockerBuild(service: DockerBuild, migrationsOverride: DockerBuildPartial | undefined): DockerBuild;
179
+ /**
180
+ * Normalise a candidate `docker` sub-object: empty-string fields are coerced
181
+ * to undefined at the parser boundary so downstream consumers never have to
182
+ * distinguish `target: ""` from `target: undefined` (AC17).
183
+ *
184
+ * `buildArgs` is carried through verbatim — it is the only channel by which
185
+ * Vite-style `VITE_*` values reach the production client bundle, so dropping it
186
+ * here ships a bundle built with no `--build-arg` flags. A value may be a plain
187
+ * string (the common case) OR the public-but-sensitive object form
188
+ * (`DockerBuildArgValue`); both are validated by the final `DockerBuildSchema`
189
+ * safeParse below (a malformed value makes the whole docker candidate invalid,
190
+ * never throwing — safeParse returns undefined). An empty map is coerced to
191
+ * undefined for parity with the empty-string scalar handling.
192
+ *
193
+ * `buildSecrets` is carried through verbatim too — an empty array is coerced to
194
+ * undefined for parity. Each ref is validated by the final `DockerBuildSchema`
195
+ * safeParse below.
196
+ */
197
+ export declare function normaliseDockerBuild(value: unknown): DockerBuild | undefined;
198
+ /**
199
+ * Canonical comparator for "identical docker configs". Both deploy-time
200
+ * guards (assertNoCrossEntityBuildKeyDivergence in deploy-core's
201
+ * dockerBuildHelper; parseLambdaDockerServicesFromManifest in ./io.ts) and
202
+ * the synth-time guard (getOrCreateImageTagParameter in
203
+ * @fjall/components-infrastructure) must agree byte-for-byte — the
204
+ * fingerprint routes through normaliseDockerBuild so the empty-value
205
+ * coercions and field order match on every side.
206
+ */
207
+ export declare function dockerBuildFingerprint(docker: DockerBuild | undefined): string | undefined;
179
208
  declare const ManifestServiceSchema: z.ZodObject<{
180
209
  name: z.ZodString;
181
210
  clusterName: z.ZodOptional<z.ZodString>;
@@ -229,6 +258,32 @@ declare const ManifestLambdaSchema: z.ZodObject<{
229
258
  secrets: z.ZodOptional<z.ZodArray<z.ZodString>>;
230
259
  ssmSecretsPath: z.ZodOptional<z.ZodString>;
231
260
  importedSecretNames: z.ZodOptional<z.ZodArray<z.ZodString>>;
261
+ docker: z.ZodOptional<z.ZodObject<{
262
+ path: z.ZodString;
263
+ context: z.ZodOptional<z.ZodString>;
264
+ target: z.ZodOptional<z.ZodString>;
265
+ buildArgs: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
266
+ ssm: z.ZodOptional<z.ZodString>;
267
+ secretsManager: z.ZodOptional<z.ZodObject<{
268
+ name: z.ZodOptional<z.ZodString>;
269
+ arn: z.ZodOptional<z.ZodString>;
270
+ field: z.ZodOptional<z.ZodString>;
271
+ }, z.core.$strict>>;
272
+ env: z.ZodOptional<z.ZodString>;
273
+ acknowledgePublic: z.ZodOptional<z.ZodBoolean>;
274
+ }, z.core.$strict>]>>>;
275
+ buildSecrets: z.ZodOptional<z.ZodArray<z.ZodObject<{
276
+ id: z.ZodString;
277
+ ssm: z.ZodOptional<z.ZodString>;
278
+ secretsManager: z.ZodOptional<z.ZodObject<{
279
+ name: z.ZodOptional<z.ZodString>;
280
+ arn: z.ZodOptional<z.ZodString>;
281
+ field: z.ZodOptional<z.ZodString>;
282
+ }, z.core.$strict>>;
283
+ env: z.ZodOptional<z.ZodString>;
284
+ }, z.core.$strict>>>;
285
+ }, z.core.$strict>>;
286
+ imageKey: z.ZodOptional<z.ZodString>;
232
287
  }, z.core.$strict>;
233
288
  export type ManifestLambda = z.infer<typeof ManifestLambdaSchema>;
234
289
  declare const ManifestStackHashSchema: z.ZodObject<{
@@ -294,6 +349,32 @@ export declare const FjallManifestSchema: z.ZodObject<{
294
349
  secrets: z.ZodOptional<z.ZodArray<z.ZodString>>;
295
350
  ssmSecretsPath: z.ZodOptional<z.ZodString>;
296
351
  importedSecretNames: z.ZodOptional<z.ZodArray<z.ZodString>>;
352
+ docker: z.ZodOptional<z.ZodObject<{
353
+ path: z.ZodString;
354
+ context: z.ZodOptional<z.ZodString>;
355
+ target: z.ZodOptional<z.ZodString>;
356
+ buildArgs: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
357
+ ssm: z.ZodOptional<z.ZodString>;
358
+ secretsManager: z.ZodOptional<z.ZodObject<{
359
+ name: z.ZodOptional<z.ZodString>;
360
+ arn: z.ZodOptional<z.ZodString>;
361
+ field: z.ZodOptional<z.ZodString>;
362
+ }, z.core.$strict>>;
363
+ env: z.ZodOptional<z.ZodString>;
364
+ acknowledgePublic: z.ZodOptional<z.ZodBoolean>;
365
+ }, z.core.$strict>]>>>;
366
+ buildSecrets: z.ZodOptional<z.ZodArray<z.ZodObject<{
367
+ id: z.ZodString;
368
+ ssm: z.ZodOptional<z.ZodString>;
369
+ secretsManager: z.ZodOptional<z.ZodObject<{
370
+ name: z.ZodOptional<z.ZodString>;
371
+ arn: z.ZodOptional<z.ZodString>;
372
+ field: z.ZodOptional<z.ZodString>;
373
+ }, z.core.$strict>>;
374
+ env: z.ZodOptional<z.ZodString>;
375
+ }, z.core.$strict>>>;
376
+ }, z.core.$strict>>;
377
+ imageKey: z.ZodOptional<z.ZodString>;
297
378
  }, z.core.$strict>>;
298
379
  pattern: z.ZodOptional<z.ZodObject<{
299
380
  type: z.ZodEnum<{
@@ -1 +1 @@
1
- import{z as e}from"zod";import{PATTERN_TYPE_VALUES as u}from"../patterns/patternTypes.js";const M="fjall-manifest.json",b=1,f=/^[A-Za-z0-9_.-]+$/,S=e.object({id:e.string().min(1,"buildSecret id cannot be empty").regex(f,"buildSecret id may contain only letters, digits, '_', '.', and '-' (no comma, '=', or whitespace, which would break the buildx --secret argv)"),ssm:e.string().min(1,"ssm parameter name cannot be empty").optional(),secretsManager:e.object({name:e.string().min(1,"secret name cannot be empty").optional(),arn:e.string().min(1,"secret arn cannot be empty").optional(),field:e.string().min(1,"secret field cannot be empty").optional()}).strict().refine(t=>t.name===void 0!=(t.arn===void 0),"secretsManager requires exactly one of name or arn").optional(),env:e.string().min(1,"env variable name cannot be empty").optional()}).strict().superRefine((t,n)=>{[t.ssm,t.secretsManager,t.env].filter(r=>r!==void 0).length!==1&&n.addIssue({code:e.ZodIssueCode.custom,message:"buildSecret requires exactly one source (ssm, secretsManager, or env)"})}),y=e.union([e.string(),e.object({ssm:e.string().min(1,"ssm parameter name cannot be empty").optional(),secretsManager:e.object({name:e.string().min(1,"secret name cannot be empty").optional(),arn:e.string().min(1,"secret arn cannot be empty").optional(),field:e.string().min(1,"secret field cannot be empty").optional()}).strict().refine(t=>t.name===void 0!=(t.arn===void 0),"secretsManager requires exactly one of name or arn").optional(),env:e.string().min(1,"env variable name cannot be empty").optional(),acknowledgePublic:e.boolean().optional()}).strict().superRefine((t,n)=>{[t.ssm,t.secretsManager,t.env].filter(r=>r!==void 0).length!==1&&n.addIssue({code:e.ZodIssueCode.custom,message:"buildArg value requires exactly one source (ssm, secretsManager, or env)"})})]),i=e.object({path:e.string(),context:e.string().min(1,"context cannot be empty").optional(),target:e.string().min(1,"target cannot be empty").optional(),buildArgs:e.record(e.string(),y).optional(),buildSecrets:e.array(S).optional()}).strict(),A=i.partial();function j(t,n){if(n===void 0)return t;const a=n.context??t.context,r=n.target??t.target,o=n.buildArgs??t.buildArgs,s=n.buildSecrets??t.buildSecrets;return{path:n.path??t.path,...a!==void 0&&{context:a},...r!==void 0&&{target:r},...o!==void 0&&{buildArgs:o},...s!==void 0&&{buildSecrets:s}}}const c=e.object({name:e.string(),clusterName:e.string().optional(),docker:i.optional(),containerPort:e.number().optional(),secrets:e.array(e.string()).optional(),ssmSecretsPath:e.string().optional(),importedSecretNames:e.array(e.string()).optional()}).strict(),m=e.object({type:e.enum(u),name:e.string(),source:e.string()}).strict(),l=e.object({repositoryName:e.string()}).strict(),p=e.object({name:e.string(),secrets:e.array(e.string()).optional(),ssmSecretsPath:e.string().optional(),importedSecretNames:e.array(e.string()).optional()}).strict(),d=e.object({templateHash:e.string(),synthTimestamp:e.string()}).strict(),g=e.object({constructPath:e.string().max(512),group:e.string().max(128),resourceType:e.string().max(256)}).strict(),E=e.object({version:e.literal(b),generatedAt:e.string(),appName:e.string(),services:e.array(c),lambdas:e.array(p),pattern:m.optional(),ecr:l.optional(),stacks:e.record(e.string(),d),resourceMap:e.record(e.string(),g).optional()}).strict();export{f as BUILDKIT_SECRET_ID_PATTERN,y as DockerBuildArgValueSchema,A as DockerBuildPartialSchema,i as DockerBuildSchema,S as DockerBuildSecretRefSchema,M as FJALL_MANIFEST_FILENAME,E as FjallManifestSchema,b as MANIFEST_SCHEMA_VERSION,l as ManifestEcrSchema,p as ManifestLambdaSchema,m as ManifestPatternSchema,c as ManifestServiceSchema,d as ManifestStackHashSchema,g as ResourceMapEntrySchema,j as mergeDockerBuild};
1
+ import{z as e}from"zod";import{PATTERN_TYPE_VALUES as b}from"../patterns/patternTypes.js";const E="fjall-manifest.json",y=1,S=/^[A-Za-z0-9_.-]+$/,h=e.object({id:e.string().min(1,"buildSecret id cannot be empty").regex(S,"buildSecret id may contain only letters, digits, '_', '.', and '-' (no comma, '=', or whitespace, which would break the buildx --secret argv)"),ssm:e.string().min(1,"ssm parameter name cannot be empty").optional(),secretsManager:e.object({name:e.string().min(1,"secret name cannot be empty").optional(),arn:e.string().min(1,"secret arn cannot be empty").optional(),field:e.string().min(1,"secret field cannot be empty").optional()}).strict().refine(t=>t.name===void 0!=(t.arn===void 0),"secretsManager requires exactly one of name or arn").optional(),env:e.string().min(1,"env variable name cannot be empty").optional()}).strict().superRefine((t,n)=>{[t.ssm,t.secretsManager,t.env].filter(r=>r!==void 0).length!==1&&n.addIssue({code:e.ZodIssueCode.custom,message:"buildSecret requires exactly one source (ssm, secretsManager, or env)"})}),x=e.union([e.string(),e.object({ssm:e.string().min(1,"ssm parameter name cannot be empty").optional(),secretsManager:e.object({name:e.string().min(1,"secret name cannot be empty").optional(),arn:e.string().min(1,"secret arn cannot be empty").optional(),field:e.string().min(1,"secret field cannot be empty").optional()}).strict().refine(t=>t.name===void 0!=(t.arn===void 0),"secretsManager requires exactly one of name or arn").optional(),env:e.string().min(1,"env variable name cannot be empty").optional(),acknowledgePublic:e.boolean().optional()}).strict().superRefine((t,n)=>{[t.ssm,t.secretsManager,t.env].filter(r=>r!==void 0).length!==1&&n.addIssue({code:e.ZodIssueCode.custom,message:"buildArg value requires exactly one source (ssm, secretsManager, or env)"})})]),a=e.object({path:e.string(),context:e.string().min(1,"context cannot be empty").optional(),target:e.string().min(1,"target cannot be empty").optional(),buildArgs:e.record(e.string(),x).optional(),buildSecrets:e.array(h).optional()}).strict(),k=a.partial();function N(t,n){if(n===void 0)return t;const s=n.context??t.context,r=n.target??t.target,o=n.buildArgs??t.buildArgs,i=n.buildSecrets??t.buildSecrets;return{path:n.path??t.path,...s!==void 0&&{context:s},...r!==void 0&&{target:r},...o!==void 0&&{buildArgs:o},...i!==void 0&&{buildSecrets:i}}}function d(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}function A(t){if(!d(t)||typeof t.path!="string"||t.path.length===0)return;const n=typeof t.context=="string"&&t.context.length>0?t.context:void 0,s=typeof t.target=="string"&&t.target.length>0?t.target:void 0,r=d(t.buildArgs)&&Object.keys(t.buildArgs).length>0?t.buildArgs:void 0,o=Array.isArray(t.buildSecrets)&&t.buildSecrets.length>0?t.buildSecrets:void 0,i={path:t.path,...n!==void 0&&{context:n},...s!==void 0&&{target:s},...r!==void 0&&{buildArgs:r},...o!==void 0&&{buildSecrets:o}},c=a.safeParse(i);return c.success?c.data:void 0}function T(t){if(t===void 0)return;const n=A(t);return n===void 0?void 0:JSON.stringify(n)}const m=e.object({name:e.string(),clusterName:e.string().optional(),docker:a.optional(),containerPort:e.number().optional(),secrets:e.array(e.string()).optional(),ssmSecretsPath:e.string().optional(),importedSecretNames:e.array(e.string()).optional()}).strict(),p=e.object({type:e.enum(b),name:e.string(),source:e.string()}).strict(),g=e.object({repositoryName:e.string()}).strict(),l=e.object({name:e.string(),secrets:e.array(e.string()).optional(),ssmSecretsPath:e.string().optional(),importedSecretNames:e.array(e.string()).optional(),docker:a.optional(),imageKey:e.string().optional()}).strict(),u=e.object({templateHash:e.string(),synthTimestamp:e.string()}).strict(),f=e.object({constructPath:e.string().max(512),group:e.string().max(128),resourceType:e.string().max(256)}).strict(),I=e.object({version:e.literal(y),generatedAt:e.string(),appName:e.string(),services:e.array(m),lambdas:e.array(l),pattern:p.optional(),ecr:g.optional(),stacks:e.record(e.string(),u),resourceMap:e.record(e.string(),f).optional()}).strict();export{S as BUILDKIT_SECRET_ID_PATTERN,x as DockerBuildArgValueSchema,k as DockerBuildPartialSchema,a as DockerBuildSchema,h as DockerBuildSecretRefSchema,E as FJALL_MANIFEST_FILENAME,I as FjallManifestSchema,y as MANIFEST_SCHEMA_VERSION,g as ManifestEcrSchema,l as ManifestLambdaSchema,p as ManifestPatternSchema,m as ManifestServiceSchema,u as ManifestStackHashSchema,f as ResourceMapEntrySchema,T as dockerBuildFingerprint,N as mergeDockerBuild,A as normaliseDockerBuild};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fjall/util",
3
- "version": "2.30.0",
3
+ "version": "2.31.1",
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": "ec35b16db566dfa5feb714c16f132c55b4663c86"
137
+ "gitHead": "a48cfaf6e050ce1736837802dfcaf517ba39f199"
138
138
  }