@fjall/util 5.0.0 → 7.0.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.
@@ -1,10 +1,15 @@
1
1
  {
2
- "version": 1,
2
+ "version": 2,
3
3
  "algorithm": "sha256",
4
4
  "sources": [
5
5
  "src"
6
6
  ],
7
- "hash": "c7da9c6581b1a1d5b8be8b5e44ba927a9cc73f9d84dee54c914882e771b3713b",
7
+ "extraFiles": [
8
+ "../scripts/minify-dist.mjs",
9
+ "package.json",
10
+ "tsconfig.json"
11
+ ],
12
+ "hash": "3de34c201d7566360e7f623c5429a95610accc983fd1057113844a0d2e1a41d0",
8
13
  "files": {
9
14
  "src/async/concurrency.ts": "3c7ebe0222a720f9",
10
15
  "src/async/singleton.ts": "7bcc21b0fb920561",
@@ -21,9 +26,10 @@
21
26
  "src/aws/maskFailureAnalysis.ts": "ae11250412cd6fd8",
22
27
  "src/aws/monitoringRole.ts": "70c8b5947dc9138d",
23
28
  "src/buildConcurrency.ts": "1804e76ddc4f8216",
29
+ "src/capacityIdentity.ts": "9e59bfc92a5ba361",
24
30
  "src/cdkTmpdirCleanup.ts": "4574b3f10e3ab0f9",
25
31
  "src/cfn/physicalNameProperties.ts": "35d3c6f28079c593",
26
- "src/config.ts": "7a6f4eb2a0d551cb",
32
+ "src/config.ts": "11c577414a91c542",
27
33
  "src/constructMap.ts": "b81fc8e90015467f",
28
34
  "src/deploy/approvalTokenOutput.ts": "4be7b52825d88a37",
29
35
  "src/devSubstrate/entrypoint.ts": "0526b88258174aa6",
@@ -54,7 +60,7 @@
54
60
  "src/errorUtils.ts": "c601f2905c74b8d0",
55
61
  "src/fsHelpers.ts": "0869d9739d523572",
56
62
  "src/fsScan.ts": "feb187758481443f",
57
- "src/index.ts": "73d86121bd8fbf3e",
63
+ "src/index.ts": "80f518c9eb6f13e6",
58
64
  "src/infra/backupVault.ts": "661678a6dfb0b648",
59
65
  "src/infra/connectionsWire.ts": "125c099da0e17ac1",
60
66
  "src/infra/deployArtefacts.ts": "235ac21dd3ccf0b2",
@@ -65,9 +71,9 @@
65
71
  "src/infra/tokenScopes.ts": "88c6a1f0da3fa491",
66
72
  "src/insights/computePatternFingerprint.ts": "b5d3a4704f42cc1f",
67
73
  "src/logger.ts": "865ec4ec62a9a588",
68
- "src/manifest/index.ts": "f31b6502053a6bfc",
69
- "src/manifest/io.ts": "60e9ecfd03959e35",
70
- "src/manifest/schemas.ts": "30d764122f289834",
74
+ "src/manifest/index.ts": "b03afdad45154d67",
75
+ "src/manifest/io.ts": "681888437b87c9d3",
76
+ "src/manifest/schemas.ts": "8e1f739cb68d6938",
71
77
  "src/mcpProtocol/index.ts": "55df3209915a5043",
72
78
  "src/migration/clickhouseSqlUsers.ts": "c916e148367715bb",
73
79
  "src/migration/compareSchemaVersion.ts": "1c9247e722ec5d5b",
@@ -94,6 +100,11 @@
94
100
  "src/resourceCategorisation.ts": "a140d1b3cb38be33",
95
101
  "src/secrets.ts": "50258d463e4e67c3",
96
102
  "src/securityHelpers.ts": "acbf209255468ff4",
97
- "src/targets.ts": "126280f0a5762e21"
98
- }
103
+ "src/targets.ts": "126280f0a5762e21",
104
+ "../scripts/minify-dist.mjs": "6b2e4b0df8aec601",
105
+ "package.json": "0c25e937fdaa1004",
106
+ "tsconfig.json": "db759831ad95f396"
107
+ },
108
+ "outputHash": "166b490f9c6abdcc3c873063892822255ad80ee8bb947828b5e48920cf78a41c",
109
+ "outputFileCount": 187
99
110
  }
package/dist/.minified CHANGED
@@ -1 +1 @@
1
- 92 files minified at 2026-07-31T11:05:08.775Z
1
+ 93 files minified at 2026-08-03T01:43:40.198Z
@@ -0,0 +1,77 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * Stable capacity identity — the shared vocabulary for capacity SLOTS and
4
+ * their identity ANCHORS (design
5
+ * `aiDocs/designs/2026-08-01-stable-capacity-identity-and-rename-safe-deploys.md`).
6
+ *
7
+ * A capacity slot is the operator-chosen, config-independent name for one EC2
8
+ * auto-scaling group within a cluster ("primary", "clickhouse-data"). Its
9
+ * anchor is the PascalCase token every CloudFormation identity surface derives
10
+ * from (logical-ID prefixes, the physical service name, the launch-template
11
+ * name). Pins freeze a deployed pre-6.0 stack's config-derived anchor so a
12
+ * re-synth reproduces the deployed identity byte-for-byte instead of renaming
13
+ * every stateful resource.
14
+ *
15
+ * Three shapes share this module so the producer and every consumer stay on
16
+ * one contract (code-quality § coupled values):
17
+ * - the PIN — identity facts captured from a deployed stack;
18
+ * - the WIRE shape — what the deploy engine injects as CDK context and the
19
+ * constructs Zod-validate (`fjall:capacityIdentity`);
20
+ * - the CONFIG shape — the target-keyed `capacityIdentity` section of
21
+ * fjall-config.json the engine projects the wire shape from.
22
+ */
23
+ /** Slot-name grammar: lowercase kebab, letter first (`web`, `clickhouse-data`). */
24
+ export declare const CAPACITY_SLOT_PATTERN: RegExp;
25
+ export declare const CAPACITY_SLOT_MAX_LENGTH = 64;
26
+ export declare const DEFAULT_CAPACITY_SLOT = "primary";
27
+ /**
28
+ * Anchor grammar: alphanumeric, letter first — must be a valid CloudFormation
29
+ * logical-ID prefix AND a valid segment of a physical service name. Legacy
30
+ * pre-6.0 anchors (alphanumeric-stripped `getEc2ConfigKey` output such as
31
+ * `m7gmediumARMnowppdvdevxvdf80useast2aazuseast2a`) satisfy this by
32
+ * construction.
33
+ */
34
+ export declare const CAPACITY_ANCHOR_PATTERN: RegExp;
35
+ export declare const CAPACITY_ANCHOR_MAX_LENGTH = 128;
36
+ /** CDK context key the deploy engine injects the wire shape under. */
37
+ export declare const CAPACITY_IDENTITY_CONTEXT_KEY = "fjall:capacityIdentity";
38
+ /**
39
+ * One frozen slot identity, captured from the deployed stack at pin time.
40
+ * Kept in fjall-config.json for the stack's whole life — deleting a pin
41
+ * renames (replaces) every stateful resource in the slot on the next deploy.
42
+ */
43
+ export declare const CapacityIdentityPinSchema: z.ZodObject<{
44
+ legacyAnchor: z.ZodString;
45
+ legacyOwnerId: z.ZodOptional<z.ZodString>;
46
+ legacySgDescription: z.ZodOptional<z.ZodString>;
47
+ }, z.core.$strict>;
48
+ export type CapacityIdentityPin = z.infer<typeof CapacityIdentityPinSchema>;
49
+ /**
50
+ * Wire shape injected as the `fjall:capacityIdentity` CDK context value:
51
+ * `{ <appName>: { <slot>: pin } }` — already projected to the current deploy
52
+ * target. Constructs route by the manifest appName plus the resolved slot.
53
+ */
54
+ export declare const CapacityIdentityWireSchema: z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodObject<{
55
+ legacyAnchor: z.ZodString;
56
+ legacyOwnerId: z.ZodOptional<z.ZodString>;
57
+ legacySgDescription: z.ZodOptional<z.ZodString>;
58
+ }, z.core.$strict>>>;
59
+ export type CapacityIdentityWire = z.infer<typeof CapacityIdentityWireSchema>;
60
+ /**
61
+ * Config-file shape (`capacityIdentity` in fjall-config.json):
62
+ * `{ <appName>: { <targetName>: { <slot>: pin } } }`. Target-keyed because
63
+ * the same app deploys to several targets, each with its own deployed
64
+ * identity history.
65
+ */
66
+ export declare const CapacityIdentityConfigSchema: z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodObject<{
67
+ legacyAnchor: z.ZodString;
68
+ legacyOwnerId: z.ZodOptional<z.ZodString>;
69
+ legacySgDescription: z.ZodOptional<z.ZodString>;
70
+ }, z.core.$strict>>>>;
71
+ export type CapacityIdentityConfig = z.infer<typeof CapacityIdentityConfigSchema>;
72
+ /**
73
+ * Project the config-file shape onto ONE deploy target, producing the wire
74
+ * shape. Apps with no pins for the target are omitted; returns `undefined`
75
+ * when nothing survives so callers can skip context injection entirely.
76
+ */
77
+ export declare function projectCapacityIdentityToTarget(config: CapacityIdentityConfig | undefined, targetName: string): CapacityIdentityWire | undefined;
@@ -0,0 +1 @@
1
+ var p=Object.defineProperty;var o=(e,n)=>p(e,"name",{value:n,configurable:!0});import{z as t}from"zod";const C=/^[a-z][a-z0-9]*(-[a-z0-9]+)*$/,g=64,y="primary",A=/^[A-Za-z][A-Za-z0-9]*$/,T=128,_="fjall:capacityIdentity",c=t.object({legacyAnchor:t.string().min(1).max(T).regex(A,"legacyAnchor must be alphanumeric and start with a letter"),legacyOwnerId:t.string().min(1).max(512).optional(),legacySgDescription:t.string().min(1).max(255).optional()}).strict(),x=t.record(t.string().min(1),t.record(t.string().min(1),c)),I=t.record(t.string().min(1),t.record(t.string().min(1),t.record(t.string().min(1),c)));function l(e,n){if(e===void 0)return;const r={};for(const[a,s]of Object.entries(e)){const i=s[n];i===void 0||Object.keys(i).length===0||(r[a]=i)}return Object.keys(r).length===0?void 0:r}o(l,"projectCapacityIdentityToTarget");export{T as CAPACITY_ANCHOR_MAX_LENGTH,A as CAPACITY_ANCHOR_PATTERN,_ as CAPACITY_IDENTITY_CONTEXT_KEY,g as CAPACITY_SLOT_MAX_LENGTH,C as CAPACITY_SLOT_PATTERN,I as CapacityIdentityConfigSchema,c as CapacityIdentityPinSchema,x as CapacityIdentityWireSchema,y as DEFAULT_CAPACITY_SLOT,l as projectCapacityIdentityToTarget};
package/dist/config.d.ts CHANGED
@@ -159,6 +159,11 @@ export declare const RootConfigSchema: z.ZodObject<{
159
159
  account: z.ZodOptional<z.ZodString>;
160
160
  region: z.ZodOptional<z.ZodString>;
161
161
  }, z.core.$strict>>>;
162
+ capacityIdentity: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodObject<{
163
+ legacyAnchor: z.ZodString;
164
+ legacyOwnerId: z.ZodOptional<z.ZodString>;
165
+ legacySgDescription: z.ZodOptional<z.ZodString>;
166
+ }, z.core.$strict>>>>>;
162
167
  }, z.core.$strict>;
163
168
  export type RootConfig = z.infer<typeof RootConfigSchema>;
