@fjall/generator 2.20.1 → 2.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/.minified CHANGED
@@ -1 +1 @@
1
- 139 files minified at 2026-06-23T21:59:10.238Z
1
+ 139 files minified at 2026-06-30T11:38:24.144Z
@@ -147,7 +147,26 @@ export declare function parseAndConvert(code: string): {
147
147
  path: string;
148
148
  context?: string | undefined;
149
149
  target?: string | undefined;
150
- buildArgs?: Record<string, string> | undefined;
150
+ buildArgs?: Record<string, string | {
151
+ ssm?: string | undefined;
152
+ secretsManager?: {
153
+ name?: string | undefined;
154
+ arn?: string | undefined;
155
+ field?: string | undefined;
156
+ } | undefined;
157
+ env?: string | undefined;
158
+ acknowledgePublic?: boolean | undefined;
159
+ }> | undefined;
160
+ buildSecrets?: {
161
+ id: string;
162
+ ssm?: string | undefined;
163
+ secretsManager?: {
164
+ name?: string | undefined;
165
+ arn?: string | undefined;
166
+ field?: string | undefined;
167
+ } | undefined;
168
+ env?: string | undefined;
169
+ }[] | undefined;
151
170
  } | undefined;
152
171
  needsDatabaseConnection?: boolean | undefined;
153
172
  needsStorageConnection?: boolean | undefined;
@@ -237,7 +256,26 @@ export declare function parseAndConvert(code: string): {
237
256
  path?: string | undefined;
238
257
  context?: string | undefined;
239
258
  target?: string | undefined;
240
- buildArgs?: Record<string, string> | undefined;
259
+ buildArgs?: Record<string, string | {
260
+ ssm?: string | undefined;
261
+ secretsManager?: {
262
+ name?: string | undefined;
263
+ arn?: string | undefined;
264
+ field?: string | undefined;
265
+ } | undefined;
266
+ env?: string | undefined;
267
+ acknowledgePublic?: boolean | undefined;
268
+ }> | undefined;
269
+ buildSecrets?: {
270
+ id: string;
271
+ ssm?: string | undefined;
272
+ secretsManager?: {
273
+ name?: string | undefined;
274
+ arn?: string | undefined;
275
+ field?: string | undefined;
276
+ } | undefined;
277
+ env?: string | undefined;
278
+ }[] | undefined;
241
279
  } | undefined;
242
280
  deployment?: "code" | "container" | undefined;
243
281
  codePath?: string | undefined;
@@ -34,7 +34,7 @@ $FJALL-CERT ${e}
34
34
  ; www IN CNAME ${e}.
35
35
  ; api IN A ALIAS fjall:ecs:my-api
36
36
  ; @ IN MX 10 mail.${e}.
37
- `}function f(e){return JSON.stringify({name:`domain-${e}`,version:c,scripts:{},devDependencies:{"@types/node":"20.4.9","ts-node":"^10.9.1",typescript:"~5.1.6"},dependencies:{"@fjall/components-infrastructure":`^${c}`,"aws-cdk-lib":"^2.239.0",constructs:"^10.0.0"}},null,2)+`
37
+ `}function f(e){return JSON.stringify({name:`domain-${e}`,version:c,scripts:{},devDependencies:{"@types/node":"20.4.9","ts-node":"^10.9.1",typescript:"~5.1.6"},dependencies:{"@fjall/components-infrastructure":`^${c}`,"aws-cdk-lib":"^2.260.0",constructs:"^10.6.0"}},null,2)+`
38
38
  `}const g=`node_modules/
39
39
  cdk.out/
40
40
  *.d.ts
@@ -1,4 +1,4 @@
1
- export { planApplicationResources, type GenerationOptions, generateInfrastructureFromPlan, } from "./resourcePlanning.js";
1
+ export { planApplicationResources, toUserServiceConfigs, type GenerationOptions, generateInfrastructureFromPlan, } from "./resourcePlanning.js";
2
2
  export { type OpenNextResourceOptions, planOpenNextResources, } from "./openNextPlanning.js";
3
3
  export { type ConnectionType, applyComputeConnections, applyServiceConnections, } from "./resourceConnections.js";
4
4
  export { type AddableResourceType, type AddResourceOptions, type DatabaseAddOptions, type ProxyAddOptions, type S3AddOptions, type NetworkAddOptions, type EcsComputeAddOptions, type LambdaComputeAddOptions, type CdnAddOptions, type TunnelAddOptions, addResourceToPlan, validateResourceAddition, listAvailableResources, } from "./resourceAddition.js";
@@ -1 +1 @@
1
- import{planApplicationResources as r,generateInfrastructureFromPlan as n}from"./resourcePlanning.js";import{planOpenNextResources as a}from"./openNextPlanning.js";import{applyComputeConnections as s,applyServiceConnections as c}from"./resourceConnections.js";import{addResourceToPlan as i,validateResourceAddition as u,listAvailableResources as m}from"./resourceAddition.js";import{generateResourceChange as x}from"./generateResourceChange.js";export{i as addResourceToPlan,s as applyComputeConnections,c as applyServiceConnections,n as generateInfrastructureFromPlan,x as generateResourceChange,m as listAvailableResources,r as planApplicationResources,a as planOpenNextResources,u as validateResourceAddition};
1
+ import{planApplicationResources as r,toUserServiceConfigs as n,generateInfrastructureFromPlan as t}from"./resourcePlanning.js";import{planOpenNextResources as p}from"./openNextPlanning.js";import{applyComputeConnections as c,applyServiceConnections as i}from"./resourceConnections.js";import{addResourceToPlan as u,validateResourceAddition as f,listAvailableResources as m}from"./resourceAddition.js";import{generateResourceChange as R}from"./generateResourceChange.js";export{u as addResourceToPlan,c as applyComputeConnections,i as applyServiceConnections,t as generateInfrastructureFromPlan,R as generateResourceChange,m as listAvailableResources,r as planApplicationResources,p as planOpenNextResources,n as toUserServiceConfigs,f as validateResourceAddition};
@@ -1,6 +1,15 @@
1
1
  import { type UserServiceConfig, type AppType } from "../presets/tierPresets.js";
2
2
  import { type Result } from "../types/Result.js";
3
3
  import type { ApplicationResourcePlan } from "../schemas/resourceSchemas.js";
