@fjall/util 4.4.0 → 6.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.
@@ -0,0 +1,109 @@
1
+ {
2
+ "version": 2,
3
+ "algorithm": "sha256",
4
+ "sources": [
5
+ "src"
6
+ ],
7
+ "extraFiles": [
8
+ "../scripts/minify-dist.mjs",
9
+ "package.json",
10
+ "tsconfig.json"
11
+ ],
12
+ "hash": "9f46961fad5c09fc71a1f5cb7e5ffa948b727a5b32661d54da8f6912f2c55352",
13
+ "files": {
14
+ "src/async/concurrency.ts": "3c7ebe0222a720f9",
15
+ "src/async/singleton.ts": "7bcc21b0fb920561",
16
+ "src/async/sleep.ts": "df52b17675ec3ed2",
17
+ "src/aws/CloudFormationFailureAnalyser.ts": "ea858b3dc7332dac",
18
+ "src/aws/cloudformationTypes.ts": "e43bab9c96a21856",
19
+ "src/aws/costAllocationTags.ts": "102100b3df7d428e",
20
+ "src/aws/deployProgress.ts": "be09dedb4deb9a7a",
21
+ "src/aws/driftSuspects.ts": "5400dc05ebd6c977",
22
+ "src/aws/errors.ts": "5addfa6bb2d1456a",
23
+ "src/aws/index.ts": "5f2c5c6c4fd0b600",
24
+ "src/aws/infraTags.ts": "6b1e65bf7119f32c",
25
+ "src/aws/ipamTags.ts": "ac19ecd6c36b3bc2",
26
+ "src/aws/maskFailureAnalysis.ts": "ae11250412cd6fd8",
27
+ "src/aws/monitoringRole.ts": "70c8b5947dc9138d",
28
+ "src/buildConcurrency.ts": "1804e76ddc4f8216",
29
+ "src/cdkTmpdirCleanup.ts": "4574b3f10e3ab0f9",
30
+ "src/cfn/physicalNameProperties.ts": "35d3c6f28079c593",
31
+ "src/config.ts": "588d7c179cbcc13d",
32
+ "src/constructMap.ts": "b81fc8e90015467f",
33
+ "src/deploy/approvalTokenOutput.ts": "4be7b52825d88a37",
34
+ "src/devSubstrate/entrypoint.ts": "0526b88258174aa6",
35
+ "src/devSubstrate/params.ts": "43bf902b57eb9edd",
36
+ "src/docker/DockerCli.build.ts": "93a74294437cc002",
37
+ "src/docker/DockerCli.daemon.ts": "11b9c3352c957d7c",
38
+ "src/docker/DockerCli.registry.ts": "f8dfcf1d7e413014",
39
+ "src/docker/DockerCli.ts": "3d2697c355b102d5",
40
+ "src/docker/abortHelpers.ts": "76daf48e617b8ec8",
41
+ "src/docker/architecture.ts": "305d87b68b905694",
42
+ "src/docker/bakeGuard.ts": "fc4120fb97756ddb",
43
+ "src/docker/buildArgInference.ts": "611dc5cb52b63f75",
44
+ "src/docker/buildxArgvBuilder.ts": "0ccc37cf5aaae62c",
45
+ "src/docker/buildxBuildMonitor.ts": "27c7b921901a9759",
46
+ "src/docker/cacheRepository.ts": "fae19107a3adbf13",
47
+ "src/docker/dockerCliConstants.ts": "2c216f214f466307",
48
+ "src/docker/dockerCliDiagnostics.ts": "250bc882b75d7bcc",
49
+ "src/docker/dockerCliSchemas.ts": "af1e89eb8ecd7023",
50
+ "src/docker/dockerErrorFormat.ts": "332dedf7ea3589c2",
51
+ "src/docker/ecrCredentialStore.ts": "0a99f7155dad5894",
52
+ "src/docker/index.ts": "f189b4e9967ab8c0",
53
+ "src/docker/metadataFileParser.ts": "299bc37a12c4594b",
54
+ "src/docker/projectBuildxResult.ts": "f462ba365b7ccdcc",
55
+ "src/docker/rawjsonParser.ts": "b9e5218abc326fa5",
56
+ "src/docker/rawjsonToVertexEvent.ts": "a356190727f0d1a4",
57
+ "src/docker/result.ts": "2ff0d59a3add8b06",
58
+ "src/environments.ts": "13d583ce2ce37454",
59
+ "src/errorUtils.ts": "c601f2905c74b8d0",
60
+ "src/fsHelpers.ts": "0869d9739d523572",
61
+ "src/fsScan.ts": "feb187758481443f",
62
+ "src/index.ts": "73d86121bd8fbf3e",
63
+ "src/infra/backupVault.ts": "661678a6dfb0b648",
64
+ "src/infra/connectionsWire.ts": "125c099da0e17ac1",
65
+ "src/infra/deployArtefacts.ts": "235ac21dd3ccf0b2",
66
+ "src/infra/deriveContentHashTag.ts": "115fbe6588794027",
67
+ "src/infra/domainExports.ts": "6a6ae87e93e12523",
68
+ "src/infra/imageTags.ts": "82d14f3dfd6ca68f",
69
+ "src/infra/regions.ts": "26b80d7cea05454c",
70
+ "src/infra/tokenScopes.ts": "88c6a1f0da3fa491",
71
+ "src/insights/computePatternFingerprint.ts": "b5d3a4704f42cc1f",
72
+ "src/logger.ts": "865ec4ec62a9a588",
73
+ "src/manifest/index.ts": "f31b6502053a6bfc",
74
+ "src/manifest/io.ts": "b078aeb22125e7ac",
75
+ "src/manifest/schemas.ts": "ffd61136a3aaee9e",
76
+ "src/mcpProtocol/index.ts": "55df3209915a5043",
77
+ "src/migration/clickhouseSqlUsers.ts": "c916e148367715bb",
78
+ "src/migration/compareSchemaVersion.ts": "1c9247e722ec5d5b",
79
+ "src/migration/constants.ts": "75c45113184b3653",
80
+ "src/migration/index.ts": "de586c9d775b3174",
81
+ "src/migration/pickLatestClickHouseMigration.ts": "a5b4a00ba63522cb",
82
+ "src/migration/pickLatestPrismaMigration.ts": "cbddc2950f4d4c85",
83
+ "src/migration/verifyExpectedSchemaVersion.ts": "f2a9c63023ffb3d2",
84
+ "src/naming/accountNameCollision.ts": "2dc8b278ff039220",
85
+ "src/naming/caseConversion.ts": "8b8984f2b58b8ab7",
86
+ "src/naming/connectedAccountName.ts": "3cd3bc7dba0a2f0b",
87
+ "src/naming/reservedAppNames.ts": "7f63dd0b84c1972e",
88
+ "src/patterns/index.ts": "6e8b1b7a4a7db24c",
89
+ "src/patterns/patternTypes.ts": "c64758645bc88702",
90
+ "src/patterns/staticSiteForms.ts": "86ffcf142d9a8eac",
91
+ "src/repo/appPath.ts": "9aa0d01262b88e65",
92
+ "src/repo/findInfrastructurePaths.ts": "dd1245f5d4004dd5",
93
+ "src/repo/findProjectsBelow.ts": "0ee63f2910a47a89",
94
+ "src/repo/findRepoRoot.ts": "6007be0f7d3407b1",
95
+ "src/repo/gitRemoteParser.ts": "2e1407d1d120baff",
96
+ "src/repo/inferContainerFromCandidates.ts": "63df34e7e5e65b34",
97
+ "src/repo/scanLocalRepository.ts": "c7bc76201622a7a5",
98
+ "src/repo/scanTypes.ts": "1fda805a7d8de93b",
99
+ "src/resourceCategorisation.ts": "a140d1b3cb38be33",
100
+ "src/secrets.ts": "50258d463e4e67c3",
101
+ "src/securityHelpers.ts": "acbf209255468ff4",
102
+ "src/targets.ts": "126280f0a5762e21",
103
+ "../scripts/minify-dist.mjs": "6b2e4b0df8aec601",
104
+ "package.json": "afa179ea73b4ffcc",
105
+ "tsconfig.json": "db759831ad95f396"
106
+ },
107
+ "outputHash": "02ef6ae83d06e52efe1c2299391aeab1fde73c1e3b6a67ddc5f980efad763847",
108
+ "outputFileCount": 185
109
+ }
package/dist/.minified CHANGED
@@ -1 +1 @@
1
- 92 files minified at 2026-07-30T00:34:06.112Z
1
+ 92 files minified at 2026-08-01T08:45:55.266Z
package/dist/config.d.ts CHANGED
@@ -274,8 +274,10 @@ export declare class Config {
274
274
  * so concurrently-registered siblings survive, keys this version does not
275
275
  * recognise ride through verbatim, and keys explicitly cleared this
276
276
  * 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.
277
+ * An absent file (first-ever save) writes the in-memory state as-is; an
278
+ * unreadable or invalid existing file REFUSES the save — the in-memory
279
+ * state came through the tolerant stripping read, so writing it unmerged
280
+ * would silently delete every key the merge could not see.
279
281
  */
280
282
  private mergeWithDisk;
281
283
  /**
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 F=Object.defineProperty;var h=(u,e)=>F(u,"name",{value:e,configurable:!0});import*as a from"fs";import*as g from"path";import{z as l}from"zod";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 y}from"./securityHelpers.js";const x=10,w="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",O=l.object({name:l.string(),type:l.enum(["apex","delegated"]),parentDomain:l.string().optional(),account:l.string().optional(),region:l.string().optional()}).strict(),k=l.object({activeTarget:l.string().optional(),domains:l.array(O).optional()}).strict(),A=l.object({activeTarget:l.string().optional(),domains:l.array(O).optional()}),b=".fjall",N="local.json",_=l.object({activeTarget:l.string().optional()});function $(u={}){return JSON.stringify(u,null,2)}h($,"serialiseRootConfig");const L=k.keyof().options;function R(u,e,n){const t=e[n];t!==void 0&&(u[n]=t)}h(R,"copyDefinedKey");function D(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(D,"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<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:y(S(n))}),null}}static loadConfig(e){const n=f.findConfigDirectory(e);if(!n)return new f;const t=g.join(n,w),o=f.loadConfigFile(t);if(o===null){const d=new f(void 0,t);return d.loadFailed=!0,d}let r,i=!1;if(o!==""){let d;try{d=JSON.parse(o)}catch(s){throw f.formatZodError(s,w)}const C=k.safeParse(d);if(C.success)r=C.data;else{const s=A.safeParse(d);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 and domains 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 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 c=new f(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=f.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}: ${y(S(c))}`))}const t=f.assertWritable(e,n);if(!t.success)return t;const o=this.mergeWithDisk(e);if(!o.success)return o;const r=$(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}: ${y(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=f.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 L)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])),d=[],C=new Set;for(const s of e??[]){const m=o(s.name);C.add(m);const v=c.get(m),j=i.get(m);if(v!==void 0&&!D(v,j)){d.push(v);continue}v===void 0&&j!==void 0||d.push(s)}for(const s of r){const m=o(s.name);C.has(m)||D(s,i.get(m))||d.push(s)}return d}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 (${y(S(r))})`}}const t=A.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 (${y(r)})`}}const o={};if(typeof n=="object"&&n!==null){const r=L;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 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,b,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(){f.warnedLegacyActiveTarget||(f.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&&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,O as DomainConfigSchema,b as LOCAL_CONFIG_DIRNAME,N as LOCAL_CONFIG_FILENAME,H as ORGANISATION_TRAIL_NAME,X as ORG_TRAIL_BUCKET_OUTPUT_KEY,W as ROOT_ACCESS_MANAGEMENT_MODES,w as ROOT_CONFIG_FILENAME,A as RootConfigReadSchema,k 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 +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 h=Object.defineProperty;var s=(t,e)=>h(t,"name",{value:e,configurable:!0});import{readFile as M,writeFile as b,unlink as E,rename as k,mkdir as F}from"fs/promises";import{readFileSync as w}from"fs";import{dirname as A,join as m}from"path";import{logger as c}from"../logger.js";import{maskSensitiveOutput as x}from"../securityHelpers.js";import{fileExists as S}from"../fsHelpers.js";import{getErrorMessage as d}from"../errorUtils.js";import{recordToConstructMap as C}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)}s(g,"getManifestFilePath");async function D(t){const e=g(t);if(!await S(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(a=>`${a.path.join(".")}: ${a.message}`)}),i.success?i.data:null}catch(r){return c.debug("FjallManifest","Failed to read manifest file",{path:e,error:d(r)}),null}}s(D,"readManifestFile");async function H(t,e){const r=g(t),n=`${r}.${Date.now()}.tmp`;await F(A(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(a){c.debug("FjallManifest","Temp file cleanup failed (non-fatal)",{path:n,error:d(a)})}throw i}}s(H,"writeManifestFile");function U(t){return{version:j,generatedAt:new Date().toISOString(),appName:t,services:[],lambdas:[],stacks:{}}}s(U,"createEmptyManifest");async function q(t){const e=await D(t);return e?.resourceMap?C(e.resourceMap):new Map}s(q,"readConstructMap");function f(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}s(f,"isRecord");function u(t,e){const r=m(t,l);let n;try{n=w(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}s(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,a=e.minimumAwsCdkCli,o=a===void 0?void 0:typeof a=="string"?a:String(a);return{synthesisedBy:n,minimumEngineVersion:r,...i!==void 0&&{maximumEngineMajor:i},...o!==void 0&&{minimumAwsCdkCli:o}}}s(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}}s(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}s(I,"parseDockerServicesFromManifest");function G(t){const e=new Map;for(const{name:r,imageKey:n,docker:i,architecture:a}of y(t)){const o=e.get(n);if(o===void 0){e.set(n,{name:n,docker:i,isLambda:!0,...a!==void 0&&{architecture:a}});continue}if(JSON.stringify(o.docker)!==JSON.stringify(i)||o.architecture!==a)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())}s(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 a=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:x(n.architecture)})),r.push({name:n.name,imageKey:a,docker:i,...o!==void 0&&{architecture:o}})}return r}s(y,"parseLambdaDockerEntriesFromManifest");function Q(t){const e=I(t),r=y(t);return{ecsServices:e,lambdaEntries:r,declaresBuild:e.length>0||r.length>0}}s(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};
@@ -465,6 +465,7 @@ export declare const FjallManifestSchema: z.ZodObject<{
465
465
  maximumEngineMajor: z.ZodOptional<z.ZodNumber>;
466
466
  minimumAwsCdkCli: z.ZodOptional<z.ZodString>;
467
467
  }, z.core.$strict>>;
468
+ identityAliases: z.ZodOptional<z.ZodUnknown>;
468
469
  }, z.core.$strict>;
469
470
  export type FjallManifest = z.infer<typeof FjallManifestSchema>;
470
471
  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 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(),identityAliases:e.unknown().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};
package/package.json CHANGED
@@ -1,6 +1,11 @@
1
1
  {
2
2
  "name": "@fjall/util",
3
- "version": "4.4.0",
3
+ "version": "6.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",
@@ -104,7 +109,7 @@
104
109
  "scripts": {
105
110
  "clean": "rm -rf ./dist ./sourcemaps",
106
111
  "clean:node": "rm -rf ./node_modules",
107
- "build": "npm run clean && npx tsc && node ../scripts/minify-dist.mjs dist",
112
+ "build": "npm run clean && npx tsc && node ../scripts/minify-dist.mjs dist && node ../scripts/stamp-build.mjs",
108
113
  "prepack": "node ../scripts/check-dist-freshness.mjs",
109
114
  "watch": "npm run build && npx tsc-watch",
110
115
  "watch:only": "npx tsc-watch",
@@ -118,14 +123,14 @@
118
123
  "author": "",
119
124
  "license": "SEE LICENSE IN LICENSE",
120
125
  "devDependencies": {
121
- "@types/node": "^26.0.0",
122
- "prettier": "^3.8.3",
123
- "tsc-watch": "^7.2.0",
126
+ "@types/node": "^26.1.2",
127
+ "prettier": "^3.9.6",
128
+ "tsc-watch": "^7.2.1",
124
129
  "typescript": "^6.0.3",
125
- "vitest": "^4.1.7"
130
+ "vitest": "^4.1.10"
126
131
  },
127
132
  "dependencies": {
128
- "@aws-sdk/client-organizations": "^3.1038.0",
133
+ "@aws-sdk/client-organizations": "^3.1098.0",
129
134
  "zod": "^4.4.3"
130
135
  },
131
136
  "overrides": {
@@ -134,5 +139,5 @@
134
139
  "engines": {
135
140
  "node": ">=22.0.0"
136
141
  },
137
- "gitHead": "c700128600ab453fa63ce28b3effe8965373be43"
142
+ "gitHead": "7620fc7c93bbef1046580d6568546afe3cd450a7"
138
143
  }