164
169
  /**
@@ -184,6 +189,11 @@ export declare const RootConfigReadSchema: z.ZodObject<{
184
189
  account: z.ZodOptional<z.ZodString>;
185
190
  region: z.ZodOptional<z.ZodString>;
186
191
  }, z.core.$strict>>>;
192
+ capacityIdentity: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodObject<{
193
+ legacyAnchor: z.ZodString;
194
+ legacyOwnerId: z.ZodOptional<z.ZodString>;
195
+ legacySgDescription: z.ZodOptional<z.ZodString>;
196
+ }, z.core.$strict>>>>>;
187
197
  }, z.core.$strip>;
188
198
  export type RootConfigRead = z.infer<typeof RootConfigReadSchema>;
189
199
  /**
@@ -274,8 +284,10 @@ export declare class Config {
274
284
  * so concurrently-registered siblings survive, keys this version does not
275
285
  * recognise ride through verbatim, and keys explicitly cleared this
276
286
  * session are removed even when the disk copy still carries them.
277
- * Unreadable or invalid disk state falls back to the in-memory state with
278
- * a warning rather than blocking the save.
287
+ * An absent file (first-ever save) writes the in-memory state as-is; an
288
+ * unreadable or invalid existing file REFUSES the save — the in-memory
289
+ * state came through the tolerant stripping read, so writing it unmerged
290
+ * would silently delete every key the merge could not see.
279
291
  */
280
292
  private mergeWithDisk;