4
+ import type { ApplicationServiceConfig } from "../schemas/computeSchemas.js";
5
+ /**
6
+ * Adapt the wire-level service config (`ApplicationServiceConfig`, validated by
7
+ * `ApplicationServiceConfigSchema`) into the planner's `UserServiceConfig`. The
8
+ * two shapes are structurally identical; this is the single shared seam every
9
+ * consumer (CLI `applicationGenerator`, webapp scaffold) routes through, so the
10
+ * wire contract is mapped one way and cannot drift per-consumer.
11
+ */
12
+ export declare function toUserServiceConfigs(services?: ApplicationServiceConfig[]): UserServiceConfig[] | undefined;
4
13
  export declare function planApplicationResources(appName: string, appType: AppType, includeDatabase?: boolean, services?: UserServiceConfig[], snapshotOptions?: {
5
14
  snapshotIdentifier?: string;
6
15
  snapshotUsername?: string;
@@ -1 +1 @@
1
- import{TIER_PRESETS as m,getDefaultDatabaseTypeForTier as C,applyTierDefaultsToServices as g}from"../presets/tierPresets.js";import{COMPUTE_TYPE as b,DEFAULT_CONTAINER_PORT as l}from"../schemas/constants.js";import{success as u,failure as P}from"../types/Result.js";import{injectCustomCodeBlocks as k}from"../ast/mutation/astCodeInjection.js";import{toVariableName as d,toValidDatabaseName as D,generateImports as h,generateAppInit as T,generateTags as E,generateNetworkCode as f,generateDatabaseCode as R,generateClickHouseCode as I,generateS3Code as S,generateDynamoDBCode as p,generateSQSCode as w,generateComputeCode as A,generateCDNCode as B,collectCdnReferencedResources as U,usesPatternApproach as j,generatePatternCodeWithComments as x}from"../generation/index.js";function L(e,n,r=!0,s,t){const a={appName:e,type:n,database:[],s3:[],compute:[]};if(n==="custom")return a;const o=n,c=m[o];return{...a,database:y(e,c,o,r,t),compute:F(e,c,o,r,s),network:c.network,backup:c.backup}}function y(e,n,r,s,t){const a=C(r),o=n.database[a];return!s||o===null?[]:[{name:e,type:a,databaseName:D(e),variableName:`${d(e)}Database`,...o,...t?.snapshotIdentifier!==void 0&&{snapshotIdentifier:t.snapshotIdentifier},...t?.snapshotUsername!==void 0&&{snapshotUsername:t.snapshotUsername}}]}function _(e,n){if(!(e===void 0&&n===void 0))return{scaling:{...e!==void 0&&{minCapacity:e},...n!==void 0&&{maxCapacity:n}}}}function $(e,n){const{minCapacity:r,maxCapacity:s,...t}=e,a=n?.containerPort??l,o=n?.docker;return{...t,...o?.path!==void 0&&{docker:{path:o.path,...o.context!==void 0&&{context:o.context},...o.target!==void 0&&{target:o.target}}},...n?.needsDatabaseConnection!==void 0&&{needsDatabaseConnection:n.needsDatabaseConnection},containers:[{port:a}],..._(r,s)}}function F(e,n,r,s,t){const a=n.compute.ecs,o=t&&t.length>0?g(r,t):a.services.map((c,i)=>({...c,name:i===0?"api":`service-${i+1}`}));return[{name:e,type:b.ECS,needsConnection:s,connectedDatabase:s?[e]:void 0,variableName:`${d(e)}Compute`,cluster:a.cluster,services:o.map((c,i)=>$(c,t?.[i]))}]}function Q(e,n){const r=[h(e),T(e),E(e)];if(j(e))r.push(x(e),f(e));else{const t=U(e);r.push(f(e),R(e),I(e),S(e),p(e),w(e),A(e,t),B(e))}const s=r.join("");if(e.customCodeBlocks&&e.customCodeBlocks.length>0){const t=k(s,e.customCodeBlocks,n?.resourceMapping);return t.success?u(t.content):P(new Error(`Custom code injection failed: ${t.error??"unknown error"}`))}return u(s)}export{Q as generateInfrastructureFromPlan,L as planApplicationResources};
1
+ import{TIER_PRESETS as g,getDefaultDatabaseTypeForTier as b,applyTierDefaultsToServices as l}from"../presets/tierPresets.js";import{COMPUTE_TYPE as k,DEFAULT_CONTAINER_PORT as P}from"../schemas/constants.js";import{success as u,failure as D}from"../types/Result.js";import{injectCustomCodeBlocks as T}from"../ast/mutation/astCodeInjection.js";import{toVariableName as f,toValidDatabaseName as h,generateImports as p,generateAppInit as v,generateTags as E,generateNetworkCode as m,generateDatabaseCode as R,generateClickHouseCode as S,generateS3Code as y,generateDynamoDBCode as I,generateSQSCode as w,generateComputeCode as A,generateCDNCode as B,collectCdnReferencedResources as U,usesPatternApproach as x,generatePatternCodeWithComments as j}from"../generation/index.js";function Y(e){return e?.map(n=>({name:n.name,...n.serviceType!==void 0&&{serviceType:n.serviceType},...n.docker!==void 0&&{docker:n.docker},...n.containerPort!==void 0&&{containerPort:n.containerPort},...n.needsDatabaseConnection!==void 0&&{needsDatabaseConnection:n.needsDatabaseConnection},...n.routing!==void 0&&{routing:n.routing}}))}function q(e,n,r=!0,c,t){const i={appName:e,type:n,database:[],s3:[],compute:[]};if(n==="custom")return i;const s=n,o=g[s];return{...i,database:_(e,o,s,r,t),compute:H(e,o,s,r,c),network:o.network,backup:o.backup}}function _(e,n,r,c,t){const i=b(r),s=n.database[i];return!c||s===null?[]:[{name:e,type:i,databaseName:h(e),variableName:`${f(e)}Database`,...s,...t?.snapshotIdentifier!==void 0&&{snapshotIdentifier:t.snapshotIdentifier},...t?.snapshotUsername!==void 0&&{snapshotUsername:t.snapshotUsername}}]}function $(e,n){if(!(e===void 0&&n===void 0))return{scaling:{...e!==void 0&&{minCapacity:e},...n!==void 0&&{maxCapacity:n}}}}function F(e,n){const{minCapacity:r,maxCapacity:c,...t}=e,i=n?.serviceType==="worker",s=n?.containerPort??P,o=n?.docker;return{...t,...o?.path!==void 0&&{docker:{path:o.path,...o.context!==void 0&&{context:o.context},...o.target!==void 0&&{target:o.target}}},...n?.needsDatabaseConnection!==void 0&&{needsDatabaseConnection:n.needsDatabaseConnection},containers:i?[{}]:[{port:s}],...$(r,c)}}function N(e,n){return n||e?.directAccess===!0?e:{...e,loadBalancer:!1}}function H(e,n,r,c,t){const i=n.compute.ecs,o=(t&&t.length>0?l(r,t):i.services.map((d,a)=>({...d,name:a===0?"api":`service-${a+1}`}))).map((d,a)=>F(d,t?.[a])),C=o.some(d=>d.containers?.some(a=>a.port!==void 0));return[{name:e,type:k.ECS,needsConnection:c,connectedDatabase:c?[e]:void 0,variableName:`${f(e)}Compute`,cluster:N(i.cluster,C),services:o}]}function z(e,n){const r=[p(e),v(e),E(e)];if(x(e))r.push(j(e),m(e));else{const t=U(e);r.push(m(e),R(e),S(e),y(e),I(e),w(e),A(e,t),B(e))}const c=r.join("");if(e.customCodeBlocks&&e.customCodeBlocks.length>0){const t=T(c,e.customCodeBlocks,n?.resourceMapping);return t.success?u(t.content):D(new Error(`Custom code injection failed: ${t.error??"unknown error"}`))}return u(c)}export{z as generateInfrastructureFromPlan,q as planApplicationResources,Y as toUserServiceConfigs};
@@ -1 +1 @@
1
- import{TIER_NAMES as d}from"../schemas/sharedTypes.js";import{TIER_NAMES as h,CUSTOM_TIER as L,APP_TYPES as M}from"../schemas/sharedTypes.js";const i="service",c="0 4 * * ? *",u="0 5 * * ? *",r=Object.freeze({tinkerer:{displayName:"Tinkerer",description:"Free tier eligible, minimal cost for experimentation",database:{Instance:{instanceType:"t4g.micro",multiAz:!1,proxy:!1,readReplica:!1,publiclyAccessible:!0},Aurora:null,GlobalAurora:null,ClickHouse:null},compute:{ecs:{services:[{name:i,capacityProvider:"EC2",desiredCount:1,minCapacity:1,maxCapacity:1,ec2Config:{instanceType:"t4g.micro",amiHardwareType:"ARM",minCapacity:1,maxCapacity:1,memoryLimitMiB:400}}],cluster:{directAccess:!0}},lambda:{timeout:30,memory:128}},network:{maxAzs:2,natGateways:!1,flowLogs:!1},backup:!1},lightweight:{displayName:"Lightweight",description:"Streamlined single-AZ deployment for cost efficiency",database:{Instance:{instanceType:"t4g.small",multiAz:!1},Aurora:{readers:!1},GlobalAurora:null,ClickHouse:null},compute:{ecs:{services:[{name:i,capacityProvider:"FARGATE_SPOT",cpu:256,memoryLimitMiB:512,desiredCount:1,minCapacity:1,maxCapacity:3}]},lambda:{timeout:30,memory:256}},network:{maxAzs:2,natGateways:{count:1},flowLogs:!1},backup:!1},standard:{displayName:"Standard",description:"Production-ready with sensible defaults",database:{Instance:{instanceType:"t4g.large"},Aurora:{readers:{count:1}},GlobalAurora:{readers:{count:1}},ClickHouse:{instanceType:"t4g.medium",coldTier:{mode:"s3"},optimiseSchedule:c,backupSchedule:u,backupRetentionDays:14}},compute:{ecs:{services:[{name:i,capacityProvider:"FARGATE",cpu:512,memoryLimitMiB:1024,desiredCount:2,minCapacity:2,maxCapacity:5}]},lambda:{timeout:60,memory:256}},network:{maxAzs:3,natGateways:{count:1},flowLogs:{},vpcEndpoints:{interface:{ecr:!0}}},backup:!1},resilient:{displayName:"Resilient",description:"High availability with enhanced monitoring and scaling",database:{Instance:{instanceType:"r7g.large",encryption:{storageKey:{useCMK:!0}},databaseInsights:{mode:"advanced",encryptionKey:{useCMK:!0}},proxy:{requireTLS:!0}},Aurora:{readers:{count:2},encryption:{storageKey:{useCMK:!0}},databaseInsights:{mode:"advanced",encryptionKey:{useCMK:!0}},proxy:{requireTLS:!0},backupRetention:30},GlobalAurora:{readers:{count:2},encryption:{storageKey:{useCMK:!0}},databaseInsights:{mode:"advanced",encryptionKey:{useCMK:!0}},proxy:{requireTLS:!0},backupRetention:30,enableGlobalWriteForwarding:!0},ClickHouse:{instanceType:"m6g.large",coldTier:{mode:"s3"},optimiseSchedule:c,backupSchedule:u,backupRetentionDays:14}},compute:{ecs:{services:[{name:i,capacityProvider:"FARGATE",cpu:1024,memoryLimitMiB:2048,desiredCount:4,minCapacity:4,maxCapacity:20}]},lambda:{timeout:120,memory:512}},network:{maxAzs:3,natGateways:{count:3},flowLogs:{retentionDays:90},vpcEndpoints:{interface:{ecr:!0,secretsManager:!0}}},backup:{tier:"resilient"}},enterprise:{displayName:"Enterprise",description:"Maximum capability with all features enabled",database:{Instance:{instanceType:"r7g.xlarge",encryption:{storageKey:{useCMK:!0}},databaseInsights:{mode:"advanced",encryptionKey:{useCMK:!0}},proxy:{requireTLS:!0},readReplica:{}},Aurora:{readers:{count:2},encryption:{storageKey:{useCMK:!0}},databaseInsights:{mode:"advanced",encryptionKey:{useCMK:!0}},proxy:{requireTLS:!0},backupRetention:35},GlobalAurora:{readers:{count:2},encryption:{storageKey:{useCMK:!0}},databaseInsights:{mode:"advanced",encryptionKey:{useCMK:!0}},proxy:{requireTLS:!0},backupRetention:35,enableGlobalWriteForwarding:!0},ClickHouse:{instanceType:"m6g.xlarge",coldTier:{mode:"s3"},optimiseSchedule:c,backupSchedule:u,backupRetentionDays:30}},compute:{ecs:{services:[{name:i,capacityProvider:"FARGATE",cpu:2048,memoryLimitMiB:4096,desiredCount:6,minCapacity:6,maxCapacity:100}]},lambda:{timeout:300,memory:1024}},network:{maxAzs:3,natGateways:{count:3},flowLogs:{destination:"s3",retentionDays:365},vpcEndpoints:{interface:{ecr:!0,secretsManager:!0,kms:!0,cloudwatchLogs:!0}}},backup:{tier:"enterprise"}}});function C(e,t){return r[e].database[t]}function f(e){return r[e].compute.ecs}function T(e){return r[e].network}function y(e){return d.filter(t=>r[t].database[e]!==null)}function A(e){return y(e).map(t=>({label:r[t].displayName,value:t,description:r[t].description}))}function x(e){switch(e){case"tinkerer":case"lightweight":case"standard":return"Instance";case"resilient":case"enterprise":return"Aurora"}}function k(e,t){const s=r[e].compute.ecs,a=s.services[0],m=!s.cluster?.directAccess&&s.cluster?.loadBalancer!==!1;return t.map((n,p)=>{const l=p===0;let o;return m&&(n.routing?o=n.routing:t.length>1&&(o={path:l?"/*":`/${n.name.toLowerCase()}/*`,...l?{}:{priority:100+p}})),{name:n.name,capacityProvider:a.capacityProvider,ec2Config:a.ec2Config,cpu:a.cpu,memoryLimitMiB:a.memoryLimitMiB,desiredCount:a.desiredCount,minCapacity:a.minCapacity,maxCapacity:a.maxCapacity,routing:o}})}export{M as APP_TYPES,L as CUSTOM_TIER,h as TIER_NAMES,r as TIER_PRESETS,k as applyTierDefaultsToServices,y as getAvailableTiersForDatabase,C as getDatabasePreset,x as getDefaultDatabaseTypeForTier,f as getEcsPreset,T as getNetworkPreset,A as getTierOptionsForDatabase};
1
+ import{TIER_NAMES as g}from"../schemas/sharedTypes.js";import{TIER_NAMES as S,CUSTOM_TIER as K,APP_TYPES as I}from"../schemas/sharedTypes.js";const n="service",c="0 4 * * ? *",u="0 5 * * ? *",i=Object.freeze({tinkerer:{displayName:"Tinkerer",description:"Free tier eligible, minimal cost for experimentation",database:{Instance:{instanceType:"t4g.micro",multiAz:!1,proxy:!1,readReplica:!1,publiclyAccessible:!0},Aurora:null,GlobalAurora:null,ClickHouse:null},compute:{ecs:{services:[{name:n,capacityProvider:"EC2",desiredCount:1,minCapacity:1,maxCapacity:1,ec2Config:{instanceType:"t4g.micro",amiHardwareType:"ARM",minCapacity:1,maxCapacity:1,memoryLimitMiB:400}}],cluster:{directAccess:!0}},lambda:{timeout:30,memory:128}},network:{maxAzs:2,natGateways:!1,flowLogs:!1},backup:!1},lightweight:{displayName:"Lightweight",description:"Streamlined single-AZ deployment for cost efficiency",database:{Instance:{instanceType:"t4g.small",multiAz:!1},Aurora:{readers:!1},GlobalAurora:null,ClickHouse:null},compute:{ecs:{services:[{name:n,capacityProvider:"FARGATE_SPOT",cpu:256,memoryLimitMiB:512,desiredCount:1,minCapacity:1,maxCapacity:3}]},lambda:{timeout:30,memory:256}},network:{maxAzs:2,natGateways:{count:1},flowLogs:!1},backup:!1},standard:{displayName:"Standard",description:"Production-ready with sensible defaults",database:{Instance:{instanceType:"t4g.large"},Aurora:{readers:{count:1}},GlobalAurora:{readers:{count:1}},ClickHouse:{instanceType:"t4g.medium",coldTier:{mode:"s3"},optimiseSchedule:c,backupSchedule:u,backupRetentionDays:14}},compute:{ecs:{services:[{name:n,capacityProvider:"FARGATE",cpu:512,memoryLimitMiB:1024,desiredCount:2,minCapacity:2,maxCapacity:5}]},lambda:{timeout:60,memory:256}},network:{maxAzs:3,natGateways:{count:1},flowLogs:{},vpcEndpoints:{interface:{ecr:!0}}},backup:!1},resilient:{displayName:"Resilient",description:"High availability with enhanced monitoring and scaling",database:{Instance:{instanceType:"r7g.large",encryption:{storageKey:{useCMK:!0}},databaseInsights:{mode:"advanced",encryptionKey:{useCMK:!0}},proxy:{requireTLS:!0}},Aurora:{readers:{count:2},encryption:{storageKey:{useCMK:!0}},databaseInsights:{mode:"advanced",encryptionKey:{useCMK:!0}},proxy:{requireTLS:!0},backupRetention:30},GlobalAurora:{readers:{count:2},encryption:{storageKey:{useCMK:!0}},databaseInsights:{mode:"advanced",encryptionKey:{useCMK:!0}},proxy:{requireTLS:!0},backupRetention:30,enableGlobalWriteForwarding:!0},ClickHouse:{instanceType:"m6g.large",coldTier:{mode:"s3"},optimiseSchedule:c,backupSchedule:u,backupRetentionDays:14}},compute:{ecs:{services:[{name:n,capacityProvider:"FARGATE",cpu:1024,memoryLimitMiB:2048,desiredCount:4,minCapacity:4,maxCapacity:20}]},lambda:{timeout:120,memory:512}},network:{maxAzs:3,natGateways:{count:3},flowLogs:{retentionDays:90},vpcEndpoints:{interface:{ecr:!0,secretsManager:!0}}},backup:{tier:"resilient"}},enterprise:{displayName:"Enterprise",description:"Maximum capability with all features enabled",database:{Instance:{instanceType:"r7g.xlarge",encryption:{storageKey:{useCMK:!0}},databaseInsights:{mode:"advanced",encryptionKey:{useCMK:!0}},proxy:{requireTLS:!0},readReplica:{}},Aurora:{readers:{count:2},encryption:{storageKey:{useCMK:!0}},databaseInsights:{mode:"advanced",encryptionKey:{useCMK:!0}},proxy:{requireTLS:!0},backupRetention:35},GlobalAurora:{readers:{count:2},encryption:{storageKey:{useCMK:!0}},databaseInsights:{mode:"advanced",encryptionKey:{useCMK:!0}},proxy:{requireTLS:!0},backupRetention:35,enableGlobalWriteForwarding:!0},ClickHouse:{instanceType:"m6g.xlarge",coldTier:{mode:"s3"},optimiseSchedule:c,backupSchedule:u,backupRetentionDays:30}},compute:{ecs:{services:[{name:n,capacityProvider:"FARGATE",cpu:2048,memoryLimitMiB:4096,desiredCount:6,minCapacity:6,maxCapacity:100}]},lambda:{timeout:300,memory:1024}},network:{maxAzs:3,natGateways:{count:3},flowLogs:{destination:"s3",retentionDays:365},vpcEndpoints:{interface:{ecr:!0,secretsManager:!0,kms:!0,cloudwatchLogs:!0}}},backup:{tier:"enterprise"}}});function k(e,t){return i[e].database[t]}function w(e){return i[e].compute.ecs}function x(e){return i[e].network}function C(e){return g.filter(t=>i[t].database[e]!==null)}function E(e){return C(e).map(t=>({label:i[t].displayName,value:t,description:i[t].description}))}function v(e){switch(e){case"tinkerer":case"lightweight":case"standard":return"Instance";case"resilient":case"enterprise":return"Aurora"}}function h(e,t){const s=i[e].compute.ecs,r=s.services[0],d=!s.cluster?.directAccess&&s.cluster?.loadBalancer!==!1,m=t.filter(a=>a.serviceType!=="worker").length,y=t.findIndex(a=>a.serviceType!=="worker");return t.map((a,p)=>{const l=p===y,b=a.serviceType==="worker";let o;return d&&!b&&(a.routing?o=a.routing:m>1&&(o={path:l?"/*":`/${a.name.toLowerCase()}/*`,...l?{}:{priority:100+p}})),{name:a.name,capacityProvider:r.capacityProvider,ec2Config:r.ec2Config,cpu:r.cpu,memoryLimitMiB:r.memoryLimitMiB,desiredCount:r.desiredCount,minCapacity:r.minCapacity,maxCapacity:r.maxCapacity,routing:o}})}export{I as APP_TYPES,K as CUSTOM_TIER,S as TIER_NAMES,i as TIER_PRESETS,h as applyTierDefaultsToServices,C as getAvailableTiersForDatabase,k as getDatabasePreset,v as getDefaultDatabaseTypeForTier,w as getEcsPreset,x as getNetworkPreset,E as getTierOptionsForDatabase};
@@ -287,6 +287,8 @@ export interface TierPreset {
287
287
  */
288
288
  export interface UserServiceConfig {
289
289
  name: string;
290
+ /** "worker" omits the inbound port + ALB route; "web" (default) keeps them. */
291
+ serviceType?: "web" | "worker";
290
292
  docker?: DockerBuildPartial;
291
293
  containerPort?: number;
292
294
  needsDatabaseConnection?: boolean;
@@ -516,7 +516,26 @@ export declare const ApplicationResourcePlanSchema: z.ZodObject<{
516
516
  path: z.ZodString;
517
517
  context: z.ZodOptional<z.ZodString>;
518
518
  target: z.ZodOptional<z.ZodString>;
519
- buildArgs: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
519
+ buildArgs: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
520
+ ssm: z.ZodOptional<z.ZodString>;
521
+ secretsManager: z.ZodOptional<z.ZodObject<{
522
+ name: z.ZodOptional<z.ZodString>;
523
+ arn: z.ZodOptional<z.ZodString>;
524
+ field: z.ZodOptional<z.ZodString>;
525
+ }, z.core.$strict>>;
526
+ env: z.ZodOptional<z.ZodString>;
527
+ acknowledgePublic: z.ZodOptional<z.ZodBoolean>;
528
+ }, z.core.$strict>]>>>;
529
+ buildSecrets: z.ZodOptional<z.ZodArray<z.ZodObject<{
530
+ id: z.ZodString;
531
+ ssm: z.ZodOptional<z.ZodString>;
532
+ secretsManager: z.ZodOptional<z.ZodObject<{
533
+ name: z.ZodOptional<z.ZodString>;
534
+ arn: z.ZodOptional<z.ZodString>;
535
+ field: z.ZodOptional<z.ZodString>;
536
+ }, z.core.$strict>>;
537
+ env: z.ZodOptional<z.ZodString>;
538
+ }, z.core.$strict>>>;
520
539
  }, z.core.$strict>>;
521
540
  needsDatabaseConnection: z.ZodOptional<z.ZodBoolean>;
522
541
  needsStorageConnection: z.ZodOptional<z.ZodBoolean>;
@@ -617,7 +636,26 @@ export declare const ApplicationResourcePlanSchema: z.ZodObject<{
617
636
  path: z.ZodOptional<z.ZodString>;
618
637
  context: z.ZodOptional<z.ZodOptional<z.ZodString>>;
619
638
  target: z.ZodOptional<z.ZodOptional<z.ZodString>>;
620
- buildArgs: z.ZodOptional<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>>;
639
+ buildArgs: z.ZodOptional<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
640
+ ssm: z.ZodOptional<z.ZodString>;
641
+ secretsManager: z.ZodOptional<z.ZodObject<{
642
+ name: z.ZodOptional<z.ZodString>;
643
+ arn: z.ZodOptional<z.ZodString>;
644
+ field: z.ZodOptional<z.ZodString>;
645
+ }, z.core.$strict>>;
646
+ env: z.ZodOptional<z.ZodString>;
647
+ acknowledgePublic: z.ZodOptional<z.ZodBoolean>;
648
+ }, z.core.$strict>]>>>>;
649
+ buildSecrets: z.ZodOptional<z.ZodOptional<z.ZodArray<z.ZodObject<{
650
+ id: z.ZodString;
651
+ ssm: z.ZodOptional<z.ZodString>;
652
+ secretsManager: z.ZodOptional<z.ZodObject<{
653
+ name: z.ZodOptional<z.ZodString>;
654
+ arn: z.ZodOptional<z.ZodString>;
655
+ field: z.ZodOptional<z.ZodString>;
656
+ }, z.core.$strict>>;
657
+ env: z.ZodOptional<z.ZodString>;
658
+ }, z.core.$strict>>>>;
621
659
  }, z.core.$strict>>;
622
660
  deployment: z.ZodOptional<z.ZodEnum<{
623
661
  code: "code";
@@ -909,11 +947,34 @@ export declare const ApplicationGeneratorSchema: z.ZodObject<{
909
947
  }, z.core.$strict>]>>;
910
948
  services: z.ZodOptional<z.ZodArray<z.ZodObject<{
911
949
  name: z.ZodString;
950
+ serviceType: z.ZodOptional<z.ZodEnum<{
951
+ web: "web";
952
+ worker: "worker";
953
+ }>>;
912
954
  docker: z.ZodOptional<z.ZodObject<{
913
955
  path: z.ZodOptional<z.ZodString>;
914
956
  context: z.ZodOptional<z.ZodOptional<z.ZodString>>;
915
957
  target: z.ZodOptional<z.ZodOptional<z.ZodString>>;
916
- buildArgs: z.ZodOptional<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>>;
958
+ buildArgs: z.ZodOptional<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
959
+ ssm: z.ZodOptional<z.ZodString>;
960
+ secretsManager: z.ZodOptional<z.ZodObject<{
961
+ name: z.ZodOptional<z.ZodString>;
962
+ arn: z.ZodOptional<z.ZodString>;
963
+ field: z.ZodOptional<z.ZodString>;
964
+ }, z.core.$strict>>;
965
+ env: z.ZodOptional<z.ZodString>;
966
+ acknowledgePublic: z.ZodOptional<z.ZodBoolean>;
967
+ }, z.core.$strict>]>>>>;
968
+ buildSecrets: z.ZodOptional<z.ZodOptional<z.ZodArray<z.ZodObject<{
969
+ id: z.ZodString;
970
+ ssm: z.ZodOptional<z.ZodString>;
971
+ secretsManager: z.ZodOptional<z.ZodObject<{
972
+ name: z.ZodOptional<z.ZodString>;
973
+ arn: z.ZodOptional<z.ZodString>;
974
+ field: z.ZodOptional<z.ZodString>;
975
+ }, z.core.$strict>>;
976
+ env: z.ZodOptional<z.ZodString>;
977
+ }, z.core.$strict>>>>;
917
978
  }, z.core.$strict>>;