281
293
  /**
package/dist/config.js CHANGED
@@ -1,2 +1,2 @@
1
- var x=Object.defineProperty;var h=(u,e)=>x(u,"name",{value:e,configurable:!0});import*as a from"fs";import*as g from"path";import{z as c}from"zod";import{failure as y,success as O}from"./docker/result.js";import{getErrorMessage as S}from"./errorUtils.js";import{logger as p}from"./logger.js";import{maskSensitiveOutput as w}from"./securityHelpers.js";const N=10,v="fjall-config.json",G=["compliance","governance","none"],B=["enforced","off"],W=["centralised","off"],Y=["account","draining","org"],Z="managementEvents",H="organisationManagementEvents",q=["active","draining","removed"],z="FjallTrailBucketName",V="FjallTrailKeyArn",X="OrganisationTrailBucketName",j=c.object({name:c.string(),type:c.enum(["apex","delegated"]),parentDomain:c.string().optional(),account:c.string().optional(),region:c.string().optional()}).strict(),A=c.object({activeTarget:c.string().optional(),domains:c.array(j).optional()}).strict(),L=c.object({activeTarget:c.string().optional(),domains:c.array(j).optional()}),_=".fjall",k="local.json",R=c.object({activeTarget:c.string().optional()});function $(u={}){return JSON.stringify(u,null,2)}h($,"serialiseRootConfig");const D=A.keyof().options;function I(u,e,n){const t=e[n];t!==void 0&&(u[n]=t)}h(I,"copyDefinedKey");function F(u,e){if(e===void 0)return!1;const n=new Set([...Object.keys(u),...Object.keys(e)]);for(const t of n)if(u[t]!==e[t])return!1;return!0}h(F,"domainEntriesEqual");class f{static{h(this,"Config")}rootConfig;configPath=null;loadFailed=!1;parseDegraded=!1;loadedSnapshot={};constructor(e,n){this.rootConfig=e??{},this.configPath=n??null}static findConfigDirectory(e){let n=e!==void 0&&e!==""?e:process.cwd();for(let t=0;t<N;t++){const i=g.join(n,"fjall"),o=g.join(i,v);if(a.existsSync(o))return i;const s=g.join(n,v);if(a.existsSync(s))return n;const l=g.dirname(n);if(l===n)break;n=l}return null}static loadConfigFile(e){try{return a.accessSync(e,a.constants.R_OK),a.readFileSync(e,{encoding:"utf8"})}catch(n){return p.warn("Config",`Config file at ${e} could not be read; using defaults`,{file:e,error:w(S(n))}),null}}static loadConfig(e){const n=f.findConfigDirectory(e);if(!n)return new f;const t=g.join(n,v),i=f.loadConfigFile(t);if(i===null){const d=new f(void 0,t);return d.loadFailed=!0,d}let o,s=!1;if(i!==""){let d;try{d=JSON.parse(i)}catch(r){throw f.formatZodError(r,v)}const C=A.safeParse(d);if(C.success)o=C.data;else{const r=L.safeParse(d);o=r.success?r.data:{},s=!r.success,r.success?p.warn("Config","fjall-config.json contains keys this version does not recognise; they were ignored (only activeTarget and domains are read). If this is an old config, regenerate it with `fjall create ...` or re-run `fjall connect`.",{file:t}):p.warn("Config","fjall-config.json has a malformed activeTarget or domains value, so its contents were ignored for this run. Fix the file (or regenerate it with `fjall create ...` / `fjall connect`).",{file:t})}}const l=new f(o,t);return l.parseDegraded=s,l.loadedSnapshot=structuredClone(l.rootConfig),l}static formatZodError(e,n){if(e instanceof c.ZodError&&e.issues.length>0){const o=e.issues.map(s=>`${s.path.join(".")}: ${s.message}`).join("; ");return new Error(`Failed to parse ${n}: ${o}`)}const i=(e instanceof Error?e.message:String(e)).replace(/\n/g," ").substring(0,500);return new Error(`Failed to parse ${n}: ${i}`)}saveConfig(){let e=this.configPath;if(!e){const s=f.findConfigDirectory()||g.join(process.cwd(),"fjall");e=g.join(s,v)}if(this.loadFailed)return y(new Error(`Refusing to save ${e}: the file exists but could not be read when this config loaded, so saving would replace its contents with state that never included them. Fix the file permissions (e.g. chmod u+rw ${e}) and retry.`));const n=g.dirname(e);try{a.mkdirSync(n,{recursive:!0})}catch(s){return y(new Error(`Cannot create config directory ${n}: ${w(S(s))}`))}const t=f.assertWritable(e,n);if(!t.success)return t;const i=$(this.mergeWithDisk(e)),o=`${e}.tmp-${process.pid}`;try{a.writeFileSync(o,i,{mode:384}),a.renameSync(o,e)}catch(s){return y(new Error(`Failed to save ${e}: ${w(S(s))}`))}return O(void 0)}static assertWritable(e,n){if(a.existsSync(e))try{a.accessSync(e,a.constants.W_OK)}catch{return y(new Error(`Cannot save ${e}: the file is read-only. Make it writable (e.g. chmod u+w ${e}) and retry.`))}try{a.accessSync(n,a.constants.W_OK)}catch{return y(new Error(`Cannot save ${e}: the directory ${n} is not writable. Make it writable (e.g. chmod u+w ${n}) and retry.`))}return O(void 0)}mergeWithDisk(e){const n=f.readDiskConfigForMerge(e);if(n===void 0)return this.rootConfig;const t={...n.foreign,...n.known};for(const o of D)o!=="domains"&&this.sessionChangedKey(o)&&(this.rootConfig[o]===void 0?delete t[o]:I(t,this.rootConfig,o));const i=this.mergeDomains(n.known.domains);return i!==void 0?t.domains=i:delete t.domains,t}sessionChangedKey(e){return JSON.stringify(this.rootConfig[e])!==JSON.stringify(this.loadedSnapshot[e])}mergeDomains(e){const n=this.rootConfig.domains,t=this.loadedSnapshot.domains??[];if(n===void 0&&t.length===0)return e;const i=h(r=>r.toLowerCase(),"norm"),o=n??[],s=new Map(t.map(r=>[i(r.name),r])),l=new Map(o.map(r=>[i(r.name),r])),d=[],C=new Set;for(const r of e??[]){const m=i(r.name);C.add(m);const T=l.get(m),E=s.get(m);if(T!==void 0&&!F(T,E)){d.push(T);continue}T===void 0&&E!==void 0||d.push(r)}for(const r of o){const m=i(r.name);C.has(m)||F(r,s.get(m))||d.push(r)}return d}static readDiskConfigForMerge(e){if(!a.existsSync(e))return;let n;try{n=JSON.parse(a.readFileSync(e,{encoding:"utf8"}))}catch(o){p.warn("Config",`Could not re-read ${e} before saving; writing in-memory state without merging`,{file:e,error:w(S(o))});return}const t=L.safeParse(n);if(!t.success){p.warn("Config",`On-disk ${e} failed validation before saving; writing in-memory state without merging`,{file:e,error:w(t.error.message)});return}const i={};if(typeof n=="object"&&n!==null){const o=D;for(const[s,l]of Object.entries(n))o.includes(s)||(i[s]=l)}return{known:t.data,foreign:i}}static getConfigDirectory(e){return f.findConfigDirectory(e)}getConfigPath(){return this.configPath}isContentUnavailable(){return this.loadFailed||this.parseDegraded}static warnedLegacyActiveTarget=!1;localConfigCache;localConfigFile(){const e=this.configPath!==null?g.dirname(this.configPath):process.cwd();return g.join(e,_,k)}loadLocalConfig(){if(this.localConfigCache===void 0)try{const e=a.readFileSync(this.localConfigFile(),{encoding:"utf8"}),n=R.safeParse(JSON.parse(e));this.localConfigCache=n.success?n.data:{}}catch{this.localConfigCache={}}return this.localConfigCache}writeLocalConfig(e){const n=this.localConfigFile();a.mkdirSync(g.dirname(n),{recursive:!0}),a.writeFileSync(n,JSON.stringify(e,null,2)+`
2
- `,{encoding:"utf8"}),this.localConfigCache=e}static warnLegacyActiveTargetOnce(){f.warnedLegacyActiveTarget||(f.warnedLegacyActiveTarget=!0,p.warn("Config","`activeTarget` in fjall-config.json is deprecated and ignored: a committed target must never re-aim a deploy or CI pipeline. Run `fjall target set <name>` to store it locally in .fjall/local.json, then remove `activeTarget` from the committed fjall-config.json."))}getActiveTarget(){const e=this.loadLocalConfig().activeTarget;if(e!==void 0)return e;this.rootConfig.activeTarget!==void 0&&f.warnLegacyActiveTargetOnce()}setActiveTarget(e){const n=this.loadLocalConfig();n.activeTarget=e,this.writeLocalConfig(n)}clearActiveTarget(){const e=this.loadLocalConfig();delete e.activeTarget,this.writeLocalConfig(e)}getDomains(){return this.rootConfig.domains??[]}setDomains(e){this.rootConfig.domains=e}addDomain(e){this.rootConfig.domains||(this.rootConfig.domains=[]),this.rootConfig.domains.push(e)}getDomain(e){return this.rootConfig.domains?.find(n=>n.name.toLowerCase()===e.toLowerCase())}removeDomain(e){if(!this.rootConfig.domains)return!1;const n=this.rootConfig.domains.findIndex(t=>t.name.toLowerCase()===e.toLowerCase());return n===-1?!1:(this.rootConfig.domains.splice(n,1),!0)}}export{Z as ACCOUNT_TRAIL_NAME,q as ACCOUNT_TRAIL_STATES,f as Config,j as DomainConfigSchema,_ as LOCAL_CONFIG_DIRNAME,k as LOCAL_CONFIG_FILENAME,H as ORGANISATION_TRAIL_NAME,X as ORG_TRAIL_BUCKET_OUTPUT_KEY,W as ROOT_ACCESS_MANAGEMENT_MODES,v as ROOT_CONFIG_FILENAME,L as RootConfigReadSchema,A as RootConfigSchema,B as S3_BPA_MODES,z as TRAIL_BUCKET_OUTPUT_KEY,V as TRAIL_KEY_ARN_OUTPUT_KEY,Y as TRAIL_LIFECYCLE_STATES,G as VAULT_LOCK_MODES,$ as serialiseRootConfig};
1
+ var b=Object.defineProperty;var h=(u,e)=>b(u,"name",{value:e,configurable:!0});import*as a from"fs";import*as g from"path";import{z as l}from"zod";import{CapacityIdentityConfigSchema as j}from"./capacityIdentity.js";import{failure as p,success as T}from"./docker/result.js";import{getErrorMessage as S}from"./errorUtils.js";import{logger as E}from"./logger.js";import{maskSensitiveOutput as C}from"./securityHelpers.js";const x=10,w="fjall-config.json",W=["compliance","governance","none"],Y=["enforced","off"],Z=["centralised","off"],H=["account","draining","org"],q="managementEvents",z="organisationManagementEvents",V=["active","draining","removed"],X="FjallTrailBucketName",Q="FjallTrailKeyArn",ee="OrganisationTrailBucketName",k=l.object({name:l.string(),type:l.enum(["apex","delegated"]),parentDomain:l.string().optional(),account:l.string().optional(),region:l.string().optional()}).strict(),A=l.object({activeTarget:l.string().optional(),domains:l.array(k).optional(),capacityIdentity:j.optional()}).strict(),L=l.object({activeTarget:l.string().optional(),domains:l.array(k).optional(),capacityIdentity:j.optional()}),N=".fjall",_="local.json",$=l.object({activeTarget:l.string().optional()});function I(u={}){return JSON.stringify(u,null,2)}h(I,"serialiseRootConfig");const D=A.keyof().options;function R(u,e,n){const t=e[n];t!==void 0&&(u[n]=t)}h(R,"copyDefinedKey");function F(u,e){if(e===void 0)return!1;const n=new Set([...Object.keys(u),...Object.keys(e)]);for(const t of n)if(u[t]!==e[t])return!1;return!0}h(F,"domainEntriesEqual");class d{static{h(this,"Config")}rootConfig;configPath=null;loadFailed=!1;parseDegraded=!1;loadedSnapshot={};constructor(e,n){this.rootConfig=e??{},this.configPath=n??null}static findConfigDirectory(e){let n=e!==void 0&&e!==""?e:process.cwd();for(let t=0;t<x;t++){const o=g.join(n,"fjall"),r=g.join(o,w);if(a.existsSync(r))return o;const i=g.join(n,w);if(a.existsSync(i))return n;const c=g.dirname(n);if(c===n)break;n=c}return null}static loadConfigFile(e){try{return a.accessSync(e,a.constants.R_OK),a.readFileSync(e,{encoding:"utf8"})}catch(n){return E.warn("Config",`Config file at ${e} could not be read; using defaults`,{file:e,error:C(S(n))}),null}}static loadConfig(e){const n=d.findConfigDirectory(e);if(!n)return new d;const t=g.join(n,w),o=d.loadConfigFile(t);if(o===null){const f=new d(void 0,t);return f.loadFailed=!0,f}let r,i=!1;if(o!==""){let f;try{f=JSON.parse(o)}catch(s){throw d.formatZodError(s,w)}const y=A.safeParse(f);if(y.success)r=y.data;else{const s=L.safeParse(f);r=s.success?s.data:{},i=!s.success,s.success?E.warn("Config","fjall-config.json contains keys this version does not recognise (only activeTarget, domains and capacityIdentity are read). They were most likely written by a newer fjall version \u2014 leave them in place; saves preserve them verbatim.",{file:t}):E.warn("Config","fjall-config.json has a malformed activeTarget, domains or capacityIdentity value, so its contents were ignored for this run \u2014 any capacity-identity pins it holds will NOT apply (a pinned stack deploys unpinned and is blocked by the rename gate). Fix the file by hand; do NOT regenerate it, which would discard the pins.",{file:t})}}const c=new d(r,t);return c.parseDegraded=i,c.loadedSnapshot=structuredClone(c.rootConfig),c}static formatZodError(e,n){if(e instanceof l.ZodError&&e.issues.length>0){const r=e.issues.map(i=>`${i.path.join(".")}: ${i.message}`).join("; ");return new Error(`Failed to parse ${n}: ${r}`)}const o=(e instanceof Error?e.message:String(e)).replace(/\n/g," ").substring(0,500);return new Error(`Failed to parse ${n}: ${o}`)}saveConfig(){let e=this.configPath;if(!e){const c=d.findConfigDirectory()||g.join(process.cwd(),"fjall");e=g.join(c,w)}if(this.loadFailed)return p(new Error(`Refusing to save ${e}: the file exists but could not be read when this config loaded, so saving would replace its contents with state that never included them. Fix the file permissions (e.g. chmod u+rw ${e}) and retry.`));const n=g.dirname(e);try{a.mkdirSync(n,{recursive:!0})}catch(c){return p(new Error(`Cannot create config directory ${n}: ${C(S(c))}`))}const t=d.assertWritable(e,n);if(!t.success)return t;const o=this.mergeWithDisk(e);if(!o.success)return o;const r=I(o.data),i=`${e}.tmp-${process.pid}`;try{a.writeFileSync(i,r,{mode:384}),a.renameSync(i,e)}catch(c){return p(new Error(`Failed to save ${e}: ${C(S(c))}`))}return T(void 0)}static assertWritable(e,n){if(a.existsSync(e))try{a.accessSync(e,a.constants.W_OK)}catch{return p(new Error(`Cannot save ${e}: the file is read-only. Make it writable (e.g. chmod u+w ${e}) and retry.`))}try{a.accessSync(n,a.constants.W_OK)}catch{return p(new Error(`Cannot save ${e}: the directory ${n} is not writable. Make it writable (e.g. chmod u+w ${n}) and retry.`))}return T(void 0)}mergeWithDisk(e){const n=d.readDiskConfigForMerge(e);if(n.kind==="unmergeable")return p(new Error(`Refusing to save ${e}: ${n.reason}. Writing now would keep only this session's state and drop everything else the file carries (including keys written by other fjall versions). Fix or remove the file and retry.`));if(n.kind==="absent")return T(this.rootConfig);const t=n.disk,o={...t.foreign,...t.known};for(const i of D)i!=="domains"&&this.sessionChangedKey(i)&&(this.rootConfig[i]===void 0?delete o[i]:R(o,this.rootConfig,i));const r=this.mergeDomains(t.known.domains);return r!==void 0?o.domains=r:delete o.domains,T(o)}sessionChangedKey(e){return JSON.stringify(this.rootConfig[e])!==JSON.stringify(this.loadedSnapshot[e])}mergeDomains(e){const n=this.rootConfig.domains,t=this.loadedSnapshot.domains??[];if(n===void 0&&t.length===0)return e;const o=h(s=>s.toLowerCase(),"norm"),r=n??[],i=new Map(t.map(s=>[o(s.name),s])),c=new Map(r.map(s=>[o(s.name),s])),f=[],y=new Set;for(const s of e??[]){const m=o(s.name);y.add(m);const v=c.get(m),O=i.get(m);if(v!==void 0&&!F(v,O)){f.push(v);continue}v===void 0&&O!==void 0||f.push(s)}for(const s of r){const m=o(s.name);y.has(m)||F(s,i.get(m))||f.push(s)}return f}static readDiskConfigForMerge(e){if(!a.existsSync(e))return{kind:"absent"};let n;try{const r=a.readFileSync(e,{encoding:"utf8"});if(r==="")return{kind:"absent"};n=JSON.parse(r)}catch(r){return{kind:"unmergeable",reason:`the existing file could not be read or parsed as JSON (${C(S(r))})`}}const t=L.safeParse(n);if(!t.success){const r=t.error.issues.map(i=>`${i.path.join(".")}: ${i.message}`).join("; ");return{kind:"unmergeable",reason:`a recognised key in the existing file is malformed (${C(r)})`}}const o={};if(typeof n=="object"&&n!==null){const r=D;for(const[i,c]of Object.entries(n))r.includes(i)||(o[i]=c)}return{kind:"ok",disk:{known:t.data,foreign:o}}}static getConfigDirectory(e){return d.findConfigDirectory(e)}getConfigPath(){return this.configPath}isContentUnavailable(){return this.loadFailed||this.parseDegraded}static warnedLegacyActiveTarget=!1;localConfigCache;localConfigFile(){const e=this.configPath!==null?g.dirname(this.configPath):process.cwd();return g.join(e,N,_)}loadLocalConfig(){if(this.localConfigCache===void 0)try{const e=a.readFileSync(this.localConfigFile(),{encoding:"utf8"}),n=$.safeParse(JSON.parse(e));this.localConfigCache=n.success?n.data:{}}catch{this.localConfigCache={}}return this.localConfigCache}writeLocalConfig(e){const n=this.localConfigFile();a.mkdirSync(g.dirname(n),{recursive:!0}),a.writeFileSync(n,JSON.stringify(e,null,2)+`
2
+ `,{encoding:"utf8"}),this.localConfigCache=e}static warnLegacyActiveTargetOnce(){d.warnedLegacyActiveTarget||(d.warnedLegacyActiveTarget=!0,E.warn("Config","`activeTarget` in fjall-config.json is deprecated and ignored: a committed target must never re-aim a deploy or CI pipeline. Run `fjall target set <name>` to store it locally in .fjall/local.json, then remove `activeTarget` from the committed fjall-config.json."))}getActiveTarget(){const e=this.loadLocalConfig().activeTarget;if(e!==void 0)return e;this.rootConfig.activeTarget!==void 0&&d.warnLegacyActiveTargetOnce()}setActiveTarget(e){const n=this.loadLocalConfig();n.activeTarget=e,this.writeLocalConfig(n)}clearActiveTarget(){const e=this.loadLocalConfig();delete e.activeTarget,this.writeLocalConfig(e)}getDomains(){return this.rootConfig.domains??[]}setDomains(e){this.rootConfig.domains=e}addDomain(e){this.rootConfig.domains||(this.rootConfig.domains=[]),this.rootConfig.domains.push(e)}getDomain(e){return this.rootConfig.domains?.find(n=>n.name.toLowerCase()===e.toLowerCase())}removeDomain(e){if(!this.rootConfig.domains)return!1;const n=this.rootConfig.domains.findIndex(t=>t.name.toLowerCase()===e.toLowerCase());return n===-1?!1:(this.rootConfig.domains.splice(n,1),!0)}}export{q as ACCOUNT_TRAIL_NAME,V as ACCOUNT_TRAIL_STATES,d as Config,k as DomainConfigSchema,N as LOCAL_CONFIG_DIRNAME,_ as LOCAL_CONFIG_FILENAME,z as ORGANISATION_TRAIL_NAME,ee as ORG_TRAIL_BUCKET_OUTPUT_KEY,Z as ROOT_ACCESS_MANAGEMENT_MODES,w as ROOT_CONFIG_FILENAME,L as RootConfigReadSchema,A as RootConfigSchema,Y as S3_BPA_MODES,X as TRAIL_BUCKET_OUTPUT_KEY,Q as TRAIL_KEY_ARN_OUTPUT_KEY,H as TRAIL_LIFECYCLE_STATES,W as VAULT_LOCK_MODES,I as serialiseRootConfig};
package/dist/index.d.ts CHANGED
@@ -3,6 +3,7 @@ export { BACKUP_VAULT_NAME } from "./infra/backupVault.js";
3
3
  export { APPROVAL_TOKEN_OUTPUT_PREFIX, TOKEN_STDERR_PREFIX } from "./deploy/approvalTokenOutput.js";
4
4
  export { imageTagParameterName } from "./infra/imageTags.js";
5
5
  export { toPascalCase, toKebab, toValidDatabaseName, toScreamingSnake, capitalise, getSafeZoneName, accountConstructKey, hasAsciiStableConstructKey } from "./naming/caseConversion.js";
6
+ export { CAPACITY_SLOT_PATTERN, CAPACITY_SLOT_MAX_LENGTH, DEFAULT_CAPACITY_SLOT, CAPACITY_ANCHOR_PATTERN, CAPACITY_ANCHOR_MAX_LENGTH, CAPACITY_IDENTITY_CONTEXT_KEY, CapacityIdentityPinSchema, type CapacityIdentityPin, CapacityIdentityWireSchema, type CapacityIdentityWire, CapacityIdentityConfigSchema, type CapacityIdentityConfig, projectCapacityIdentityToTarget } from "./capacityIdentity.js";
6
7
  export { findAccountNameCollision, type AccountNameCollision } from "./naming/accountNameCollision.js";
7
8
  export { defaultConnectedAccountName, suffixedAccountName, REGION_SHORT_CODES, findTrailingRegionShortCode, regionSuffixRejectionMessage } from "./naming/connectedAccountName.js";
8
9
  export { normaliseError, getErrorMessage, hasErrorCode, getErrorCode, getErrorStack, formatErrorString } from "./errorUtils.js";
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{DNS_APEX as E,getDomainExportNames as o,getDomainStackName as t,getDomainUsEast1CertificatesStackName as _,isManagedDomainBinding as a,DOMAIN_DEPLOY_DEFAULT_PHASE as S}from"./infra/domainExports.js";import{BACKUP_VAULT_NAME as T}from"./infra/backupVault.js";import{APPROVAL_TOKEN_OUTPUT_PREFIX as n,TOKEN_STDERR_PREFIX as i}from"./deploy/approvalTokenOutput.js";import{imageTagParameterName as m}from"./infra/imageTags.js";import{toPascalCase as O,toKebab as P,toValidDatabaseName as C,toScreamingSnake as p,capitalise as f,getSafeZoneName as c,accountConstructKey as g,hasAsciiStableConstructKey as I}from"./naming/caseConversion.js";import{findAccountNameCollision as M}from"./naming/accountNameCollision.js";import{defaultConnectedAccountName as u,suffixedAccountName as d,REGION_SHORT_CODES as U,findTrailingRegionShortCode as L,regionSuffixRejectionMessage as V}from"./naming/connectedAccountName.js";import{normaliseError as G,getErrorMessage as F,hasErrorCode as h,getErrorCode as v,getErrorStack as H,formatErrorString as b}from"./errorUtils.js";import{singleton as Y}from"./async/singleton.js";import{DANGEROUS_ENV_VARS as B,filterDangerousEnvVars as K,maskSensitiveOutput as W,parseShellArgs as k,SCOPED_TOKEN_REGEX as j}from"./securityHelpers.js";import{sleep as Q}from"./async/sleep.js";import{mapSettledWithConcurrency as q}from"./async/concurrency.js";import{ACCOUNT_STAGES_WITH_ROOT as J,STRUCTURAL_ENVIRONMENTS as $,ACCOUNT_STAGES as ee,ACCOUNT_STAGE_LABELS as re,isAccountStage as Ee,ACCOUNT_TIERS as oe,AccountTierSchema as te,isAccountTier as _e,GOVERNANCE_ACCOUNT_TIERS as ae,isGovernanceTier as Se,environmentToTier as Ae,stageFromWireEnvironment as Te,accountTier as Re,getEnvironmentLabel as ne,ACCOUNT_ROLES as ie}from"./environments.js";import{RESOURCE_CATEGORIES as me,categoriseResource as se,getExpectedDuration as Oe,getFriendlyResourceType as Pe}from"./resourceCategorisation.js";import{parseGitRemoteUrl as pe}from"./repo/gitRemoteParser.js";import{abbreviateRegion as ce,AWS_REGIONS_METADATA as ge,DEFAULT_REGION as Ie,getRegionInfo as De,MAX_SECONDARY_REGIONS as Me,OPT_IN_REGION_CODES as xe,optInRegionWarning as ue,regions as de,suggestRegionForTimezone as Ue}from"./infra/regions.js";import{SCOPE_VALUES as Ve,MACHINE_ONLY_SCOPES as le,USER_GRANTABLE_SCOPES as Ge,GOVERNANCE_SCOPE_REQUIRED_CODE as Fe}from"./infra/tokenScopes.js";import{SECRET_NAME_PATTERN as ve,SECRET_NAME_ERROR as He,SSM_COMPONENT_PATTERN as be,SSM_COMPONENT_ERROR as Xe,SSM_STANDARD_MAX_VALUE_BYTES as Ye,SecretNamespaceSchema as ye,buildNamespaceParts as Be,buildParameterPath as Ke,parseParameterPath as We,isManageablePath as ke,parseDotEnv as je,escapeDotEnvValue as ze}from"./secrets.js";import{ConnectionWireSchema as Ze,ConnectionsListResponseSchema as qe}from"./infra/connectionsWire.js";import{deriveRegionsFromOrgConfig as Je,deriveTargets as $e,deriveAllTargets as er,environmentOrTier as rr,findTarget as Er,generateTargetName as or}from"./targets.js";import{buildAppConfigPath as _r}from"./repo/appPath.js";import{findInfrastructurePaths as Sr,findBoundaryPath as Ar,isInfrastructureFile as Tr}from"./repo/findInfrastructurePaths.js";import{inferContainerFromCandidates as nr}from"./repo/inferContainerFromCandidates.js";import{RESERVED_APP_NAMES as Nr,RESERVED_APP_NAME_MESSAGE as mr,isReservedAppName as sr,RESERVED_APP_NAME_SUFFIX as Or,RESERVED_APP_NAME_SUFFIX_MESSAGE as Pr,hasReservedAppNameSuffix as Cr}from"./naming/reservedAppNames.js";import{deriveContentHashTag as fr,CONTENT_HASH_TAG_PATTERN as cr}from"./infra/deriveContentHashTag.js";import{DEPLOY_MODES as Ir,DeployModeSchema as Dr,IMAGE_TAG_PATTERN as Mr,ImageTagSchema as xr,ServiceArtefactSchema as ur,ServiceArtefactsSchema as dr,ARTEFACT_OUTPUT_FIELDS as Ur,artefactOutputKey as Lr}from"./infra/deployArtefacts.js";import{MIGRATION_SNAPSHOT_NAME_PREFIX as lr,EXPECTED_SCHEMA_VERSION_ENV as Gr,EXPECTED_SCHEMA_VERSION_TOOL_ENV as Fr,EXPECTED_CH_SCHEMA_VERSION_ENV as hr,SCHEMA_ADMIN_USER_ENV as vr,SCHEMA_ADMIN_PASSWORD_ENV as Hr,PRISMA_MIGRATION_DIR_RE as br,CLICKHOUSE_MIGRATION_SKIP_RE as Xr}from"./migration/constants.js";import{PHYSICAL_NAME_FALLBACK_PROPERTIES as yr}from"./cfn/physicalNameProperties.js";import{PATTERN_TYPE_VALUES as Kr,PATTERN_TYPES as Wr,isPatternType as kr,PATTERN_REGISTRY as jr,DEPLOYABLE_PATTERN_TYPES as zr,OPENNEXT_PATTERN_TYPES as Qr,isOpenNextPatternType as Zr,STATIC_SITE_ROUTING_VALUES as qr}from"./patterns/patternTypes.js";import{DEFAULT_FORMS_FROM_LOCAL_PART as Jr,defaultFormsFromAddress as $r,defaultFormsCorsOrigin as eE,isAddressAtDomain as rE}from"./patterns/staticSiteForms.js";import{DEV_SUBSTRATE_PARAMS_SCHEMA_VERSION as oE,DEV_SUBSTRATE_PARAMS_FILENAME as tE,DevSubstrateSynthPropsSchema as _E,DevSubstrateParamsSchema as aE}from"./devSubstrate/params.js";import{DEV_SUBSTRATE_ENTRYPOINT_SOURCE as AE}from"./devSubstrate/entrypoint.js";export{ie as ACCOUNT_ROLES,ee as ACCOUNT_STAGES,J as ACCOUNT_STAGES_WITH_ROOT,re as ACCOUNT_STAGE_LABELS,oe as ACCOUNT_TIERS,n as APPROVAL_TOKEN_OUTPUT_PREFIX,Ur as ARTEFACT_OUTPUT_FIELDS,ge as AWS_REGIONS_METADATA,te as AccountTierSchema,T as BACKUP_VAULT_NAME,Xr as CLICKHOUSE_MIGRATION_SKIP_RE,cr as CONTENT_HASH_TAG_PATTERN,Ze as ConnectionWireSchema,qe as ConnectionsListResponseSchema,B as DANGEROUS_ENV_VARS,Jr as DEFAULT_FORMS_FROM_LOCAL_PART,Ie as DEFAULT_REGION,zr as DEPLOYABLE_PATTERN_TYPES,Ir as DEPLOY_MODES,AE as DEV_SUBSTRATE_ENTRYPOINT_SOURCE,tE as DEV_SUBSTRATE_PARAMS_FILENAME,oE as DEV_SUBSTRATE_PARAMS_SCHEMA_VERSION,E as DNS_APEX,S as DOMAIN_DEPLOY_DEFAULT_PHASE,Dr as DeployModeSchema,aE as DevSubstrateParamsSchema,_E as DevSubstrateSynthPropsSchema,hr as EXPECTED_CH_SCHEMA_VERSION_ENV,Gr as EXPECTED_SCHEMA_VERSION_ENV,Fr as EXPECTED_SCHEMA_VERSION_TOOL_ENV,ae as GOVERNANCE_ACCOUNT_TIERS,Fe as GOVERNANCE_SCOPE_REQUIRED_CODE,Mr as IMAGE_TAG_PATTERN,xr as ImageTagSchema,le as MACHINE_ONLY_SCOPES,Me as MAX_SECONDARY_REGIONS,lr as MIGRATION_SNAPSHOT_NAME_PREFIX,Qr as OPENNEXT_PATTERN_TYPES,xe as OPT_IN_REGION_CODES,jr as PATTERN_REGISTRY,Wr as PATTERN_TYPES,Kr as PATTERN_TYPE_VALUES,yr as PHYSICAL_NAME_FALLBACK_PROPERTIES,br as PRISMA_MIGRATION_DIR_RE,U as REGION_SHORT_CODES,Nr as RESERVED_APP_NAMES,mr as RESERVED_APP_NAME_MESSAGE,Or as RESERVED_APP_NAME_SUFFIX,Pr as RESERVED_APP_NAME_SUFFIX_MESSAGE,me as RESOURCE_CATEGORIES,Hr as SCHEMA_ADMIN_PASSWORD_ENV,vr as SCHEMA_ADMIN_USER_ENV,j as SCOPED_TOKEN_REGEX,Ve as SCOPE_VALUES,He as SECRET_NAME_ERROR,ve as SECRET_NAME_PATTERN,Xe as SSM_COMPONENT_ERROR,be as SSM_COMPONENT_PATTERN,Ye as SSM_STANDARD_MAX_VALUE_BYTES,qr as STATIC_SITE_ROUTING_VALUES,$ as STRUCTURAL_ENVIRONMENTS,ye as SecretNamespaceSchema,ur as ServiceArtefactSchema,dr as ServiceArtefactsSchema,i as TOKEN_STDERR_PREFIX,Ge as USER_GRANTABLE_SCOPES,ce as abbreviateRegion,g as accountConstructKey,Re as accountTier,Lr as artefactOutputKey,_r as buildAppConfigPath,Be as buildNamespaceParts,Ke as buildParameterPath,f as capitalise,se as categoriseResource,u as defaultConnectedAccountName,eE as defaultFormsCorsOrigin,$r as defaultFormsFromAddress,er as deriveAllTargets,fr as deriveContentHashTag,Je as deriveRegionsFromOrgConfig,$e as deriveTargets,rr as environmentOrTier,Ae as environmentToTier,ze as escapeDotEnvValue,K as filterDangerousEnvVars,M as findAccountNameCollision,Ar as findBoundaryPath,Sr as findInfrastructurePaths,Er as findTarget,L as findTrailingRegionShortCode,b as formatErrorString,or as generateTargetName,o as getDomainExportNames,t as getDomainStackName,_ as getDomainUsEast1CertificatesStackName,ne as getEnvironmentLabel,v as getErrorCode,F as getErrorMessage,H as getErrorStack,Oe as getExpectedDuration,Pe as getFriendlyResourceType,De as getRegionInfo,c as getSafeZoneName,I as hasAsciiStableConstructKey,h as hasErrorCode,Cr as hasReservedAppNameSuffix,m as imageTagParameterName,nr as inferContainerFromCandidates,Ee as isAccountStage,_e as isAccountTier,rE as isAddressAtDomain,Se as isGovernanceTier,Tr as isInfrastructureFile,ke as isManageablePath,a as isManagedDomainBinding,Zr as isOpenNextPatternType,kr as isPatternType,sr as isReservedAppName,q as mapSettledWithConcurrency,W as maskSensitiveOutput,G as normaliseError,ue as optInRegionWarning,je as parseDotEnv,pe as parseGitRemoteUrl,We as parseParameterPath,k as parseShellArgs,V as regionSuffixRejectionMessage,de as regions,Y as singleton,Q as sleep,Te as stageFromWireEnvironment,d as suffixedAccountName,Ue as suggestRegionForTimezone,P as toKebab,O as toPascalCase,p as toScreamingSnake,C as toValidDatabaseName};
1
+ import{DNS_APEX as E,getDomainExportNames as t,getDomainStackName as o,getDomainUsEast1CertificatesStackName as _,isManagedDomainBinding as a,DOMAIN_DEPLOY_DEFAULT_PHASE as A}from"./infra/domainExports.js";import{BACKUP_VAULT_NAME as T}from"./infra/backupVault.js";import{APPROVAL_TOKEN_OUTPUT_PREFIX as R,TOKEN_STDERR_PREFIX as n}from"./deploy/approvalTokenOutput.js";import{imageTagParameterName as C}from"./infra/imageTags.js";import{toPascalCase as O,toKebab as P,toValidDatabaseName as s,toScreamingSnake as c,capitalise as p,getSafeZoneName as I,accountConstructKey as f,hasAsciiStableConstructKey as g}from"./naming/caseConversion.js";import{CAPACITY_SLOT_PATTERN as M,CAPACITY_SLOT_MAX_LENGTH as d,DEFAULT_CAPACITY_SLOT as x,CAPACITY_ANCHOR_PATTERN as u,CAPACITY_ANCHOR_MAX_LENGTH as U,CAPACITY_IDENTITY_CONTEXT_KEY as L,CapacityIdentityPinSchema as V,CapacityIdentityWireSchema as l,CapacityIdentityConfigSchema as G,projectCapacityIdentityToTarget as h}from"./capacityIdentity.js";import{findAccountNameCollision as H}from"./naming/accountNameCollision.js";import{defaultConnectedAccountName as v,suffixedAccountName as y,REGION_SHORT_CODES as X,findTrailingRegionShortCode as b,regionSuffixRejectionMessage as K}from"./naming/connectedAccountName.js";import{normaliseError as W,getErrorMessage as k,hasErrorCode as j,getErrorCode as z,getErrorStack as Q,formatErrorString as Z}from"./errorUtils.js";import{singleton as w}from"./async/singleton.js";import{DANGEROUS_ENV_VARS as $,filterDangerousEnvVars as ee,maskSensitiveOutput as re,parseShellArgs as Ee,SCOPED_TOKEN_REGEX as te}from"./securityHelpers.js";import{sleep as _e}from"./async/sleep.js";import{mapSettledWithConcurrency as Ae}from"./async/concurrency.js";import{ACCOUNT_STAGES_WITH_ROOT as Te,STRUCTURAL_ENVIRONMENTS as ie,ACCOUNT_STAGES as Re,ACCOUNT_STAGE_LABELS as ne,isAccountStage as Ne,ACCOUNT_TIERS as Ce,AccountTierSchema as me,isAccountTier as Oe,GOVERNANCE_ACCOUNT_TIERS as Pe,isGovernanceTier as se,environmentToTier as ce,stageFromWireEnvironment as pe,accountTier as Ie,getEnvironmentLabel as fe,ACCOUNT_ROLES as ge}from"./environments.js";import{RESOURCE_CATEGORIES as Me,categoriseResource as de,getExpectedDuration as xe,getFriendlyResourceType as ue}from"./resourceCategorisation.js";import{parseGitRemoteUrl as Le}from"./repo/gitRemoteParser.js";import{abbreviateRegion as le,AWS_REGIONS_METADATA as Ge,DEFAULT_REGION as he,getRegionInfo as Fe,MAX_SECONDARY_REGIONS as He,OPT_IN_REGION_CODES as Ye,optInRegionWarning as ve,regions as ye,suggestRegionForTimezone as Xe}from"./infra/regions.js";import{SCOPE_VALUES as Ke,MACHINE_ONLY_SCOPES as Be,USER_GRANTABLE_SCOPES as We,GOVERNANCE_SCOPE_REQUIRED_CODE as ke}from"./infra/tokenScopes.js";import{SECRET_NAME_PATTERN as ze,SECRET_NAME_ERROR as Qe,SSM_COMPONENT_PATTERN as Ze,SSM_COMPONENT_ERROR as qe,SSM_STANDARD_MAX_VALUE_BYTES as we,SecretNamespaceSchema as Je,buildNamespaceParts as $e,buildParameterPath as er,parseParameterPath as rr,isManageablePath as Er,parseDotEnv as tr,escapeDotEnvValue as or}from"./secrets.js";import{ConnectionWireSchema as ar,ConnectionsListResponseSchema as Ar}from"./infra/connectionsWire.js";import{deriveRegionsFromOrgConfig as Tr,deriveTargets as ir,deriveAllTargets as Rr,environmentOrTier as nr,findTarget as Nr,generateTargetName as Cr}from"./targets.js";import{buildAppConfigPath as Or}from"./repo/appPath.js";import{findInfrastructurePaths as sr,findBoundaryPath as cr,isInfrastructureFile as pr}from"./repo/findInfrastructurePaths.js";import{inferContainerFromCandidates as fr}from"./repo/inferContainerFromCandidates.js";import{RESERVED_APP_NAMES as Dr,RESERVED_APP_NAME_MESSAGE as Mr,isReservedAppName as dr,RESERVED_APP_NAME_SUFFIX as xr,RESERVED_APP_NAME_SUFFIX_MESSAGE as ur,hasReservedAppNameSuffix as Ur}from"./naming/reservedAppNames.js";import{deriveContentHashTag as Vr,CONTENT_HASH_TAG_PATTERN as lr}from"./infra/deriveContentHashTag.js";import{DEPLOY_MODES as hr,DeployModeSchema as Fr,IMAGE_TAG_PATTERN as Hr,ImageTagSchema as Yr,ServiceArtefactSchema as vr,ServiceArtefactsSchema as yr,ARTEFACT_OUTPUT_FIELDS as Xr,artefactOutputKey as br}from"./infra/deployArtefacts.js";import{MIGRATION_SNAPSHOT_NAME_PREFIX as Br,EXPECTED_SCHEMA_VERSION_ENV as Wr,EXPECTED_SCHEMA_VERSION_TOOL_ENV as kr,EXPECTED_CH_SCHEMA_VERSION_ENV as jr,SCHEMA_ADMIN_USER_ENV as zr,SCHEMA_ADMIN_PASSWORD_ENV as Qr,PRISMA_MIGRATION_DIR_RE as Zr,CLICKHOUSE_MIGRATION_SKIP_RE as qr}from"./migration/constants.js";import{PHYSICAL_NAME_FALLBACK_PROPERTIES as Jr}from"./cfn/physicalNameProperties.js";import{PATTERN_TYPE_VALUES as eE,PATTERN_TYPES as rE,isPatternType as EE,PATTERN_REGISTRY as tE,DEPLOYABLE_PATTERN_TYPES as oE,OPENNEXT_PATTERN_TYPES as _E,isOpenNextPatternType as aE,STATIC_SITE_ROUTING_VALUES as AE}from"./patterns/patternTypes.js";import{DEFAULT_FORMS_FROM_LOCAL_PART as TE,defaultFormsFromAddress as iE,defaultFormsCorsOrigin as RE,isAddressAtDomain as nE}from"./patterns/staticSiteForms.js";import{DEV_SUBSTRATE_PARAMS_SCHEMA_VERSION as CE,DEV_SUBSTRATE_PARAMS_FILENAME as mE,DevSubstrateSynthPropsSchema as OE,DevSubstrateParamsSchema as PE}from"./devSubstrate/params.js";import{DEV_SUBSTRATE_ENTRYPOINT_SOURCE as cE}from"./devSubstrate/entrypoint.js";export{ge as ACCOUNT_ROLES,Re as ACCOUNT_STAGES,Te as ACCOUNT_STAGES_WITH_ROOT,ne as ACCOUNT_STAGE_LABELS,Ce as ACCOUNT_TIERS,R as APPROVAL_TOKEN_OUTPUT_PREFIX,Xr as ARTEFACT_OUTPUT_FIELDS,Ge as AWS_REGIONS_METADATA,me as AccountTierSchema,T as BACKUP_VAULT_NAME,U as CAPACITY_ANCHOR_MAX_LENGTH,u as CAPACITY_ANCHOR_PATTERN,L as CAPACITY_IDENTITY_CONTEXT_KEY,d as CAPACITY_SLOT_MAX_LENGTH,M as CAPACITY_SLOT_PATTERN,qr as CLICKHOUSE_MIGRATION_SKIP_RE,lr as CONTENT_HASH_TAG_PATTERN,G as CapacityIdentityConfigSchema,V as CapacityIdentityPinSchema,l as CapacityIdentityWireSchema,ar as ConnectionWireSchema,Ar as ConnectionsListResponseSchema,$ as DANGEROUS_ENV_VARS,x as DEFAULT_CAPACITY_SLOT,TE as DEFAULT_FORMS_FROM_LOCAL_PART,he as DEFAULT_REGION,oE as DEPLOYABLE_PATTERN_TYPES,hr as DEPLOY_MODES,cE as DEV_SUBSTRATE_ENTRYPOINT_SOURCE,mE as DEV_SUBSTRATE_PARAMS_FILENAME,CE as DEV_SUBSTRATE_PARAMS_SCHEMA_VERSION,E as DNS_APEX,A as DOMAIN_DEPLOY_DEFAULT_PHASE,Fr as DeployModeSchema,PE as DevSubstrateParamsSchema,OE as DevSubstrateSynthPropsSchema,jr as EXPECTED_CH_SCHEMA_VERSION_ENV,Wr as EXPECTED_SCHEMA_VERSION_ENV,kr as EXPECTED_SCHEMA_VERSION_TOOL_ENV,Pe as GOVERNANCE_ACCOUNT_TIERS,ke as GOVERNANCE_SCOPE_REQUIRED_CODE,Hr as IMAGE_TAG_PATTERN,Yr as ImageTagSchema,Be as MACHINE_ONLY_SCOPES,He as MAX_SECONDARY_REGIONS,Br as MIGRATION_SNAPSHOT_NAME_PREFIX,_E as OPENNEXT_PATTERN_TYPES,Ye as OPT_IN_REGION_CODES,tE as PATTERN_REGISTRY,rE as PATTERN_TYPES,eE as PATTERN_TYPE_VALUES,Jr as PHYSICAL_NAME_FALLBACK_PROPERTIES,Zr as PRISMA_MIGRATION_DIR_RE,X as REGION_SHORT_CODES,Dr as RESERVED_APP_NAMES,Mr as RESERVED_APP_NAME_MESSAGE,xr as RESERVED_APP_NAME_SUFFIX,ur as RESERVED_APP_NAME_SUFFIX_MESSAGE,Me as RESOURCE_CATEGORIES,Qr as SCHEMA_ADMIN_PASSWORD_ENV,zr as SCHEMA_ADMIN_USER_ENV,te as SCOPED_TOKEN_REGEX,Ke as SCOPE_VALUES,Qe as SECRET_NAME_ERROR,ze as SECRET_NAME_PATTERN,qe as SSM_COMPONENT_ERROR,Ze as SSM_COMPONENT_PATTERN,we as SSM_STANDARD_MAX_VALUE_BYTES,AE as STATIC_SITE_ROUTING_VALUES,ie as STRUCTURAL_ENVIRONMENTS,Je as SecretNamespaceSchema,vr as ServiceArtefactSchema,yr as ServiceArtefactsSchema,n as TOKEN_STDERR_PREFIX,We as USER_GRANTABLE_SCOPES,le as abbreviateRegion,f as accountConstructKey,Ie as accountTier,br as artefactOutputKey,Or as buildAppConfigPath,$e as buildNamespaceParts,er as buildParameterPath,p as capitalise,de as categoriseResource,v as defaultConnectedAccountName,RE as defaultFormsCorsOrigin,iE as defaultFormsFromAddress,Rr as deriveAllTargets,Vr as deriveContentHashTag,Tr as deriveRegionsFromOrgConfig,ir as deriveTargets,nr as environmentOrTier,ce as environmentToTier,or as escapeDotEnvValue,ee as filterDangerousEnvVars,H as findAccountNameCollision,cr as findBoundaryPath,sr as findInfrastructurePaths,Nr as findTarget,b as findTrailingRegionShortCode,Z as formatErrorString,Cr as generateTargetName,t as getDomainExportNames,o as getDomainStackName,_ as getDomainUsEast1CertificatesStackName,fe as getEnvironmentLabel,z as getErrorCode,k as getErrorMessage,Q as getErrorStack,xe as getExpectedDuration,ue as getFriendlyResourceType,Fe as getRegionInfo,I as getSafeZoneName,g as hasAsciiStableConstructKey,j as hasErrorCode,Ur as hasReservedAppNameSuffix,C as imageTagParameterName,fr as inferContainerFromCandidates,Ne as isAccountStage,Oe as isAccountTier,nE as isAddressAtDomain,se as isGovernanceTier,pr as isInfrastructureFile,Er as isManageablePath,a as isManagedDomainBinding,aE as isOpenNextPatternType,EE as isPatternType,dr as isReservedAppName,Ae as mapSettledWithConcurrency,re as maskSensitiveOutput,W as normaliseError,ve as optInRegionWarning,tr as parseDotEnv,Le as parseGitRemoteUrl,rr as parseParameterPath,Ee as parseShellArgs,h as projectCapacityIdentityToTarget,K as regionSuffixRejectionMessage,ye as regions,w as singleton,_e as sleep,pe as stageFromWireEnvironment,y as suffixedAccountName,Xe as suggestRegionForTimezone,P as toKebab,O as toPascalCase,c as toScreamingSnake,s as toValidDatabaseName};
@@ -6,5 +6,5 @@
6
6
  * pure CDK synth path) MUST import directly from `./schemas` instead of
7
7
  * the barrel — the package.json `exports` map exposes both subpaths.
8
8
  */