918
979
  containerPort: z.ZodOptional<z.ZodNumber>;
919
980
  needsDatabaseConnection: z.ZodOptional<z.ZodBoolean>;
@@ -152,7 +152,26 @@ export declare const EcsServiceConfigSchema: z.ZodObject<{
152
152
  path: z.ZodString;
153
153
  context: z.ZodOptional<z.ZodString>;
154
154
  target: z.ZodOptional<z.ZodString>;
155
- buildArgs: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
155
+ buildArgs: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
156
+ ssm: z.ZodOptional<z.ZodString>;
157
+ secretsManager: z.ZodOptional<z.ZodObject<{
158
+ name: z.ZodOptional<z.ZodString>;
159
+ arn: z.ZodOptional<z.ZodString>;
160
+ field: z.ZodOptional<z.ZodString>;
161
+ }, z.core.$strict>>;
162
+ env: z.ZodOptional<z.ZodString>;
163
+ acknowledgePublic: z.ZodOptional<z.ZodBoolean>;
164
+ }, z.core.$strict>]>>>;
165
+ buildSecrets: z.ZodOptional<z.ZodArray<z.ZodObject<{
166
+ id: z.ZodString;
167
+ ssm: z.ZodOptional<z.ZodString>;
168
+ secretsManager: z.ZodOptional<z.ZodObject<{
169
+ name: z.ZodOptional<z.ZodString>;
170
+ arn: z.ZodOptional<z.ZodString>;
171
+ field: z.ZodOptional<z.ZodString>;
172
+ }, z.core.$strict>>;
173
+ env: z.ZodOptional<z.ZodString>;
174
+ }, z.core.$strict>>>;
156
175
  }, z.core.$strict>>;
157
176
  needsDatabaseConnection: z.ZodOptional<z.ZodBoolean>;
158
177
  needsStorageConnection: z.ZodOptional<z.ZodBoolean>;
@@ -282,7 +301,26 @@ export declare const ComputeResourcePlanSchema: z.ZodObject<{
282
301
  path: z.ZodString;
283
302
  context: z.ZodOptional<z.ZodString>;
284
303
  target: z.ZodOptional<z.ZodString>;
285
- buildArgs: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
304
+ buildArgs: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
305
+ ssm: z.ZodOptional<z.ZodString>;
306
+ secretsManager: z.ZodOptional<z.ZodObject<{
307
+ name: z.ZodOptional<z.ZodString>;
308
+ arn: z.ZodOptional<z.ZodString>;
309
+ field: z.ZodOptional<z.ZodString>;
310
+ }, z.core.$strict>>;
311
+ env: z.ZodOptional<z.ZodString>;
312
+ acknowledgePublic: z.ZodOptional<z.ZodBoolean>;
313
+ }, z.core.$strict>]>>>;
314
+ buildSecrets: z.ZodOptional<z.ZodArray<z.ZodObject<{
315
+ id: z.ZodString;
316
+ ssm: z.ZodOptional<z.ZodString>;
317
+ secretsManager: z.ZodOptional<z.ZodObject<{
318
+ name: z.ZodOptional<z.ZodString>;
319
+ arn: z.ZodOptional<z.ZodString>;
320
+ field: z.ZodOptional<z.ZodString>;
321
+ }, z.core.$strict>>;
322
+ env: z.ZodOptional<z.ZodString>;
323
+ }, z.core.$strict>>>;
286
324
  }, z.core.$strict>>;
287
325
  needsDatabaseConnection: z.ZodOptional<z.ZodBoolean>;
288
326
  needsStorageConnection: z.ZodOptional<z.ZodBoolean>;
@@ -383,7 +421,26 @@ export declare const ComputeResourcePlanSchema: z.ZodObject<{
383
421
  path: z.ZodOptional<z.ZodString>;
384
422
  context: z.ZodOptional<z.ZodOptional<z.ZodString>>;
385
423
  target: z.ZodOptional<z.ZodOptional<z.ZodString>>;
386
- buildArgs: z.ZodOptional<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>>;
424
+ buildArgs: z.ZodOptional<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
425
+ ssm: z.ZodOptional<z.ZodString>;
426
+ secretsManager: z.ZodOptional<z.ZodObject<{
427
+ name: z.ZodOptional<z.ZodString>;
428
+ arn: z.ZodOptional<z.ZodString>;
429
+ field: z.ZodOptional<z.ZodString>;
430
+ }, z.core.$strict>>;
431
+ env: z.ZodOptional<z.ZodString>;
432
+ acknowledgePublic: z.ZodOptional<z.ZodBoolean>;
433
+ }, z.core.$strict>]>>>>;
434
+ buildSecrets: z.ZodOptional<z.ZodOptional<z.ZodArray<z.ZodObject<{
435
+ id: z.ZodString;
436
+ ssm: z.ZodOptional<z.ZodString>;
437
+ secretsManager: z.ZodOptional<z.ZodObject<{
438
+ name: z.ZodOptional<z.ZodString>;
439
+ arn: z.ZodOptional<z.ZodString>;
440
+ field: z.ZodOptional<z.ZodString>;
441
+ }, z.core.$strict>>;
442
+ env: z.ZodOptional<z.ZodString>;
443
+ }, z.core.$strict>>>>;
387
444
  }, z.core.$strict>>;
388
445
  deployment: z.ZodOptional<z.ZodEnum<{
389
446
  code: "code";
@@ -586,7 +643,26 @@ export declare const AddServiceGeneratorSchema: z.ZodObject<{
586
643
  path: z.ZodOptional<z.ZodString>;
587
644
  context: z.ZodOptional<z.ZodOptional<z.ZodString>>;
588
645
  target: z.ZodOptional<z.ZodOptional<z.ZodString>>;
589
- buildArgs: z.ZodOptional<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>>;
646
+ buildArgs: z.ZodOptional<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
647
+ ssm: z.ZodOptional<z.ZodString>;
648
+ secretsManager: z.ZodOptional<z.ZodObject<{
649
+ name: z.ZodOptional<z.ZodString>;
650
+ arn: z.ZodOptional<z.ZodString>;
651
+ field: z.ZodOptional<z.ZodString>;
652
+ }, z.core.$strict>>;
653
+ env: z.ZodOptional<z.ZodString>;
654
+ acknowledgePublic: z.ZodOptional<z.ZodBoolean>;
655
+ }, z.core.$strict>]>>>>;
656
+ buildSecrets: z.ZodOptional<z.ZodOptional<z.ZodArray<z.ZodObject<{
657
+ id: z.ZodString;
658
+ ssm: z.ZodOptional<z.ZodString>;
659
+ secretsManager: z.ZodOptional<z.ZodObject<{
660
+ name: z.ZodOptional<z.ZodString>;
661
+ arn: z.ZodOptional<z.ZodString>;
662
+ field: z.ZodOptional<z.ZodString>;
663
+ }, z.core.$strict>>;
664
+ env: z.ZodOptional<z.ZodString>;
665
+ }, z.core.$strict>>>>;
590
666
  }, z.core.$strict>>;
591
667
  nameProvidedByFlag: z.ZodOptional<z.ZodBoolean>;
592
668
  connectionConfig: z.ZodOptional<z.ZodObject<{
@@ -624,7 +700,26 @@ export declare const ComputeGeneratorSchema: z.ZodDiscriminatedUnion<[z.ZodObjec
624
700
  path: z.ZodString;
625
701
  context: z.ZodOptional<z.ZodString>;
626
702
  target: z.ZodOptional<z.ZodString>;
627
- buildArgs: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
703
+ buildArgs: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
704
+ ssm: z.ZodOptional<z.ZodString>;
705
+ secretsManager: z.ZodOptional<z.ZodObject<{
706
+ name: z.ZodOptional<z.ZodString>;
707
+ arn: z.ZodOptional<z.ZodString>;
708
+ field: z.ZodOptional<z.ZodString>;
709
+ }, z.core.$strict>>;
710
+ env: z.ZodOptional<z.ZodString>;
711
+ acknowledgePublic: z.ZodOptional<z.ZodBoolean>;
712
+ }, z.core.$strict>]>>>;
713
+ buildSecrets: z.ZodOptional<z.ZodArray<z.ZodObject<{
714
+ id: z.ZodString;
715
+ ssm: z.ZodOptional<z.ZodString>;
716
+ secretsManager: z.ZodOptional<z.ZodObject<{
717
+ name: z.ZodOptional<z.ZodString>;
718
+ arn: z.ZodOptional<z.ZodString>;
719
+ field: z.ZodOptional<z.ZodString>;
720
+ }, z.core.$strict>>;
721
+ env: z.ZodOptional<z.ZodString>;
722
+ }, z.core.$strict>>>;
628
723
  }, z.core.$strict>>;
629
724
  needsDatabaseConnection: z.ZodOptional<z.ZodBoolean>;
630
725
  needsStorageConnection: z.ZodOptional<z.ZodBoolean>;
@@ -725,7 +820,26 @@ export declare const ComputeGeneratorSchema: z.ZodDiscriminatedUnion<[z.ZodObjec
725
820
  path: z.ZodOptional<z.ZodString>;
726
821
  context: z.ZodOptional<z.ZodOptional<z.ZodString>>;
727
822
  target: z.ZodOptional<z.ZodOptional<z.ZodString>>;
728
- buildArgs: z.ZodOptional<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>>;
823
+ buildArgs: z.ZodOptional<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
824
+ ssm: z.ZodOptional<z.ZodString>;
825
+ secretsManager: z.ZodOptional<z.ZodObject<{
826
+ name: z.ZodOptional<z.ZodString>;
827
+ arn: z.ZodOptional<z.ZodString>;
828
+ field: z.ZodOptional<z.ZodString>;
829
+ }, z.core.$strict>>;
830
+ env: z.ZodOptional<z.ZodString>;
831
+ acknowledgePublic: z.ZodOptional<z.ZodBoolean>;
832
+ }, z.core.$strict>]>>>>;
833
+ buildSecrets: z.ZodOptional<z.ZodOptional<z.ZodArray<z.ZodObject<{
834
+ id: z.ZodString;
835
+ ssm: z.ZodOptional<z.ZodString>;
836
+ secretsManager: z.ZodOptional<z.ZodObject<{
837
+ name: z.ZodOptional<z.ZodString>;
838
+ arn: z.ZodOptional<z.ZodString>;
839
+ field: z.ZodOptional<z.ZodString>;
840
+ }, z.core.$strict>>;
841
+ env: z.ZodOptional<z.ZodString>;
842
+ }, z.core.$strict>>>>;
729
843
  }, z.core.$strict>>;