9
- export { DockerBuildSchema, DockerBuildArgValueSchema, DockerBuildSecretRefSchema, DockerBuildPartialSchema, mergeDockerBuild, ManifestServiceSchema, ManifestPatternSchema, ManifestEcrSchema, ManifestLambdaSchema, ManifestStackHashSchema, ResourceMapEntrySchema, FjallManifestSchema, EngineCompatSchema, FJALL_MANIFEST_FILENAME, MANIFEST_SCHEMA_VERSION, MAX_SUPPORTED_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, type EngineCompat } from "./schemas.js";
10
- export { getManifestFilePath, readManifestFile, writeManifestFile, createEmptyManifest, readConstructMap, parseDockerServicesFromManifest, parseLambdaDockerServicesFromManifest, parseLambdaDockerEntriesFromManifest, parseDockerDeclarationsFromManifest, readEngineCompatEnvelope, type ManifestDockerService, type ManifestLambdaDockerEntry, type ManifestDockerDeclarations, type EngineCompatEnvelope } from "./io.js";
9
+ export { DockerBuildSchema, DockerBuildArgValueSchema, DockerBuildSecretRefSchema, DockerBuildPartialSchema, mergeDockerBuild, ManifestServiceSchema, ManifestPatternSchema, ManifestEcrSchema, ManifestLambdaSchema, ManifestStackHashSchema, ResourceMapEntrySchema, FjallManifestSchema, EngineCompatSchema, ManifestCapacityAliasSchema, FJALL_MANIFEST_FILENAME, MANIFEST_SCHEMA_VERSION, MAX_SUPPORTED_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, type EngineCompat, type ManifestCapacityAlias } from "./schemas.js";
10
+ export { getManifestFilePath, readManifestFile, readManifestFileOutcome, writeManifestFile, createEmptyManifest, readConstructMap, parseDockerServicesFromManifest, parseLambdaDockerServicesFromManifest, parseLambdaDockerEntriesFromManifest, parseDockerDeclarationsFromManifest, readEngineCompatEnvelope, readManifestAppName, readManifestAppNameOutcome, type ManifestAppNameOutcome, type ManifestDockerService, type ManifestFileReadOutcome, type ManifestLambdaDockerEntry, type ManifestDockerDeclarations, type EngineCompatEnvelope } 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 s,ManifestEcrSchema as n,ManifestLambdaSchema as o,ManifestStackHashSchema as M,ResourceMapEntrySchema as E,FjallManifestSchema as f,EngineCompatSchema as h,FJALL_MANIFEST_FILENAME as l,MANIFEST_SCHEMA_VERSION as D,MAX_SUPPORTED_MANIFEST_SCHEMA_VERSION as F,BUILDKIT_SECRET_ID_PATTERN as p}from"./schemas.js";import{getManifestFilePath as _,readManifestFile as k,writeManifestFile as A,createEmptyManifest as I,readConstructMap as u,parseDockerServicesFromManifest as T,parseLambdaDockerServicesFromManifest as L,parseLambdaDockerEntriesFromManifest as N,parseDockerDeclarationsFromManifest as R,readEngineCompatEnvelope as B}from"./io.js";export{p as BUILDKIT_SECRET_ID_PATTERN,t as DockerBuildArgValueSchema,i as DockerBuildPartialSchema,r as DockerBuildSchema,c as DockerBuildSecretRefSchema,h as EngineCompatSchema,l as FJALL_MANIFEST_FILENAME,f as FjallManifestSchema,D as MANIFEST_SCHEMA_VERSION,F as MAX_SUPPORTED_MANIFEST_SCHEMA_VERSION,n as ManifestEcrSchema,o as ManifestLambdaSchema,s as ManifestPatternSchema,m as ManifestServiceSchema,M as ManifestStackHashSchema,E as ResourceMapEntrySchema,I as createEmptyManifest,_ as getManifestFilePath,S as mergeDockerBuild,R as parseDockerDeclarationsFromManifest,T as parseDockerServicesFromManifest,N as parseLambdaDockerEntriesFromManifest,L as parseLambdaDockerServicesFromManifest,u as readConstructMap,B as readEngineCompatEnvelope,k as readManifestFile,A as writeManifestFile};
1
+ import{DockerBuildSchema as r,DockerBuildArgValueSchema as t,DockerBuildSecretRefSchema as i,DockerBuildPartialSchema as c,mergeDockerBuild as m,ManifestServiceSchema as s,ManifestPatternSchema as n,ManifestEcrSchema as M,ManifestLambdaSchema as S,ManifestStackHashSchema as o,ResourceMapEntrySchema as f,FjallManifestSchema as E,EngineCompatSchema as p,ManifestCapacityAliasSchema as l,FJALL_MANIFEST_FILENAME as h,MANIFEST_SCHEMA_VERSION as d,MAX_SUPPORTED_MANIFEST_SCHEMA_VERSION as F,BUILDKIT_SECRET_ID_PATTERN as A}from"./schemas.js";import{getManifestFilePath as _,readManifestFile as k,readManifestFileOutcome as u,writeManifestFile as I,createEmptyManifest as N,readConstructMap as T,parseDockerServicesFromManifest as C,parseLambdaDockerServicesFromManifest as L,parseLambdaDockerEntriesFromManifest as R,parseDockerDeclarationsFromManifest as B,readEngineCompatEnvelope as P,readManifestAppName as g,readManifestAppNameOutcome as O}from"./io.js";export{A as BUILDKIT_SECRET_ID_PATTERN,t as DockerBuildArgValueSchema,c as DockerBuildPartialSchema,r as DockerBuildSchema,i as DockerBuildSecretRefSchema,p as EngineCompatSchema,h as FJALL_MANIFEST_FILENAME,E as FjallManifestSchema,d as MANIFEST_SCHEMA_VERSION,F as MAX_SUPPORTED_MANIFEST_SCHEMA_VERSION,l as ManifestCapacityAliasSchema,M as ManifestEcrSchema,S as ManifestLambdaSchema,n as ManifestPatternSchema,s as ManifestServiceSchema,o as ManifestStackHashSchema,f as ResourceMapEntrySchema,N as createEmptyManifest,_ as getManifestFilePath,m as mergeDockerBuild,B as parseDockerDeclarationsFromManifest,C as parseDockerServicesFromManifest,R as parseLambdaDockerEntriesFromManifest,L as parseLambdaDockerServicesFromManifest,T as readConstructMap,P as readEngineCompatEnvelope,g as readManifestAppName,O as readManifestAppNameOutcome,k as readManifestFile,u as readManifestFileOutcome,I as writeManifestFile};
@@ -11,6 +11,24 @@ import { type DockerBuild, type EngineCompat, type FjallManifest, type LambdaArc
11
11
  * Get the manifest file path for a cdk.out directory.
12
12
  */
13
13
  export declare function getManifestFilePath(cdkOutPath: string): string;
14
+ /**
15
+ * Completeness-signalled manifest read: consumers whose verdicts authorise
16
+ * or withhold work (identity-pin candidate collection, compatibility gates)
17
+ * must distinguish a genuinely absent manifest from one that is present but
18
+ * unreadable — collapsing both to "no manifest" turns a corrupt assembly
19
+ * into a clean "nothing to do" verdict. `detail` is pre-masked at
20
+ * construction.
21
+ */
22
+ export type ManifestFileReadOutcome = {
23
+ status: "ok";
24
+ manifest: FjallManifest;
25
+ } | {
26
+ status: "absent";
27
+ } | {
28
+ status: "unreadable";
29
+ detail: string;
30
+ };
31
+ export declare function readManifestFileOutcome(cdkOutPath: string): Promise<ManifestFileReadOutcome>;
14
32
  /**
15
33
  * Read manifest file from cdk.out directory.
16
34
  * Returns null if file doesn't exist or is corrupt.
@@ -99,6 +117,34 @@ export interface EngineCompatEnvelope {
99
117
  * the deploy phase.
100
118
  */
101
119
  export declare function readEngineCompatEnvelope(cdkOutPath: string): EngineCompatEnvelope;
120
+ /**
121
+ * Read the manifest's declared `appName` from a cdk.out directory — the
122
+ * assembly's own identity, which can diverge from the deploy operation's
123
+ * on-disk app name (folder "web-app" vs manifest "WebApp"). Returns undefined
124
+ * when the manifest is missing/unreadable or carries no usable appName.
125
+ *
126
+ * Reads synchronously to match the deploy-core chokepoints' synchronous
127
+ * orchestration context; the file is small and sealed by CDK synth ahead of
128
+ * the deploy phase.
129
+ */
130
+ export declare function readManifestAppName(cdkOutPath: string): string | undefined;
131
+ /**
132
+ * Completeness-signalled variant of {@link readManifestAppName}: gates whose
133
+ * verdicts hinge on the manifest identity (the AC-3.7 downgrade tripwire)
134
+ * must distinguish an absent manifest (no identity to diverge from — folder
135
+ * matching is complete) from a present-but-unreadable one (the identity
136
+ * exists but cannot be proven — fail closed). `appName: undefined` on an
137
+ * `ok` outcome means the manifest is readable but declares no usable name.
138
+ */
139
+ export type ManifestAppNameOutcome = {
140
+ status: "ok";
141
+ appName: string | undefined;
142
+ } | {
143
+ status: "absent";
144
+ } | {
145
+ status: "unreadable";
146
+ };
147
+ export declare function readManifestAppNameOutcome(cdkOutPath: string): ManifestAppNameOutcome;
102
148
  /**
103
149
  * Extract services with a Docker build configuration from the Fjall manifest.
104
150
  *
@@ -1 +1 @@
1
- var h=Object.defineProperty;var a=(t,e)=>h(t,"name",{value:e,configurable:!0});import{readFile as M,writeFile as b,unlink as E,rename as k,mkdir as A}from"fs/promises";import{readFileSync as F}from"fs";import{dirname as w,join as m}from"path";import{logger as c}from"../logger.js";import{maskSensitiveOutput as C}from"../securityHelpers.js";import{fileExists as x}from"../fsHelpers.js";import{getErrorMessage as d}from"../errorUtils.js";import{recordToConstructMap as S}from"../constructMap.js";import{FjallManifestSchema as v,FJALL_MANIFEST_FILENAME as l,MANIFEST_SCHEMA_VERSION as j,normaliseDockerBuild as p,LAMBDA_ARCHITECTURE_VALUES as L}from"./schemas.js";function g(t){return m(t,l)}a(g,"getManifestFilePath");async function D(t){const e=g(t);if(!await x(e))return null;try{const r=await M(e,"utf-8"),n=JSON.parse(r),i=v.safeParse(n);return i.success||c.debug("FjallManifest","Manifest validation failed",{path:e,errors:i.error.issues.map(s=>`${s.path.join(".")}: ${s.message}`)}),i.success?i.data:null}catch(r){return c.debug("FjallManifest","Failed to read manifest file",{path:e,error:d(r)}),null}}a(D,"readManifestFile");async function H(t,e){const r=g(t),n=`${r}.${Date.now()}.tmp`;await A(w(r),{recursive:!0});try{await b(n,JSON.stringify(e,null,2),"utf-8"),await k(n,r)}catch(i){try{await E(n)}catch(s){c.debug("FjallManifest","Temp file cleanup failed (non-fatal)",{path:n,error:d(s)})}throw i}}a(H,"writeManifestFile");function U(t){return{version:j,generatedAt:new Date().toISOString(),appName:t,services:[],lambdas:[],stacks:{}}}a(U,"createEmptyManifest");async function q(t){const e=await D(t);return e?.resourceMap?S(e.resourceMap):new Map}a(q,"readConstructMap");function f(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}a(f,"isRecord");function u(t,e){const r=m(t,l);let n;try{n=F(r,"utf-8")}catch{c.debug("FjallManifest",`Manifest file not readable \u2014 no ${e} extracted`,{path:r});return}let i;try{i=JSON.parse(n)}catch{c.debug("FjallManifest",`Manifest is not valid JSON \u2014 no ${e} extracted`,{path:r});return}return f(i)?i:void 0}a(u,"readManifestRecord");function N(t){const e=t.engineCompat;if(!f(e))return;const r=e.minimumEngineVersion;if(typeof r!="string"||r.length===0)return;const n=typeof e.synthesisedBy=="string"&&e.synthesisedBy.length>0?e.synthesisedBy:"",i=typeof e.maximumEngineMajor=="number"&&Number.isInteger(e.maximumEngineMajor)&&e.maximumEngineMajor>=0?e.maximumEngineMajor:void 0,s=typeof e.minimumAwsCdkCli=="string"&&e.minimumAwsCdkCli.length>0?e.minimumAwsCdkCli:void 0;return{synthesisedBy:n,minimumEngineVersion:r,...i!==void 0&&{maximumEngineMajor:i},...s!==void 0&&{minimumAwsCdkCli:s}}}a(N,"extractEngineCompat");function z(t){const e=u(t,"engine compatibility");if(e===void 0)return{manifestVersion:void 0,engineCompatPresent:!1,engineCompat:void 0};const r=typeof e.version=="number"?e.version:void 0,n=f(e.engineCompat),i=N(e);return{manifestVersion:r,engineCompatPresent:n,engineCompat:i}}a(z,"readEngineCompatEnvelope");function I(t){const e=u(t,"Docker services");if(e===void 0||!Array.isArray(e.services))return[];const r=[];for(const n of e.services){if(!f(n)||typeof n.name!="string")continue;const i=p(n.docker);i!==void 0&&r.push({name:n.name,docker:i,isLambda:!1})}return r}a(I,"parseDockerServicesFromManifest");function G(t){const e=new Map;for(const{name:r,imageKey:n,docker:i,architecture:s}of y(t)){const o=e.get(n);if(o===void 0){e.set(n,{name:n,docker:i,isLambda:!0,...s!==void 0&&{architecture:s}});continue}if(JSON.stringify(o.docker)!==JSON.stringify(i)||o.architecture!==s)throw new Error(`Lambda functions sharing image key "${n}" declare different \`docker\` configs or \`architecture\` \u2014 every Lambda function sharing an \`image\` must build from the identical Dockerfile/context/target/buildArgs and target the same architecture (offending function: "${r}").`)}return Array.from(e.values())}a(G,"parseLambdaDockerServicesFromManifest");function y(t){const e=u(t,"Lambda Docker entries");if(e===void 0||!Array.isArray(e.lambdas))return[];const r=[];for(const n of e.lambdas){if(!f(n)||typeof n.name!="string")continue;const i=p(n.docker);if(i===void 0)continue;const s=typeof n.imageKey=="string"&&n.imageKey.length>0?n.imageKey:n.name;let o;typeof n.architecture=="string"&&(L.includes(n.architecture)?o=n.architecture:c.debug("FjallManifest","Ignoring unrecognised Lambda architecture \u2014 build falls back to the default platform",{lambda:n.name,architecture:C(n.architecture)})),r.push({name:n.name,imageKey:s,docker:i,...o!==void 0&&{architecture:o}})}return r}a(y,"parseLambdaDockerEntriesFromManifest");function Q(t){const e=I(t),r=y(t);return{ecsServices:e,lambdaEntries:r,declaresBuild:e.length>0||r.length>0}}a(Q,"parseDockerDeclarationsFromManifest");export{U as createEmptyManifest,g as getManifestFilePath,Q as parseDockerDeclarationsFromManifest,I as parseDockerServicesFromManifest,y as parseLambdaDockerEntriesFromManifest,G as parseLambdaDockerServicesFromManifest,q as readConstructMap,z as readEngineCompatEnvelope,D as readManifestFile,H as writeManifestFile};
1
+ var b=Object.defineProperty;var s=(n,e)=>b(n,"name",{value:e,configurable:!0});import{readFile as E,writeFile as k,unlink as F,rename as w,mkdir as x}from"fs/promises";import{readFileSync as g}from"fs";import{dirname as A,join as m}from"path";import{logger as c}from"../logger.js";import{maskSensitiveOutput as f}from"../securityHelpers.js";import{fileExists as N}from"../fsHelpers.js";import{getErrorMessage as d}from"../errorUtils.js";import{recordToConstructMap as S}from"../constructMap.js";import{FjallManifestSchema as j,FJALL_MANIFEST_FILENAME as p,MANIFEST_SCHEMA_VERSION as C,normaliseDockerBuild as y,LAMBDA_ARCHITECTURE_VALUES as v}from"./schemas.js";function h(n){return m(n,p)}s(h,"getManifestFilePath");async function O(n){const e=h(n);if(!await N(e))return{status:"absent"};try{const r=await E(e,"utf-8"),t=JSON.parse(r),a=j.safeParse(t);if(!a.success){const i=f(a.error.issues.map(o=>`${o.path.join(".")}: ${o.message}`).join("; "));return c.debug("FjallManifest","Manifest validation failed",{path:e,errors:i}),{status:"unreadable",detail:i}}return{status:"ok",manifest:a.data}}catch(r){const t=f(d(r));return c.debug("FjallManifest","Failed to read manifest file",{path:e,error:t}),{status:"unreadable",detail:t}}}s(O,"readManifestFileOutcome");async function D(n){const e=await O(n);return e.status==="ok"?e.manifest:null}s(D,"readManifestFile");async function q(n,e){const r=h(n),t=`${r}.${Date.now()}.tmp`;await x(A(r),{recursive:!0});try{await k(t,JSON.stringify(e,null,2),"utf-8"),await w(t,r)}catch(a){try{await F(t)}catch(i){c.debug("FjallManifest","Temp file cleanup failed (non-fatal)",{path:t,error:d(i)})}throw a}}s(q,"writeManifestFile");function z(n){return{version:C,generatedAt:new Date().toISOString(),appName:n,services:[],lambdas:[],stacks:{}}}s(z,"createEmptyManifest");async function G(n){const e=await D(n);return e?.resourceMap?S(e.resourceMap):new Map}s(G,"readConstructMap");function u(n){return typeof n=="object"&&n!==null&&!Array.isArray(n)}s(u,"isRecord");function l(n,e){const r=m(n,p);let t;try{t=g(r,"utf-8")}catch{c.debug("FjallManifest",`Manifest file not readable \u2014 no ${e} extracted`,{path:r});return}let a;try{a=JSON.parse(t)}catch{c.debug("FjallManifest",`Manifest is not valid JSON \u2014 no ${e} extracted`,{path:r});return}return u(a)?a:void 0}s(l,"readManifestRecord");function L(n){const e=n.engineCompat;if(!u(e))return;const r=e.minimumEngineVersion;if(typeof r!="string"||r.length===0)return;const t=typeof e.synthesisedBy=="string"&&e.synthesisedBy.length>0?e.synthesisedBy:"",a=typeof e.maximumEngineMajor=="number"&&Number.isInteger(e.maximumEngineMajor)&&e.maximumEngineMajor>=0?e.maximumEngineMajor:void 0,i=e.minimumAwsCdkCli,o=i===void 0?void 0:typeof i=="string"?i:String(i);return{synthesisedBy:t,minimumEngineVersion:r,...a!==void 0&&{maximumEngineMajor:a},...o!==void 0&&{minimumAwsCdkCli:o}}}s(L,"extractEngineCompat");function Q(n){const e=l(n,"engine compatibility");if(e===void 0)return{manifestVersion:void 0,engineCompatPresent:!1,engineCompat:void 0};const r=typeof e.version=="number"?e.version:void 0,t=u(e.engineCompat),a=L(e);return{manifestVersion:r,engineCompatPresent:t,engineCompat:a}}s(Q,"readEngineCompatEnvelope");function W(n){const e=I(n);return e.status==="ok"?e.appName:void 0}s(W,"readManifestAppName");function I(n){const e=m(n,p);let r;try{r=g(e,"utf-8")}catch(a){const i=a!==null&&typeof a=="object"&&"code"in a?a.code:void 0;return i==="ENOENT"||i==="ENOTDIR"?{status:"absent"}:(c.debug("FjallManifest","Manifest file not readable \u2014 no app name",{path:e,error:f(d(a))}),{status:"unreadable"})}let t;try{t=JSON.parse(r)}catch(a){return c.debug("FjallManifest","Manifest is not valid JSON \u2014 no app name",{path:e,error:f(d(a))}),{status:"unreadable"}}return u(t)?{status:"ok",appName:typeof t.appName=="string"&&t.appName!==""?t.appName:void 0}:{status:"unreadable"}}s(I,"readManifestAppNameOutcome");function J(n){const e=l(n,"Docker services");if(e===void 0||!Array.isArray(e.services))return[];const r=[];for(const t of e.services){if(!u(t)||typeof t.name!="string")continue;const a=y(t.docker);a!==void 0&&r.push({name:t.name,docker:a,isLambda:!1})}return r}s(J,"parseDockerServicesFromManifest");function X(n){const e=new Map;for(const{name:r,imageKey:t,docker:a,architecture:i}of M(n)){const o=e.get(t);if(o===void 0){e.set(t,{name:t,docker:a,isLambda:!0,...i!==void 0&&{architecture:i}});continue}if(JSON.stringify(o.docker)!==JSON.stringify(a)||o.architecture!==i)throw new Error(`Lambda functions sharing image key "${t}" declare different \`docker\` configs or \`architecture\` \u2014 every Lambda function sharing an \`image\` must build from the identical Dockerfile/context/target/buildArgs and target the same architecture (offending function: "${r}").`)}return Array.from(e.values())}s(X,"parseLambdaDockerServicesFromManifest");function M(n){const e=l(n,"Lambda Docker entries");if(e===void 0||!Array.isArray(e.lambdas))return[];const r=[];for(const t of e.lambdas){if(!u(t)||typeof t.name!="string")continue;const a=y(t.docker);if(a===void 0)continue;const i=typeof t.imageKey=="string"&&t.imageKey.length>0?t.imageKey:t.name;let o;typeof t.architecture=="string"&&(v.includes(t.architecture)?o=t.architecture:c.debug("FjallManifest","Ignoring unrecognised Lambda architecture \u2014 build falls back to the default platform",{lambda:t.name,architecture:f(t.architecture)})),r.push({name:t.name,imageKey:i,docker:a,...o!==void 0&&{architecture:o}})}return r}s(M,"parseLambdaDockerEntriesFromManifest");function Y(n){const e=J(n),r=M(n);return{ecsServices:e,lambdaEntries:r,declaresBuild:e.length>0||r.length>0}}s(Y,"parseDockerDeclarationsFromManifest");export{z as createEmptyManifest,h as getManifestFilePath,Y as parseDockerDeclarationsFromManifest,J as parseDockerServicesFromManifest,M as parseLambdaDockerEntriesFromManifest,X as parseLambdaDockerServicesFromManifest,G as readConstructMap,Q as readEngineCompatEnvelope,W as readManifestAppName,I as readManifestAppNameOutcome,D as readManifestFile,O as readManifestFileOutcome,q as writeManifestFile};
@@ -361,6 +361,34 @@ declare const EngineCompatSchema: z.ZodObject<{
361
361
  minimumAwsCdkCli: z.ZodOptional<z.ZodString>;
362
362
  }, z.core.$strict>;
363
363
  export type EngineCompat = z.infer<typeof EngineCompatSchema>;
364
+ /**
365
+ * One capacity-slot identity alias, emitted at synth for EVERY EC2 capacity
366
+ * slot unconditionally (pinned or not) by the constructs' capacity factory.
367
+ * Ties the slot's CURRENT identity derivation to the HYPOTHETICAL pre-6.0
368
+ * (config-keyed) derivation computed from the same config, so:
369
+ * - rename detection (deploy-core) can confirm a legacy→anchor rename pair
370
+ * from the emitter's own testimony (matcher (a), the highest-precedence
371
+ * evidence) and name the config fields that used to drive the identity;
372
+ * - the pin writer (`fjall migrate identity`) can route a CREATE-side row
373
+ * back to `{ appName, slot }` when composing a pin.
374
+ *
375
+ * WRITE contract: `.strict()` like `EngineCompatSchema` — emitter and reader
376
+ * live in Lerna FIXED lockstep, and a future additive field revs through
377
+ * `minimumEngineVersion` before any older reader can meet it.
378
+ */
379
+ export declare const ManifestCapacityAliasSchema: z.ZodObject<{
380
+ appName: z.ZodString;
381
+ slot: z.ZodString;
382
+ clusterName: z.ZodString;
383
+ anchor: z.ZodString;
384
+ pinned: z.ZodBoolean;
385
+ currentServiceName: z.ZodString;
386
+ legacyKey: z.ZodString;
387
+ legacyAnchor: z.ZodString;
388
+ legacyServiceName: z.ZodString;
389
+ legacyKeyFields: z.ZodArray<z.ZodString>;
390
+ }, z.core.$strict>;
391
+ export type ManifestCapacityAlias = z.infer<typeof ManifestCapacityAliasSchema>;
364
392
  /**
365
393
  * Fjall manifest schema — generated during CDK synth.
366
394
  * Location: `<cdk.out>/fjall-manifest.json`.
@@ -465,6 +493,18 @@ export declare const FjallManifestSchema: z.ZodObject<{
465
493
  maximumEngineMajor: z.ZodOptional<z.ZodNumber>;
466
494
  minimumAwsCdkCli: z.ZodOptional<z.ZodString>;
467
495
  }, z.core.$strict>>;
496
+ identityAliases: z.ZodOptional<z.ZodArray<z.ZodObject<{
497
+ appName: z.ZodString;
498
+ slot: z.ZodString;
499
+ clusterName: z.ZodString;
500
+ anchor: z.ZodString;
501
+ pinned: z.ZodBoolean;
502
+ currentServiceName: z.ZodString;
503
+ legacyKey: z.ZodString;
504
+ legacyAnchor: z.ZodString;
505
+ legacyServiceName: z.ZodString;
506
+ legacyKeyFields: z.ZodArray<z.ZodString>;
507
+ }, z.core.$strict>>>;
468
508
  }, z.core.$strict>;
469
509
  export type FjallManifest = z.infer<typeof FjallManifestSchema>;
470
510
  export { ManifestServiceSchema, ManifestPatternSchema, ManifestEcrSchema, ManifestLambdaSchema, ManifestStackHashSchema, ResourceMapEntrySchema, EngineCompatSchema };
@@ -1 +1 @@
1
- var S=Object.defineProperty;var s=(t,n)=>S(t,"name",{value:n,configurable:!0});import{z as e}from"zod";import{PATTERN_TYPE_VALUES as h}from"../patterns/patternTypes.js";const N="fjall-manifest.json",x=1,P=1,A=/^[A-Za-z0-9_.-]+$/,M=e.object({id:e.string().min(1,"buildSecret id cannot be empty").regex(A,"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)"})}),E=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)"})})]),c=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(),E).optional(),buildSecrets:e.array(M).optional()}).strict(),R=c.partial();function B(t,n){if(n===void 0)return t;const i=n.context??t.context,r=n.target??t.target,o=n.buildArgs??t.buildArgs,a=n.buildSecrets??t.buildSecrets;return{path:n.path??t.path,...i!==void 0&&{context:i},...r!==void 0&&{target:r},...o!==void 0&&{buildArgs:o},...a!==void 0&&{buildSecrets:a}}}s(B,"mergeDockerBuild");function m(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}s(m,"isRecord");function j(t){if(!m(t)||typeof t.path!="string"||t.path.length===0)return;const n=typeof t.context=="string"&&t.context.length>0?t.context:void 0,i=typeof t.target=="string"&&t.target.length>0?t.target:void 0,r=m(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,a={path:t.path,...n!==void 0&&{context:n},...i!==void 0&&{target:i},...r!==void 0&&{buildArgs:r},...o!==void 0&&{buildSecrets:o}},d=c.safeParse(a);return d.success?d.data:void 0}s(j,"normaliseDockerBuild");function C(t){if(t===void 0)return;const n=j(t);return n===void 0?void 0:JSON.stringify(n)}s(C,"dockerBuildFingerprint");const p=e.object({name:e.string(),clusterName:e.string().optional(),docker:c.optional(),containerPort:e.number().optional(),secrets:e.array(e.string()).optional(),ssmSecretsPath:e.string().optional(),importedSecretNames:e.array(e.string()).optional()}).strict(),g=e.object({type:e.enum(h),name:e.string(),source:e.string()}).strict(),l=e.object({repositoryName:e.string()}).strict(),_=["x86_64","arm64"],u=e.object({name:e.string(),secrets:e.array(e.string()).optional(),ssmSecretsPath:e.string().optional(),importedSecretNames:e.array(e.string()).optional(),docker:c.optional(),imageKey:e.string().optional(),architecture:e.enum(_).optional()}).strict(),f=e.object({templateHash:e.string(),synthTimestamp:e.string()}).strict(),b=e.object({constructPath:e.string().max(512),group:e.string().max(128),resourceType:e.string().max(256)}).strict(),y=e.object({synthesisedBy:e.string().min(1).max(128),minimumEngineVersion:e.string().min(1).max(32),maximumEngineMajor:e.number().int().min(0).optional(),minimumAwsCdkCli:e.string().min(1).max(32).optional()}).strict(),D=e.object({version:e.literal(x),generatedAt:e.string(),appName:e.string(),services:e.array(p),lambdas:e.array(u),pattern:g.optional(),ecr:l.optional(),stacks:e.record(e.string(),f),resourceMap:e.record(e.string(),b).optional(),engineCompat:y.optional()}).strict();export{A as BUILDKIT_SECRET_ID_PATTERN,E as DockerBuildArgValueSchema,R as DockerBuildPartialSchema,c as DockerBuildSchema,M as DockerBuildSecretRefSchema,y as EngineCompatSchema,N as FJALL_MANIFEST_FILENAME,D as FjallManifestSchema,_ as LAMBDA_ARCHITECTURE_VALUES,x as MANIFEST_SCHEMA_VERSION,P as MAX_SUPPORTED_MANIFEST_SCHEMA_VERSION,l as ManifestEcrSchema,u as ManifestLambdaSchema,g as ManifestPatternSchema,p as ManifestServiceSchema,f as ManifestStackHashSchema,b as ResourceMapEntrySchema,C as dockerBuildFingerprint,B as mergeDockerBuild,j as normaliseDockerBuild};
1
+ var x=Object.defineProperty;var o=(t,n)=>x(t,"name",{value:n,configurable:!0});import{z as e}from"zod";import{PATTERN_TYPE_VALUES as S}from"../patterns/patternTypes.js";const C="fjall-manifest.json",h=1,P=1,A=/^[A-Za-z0-9_.-]+$/,M=e.object({id:e.string().min(1,"buildSecret id cannot be empty").regex(A,"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)"})}),E=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)"})})]),c=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(),E).optional(),buildSecrets:e.array(M).optional()}).strict(),R=c.partial();function B(t,n){if(n===void 0)return t;const i=n.context??t.context,r=n.target??t.target,s=n.buildArgs??t.buildArgs,a=n.buildSecrets??t.buildSecrets;return{path:n.path??t.path,...i!==void 0&&{context:i},...r!==void 0&&{target:r},...s!==void 0&&{buildArgs:s},...a!==void 0&&{buildSecrets:a}}}o(B,"mergeDockerBuild");function d(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}o(d,"isRecord");function j(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,i=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,s=Array.isArray(t.buildSecrets)&&t.buildSecrets.length>0?t.buildSecrets:void 0,a={path:t.path,...n!==void 0&&{context:n},...i!==void 0&&{target:i},...r!==void 0&&{buildArgs:r},...s!==void 0&&{buildSecrets:s}},m=c.safeParse(a);return m.success?m.data:void 0}o(j,"normaliseDockerBuild");function D(t){if(t===void 0)return;const n=j(t);return n===void 0?void 0:JSON.stringify(n)}o(D,"dockerBuildFingerprint");const g=e.object({name:e.string(),clusterName:e.string().optional(),docker:c.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(S),name:e.string(),source:e.string()}).strict(),l=e.object({repositoryName:e.string()}).strict(),N=["x86_64","arm64"],u=e.object({name:e.string(),secrets:e.array(e.string()).optional(),ssmSecretsPath:e.string().optional(),importedSecretNames:e.array(e.string()).optional(),docker:c.optional(),imageKey:e.string().optional(),architecture:e.enum(N).optional()}).strict(),f=e.object({templateHash:e.string(),synthTimestamp:e.string()}).strict(),b=e.object({constructPath:e.string().max(512),group:e.string().max(128),resourceType:e.string().max(256)}).strict(),y=e.object({synthesisedBy:e.string().min(1).max(128),minimumEngineVersion:e.string().min(1).max(32),maximumEngineMajor:e.number().int().min(0).optional(),minimumAwsCdkCli:e.string().min(1).max(32).optional()}).strict(),_=e.object({appName:e.string().min(1).max(128),slot:e.string().min(1).max(64),clusterName:e.string().min(1).max(128),anchor:e.string().min(1).max(128),pinned:e.boolean(),currentServiceName:e.string().min(1).max(256),legacyKey:e.string().min(1).max(256),legacyAnchor:e.string().min(1).max(256),legacyServiceName:e.string().min(1).max(512),legacyKeyFields:e.array(e.string().max(64)).max(32)}).strict(),F=e.object({version:e.literal(h),generatedAt:e.string(),appName:e.string(),services:e.array(g),lambdas:e.array(u),pattern:p.optional(),ecr:l.optional(),stacks:e.record(e.string(),f),resourceMap:e.record(e.string(),b).optional(),engineCompat:y.optional(),identityAliases:e.array(_).optional()}).strict();export{A as BUILDKIT_SECRET_ID_PATTERN,E as DockerBuildArgValueSchema,R as DockerBuildPartialSchema,c as DockerBuildSchema,M as DockerBuildSecretRefSchema,y as EngineCompatSchema,C as FJALL_MANIFEST_FILENAME,F as FjallManifestSchema,N as LAMBDA_ARCHITECTURE_VALUES,h as MANIFEST_SCHEMA_VERSION,P as MAX_SUPPORTED_MANIFEST_SCHEMA_VERSION,_ as ManifestCapacityAliasSchema,l as ManifestEcrSchema,u as ManifestLambdaSchema,p as ManifestPatternSchema,g as ManifestServiceSchema,f as ManifestStackHashSchema,b as ResourceMapEntrySchema,D as dockerBuildFingerprint,B as mergeDockerBuild,j as normaliseDockerBuild};
package/package.json CHANGED
@@ -1,6 +1,11 @@
1
1
  {
2
2
  "name": "@fjall/util",
3
- "version": "5.0.0",
3
+ "version": "7.0.0",
4
+ "repository": {
5
+ "type": "git",
6
+ "url": "git+https://github.com/fjall-tech/fjall.git",
7
+ "directory": "util"
8
+ },
4
9
  "description": "Common utility methods",
5
10
  "type": "module",
6
11
  "main": "dist/index.js",
@@ -133,6 +138,5 @@
133
138
  },
134
139
  "engines": {
135
140
  "node": ">=22.0.0"
136
- },
137
- "gitHead": "78dded6f582368076e8b5f351399219e5a954659"
141
+ }
138
142
  }