730
844
  }, z.core.$strict>, z.ZodObject<{
731
845
  appName: z.ZodString;
@@ -803,11 +917,34 @@ export declare const ApplicationServiceRoutingSchema: z.ZodObject<{
803
917
  */
804
918
  export declare const ApplicationServiceConfigSchema: z.ZodObject<{
805
919
  name: z.ZodString;
920
+ serviceType: z.ZodOptional<z.ZodEnum<{
921
+ web: "web";
922
+ worker: "worker";
923
+ }>>;
806
924
  docker: z.ZodOptional<z.ZodObject<{
807
925
  path: z.ZodOptional<z.ZodString>;
808
926
  context: z.ZodOptional<z.ZodOptional<z.ZodString>>;
809
927
  target: z.ZodOptional<z.ZodOptional<z.ZodString>>;
810
- buildArgs: z.ZodOptional<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>>;
928
+ buildArgs: z.ZodOptional<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
929
+ ssm: z.ZodOptional<z.ZodString>;
930
+ secretsManager: z.ZodOptional<z.ZodObject<{
931
+ name: z.ZodOptional<z.ZodString>;
932
+ arn: z.ZodOptional<z.ZodString>;
933
+ field: z.ZodOptional<z.ZodString>;
934
+ }, z.core.$strict>>;
935
+ env: z.ZodOptional<z.ZodString>;
936
+ acknowledgePublic: z.ZodOptional<z.ZodBoolean>;
937
+ }, z.core.$strict>]>>>>;
938
+ buildSecrets: z.ZodOptional<z.ZodOptional<z.ZodArray<z.ZodObject<{
939
+ id: z.ZodString;
940
+ ssm: z.ZodOptional<z.ZodString>;
941
+ secretsManager: z.ZodOptional<z.ZodObject<{
942
+ name: z.ZodOptional<z.ZodString>;
943
+ arn: z.ZodOptional<z.ZodString>;
944
+ field: z.ZodOptional<z.ZodString>;
945
+ }, z.core.$strict>>;
946
+ env: z.ZodOptional<z.ZodString>;
947
+ }, z.core.$strict>>>>;
811
948
  }, z.core.$strict>>;
812
949
  containerPort: z.ZodOptional<z.ZodNumber>;
813
950
  needsDatabaseConnection: z.ZodOptional<z.ZodBoolean>;
@@ -1 +1 @@
1
- import{z as e}from"zod";import{VALIDATION_PATTERNS as m,VALIDATION_MESSAGES as o}from"../validation/patterns.js";import{COMPUTE_TYPES as h,ECS_CAPACITY_PROVIDERS as f,EC2_INSTANCE_TYPES as j,HTTP_METHODS as k,MIN_LAMBDA_MEMORY as W,MAX_LAMBDA_MEMORY as w,MIN_LAMBDA_TIMEOUT as S,MAX_LAMBDA_TIMEOUT as g,MIN_ECS_CAPACITY as x,MAX_ECS_CAPACITY as O,MAX_SCALING_CAPACITY as p,MAX_WARM_POOL_SIZE as V,constIncludes as K,COMPUTE_ARCHITECTURES as F,FUNCTION_URL_AUTH_TYPES as L,DEPLOYMENT_TYPES as Z,AMI_HARDWARE_TYPES as z,LOAD_BALANCER_TYPES as Q,SCALING_TYPES as $}from"./constants.js";import{validateArchitectureMatch as q,getArchitectureForInstanceType as J}from"./instanceTypeArchitecture.js";import{optionalOrDisabled as ee,CAPACITY_REFINEMENT as r,memoryLimitMiBSchema as I,ResourceNameSchema as c,AppNameSchema as s,PortSchema as T,ExtraPropertySchema as l,EnvironmentRecordSchema as E,SecretsImportRecordSchema as oe}from"./baseSchemas.js";import{DockerBuildSchema as A}from"@fjall/util/manifest/schemas";import{EcsServiceAlarmConfigSchema as ne,LambdaAlarmConfigSchema as te}from"./alarmSchemas.js";function ie(n){return!(n.image!==void 0&&n.docker!==void 0)}const H=e.number().int(o.CAPACITY.MIN.INTEGER).min(x,o.GENERATOR_CAPACITY.MIN.MIN).max(O,o.GENERATOR_CAPACITY.MIN.MAX),D=e.number().int(o.CAPACITY.MAX.INTEGER).min(x,o.GENERATOR_CAPACITY.MAX.MIN).max(O,o.GENERATOR_CAPACITY.MAX.MAX),N=e.number().int(o.LAMBDA.MEMORY.INTEGER).min(W,o.LAMBDA.MEMORY.MIN).max(w,o.LAMBDA.MEMORY.MAX).refine(n=>n===128||n%64===0,o.LAMBDA.MEMORY.MULTIPLE),G=e.string().regex(m.LAMBDA_RUNTIME_IDENTIFIER,o.LAMBDA.RUNTIME),d=e.number().int(o.CPU.INTEGER).min(256,o.CPU.MIN).max(4096,o.CPU.MAX),M=e.number().int(o.CAPACITY.DESIRED.INTEGER).min(0,o.CAPACITY.DESIRED.MIN).max(p,o.CAPACITY.DESIRED.MAX),C=e.object({connectToDatabase:e.array(e.string()).optional()}).strict(),ae=e.object({minSize:e.number().int(o.CAPACITY.WARM_POOL.MIN_SIZE.INTEGER).min(0,o.CAPACITY.WARM_POOL.MIN_SIZE.MIN).max(V,o.CAPACITY.WARM_POOL.MIN_SIZE.MAX).optional(),reuseOnScaleIn:e.boolean().optional()}).strict(),_=e.object({instanceType:e.string().optional(),amiHardwareType:e.enum(z).optional(),minCapacity:e.number().int(o.CAPACITY.MIN.INTEGER).min(0,o.CAPACITY.MIN.MIN_0).max(p,o.CAPACITY.MIN.MAX).optional(),maxCapacity:e.number().int(o.CAPACITY.MAX.INTEGER).min(1,o.CAPACITY.MAX.MIN_1).max(p,o.CAPACITY.MAX.MAX).optional(),memoryLimitMiB:I(128).optional(),warmPool:ae.optional(),extraProperties:e.array(l).optional()}).strict().superRefine((n,i)=>{if(!n.instanceType||!n.amiHardwareType)return;const t=q(n.instanceType,n.amiHardwareType);t.valid||i.addIssue({code:"custom",message:t.message??o.ARCHITECTURE_MISMATCH,path:["instanceType"]})}).superRefine((n,i)=>{n.minCapacity===0&&!n.warmPool&&i.addIssue({code:"custom",message:o.CAPACITY.WARM_POOL_REQUIRED,path:["minCapacity"]}),n.warmPool?.minSize!==void 0&&n.maxCapacity!==void 0&&n.warmPool.minSize>n.maxCapacity&&i.addIssue({code:"custom",message:o.CAPACITY.WARM_POOL.MIN_SIZE_EXCEEDS_MAX_CAPACITY,path:["warmPool","minSize"]})}),re=e.enum(h).describe(`Compute type must be one of: ${h.join(", ")}`),y=e.enum(f).describe(`ECS capacity provider must be one of: ${f.join(", ")}`),b=e.string().refine(n=>K(j,n),{message:o.INSTANCE_TYPE}),Y=e.object({sourceType:e.enum(["sqs","dynamodb","eventbridge"]),sourceRef:e.string().describe("Name of the source resource"),batchSize:e.number().int(o.BATCH_SIZE.INTEGER).min(1,o.BATCH_SIZE.MIN).max(1e4,o.BATCH_SIZE.MAX).optional(),startingPosition:e.enum(["TRIM_HORIZON","LATEST"]).optional(),maxBatchingWindow:e.number().int(o.BATCHING_WINDOW.INTEGER).min(0,o.BATCHING_WINDOW.MIN).max(300,o.BATCHING_WINDOW.MAX).optional(),reportBatchItemFailures:e.boolean().optional()}).strict(),ce=e.object({name:e.string().min(1,o.REQUIRED.CONTAINER_NAME).optional(),image:e.string().optional(),port:T.optional(),environment:E.optional(),secretsImport:oe.optional(),command:e.array(e.string()).optional(),entryPoint:e.array(e.string()).optional(),essential:e.boolean().optional(),healthCheck:e.object({command:e.array(e.string()),interval:e.number().int(o.HEALTH_CHECK.INTERVAL.INTEGER).min(5,o.HEALTH_CHECK.INTERVAL.MIN).max(300,o.HEALTH_CHECK.INTERVAL.MAX).optional(),timeout:e.number().int(o.HEALTH_CHECK.TIMEOUT.INTEGER).min(2,o.HEALTH_CHECK.TIMEOUT.MIN).max(60,o.HEALTH_CHECK.TIMEOUT.MAX).optional(),retries:e.number().int(o.HEALTH_CHECK.RETRIES.INTEGER).min(1,o.HEALTH_CHECK.RETRIES.MIN).max(10,o.HEALTH_CHECK.RETRIES.MAX).optional(),startPeriod:e.number().int(o.HEALTH_CHECK.START_PERIOD.INTEGER).min(0,o.HEALTH_CHECK.START_PERIOD.MIN).max(300,o.HEALTH_CHECK.START_PERIOD.MAX).optional()}).strict().optional(),ssmSecrets:e.array(e.string().regex(m.SECRET_NAME,o.SECRET_NAME)).optional(),extraProperties:e.array(l).optional()}).strict(),U=e.string().min(1,o.REQUIRED.SERVICE_NAME).max(255,o.MAX_LENGTH.SERVICE_NAME).regex(m.ECS_SERVICE_NAME,o.ECS_SERVICE_NAME),v=e.object({domain:e.string().optional(),loadBalancer:e.union([e.literal(!1),e.enum(Q)]).optional(),directAccess:e.boolean().optional(),extraProperties:e.array(l).optional()}).strict().refine(n=>!(n.directAccess&&n.domain),{message:o.DIRECT_ACCESS.NO_DOMAIN,path:["directAccess"]}).refine(n=>!(n.directAccess&&typeof n.loadBalancer=="string"),{message:o.DIRECT_ACCESS.NO_LOAD_BALANCER}).describe("Cluster-level configuration"),u=e.object({path:e.string().optional(),host:e.string().optional(),priority:e.number().int(o.PRIORITY.INTEGER).min(1,o.PRIORITY.MIN).max(5e4,o.PRIORITY.MAX).optional(),healthCheckPath:e.string().optional()}).strict().describe("Path/host-based routing configuration"),se=e.object({desiredCount:M.optional(),minCapacity:e.number().int(o.CAPACITY.MIN.INTEGER).min(0,o.CAPACITY.MIN.MIN_0).max(p,o.CAPACITY.MIN.MAX).optional(),maxCapacity:e.number().int(o.CAPACITY.MAX.INTEGER).min(1,o.CAPACITY.MAX.MIN_1).max(p,o.CAPACITY.MAX.MAX).optional(),scalingType:e.enum($).optional()}).strict().refine(r.check,r.params).describe("ECS service scaling configuration"),B=e.object({name:U,docker:A.optional(),needsDatabaseConnection:e.boolean().optional(),needsStorageConnection:e.boolean().optional(),needsMessagingConnection:e.boolean().optional(),image:e.string().optional(),containers:e.array(ce).optional(),routing:e.union([u,e.array(u).min(1)]).optional(),cpu:d.optional(),memoryLimitMiB:I(512).optional(),desiredCount:M.optional(),scaling:ee(se).optional(),capacityProvider:y,ec2Config:_.optional(),ssmSecretsPath:e.string().regex(m.SSM_PATH,o.SSM_PATH).optional(),extraProperties:e.array(l).optional(),alarms:ne.optional()}).strict().superRefine((n,i)=>{ie(n)||i.addIssue({code:"custom",path:["docker"],message:o.IMAGE_DOCKER_MUTEX})}).describe("Configuration for a service in an ECS cluster"),Re=e.object({name:c,type:re,needsConnection:e.boolean(),connectedDatabase:e.array(e.string()).optional(),connectedStorage:e.array(e.string()).optional(),connectedMessaging:e.array(e.string()).optional(),cluster:v.optional(),services:e.array(B).optional(),docker:A.partial().optional(),deployment:e.enum(Z).optional(),codePath:e.string().optional(),timeout:e.number().int(o.LAMBDA.TIMEOUT.INTEGER).min(S,o.LAMBDA.TIMEOUT.MIN).max(g,o.LAMBDA.TIMEOUT.MAX).optional(),memory:N.optional(),handler:e.string().optional(),runtime:G.optional(),environment:E.optional(),secrets:E.optional(),eventSources:e.array(Y).optional(),functionUrl:e.object({authType:e.enum(L)}).strict().optional(),description:e.string().optional(),scheduleExpression:e.string().optional(),architecture:e.enum(F).optional(),ephemeralStorageSize:e.number().int(o.EPHEMERAL_STORAGE.INTEGER).min(512,o.EPHEMERAL_STORAGE.MIN).max(10240,o.EPHEMERAL_STORAGE.MAX).optional(),functionName:e.string().optional(),ssmSecrets:e.array(e.string()).optional(),ssmSecretsPath:e.string().optional(),alarms:te.optional(),instanceType:b.optional(),enableSSH:e.boolean().optional(),keyName:e.string().optional(),userData:e.string().optional(),securityGroups:e.array(e.string()).optional(),variableName:e.string().optional(),extraProperties:e.array(l).optional()}).strict().superRefine((n,i)=>{if(n.type==="ecs"&&n.services)for(let t=0;t<n.services.length;t++){const a=n.services[t];a?.ec2Config?.instanceType&&!a.ec2Config.amiHardwareType&&J(a.ec2Config.instanceType)!=="ARM"&&i.addIssue({code:"custom",message:`Service '${a.name??t}' uses instance type '${a.ec2Config.instanceType}' (x86), which requires Docker images built for linux/amd64. The default build targets linux/arm64 (Graviton). Use a Graviton instance type (t4g, c6g, r6g, m6g, etc.) or set amiHardwareType: "STANDARD" to acknowledge x86.`,path:["services",t,"ec2Config","instanceType"]})}n.type==="lambda"&&n.deployment==="container"&&n.architecture==="X86_64"&&i.addIssue({code:"custom",message:"Lambda architecture 'X86_64' requires Docker images built for linux/amd64, but the default build targets linux/arm64. Use 'ARM_64' for Graviton Lambdas (recommended) or ensure your build pipeline targets linux/amd64.",path:["architecture"]})}),Se=e.object({appName:s,clusterName:c,containerPort:T,nameProvidedByFlag:e.boolean().optional(),ecrRepository:e.string().optional(),capacityProvider:y.optional(),useAppEcr:e.boolean().optional(),desiredCount:M.optional(),cpu:d.optional(),memoryLimitMiB:I(512).optional(),minCapacity:H.optional(),maxCapacity:D.optional(),ec2Config:_.optional(),connectionConfig:C.optional()}).strict().refine(r.check,r.params),ge=e.object({appName:s,functionName:c,nameProvidedByFlag:e.boolean().optional(),lambdaType:e.enum(["basic","web","custom"]).optional(),ecrRepository:e.string().optional(),timeout:e.number().int(o.LAMBDA.TIMEOUT.INTEGER).min(S,o.LAMBDA.TIMEOUT.MIN).max(g,o.LAMBDA.TIMEOUT.MAX).optional(),memory:N.optional(),enableFunctionUrl:e.boolean().optional(),description:e.string().optional(),enableCors:e.boolean().optional(),corsOrigins:e.string().optional(),corsHeaders:e.string().optional(),corsMethods:e.array(e.enum(k)).optional(),corsCredentials:e.boolean().optional(),connectionConfig:C.optional()}).strict(),Ne=e.object({appName:s,instanceName:c,nameProvidedByFlag:e.boolean().optional(),instanceType:b.optional(),enableSSH:e.boolean().optional(),minCapacity:H.optional(),maxCapacity:D.optional(),connectionConfig:C.optional()}).strict().refine(r.check,r.params),de=e.object({appName:s,clusterName:c,serviceName:U,capacityProvider:y,containerPort:T.optional(),cpu:d.optional(),memoryLimitMiB:I(512).optional(),desiredCount:M.optional(),ec2Config:_.optional(),routing:e.union([u,e.array(u).min(1)]).optional(),docker:A.partial().optional(),nameProvidedByFlag:e.boolean().optional(),connectionConfig:C.optional()}).strict(),P=e.object({appName:s,computeName:c,nameProvidedByFlag:e.boolean().optional(),connectionConfig:C.optional()}).strict(),me=P.extend({type:e.literal("ecs"),cluster:v.optional(),services:e.array(B).min(1,o.SERVICE.MIN_REQUIRED),docker:A.partial().optional()}).strict().refine(n=>{const i=n.services.filter(t=>t.containers?.some(a=>a.port));return i.length>1?i.every(t=>(Array.isArray(t.routing)?t.routing:t.routing?[t.routing]:[]).some(R=>R.path||R.host)):!0},{message:o.SERVICE.ROUTING_REQUIRED}).refine(n=>{const i=n.services.map(t=>t.name);return new Set(i).size===i.length},{message:o.SERVICE.UNIQUE_WITHIN_CLUSTER}),pe=P.extend({type:e.literal("lambda"),timeout:e.number().int(o.LAMBDA.TIMEOUT.INTEGER).min(S,o.LAMBDA.TIMEOUT.MIN).max(g,o.LAMBDA.TIMEOUT.MAX).optional(),memory:N.optional(),handler:e.string().optional(),runtime:G.optional(),environment:E.optional(),secrets:E.optional(),description:e.string().optional(),functionUrl:e.union([e.object({authType:e.enum(L).optional()}).strict(),e.literal(!1)]).optional(),eventSources:e.array(Y).optional()}).strict(),le=P.extend({type:e.literal("ec2"),instanceType:b.optional(),enableSSH:e.boolean().optional(),keyName:e.string().optional(),userData:e.string().optional(),securityGroups:e.array(e.string()).optional()}).strict(),_e=e.discriminatedUnion("type",[me,pe,le]),X=e.object({path:e.string().min(1,o.REQUIRED.ROUTING_PATH),priority:e.number().int(o.PRIORITY.INTEGER).min(1,o.PRIORITY.MIN).max(5e4,o.PRIORITY.MAX).optional()}).strict(),ye=e.object({name:e.string().min(1,o.REQUIRED.SERVICE_NAME).max(255,o.MAX_LENGTH.SERVICE_NAME).regex(m.RESOURCE_NAME,o.RESOURCE_NAME),docker:A.partial().optional(),containerPort:T.optional(),needsDatabaseConnection:e.boolean().optional(),routing:e.union([X,e.array(X).min(1)]).optional()}).strict(),be=e.object({appName:s,instanceType:e.string().optional()}).strict();export{de as AddServiceGeneratorSchema,ye as ApplicationServiceConfigSchema,X as ApplicationServiceRoutingSchema,_e as ComputeGeneratorSchema,Re as ComputeResourcePlanSchema,re as ComputeTypeSchema,ce as ContainerConfigSchema,Ne as EC2GeneratorSchema,Se as ECSGeneratorSchema,_ as Ec2ConfigSchema,y as EcsCapacityProviderSchema,v as EcsClusterConfigSchema,u as EcsRoutingConfigSchema,se as EcsScalingConfigSchema,B as EcsServiceConfigSchema,U as EcsServiceNameSchema,b as InstanceTypeSchema,Y as LambdaEventSourceSchema,ge as LambdaGeneratorSchema,N as LambdaMemorySchema,G as LambdaRuntimeSchema,be as TunnelGeneratorSchema,ae as WarmPoolSchema};
1
+ import{z as e}from"zod";import{VALIDATION_PATTERNS as m,VALIDATION_MESSAGES as o}from"../validation/patterns.js";import{COMPUTE_TYPES as h,ECS_CAPACITY_PROVIDERS as f,EC2_INSTANCE_TYPES as k,HTTP_METHODS as j,MIN_LAMBDA_MEMORY as W,MAX_LAMBDA_MEMORY as w,MIN_LAMBDA_TIMEOUT as S,MAX_LAMBDA_TIMEOUT as g,MIN_ECS_CAPACITY as x,MAX_ECS_CAPACITY as O,MAX_SCALING_CAPACITY as p,MAX_WARM_POOL_SIZE as V,constIncludes as K,COMPUTE_ARCHITECTURES as F,FUNCTION_URL_AUTH_TYPES as L,DEPLOYMENT_TYPES as Z,AMI_HARDWARE_TYPES as z,LOAD_BALANCER_TYPES as Q,SCALING_TYPES as $}from"./constants.js";import{validateArchitectureMatch as q,getArchitectureForInstanceType as J}from"./instanceTypeArchitecture.js";import{optionalOrDisabled as ee,CAPACITY_REFINEMENT as r,memoryLimitMiBSchema as I,ResourceNameSchema as c,AppNameSchema as s,PortSchema as T,ExtraPropertySchema as l,EnvironmentRecordSchema as E,SecretsImportRecordSchema as oe}from"./baseSchemas.js";import{DockerBuildSchema as A}from"@fjall/util/manifest/schemas";import{EcsServiceAlarmConfigSchema as ne,LambdaAlarmConfigSchema as te}from"./alarmSchemas.js";function ie(n){return!(n.image!==void 0&&n.docker!==void 0)}const H=e.number().int(o.CAPACITY.MIN.INTEGER).min(x,o.GENERATOR_CAPACITY.MIN.MIN).max(O,o.GENERATOR_CAPACITY.MIN.MAX),D=e.number().int(o.CAPACITY.MAX.INTEGER).min(x,o.GENERATOR_CAPACITY.MAX.MIN).max(O,o.GENERATOR_CAPACITY.MAX.MAX),N=e.number().int(o.LAMBDA.MEMORY.INTEGER).min(W,o.LAMBDA.MEMORY.MIN).max(w,o.LAMBDA.MEMORY.MAX).refine(n=>n===128||n%64===0,o.LAMBDA.MEMORY.MULTIPLE),G=e.string().regex(m.LAMBDA_RUNTIME_IDENTIFIER,o.LAMBDA.RUNTIME),d=e.number().int(o.CPU.INTEGER).min(256,o.CPU.MIN).max(4096,o.CPU.MAX),u=e.number().int(o.CAPACITY.DESIRED.INTEGER).min(0,o.CAPACITY.DESIRED.MIN).max(p,o.CAPACITY.DESIRED.MAX),C=e.object({connectToDatabase:e.array(e.string()).optional()}).strict(),ae=e.object({minSize:e.number().int(o.CAPACITY.WARM_POOL.MIN_SIZE.INTEGER).min(0,o.CAPACITY.WARM_POOL.MIN_SIZE.MIN).max(V,o.CAPACITY.WARM_POOL.MIN_SIZE.MAX).optional(),reuseOnScaleIn:e.boolean().optional()}).strict(),_=e.object({instanceType:e.string().optional(),amiHardwareType:e.enum(z).optional(),minCapacity:e.number().int(o.CAPACITY.MIN.INTEGER).min(0,o.CAPACITY.MIN.MIN_0).max(p,o.CAPACITY.MIN.MAX).optional(),maxCapacity:e.number().int(o.CAPACITY.MAX.INTEGER).min(1,o.CAPACITY.MAX.MIN_1).max(p,o.CAPACITY.MAX.MAX).optional(),memoryLimitMiB:I(128).optional(),warmPool:ae.optional(),extraProperties:e.array(l).optional()}).strict().superRefine((n,t)=>{if(!n.instanceType||!n.amiHardwareType)return;const i=q(n.instanceType,n.amiHardwareType);i.valid||t.addIssue({code:"custom",message:i.message??o.ARCHITECTURE_MISMATCH,path:["instanceType"]})}).superRefine((n,t)=>{n.minCapacity===0&&!n.warmPool&&t.addIssue({code:"custom",message:o.CAPACITY.WARM_POOL_REQUIRED,path:["minCapacity"]}),n.warmPool?.minSize!==void 0&&n.maxCapacity!==void 0&&n.warmPool.minSize>n.maxCapacity&&t.addIssue({code:"custom",message:o.CAPACITY.WARM_POOL.MIN_SIZE_EXCEEDS_MAX_CAPACITY,path:["warmPool","minSize"]})}),re=e.enum(h).describe(`Compute type must be one of: ${h.join(", ")}`),y=e.enum(f).describe(`ECS capacity provider must be one of: ${f.join(", ")}`),b=e.string().refine(n=>K(k,n),{message:o.INSTANCE_TYPE}),Y=e.object({sourceType:e.enum(["sqs","dynamodb","eventbridge"]),sourceRef:e.string().describe("Name of the source resource"),batchSize:e.number().int(o.BATCH_SIZE.INTEGER).min(1,o.BATCH_SIZE.MIN).max(1e4,o.BATCH_SIZE.MAX).optional(),startingPosition:e.enum(["TRIM_HORIZON","LATEST"]).optional(),maxBatchingWindow:e.number().int(o.BATCHING_WINDOW.INTEGER).min(0,o.BATCHING_WINDOW.MIN).max(300,o.BATCHING_WINDOW.MAX).optional(),reportBatchItemFailures:e.boolean().optional()}).strict(),ce=e.object({name:e.string().min(1,o.REQUIRED.CONTAINER_NAME).optional(),image:e.string().optional(),port:T.optional(),environment:E.optional(),secretsImport:oe.optional(),command:e.array(e.string()).optional(),entryPoint:e.array(e.string()).optional(),essential:e.boolean().optional(),healthCheck:e.object({command:e.array(e.string()),interval:e.number().int(o.HEALTH_CHECK.INTERVAL.INTEGER).min(5,o.HEALTH_CHECK.INTERVAL.MIN).max(300,o.HEALTH_CHECK.INTERVAL.MAX).optional(),timeout:e.number().int(o.HEALTH_CHECK.TIMEOUT.INTEGER).min(2,o.HEALTH_CHECK.TIMEOUT.MIN).max(60,o.HEALTH_CHECK.TIMEOUT.MAX).optional(),retries:e.number().int(o.HEALTH_CHECK.RETRIES.INTEGER).min(1,o.HEALTH_CHECK.RETRIES.MIN).max(10,o.HEALTH_CHECK.RETRIES.MAX).optional(),startPeriod:e.number().int(o.HEALTH_CHECK.START_PERIOD.INTEGER).min(0,o.HEALTH_CHECK.START_PERIOD.MIN).max(300,o.HEALTH_CHECK.START_PERIOD.MAX).optional()}).strict().optional(),ssmSecrets:e.array(e.string().regex(m.SECRET_NAME,o.SECRET_NAME)).optional(),extraProperties:e.array(l).optional()}).strict(),v=e.string().min(1,o.REQUIRED.SERVICE_NAME).max(255,o.MAX_LENGTH.SERVICE_NAME).regex(m.ECS_SERVICE_NAME,o.ECS_SERVICE_NAME),U=e.object({domain:e.string().optional(),loadBalancer:e.union([e.literal(!1),e.enum(Q)]).optional(),directAccess:e.boolean().optional(),extraProperties:e.array(l).optional()}).strict().refine(n=>!(n.directAccess&&n.domain),{message:o.DIRECT_ACCESS.NO_DOMAIN,path:["directAccess"]}).refine(n=>!(n.directAccess&&typeof n.loadBalancer=="string"),{message:o.DIRECT_ACCESS.NO_LOAD_BALANCER}).describe("Cluster-level configuration"),M=e.object({path:e.string().optional(),host:e.string().optional(),priority:e.number().int(o.PRIORITY.INTEGER).min(1,o.PRIORITY.MIN).max(5e4,o.PRIORITY.MAX).optional(),healthCheckPath:e.string().optional()}).strict().describe("Path/host-based routing configuration"),se=e.object({desiredCount:u.optional(),minCapacity:e.number().int(o.CAPACITY.MIN.INTEGER).min(0,o.CAPACITY.MIN.MIN_0).max(p,o.CAPACITY.MIN.MAX).optional(),maxCapacity:e.number().int(o.CAPACITY.MAX.INTEGER).min(1,o.CAPACITY.MAX.MIN_1).max(p,o.CAPACITY.MAX.MAX).optional(),scalingType:e.enum($).optional()}).strict().refine(r.check,r.params).describe("ECS service scaling configuration"),B=e.object({name:v,docker:A.optional(),needsDatabaseConnection:e.boolean().optional(),needsStorageConnection:e.boolean().optional(),needsMessagingConnection:e.boolean().optional(),image:e.string().optional(),containers:e.array(ce).optional(),routing:e.union([M,e.array(M).min(1)]).optional(),cpu:d.optional(),memoryLimitMiB:I(512).optional(),desiredCount:u.optional(),scaling:ee(se).optional(),capacityProvider:y,ec2Config:_.optional(),ssmSecretsPath:e.string().regex(m.SSM_PATH,o.SSM_PATH).optional(),extraProperties:e.array(l).optional(),alarms:ne.optional()}).strict().superRefine((n,t)=>{ie(n)||t.addIssue({code:"custom",path:["docker"],message:o.IMAGE_DOCKER_MUTEX})}).describe("Configuration for a service in an ECS cluster"),Re=e.object({name:c,type:re,needsConnection:e.boolean(),connectedDatabase:e.array(e.string()).optional(),connectedStorage:e.array(e.string()).optional(),connectedMessaging:e.array(e.string()).optional(),cluster:U.optional(),services:e.array(B).optional(),docker:A.partial().optional(),deployment:e.enum(Z).optional(),codePath:e.string().optional(),timeout:e.number().int(o.LAMBDA.TIMEOUT.INTEGER).min(S,o.LAMBDA.TIMEOUT.MIN).max(g,o.LAMBDA.TIMEOUT.MAX).optional(),memory:N.optional(),handler:e.string().optional(),runtime:G.optional(),environment:E.optional(),secrets:E.optional(),eventSources:e.array(Y).optional(),functionUrl:e.object({authType:e.enum(L)}).strict().optional(),description:e.string().optional(),scheduleExpression:e.string().optional(),architecture:e.enum(F).optional(),ephemeralStorageSize:e.number().int(o.EPHEMERAL_STORAGE.INTEGER).min(512,o.EPHEMERAL_STORAGE.MIN).max(10240,o.EPHEMERAL_STORAGE.MAX).optional(),functionName:e.string().optional(),ssmSecrets:e.array(e.string()).optional(),ssmSecretsPath:e.string().optional(),alarms:te.optional(),instanceType:b.optional(),enableSSH:e.boolean().optional(),keyName:e.string().optional(),userData:e.string().optional(),securityGroups:e.array(e.string()).optional(),variableName:e.string().optional(),extraProperties:e.array(l).optional()}).strict().superRefine((n,t)=>{if(n.type==="ecs"&&n.services)for(let i=0;i<n.services.length;i++){const a=n.services[i];a?.ec2Config?.instanceType&&!a.ec2Config.amiHardwareType&&J(a.ec2Config.instanceType)!=="ARM"&&t.addIssue({code:"custom",message:`Service '${a.name??i}' uses instance type '${a.ec2Config.instanceType}' (x86), which requires Docker images built for linux/amd64. The default build targets linux/arm64 (Graviton). Use a Graviton instance type (t4g, c6g, r6g, m6g, etc.) or set amiHardwareType: "STANDARD" to acknowledge x86.`,path:["services",i,"ec2Config","instanceType"]})}n.type==="lambda"&&n.deployment==="container"&&n.architecture==="X86_64"&&t.addIssue({code:"custom",message:"Lambda architecture 'X86_64' requires Docker images built for linux/amd64, but the default build targets linux/arm64. Use 'ARM_64' for Graviton Lambdas (recommended) or ensure your build pipeline targets linux/amd64.",path:["architecture"]})}),Se=e.object({appName:s,clusterName:c,containerPort:T,nameProvidedByFlag:e.boolean().optional(),ecrRepository:e.string().optional(),capacityProvider:y.optional(),useAppEcr:e.boolean().optional(),desiredCount:u.optional(),cpu:d.optional(),memoryLimitMiB:I(512).optional(),minCapacity:H.optional(),maxCapacity:D.optional(),ec2Config:_.optional(),connectionConfig:C.optional()}).strict().refine(r.check,r.params),ge=e.object({appName:s,functionName:c,nameProvidedByFlag:e.boolean().optional(),lambdaType:e.enum(["basic","web","custom"]).optional(),ecrRepository:e.string().optional(),timeout:e.number().int(o.LAMBDA.TIMEOUT.INTEGER).min(S,o.LAMBDA.TIMEOUT.MIN).max(g,o.LAMBDA.TIMEOUT.MAX).optional(),memory:N.optional(),enableFunctionUrl:e.boolean().optional(),description:e.string().optional(),enableCors:e.boolean().optional(),corsOrigins:e.string().optional(),corsHeaders:e.string().optional(),corsMethods:e.array(e.enum(j)).optional(),corsCredentials:e.boolean().optional(),connectionConfig:C.optional()}).strict(),Ne=e.object({appName:s,instanceName:c,nameProvidedByFlag:e.boolean().optional(),instanceType:b.optional(),enableSSH:e.boolean().optional(),minCapacity:H.optional(),maxCapacity:D.optional(),connectionConfig:C.optional()}).strict().refine(r.check,r.params),de=e.object({appName:s,clusterName:c,serviceName:v,capacityProvider:y,containerPort:T.optional(),cpu:d.optional(),memoryLimitMiB:I(512).optional(),desiredCount:u.optional(),ec2Config:_.optional(),routing:e.union([M,e.array(M).min(1)]).optional(),docker:A.partial().optional(),nameProvidedByFlag:e.boolean().optional(),connectionConfig:C.optional()}).strict(),P=e.object({appName:s,computeName:c,nameProvidedByFlag:e.boolean().optional(),connectionConfig:C.optional()}).strict(),me=P.extend({type:e.literal("ecs"),cluster:U.optional(),services:e.array(B).min(1,o.SERVICE.MIN_REQUIRED),docker:A.partial().optional()}).strict().refine(n=>{const t=n.services.filter(i=>i.containers?.some(a=>a.port));return t.length>1?t.every(i=>(Array.isArray(i.routing)?i.routing:i.routing?[i.routing]:[]).some(R=>R.path||R.host)):!0},{message:o.SERVICE.ROUTING_REQUIRED}).refine(n=>{const t=n.services.map(i=>i.name);return new Set(t).size===t.length},{message:o.SERVICE.UNIQUE_WITHIN_CLUSTER}),pe=P.extend({type:e.literal("lambda"),timeout:e.number().int(o.LAMBDA.TIMEOUT.INTEGER).min(S,o.LAMBDA.TIMEOUT.MIN).max(g,o.LAMBDA.TIMEOUT.MAX).optional(),memory:N.optional(),handler:e.string().optional(),runtime:G.optional(),environment:E.optional(),secrets:E.optional(),description:e.string().optional(),functionUrl:e.union([e.object({authType:e.enum(L).optional()}).strict(),e.literal(!1)]).optional(),eventSources:e.array(Y).optional()}).strict(),le=P.extend({type:e.literal("ec2"),instanceType:b.optional(),enableSSH:e.boolean().optional(),keyName:e.string().optional(),userData:e.string().optional(),securityGroups:e.array(e.string()).optional()}).strict(),_e=e.discriminatedUnion("type",[me,pe,le]),X=e.object({path:e.string().min(1,o.REQUIRED.ROUTING_PATH),priority:e.number().int(o.PRIORITY.INTEGER).min(1,o.PRIORITY.MIN).max(5e4,o.PRIORITY.MAX).optional()}).strict(),ye=e.object({name:e.string().min(1,o.REQUIRED.SERVICE_NAME).max(255,o.MAX_LENGTH.SERVICE_NAME).regex(m.RESOURCE_NAME,o.RESOURCE_NAME),serviceType:e.enum(["web","worker"]).optional(),docker:A.partial().optional(),containerPort:T.optional(),needsDatabaseConnection:e.boolean().optional(),routing:e.union([X,e.array(X).min(1)]).optional()}).strict().superRefine((n,t)=>{n.serviceType==="worker"&&(n.containerPort!==void 0&&t.addIssue({code:"custom",path:["containerPort"],message:"Worker services are not reachable inbound; remove containerPort."}),n.routing!==void 0&&t.addIssue({code:"custom",path:["routing"],message:"Worker services have no ALB route; remove routing."}))}),be=e.object({appName:s,instanceType:e.string().optional()}).strict();export{de as AddServiceGeneratorSchema,ye as ApplicationServiceConfigSchema,X as ApplicationServiceRoutingSchema,_e as ComputeGeneratorSchema,Re as ComputeResourcePlanSchema,re as ComputeTypeSchema,ce as ContainerConfigSchema,Ne as EC2GeneratorSchema,Se as ECSGeneratorSchema,_ as Ec2ConfigSchema,y as EcsCapacityProviderSchema,U as EcsClusterConfigSchema,M as EcsRoutingConfigSchema,se as EcsScalingConfigSchema,B as EcsServiceConfigSchema,v as EcsServiceNameSchema,b as InstanceTypeSchema,Y as LambdaEventSourceSchema,ge as LambdaGeneratorSchema,N as LambdaMemorySchema,G as LambdaRuntimeSchema,be as TunnelGeneratorSchema,ae as WarmPoolSchema};
@@ -1 +1 @@
1
- export declare const GENERATOR_VERSION = "2.20.0";
1
+ export declare const GENERATOR_VERSION = "2.21.0";
@@ -1 +1 @@
1
- const E="2.20.0";export{E as GENERATOR_VERSION};
1
+ const E="2.21.0";export{E as GENERATOR_VERSION};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fjall/generator",
3
- "version": "2.20.1",
3
+ "version": "2.22.0",
4
4
  "description": "Pure infrastructure generation logic for Fjall",
5
5
  "type": "module",
6
6
  "main": "dist/src/index.js",
@@ -17,6 +17,10 @@
17
17
  "./detection": {
18
18
  "types": "./dist/src/detection/index.d.ts",
19
19
  "default": "./dist/src/detection/index.js"
20
+ },
21
+ "./schemas": {
22
+ "types": "./dist/src/schemas/index.d.ts",
23
+ "default": "./dist/src/schemas/index.js"
20
24
  }
21
25
  },
22
26
  "files": [
@@ -43,7 +47,7 @@
43
47
  },
44
48
  "license": "SEE LICENSE IN LICENSE",
45
49
  "dependencies": {
46
- "@fjall/util": "^2.20.1",
50
+ "@fjall/util": "^2.22.0",
47
51
  "ast-types": "^0.16.1",
48
52
  "recast": "^0.23.11",
49
53
  "ts-morph": "^28.0.0",
@@ -59,5 +63,5 @@
59
63
  "typescript-eslint": "^8.59.1",
60
64
  "vitest": "^4.1.5"
61
65
  },
62
- "gitHead": "397880361ea533450ea5c888f7e7b9593254f663"
66
+ "gitHead": "448c771d258e87f0535ae7698f11438e0f7c57b1"
63
67
  }