@fjall/generator 7.2.0 → 8.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.
Files changed (46) hide show
  1. package/dist/.build-source-hash +30 -21
  2. package/dist/.minified +1 -1
  3. package/dist/src/ast/domain/astDomainParser.d.ts +2 -0
  4. package/dist/src/ast/domain/astDomainParser.js +1 -1
  5. package/dist/src/codemod/drift/snapshot.js +1 -1
  6. package/dist/src/codemod/edits/addResource/propertyBuilder.d.ts +8 -1
  7. package/dist/src/codemod/edits/addResource/propertyBuilder.js +1 -1
  8. package/dist/src/codemod/edits/addResource.js +1 -1
  9. package/dist/src/codemod/edits/appendAccountToStage.js +1 -1
  10. package/dist/src/codemod/edits/modifyResource.js +1 -1
  11. package/dist/src/codemod/edits/moduleConstResolver.d.ts +24 -0
  12. package/dist/src/codemod/edits/moduleConstResolver.js +1 -0
  13. package/dist/src/codemod/edits/objectGraph.d.ts +28 -0
  14. package/dist/src/codemod/edits/objectGraph.js +1 -0
  15. package/dist/src/codemod/edits/secretsProvability.d.ts +48 -0
  16. package/dist/src/codemod/edits/secretsProvability.js +1 -0
  17. package/dist/src/codemod/edits/setContainerSecrets.d.ts +55 -0
  18. package/dist/src/codemod/edits/setContainerSecrets.js +1 -0
  19. package/dist/src/codemod/emitProjection.d.ts +29 -0
  20. package/dist/src/codemod/emitProjection.js +1 -0
  21. package/dist/src/codemod/index.d.ts +1 -0
  22. package/dist/src/codemod/index.js +1 -1
  23. package/dist/src/codemod/registry.d.ts +15 -10
  24. package/dist/src/codemod/registry.js +1 -1
  25. package/dist/src/dns/bindParser.js +2 -2
  26. package/dist/src/dns/bindWriter.js +2 -2
  27. package/dist/src/dns/domainRecords.d.ts +4 -0
  28. package/dist/src/dns/domainRecords.js +1 -1
  29. package/dist/src/generation/common.d.ts +7 -0
  30. package/dist/src/generation/common.js +6 -5
  31. package/dist/src/generation/storage.js +27 -33
  32. package/dist/src/planning/index.d.ts +1 -1
  33. package/dist/src/planning/index.js +1 -1
  34. package/dist/src/planning/resourcePlanning.d.ts +14 -2
  35. package/dist/src/planning/resourcePlanning.js +1 -1
  36. package/dist/src/projection/index.d.ts +3 -0
  37. package/dist/src/projection/index.js +1 -0
  38. package/dist/src/projection/project.d.ts +22 -0
  39. package/dist/src/projection/project.js +1 -0
  40. package/dist/src/projection/tables.d.ts +32 -0
  41. package/dist/src/projection/tables.js +1 -0
  42. package/dist/src/projection/types.d.ts +108 -0
  43. package/dist/src/projection/types.js +0 -0
  44. package/dist/src/version.d.ts +1 -1
  45. package/dist/src/version.js +1 -1
  46. package/package.json +2 -2
@@ -1 +1 @@
1
- import{addResource as o}from"./edits/addResource.js";import{removeResource as c}from"./edits/removeResource.js";import{modifyResource as m}from"./edits/modifyResource.js";import{appendAccountToStage as s}from"./edits/appendAccountToStage.js";import{addVpcPeer as d,modifyVpcPeer as E,removeVpcPeer as i}from"./edits/vpcPeer.js";import{addVpcPeerAccepter as f,modifyVpcPeerAccepter as u,removeVpcPeerAccepter as P}from"./edits/vpcPeerAccepter.js";import{addCrossPlanConnection as R,modifyCrossPlanConnection as T,removeCrossPlanConnection as S}from"./edits/crossPlanConnection.js";import{resolveDriftPolicy as A}from"./edits/driftPolicy.js";import{listResources as V}from"./listResources.js";import{resolveConstructByLiteralProperty as y}from"./semanticIndex/index.js";import{parse as D}from"./fileRewriter/parse.js";import{CrossPlanConnectionResourcePlanSchema as N,VpcPeerAccepterResourcePlanSchema as h,VpcPeerResourcePlanSchema as F}from"../schemas/index.js";import{detectDrift as I,mergeProperties as M,snapshotProperties as O}from"./drift/index.js";import{computeLinesDelta as k}from"./_internal.js";import{ResourceNameSchema as U,StatementTypeSchema as K}from"./types.js";import{REGISTERED_STATEMENT_TYPES as j,STATEMENT_REGISTRY as q}from"./registry.js";import{evaluateEmitGuard as z,UNRESOLVED as H}from"./emitGuard.js";import{CODEMOD_ERROR_KINDS as Q}from"./telemetry/errorKinds.js";import{buildEgressBlockedEvent as X,buildFiredEvent as Z,buildGateFailedEvent as $,buildGatePassedEvent as ee,buildRejectedEvent as re,buildSucceededEvent as oe,buildTimeoutEvent as te,estimateCostUsd as ce,FALLBACK_EVENTS as pe,GATE_EVENTS as me,PARSE_GATE as ae,RUNTIME_GATE as se,runFallback as ne,shouldTryFallback as de}from"./llmFallback/index.js";export{Q as CODEMOD_ERROR_KINDS,N as CrossPlanConnectionResourcePlanSchema,pe as FALLBACK_EVENTS,me as GATE_EVENTS,ae as PARSE_GATE,j as REGISTERED_STATEMENT_TYPES,se as RUNTIME_GATE,U as ResourceNameSchema,q as STATEMENT_REGISTRY,K as StatementTypeSchema,H as UNRESOLVED,h as VpcPeerAccepterResourcePlanSchema,F as VpcPeerResourcePlanSchema,R as addCrossPlanConnection,o as addResource,d as addVpcPeer,f as addVpcPeerAccepter,s as appendAccountToStage,X as buildEgressBlockedEvent,Z as buildFiredEvent,$ as buildGateFailedEvent,ee as buildGatePassedEvent,re as buildRejectedEvent,oe as buildSucceededEvent,te as buildTimeoutEvent,k as computeLinesDelta,I as detectDrift,ce as estimateCostUsd,z as evaluateEmitGuard,V as listResources,M as mergeProperties,T as modifyCrossPlanConnection,m as modifyResource,E as modifyVpcPeer,u as modifyVpcPeerAccepter,D as parse,S as removeCrossPlanConnection,c as removeResource,i as removeVpcPeer,P as removeVpcPeerAccepter,y as resolveConstructByLiteralProperty,A as resolveDriftPolicy,ne as runFallback,de as shouldTryFallback,O as snapshotProperties};
1
+ import{addResource as o}from"./edits/addResource.js";import{removeResource as c}from"./edits/removeResource.js";import{modifyResource as m}from"./edits/modifyResource.js";import{appendAccountToStage as s}from"./edits/appendAccountToStage.js";import{setContainerSecrets as d}from"./edits/setContainerSecrets.js";import{addVpcPeer as i,modifyVpcPeer as l,removeVpcPeer as f}from"./edits/vpcPeer.js";import{addVpcPeerAccepter as P,modifyVpcPeerAccepter as x,removeVpcPeerAccepter as R}from"./edits/vpcPeerAccepter.js";import{addCrossPlanConnection as T,modifyCrossPlanConnection as v,removeCrossPlanConnection as A}from"./edits/crossPlanConnection.js";import{resolveDriftPolicy as V}from"./edits/driftPolicy.js";import{listResources as y}from"./listResources.js";import{resolveConstructByLiteralProperty as D}from"./semanticIndex/index.js";import{parse as N}from"./fileRewriter/parse.js";import{CrossPlanConnectionResourcePlanSchema as F,VpcPeerAccepterResourcePlanSchema as L,VpcPeerResourcePlanSchema as I}from"../schemas/index.js";import{detectDrift as O,mergeProperties as g,snapshotProperties as k}from"./drift/index.js";import{computeLinesDelta as U}from"./_internal.js";import{ResourceNameSchema as Y,StatementTypeSchema as j}from"./types.js";import{REGISTERED_STATEMENT_TYPES as w,STATEMENT_REGISTRY as z}from"./registry.js";import{evaluateEmitGuard as J,UNRESOLVED as Q}from"./emitGuard.js";import{CODEMOD_ERROR_KINDS as X}from"./telemetry/errorKinds.js";import{buildEgressBlockedEvent as $,buildFiredEvent as ee,buildGateFailedEvent as re,buildGatePassedEvent as oe,buildRejectedEvent as te,buildSucceededEvent as ce,buildTimeoutEvent as pe,estimateCostUsd as me,FALLBACK_EVENTS as ae,GATE_EVENTS as se,PARSE_GATE as ne,RUNTIME_GATE as de,runFallback as Ee,shouldTryFallback as ie}from"./llmFallback/index.js";export{X as CODEMOD_ERROR_KINDS,F as CrossPlanConnectionResourcePlanSchema,ae as FALLBACK_EVENTS,se as GATE_EVENTS,ne as PARSE_GATE,w as REGISTERED_STATEMENT_TYPES,de as RUNTIME_GATE,Y as ResourceNameSchema,z as STATEMENT_REGISTRY,j as StatementTypeSchema,Q as UNRESOLVED,L as VpcPeerAccepterResourcePlanSchema,I as VpcPeerResourcePlanSchema,T as addCrossPlanConnection,o as addResource,i as addVpcPeer,P as addVpcPeerAccepter,s as appendAccountToStage,$ as buildEgressBlockedEvent,ee as buildFiredEvent,re as buildGateFailedEvent,oe as buildGatePassedEvent,te as buildRejectedEvent,ce as buildSucceededEvent,pe as buildTimeoutEvent,U as computeLinesDelta,O as detectDrift,me as estimateCostUsd,J as evaluateEmitGuard,y as listResources,g as mergeProperties,v as modifyCrossPlanConnection,m as modifyResource,l as modifyVpcPeer,x as modifyVpcPeerAccepter,N as parse,A as removeCrossPlanConnection,c as removeResource,f as removeVpcPeer,R as removeVpcPeerAccepter,D as resolveConstructByLiteralProperty,V as resolveDriftPolicy,Ee as runFallback,d as setContainerSecrets,ie as shouldTryFallback,k as snapshotProperties};
@@ -61,13 +61,16 @@ export interface StatementTypeEntry {
61
61
  * Property shapes the ADD and MODIFY paths must REFUSE to write, checked
62
62
  * before any file is touched. Declared here, beside `emitWrapper`, because
63
63
  * `emitWrapper` is precisely what creates the hazard: wrapping makes the
64
- * emitted props load-bearing at synth, and the codemod writes resource-PLAN
65
- * vocabulary verbatim into a file the constructs read as CONSTRUCT
66
- * vocabulary. The generator scaffold has a translation layer for that seam
67
- * (`generation/compute/lambda.ts` turns `codePath` into
68
- * `Code.fromAsset(...)`); the codemod has none, so where the two
69
- * vocabularies disagree the statement either takes the whole app's synth
70
- * down or deploys infrastructure that is not what was asked for.
64
+ * emitted props load-bearing at synth, and the plan and construct
65
+ * vocabularies disagree.
66
+ *
67
+ * ONLY for types the plan→construct projection cannot describe. Where it
68
+ * can (`src/projection/tables.ts`), the disagreement is TRANSLATED at
69
+ * emission and no rule belongs here `emitProjection.ts` reports what is
70
+ * left from the projection's own `unprojectable` list. What survives is
71
+ * props needing a live sibling construct (`cdn`'s origin, `compute`'s
72
+ * connection expansion) and cross-key conditions no per-key table can
73
+ * state.
71
74
  *
72
75
  * Rules cover exactly two classes, and nothing else:
73
76
  *
@@ -88,9 +91,11 @@ export interface StatementTypeEntry {
88
91
  * through (a separate, recorded gap).
89
92
  *
90
93
  * Absent = every expressible property shape for this type reaches a
91
- * synthesising statement. That is a claim, not an oversight: `network`,
92
- * `vpc-peer` and `buildkite` each have full plan/construct parity, and the
93
- * components-infrastructure materialisation contract pins it.
94
+ * synthesising statement. That is a claim, not an oversight, and it is now
95
+ * true two ways: `network` and `buildkite` have outright plan/construct
96
+ * parity, while `database`, `storage` and `messaging` reach it through the
97
+ * projection. The components-infrastructure materialisation contract pins
98
+ * both.
94
99
  */
95
100
  emitGuard?: ReadonlyArray<EmitGuardRule>;
96
101
  }
@@ -1 +1 @@
1
- var v=Object.defineProperty;var a=(e,t)=>v(e,"name",{value:t,configurable:!0});import{z as u}from"zod";import{BuildkitePropsObjectSchema as E,CDNResourcePlanSchema as R,ComputeResourcePlanSchema as k,CrossPlanConnectionResourcePlanSchema as T,DatabaseResourcePlanSchema as w,NetworkResourcePlanSchema as A,NextJSPatternConfigSchema as F,OrganisationResourcePlanSchema as N,PayloadPatternConfigSchema as M,S3ResourcePlanSchema as D,SQSResourcePlanSchema as x,StaticSitePatternConfigSchema as G,VpcPeerAccepterResourcePlanSchema as W,VpcPeerResourcePlanSchema as _}from"../schemas/index.js";import{failure as O}from"../types/Result.js";import{isRecord as I}from"./_internal.js";import{AUTHOR_BY_HAND as c,requiresLiveValue as f,silentlyDropped as n,UNRESOLVED as h,whenAbsent as p}from"./emitGuard.js";const r={database:"DatabaseFactory",storage:"StorageFactory",compute:"ComputeFactory",messaging:"MessagingFactory",cdn:"CdnFactory",network:"NetworkFactory",pattern:"PatternFactory","vpc-peer":"VpcPeerFactory","vpc-peer-accepter":"VpcPeerAccepterFactory","cross-plan-connection":"CrossPlanConnectionFactory",organisation:"OrganisationFactory",buildkite:"BuildkiteFactory"};function s(e){const{name:t,...i}=e.shape;return u.object(i).partial().strict()}a(s,"fragmentOf");const B=s(w),j=s(D),q=(()=>{const{name:e,...t}=k.shape;return u.object(t).partial().strict()})(),L=s(x),V=s(R),Y=s(A),K=(()=>{const{name:e,type:t,cdn:i,...b}=M.shape,{name:se,type:ie,cdn:ce,...P}=F.shape,{name:pe,type:de,domain:ue,cdn:S,...C}=G.shape;return u.object({...b,...P,...C,cdn:u.union([i,S])}).partial().strict()})(),U=s(_),z=s(W),H=s(T),Q=s(N),$=s(E);function g(e,t){return O({kind:"SemanticQueryError",reason:`StatementTypeEntry.${e} for ${t} is not wired; existing types dispatch through the shared locator/generator.`})}a(g,"notWiredError");function J(e){return{factoryIdentifier:e,findByShape:a(()=>g("locator.findByShape",e),"findByShape"),validateContext:a(()=>g("locator.validateContext",e),"validateContext")}}a(J,"createLocator");function X(e){return{build:a(()=>{const t=g("generator.build",e);throw new Error(t.success?"unreachable":t.error.reason)},"build")}}a(X,"createGenerator");const m=n("variableName","`variableName` is a plan-only round-trip key naming the `const <var> =` binding the scaffold emits; no construct reads it."),d=n("extraProperties","`extraProperties` is a plan-only round-trip key: the scaffold flattens each `{ key, sourceText }` entry into a sibling property, and no construct reads the array."),Z=[n("engineExpression","`engineExpression` carries a raw CDK engine expression for the scaffold to inline; the construct reads `databaseEngine` instead, so a cluster pinned to `DatabaseClusterEngine.auroraMysql(...)` still deploys as aurora-postgresql."),m,d],ee=[m,d],l="the connection keys are scaffold inputs, not construct props: the scaffold expands them into environment variables and a `connections: [...]` array, and the compute constructs read none of them.",te=[{property:"deployment",refuseWhen:a(e=>(e.type==="lambda"||e.deployment!==void 0)&&e.deployment!=="container"&&e.code!==h,"refuseWhen"),reason:"a code-deployed Lambda requires `code: Code`, a CDK object built by `Code.fromAsset(...)` that no flag value can carry, so the statement takes the whole app's synth down with `Cannot read properties of undefined (reading 'bind')` \u2014 naming no resource. Use `--deployment container`, which is fully expressible, or write this compute in infrastructure.ts by hand."},n("codePath","`codePath` is the scaffold's input to `Code.fromAsset(...)`; no compute construct reads it, and a container Lambda takes its code from the image."),f("runtime","the construct expects a CDK `Runtime`, not a version string, and a container Lambda takes its runtime from the image (`Runtime.FROM_IMAGE`) regardless."),f("architecture","the construct expects a CDK `Architecture`, not a string: `--architecture ARM_64` emits an EMPTY `Architectures` list, whereas omitting the flag emits the correct default."),n("memory","the Lambda construct reads `memorySize`, so `--memory 1024` deploys a function at the 128 MB default."),n("ssmSecrets","the Lambda construct reads `secrets`, so `--ssmSecrets` deploys a function with no SSM wiring and no secrets environment at all."),n("scheduleExpression","`scheduleExpression` is not a compute prop: the scaffold turns it into a SEPARATE `app.addSchedule(...)` statement, which this command cannot emit."),n("needsConnection",l),n("connectedDatabase",l),n("connectedStorage",l),n("connectedMessaging",l),m,d],ae=[{property:"type",refuseWhen:p("type"),reason:"`MessagingFactory.build` selects queue/topic/eventBus from a `type` discriminator that the messaging vocabulary does not carry, so a queue built from messaging properties throws `Unsupported messaging type: undefined` the moment `app.addMessaging` materialises it. "+c},n("retentionPeriod","the queue construct reads `messageRetentionPeriod`, so `--retentionPeriod` deploys a queue at the 4-day default."),m,d],ne=[{property:"originType",refuseWhen:p("originType"),reason:"`Cdn` selects its origin implementation from an `originType` discriminator that the CDN vocabulary does not carry, so a distribution built from CDN properties throws `Unsupported CDN origin type: undefined` the moment `app.addCdn` materialises it. "+c},{property:"originType",refuseWhen:a(e=>e.originType==="s3"&&e.bucket!==h,"refuseWhen"),reason:"an s3 origin needs `bucket` to be an `IBucket` or a Fjall `Storage` \u2014 a live construct, not a name, and not a string; omitting it throws `Cannot read properties of undefined (reading 'bucketRegionalDomainName')` at synth. "+c},{property:"originType",refuseWhen:a(e=>e.originType==="alb"&&e.loadBalancer!==h,"refuseWhen"),reason:'an alb origin needs `loadBalancer` to be an `IApplicationLoadBalancer` or an ECS compute \u2014 a live construct, not a name, and not a string; a string reaches CloudFormation as `Supplied properties not correct for "OriginProperty"`. '+c},{property:"behaviours",refuseWhen:a(e=>Array.isArray(e.behaviours)&&e.behaviours.some(t=>I(t)&&t.originRef!==void 0),"refuseWhen"),reason:"the plan's `behaviours[].originRef` names another planned resource, while the construct's behaviour takes a live origin object; the plan shape throws `Cannot read properties of undefined (reading 'computeType')` at synth. "+c},n("customDomain","the distribution reads `domainNames`, so `--customDomain` deploys a distribution with no alias."),n("defaultOriginRef","`defaultOriginRef` names another planned resource for the scaffold to resolve into a live origin; no CDN construct reads it."),d],re=[{property:"name",refuseWhen:p("name"),reason:"every pattern construct requires a `name` PROPERTY in addition to its construct id, and `fjall add --name` binds the construct id, so no invocation can deliver it \u2014 `toPascalCase(props.name)` throws at synth and takes the whole app down. "+c},{property:"type",refuseWhen:p("type"),reason:"`PatternFactory.build` reads `PATTERN_REGISTRY[props.type]` before it even returns the thunk, and the pattern vocabulary carries no `type` discriminator. "+c}],oe=[{property:"peerAppName",refuseWhen:p("peerAppName"),reason:"`peerAppName` is required: it is the SSM prefix every remote lookup is built from, and omitting it does NOT fail \u2014 synth succeeds and the app deploys a peering connection pointed at `/fjall/default/undefined/vpc-id`. Pass `--peerAppName <remote app>`."},{property:"peerAccountId",refuseWhen:p("peerAccountId"),reason:"`peerAccountId` is required: omitting it does NOT fail, it deploys a VPC peering connection with no `PeerOwnerId`. Pass `--peerAccountId <12-digit account>`."}];function o(e,t,i={}){return{factoryIdentifier:e,locator:J(e),generator:X(e),schemaFragment:t,...i}}a(o,"createEntry");const y={database:o(r.database,B,{emitWrapper:{appMethod:"addDatabase"},emitGuard:Z}),storage:o(r.storage,j,{emitWrapper:{appMethod:"addStorage"},emitGuard:ee}),compute:o(r.compute,q,{emitWrapper:{appMethod:"addCompute"},emitGuard:te}),messaging:o(r.messaging,L,{emitWrapper:{appMethod:"addMessaging"},emitGuard:ae}),cdn:o(r.cdn,V,{emitWrapper:{appMethod:"addCdn"},emitGuard:ne}),network:o(r.network,Y,{emitWrapper:{appMethod:"addNetwork"}}),pattern:o(r.pattern,K,{emitWrapper:{appMethod:"addPattern"},emitGuard:re}),"vpc-peer":o(r["vpc-peer"],U,{emitWrapper:{appMethod:"addVpcPeer"},emitGuard:oe}),"vpc-peer-accepter":o(r["vpc-peer-accepter"],z,{emitWrapper:{appMethod:"addVpcPeerAccepter"}}),"cross-plan-connection":o(r["cross-plan-connection"],H),organisation:o(r.organisation,Q),buildkite:o(r.buildkite,$,{emitWrapper:{appMethod:"addBuildkite",propsOverloadConstructId:"Buildkite"}})},be=Object.keys(y);function Pe(e){const t=Object.keys(y);for(const i of t)if(y[i].factoryIdentifier===e)return i}a(Pe,"findTypeByIdentifier");export{be as REGISTERED_STATEMENT_TYPES,y as STATEMENT_REGISTRY,Pe as findTypeByIdentifier};
1
+ var C=Object.defineProperty;var n=(e,t)=>C(e,"name",{value:t,configurable:!0});import{z as d}from"zod";import{BuildkitePropsObjectSchema as v,CDNResourcePlanSchema as R,ComputeResourcePlanSchema as k,CrossPlanConnectionResourcePlanSchema as T,DatabaseResourcePlanSchema as A,NetworkResourcePlanSchema as E,NextJSPatternConfigSchema as w,OrganisationResourcePlanSchema as F,PayloadPatternConfigSchema as N,S3ResourcePlanSchema as M,SQSResourcePlanSchema as D,StaticSitePatternConfigSchema as _,VpcPeerAccepterResourcePlanSchema as O,VpcPeerResourcePlanSchema as W}from"../schemas/index.js";import{failure as x}from"../types/Result.js";import{isRecord as G}from"./_internal.js";import{AUTHOR_BY_HAND as c,requiresLiveValue as g,silentlyDropped as a,UNRESOLVED as m,whenAbsent as p}from"./emitGuard.js";const r={database:"DatabaseFactory",storage:"StorageFactory",compute:"ComputeFactory",messaging:"MessagingFactory",cdn:"CdnFactory",network:"NetworkFactory",pattern:"PatternFactory","vpc-peer":"VpcPeerFactory","vpc-peer-accepter":"VpcPeerAccepterFactory","cross-plan-connection":"CrossPlanConnectionFactory",organisation:"OrganisationFactory",buildkite:"BuildkiteFactory"};function s(e){const{name:t,...i}=e.shape;return d.object(i).partial().strict()}n(s,"fragmentOf");const I=s(A),B=s(M),j=(()=>{const{name:e,...t}=k.shape;return d.object(t).partial().strict()})(),L=s(D),V=s(R),Y=s(E),q=(()=>{const{name:e,type:t,cdn:i,...f}=N.shape,{name:ae,type:re,cdn:oe,...b}=w.shape,{name:se,type:ie,domain:ce,cdn:S,...P}=_.shape;return d.object({...f,...b,...P,cdn:d.union([i,S])}).partial().strict()})(),K=s(W),U=s(O),z=s(T),H=s(F),Q=s(v);function l(e,t){return x({kind:"SemanticQueryError",reason:`StatementTypeEntry.${e} for ${t} is not wired; existing types dispatch through the shared locator/generator.`})}n(l,"notWiredError");function $(e){return{factoryIdentifier:e,findByShape:n(()=>l("locator.findByShape",e),"findByShape"),validateContext:n(()=>l("locator.validateContext",e),"validateContext")}}n($,"createLocator");function J(e){return{build:n(()=>{const t=l("generator.build",e);throw new Error(t.success?"unreachable":t.error.reason)},"build")}}n(J,"createGenerator");const X=a("variableName","`variableName` is a plan-only round-trip key naming the `const <var> =` binding the scaffold emits; no construct reads it."),y=a("extraProperties","`extraProperties` is a plan-only round-trip key: the scaffold flattens each `{ key, sourceText }` entry into a sibling property, and no construct reads the array."),u="the connection keys are scaffold inputs, not construct props: the scaffold expands them into environment variables and a `connections: [...]` array, and the compute constructs read none of them.",Z=[{property:"deployment",refuseWhen:n(e=>(e.type==="lambda"||e.deployment!==void 0)&&e.deployment!=="container"&&e.code!==m,"refuseWhen"),reason:"a code-deployed Lambda requires `code: Code`, a CDK object built by `Code.fromAsset(...)` that no flag value can carry, so the statement takes the whole app's synth down with `Cannot read properties of undefined (reading 'bind')` \u2014 naming no resource. Use `--deployment container`, which is fully expressible, or write this compute in infrastructure.ts by hand."},a("codePath","`codePath` is the scaffold's input to `Code.fromAsset(...)`; no compute construct reads it, and a container Lambda takes its code from the image."),g("runtime","the construct expects a CDK `Runtime`, not a version string, and a container Lambda takes its runtime from the image (`Runtime.FROM_IMAGE`) regardless."),g("architecture","the construct expects a CDK `Architecture`, not a string: `--architecture ARM_64` emits an EMPTY `Architectures` list, whereas omitting the flag emits the correct default."),a("memory","the Lambda construct reads `memorySize`, so `--memory 1024` deploys a function at the 128 MB default."),a("ssmSecrets","the Lambda construct reads `secrets`, so `--ssmSecrets` deploys a function with no SSM wiring and no secrets environment at all."),a("scheduleExpression","`scheduleExpression` is not a compute prop: the scaffold turns it into a SEPARATE `app.addSchedule(...)` statement, which this command cannot emit."),a("needsConnection",u),a("connectedDatabase",u),a("connectedStorage",u),a("connectedMessaging",u),X,y],ee=[{property:"originType",refuseWhen:p("originType"),reason:"`Cdn` selects its origin implementation from an `originType` discriminator that the CDN vocabulary does not carry, so a distribution built from CDN properties throws `Unsupported CDN origin type: undefined` the moment `app.addCdn` materialises it. "+c},{property:"originType",refuseWhen:n(e=>e.originType==="s3"&&e.bucket!==m,"refuseWhen"),reason:"an s3 origin needs `bucket` to be an `IBucket` or a Fjall `Storage` \u2014 a live construct, not a name, and not a string; omitting it throws `Cannot read properties of undefined (reading 'bucketRegionalDomainName')` at synth. "+c},{property:"originType",refuseWhen:n(e=>e.originType==="alb"&&e.loadBalancer!==m,"refuseWhen"),reason:'an alb origin needs `loadBalancer` to be an `IApplicationLoadBalancer` or an ECS compute \u2014 a live construct, not a name, and not a string; a string reaches CloudFormation as `Supplied properties not correct for "OriginProperty"`. '+c},{property:"behaviours",refuseWhen:n(e=>Array.isArray(e.behaviours)&&e.behaviours.some(t=>G(t)&&t.originRef!==void 0),"refuseWhen"),reason:"the plan's `behaviours[].originRef` names another planned resource, while the construct's behaviour takes a live origin object; the plan shape throws `Cannot read properties of undefined (reading 'computeType')` at synth. "+c},a("customDomain","the distribution reads `domainNames`, so `--customDomain` deploys a distribution with no alias."),a("defaultOriginRef","`defaultOriginRef` names another planned resource for the scaffold to resolve into a live origin; no CDN construct reads it."),y],te=[{property:"name",refuseWhen:p("name"),reason:"every pattern construct requires a `name` PROPERTY in addition to its construct id, and `fjall add --name` binds the construct id, so no invocation can deliver it \u2014 `toPascalCase(props.name)` throws at synth and takes the whole app down. "+c},{property:"type",refuseWhen:p("type"),reason:"`PatternFactory.build` reads `PATTERN_REGISTRY[props.type]` before it even returns the thunk, and the pattern vocabulary carries no `type` discriminator. "+c}],ne=[{property:"peerAppName",refuseWhen:p("peerAppName"),reason:"`peerAppName` is required: it is the SSM prefix every remote lookup is built from, and omitting it does NOT fail \u2014 synth succeeds and the app deploys a peering connection pointed at `/fjall/default/undefined/vpc-id`. Pass `--peerAppName <remote app>`."},{property:"peerAccountId",refuseWhen:p("peerAccountId"),reason:"`peerAccountId` is required: omitting it does NOT fail, it deploys a VPC peering connection with no `PeerOwnerId`. Pass `--peerAccountId <12-digit account>`."}];function o(e,t,i={}){return{factoryIdentifier:e,locator:$(e),generator:J(e),schemaFragment:t,...i}}n(o,"createEntry");const h={database:o(r.database,I,{emitWrapper:{appMethod:"addDatabase"}}),storage:o(r.storage,B,{emitWrapper:{appMethod:"addStorage"}}),compute:o(r.compute,j,{emitWrapper:{appMethod:"addCompute"},emitGuard:Z}),messaging:o(r.messaging,L,{emitWrapper:{appMethod:"addMessaging"}}),cdn:o(r.cdn,V,{emitWrapper:{appMethod:"addCdn"},emitGuard:ee}),network:o(r.network,Y,{emitWrapper:{appMethod:"addNetwork"}}),pattern:o(r.pattern,q,{emitWrapper:{appMethod:"addPattern"},emitGuard:te}),"vpc-peer":o(r["vpc-peer"],K,{emitWrapper:{appMethod:"addVpcPeer"},emitGuard:ne}),"vpc-peer-accepter":o(r["vpc-peer-accepter"],U,{emitWrapper:{appMethod:"addVpcPeerAccepter"}}),"cross-plan-connection":o(r["cross-plan-connection"],z),organisation:o(r.organisation,H),buildkite:o(r.buildkite,Q,{emitWrapper:{appMethod:"addBuildkite",propsOverloadConstructId:"Buildkite"}})},ge=Object.keys(h);function ye(e){const t=Object.keys(h);for(const i of t)if(h[i].factoryIdentifier===e)return i}n(ye,"findTypeByIdentifier");export{ge as REGISTERED_STATEMENT_TYPES,h as STATEMENT_REGISTRY,ye as findTypeByIdentifier};
@@ -1,2 +1,2 @@
1
- var m=Object.defineProperty;var c=(e,n)=>m(e,"name",{value:n,configurable:!0});import{success as I,failure as T}from"../types/Result.js";import{DnsRecordTypeSchema as A,BIND_DIRECTIVES as d,ALIAS_PREFIX as E}from"./types.js";const v=new Set(A.options);function L(e){return v.has(e.toUpperCase())}c(L,"isRecordType");function C(e){return e.endsWith(".")?e.slice(0,-1):e}c(C,"stripTrailingDot");function R(e){let n=!1;for(let t=0;t<e.length;t++)if(e[t]==='"')n=!n;else if(e[t]===";"&&!n)return e.slice(0,t).trimEnd();return e}c(R,"stripInlineComment");function D(e,n){const t=e.slice(n).join(" "),s=[];let i="",r=!1;for(const o of t)o==='"'?(r&&(s.push(i),i=""),r=!r):r&&(i+=o);return s.join(" ")}c(D,"parseTxtValue");function $(e){const n=/;\s*auto\s*$/.test(e),s=e.replace(/;\s*auto\s*$/,"").trim().match(/^\$FJALL-DELEGATE\s+(\S+)\s+TO\s+(\S+)$/i);if(s)return{subdomain:s[1],targetAccount:s[2],auto:n}}c($,"parseDelegateDirective");function S(e){if(e.length<2)return;const n=e[1],t=e.slice(2);return{domainName:n,subjectAlternativeNames:t}}c(S,"parseCertDirective");function j(e){const n=[];let t="",s=!1;for(const i of e)i==='"'?(s=!s,t+=i):/\s/.test(i)&&!s?t.length>0&&(n.push(t),t=""):t+=i;return t.length>0&&n.push(t),n}c(j,"tokenise");function w(e){if(e.length<2)return;let n=0;const t=e[n++];let s,i;for(;n<e.length&&i===void 0;){const o=e[n].toUpperCase();if(o==="IN")n++;else if(L(o))i=o,n++;else if(/^\d+$/.test(e[n]))s=parseInt(e[n],10),n++;else return}if(!i)return;const r=e.slice(n);switch(i){case"MX":{if(r.length<2)return;const o=parseInt(r[0],10),f=r.slice(1).join(" ");return{name:t,type:i,ttl:s,value:f,priority:o}}case"SRV":{if(r.length<4)return;const o=parseInt(r[0],10),f=parseInt(r[1],10),l=parseInt(r[2],10),p=r[3];return{name:t,type:i,ttl:s,value:p,priority:o,weight:f,port:l}}case"TXT":{const o=D(e,n);return{name:t,type:i,ttl:s,value:o}}case"CAA":{const o=r.join(" ");return{name:t,type:i,ttl:s,value:o}}case"A":{if(r.length===0)return;if(r[0].toUpperCase()==="ALIAS"){if(r.length<2)return;const f=r.slice(1).join(" ");return{name:t,type:i,ttl:s,value:`${E}${f}`}}return{name:t,type:i,ttl:s,value:r[0]}}default:return r.length===0?void 0:{name:t,type:i,ttl:s,value:r[0]}}}c(w,"parseRecord");function U(e){const n=e.split(`
2
- `);let t,s=300;const i=[],r=[],o=[];for(const f of n){const l=f.trim();if(l===""||l.startsWith(";"))continue;if(l.toUpperCase().startsWith(d.FJALL_DELEGATE)){const a=$(l);a&&r.push(a);continue}const p=R(l);if(p==="")continue;const u=j(p);if(u.length===0)continue;const h=u[0].toUpperCase();if(h===d.ORIGIN){if(u.length<2)continue;t=C(u[1]);continue}if(h===d.TTL){if(u.length<2)continue;s=parseInt(u[1],10);continue}if(h===d.FJALL_CERT){const a=S(u);a&&o.push(a);continue}const g=w(u);g&&i.push(g)}return t?I({origin:t,ttl:s,records:i,delegations:r,certificates:o}):T(new Error("Missing $ORIGIN directive"))}c(U,"parseZoneFile");function _(e,n){if(!e.startsWith("fjall:"))return;const t=e.split(":");if(t.length<3)return;const s=t[1],i=t[2],r=`${s}:${i}`;return n.get(r)??n.get(e)}c(_,"resolveAlias");export{U as parseZoneFile,_ as resolveAlias};
1
+ var m=Object.defineProperty;var c=(e,n)=>m(e,"name",{value:n,configurable:!0});import{success as A,failure as I}from"../types/Result.js";import{DnsRecordTypeSchema as T,BIND_DIRECTIVES as d,ALIAS_PREFIX as E}from"./types.js";const v=new Set(T.options);function L(e){return v.has(e.toUpperCase())}c(L,"isRecordType");function C(e){return e.endsWith(".")?e.slice(0,-1):e}c(C,"stripTrailingDot");function R(e){let n=!1;for(let t=0;t<e.length;t++)if(e[t]==='"')n=!n;else if(e[t]===";"&&!n)return e.slice(0,t).trimEnd();return e}c(R,"stripInlineComment");function D(e,n){const t=e.slice(n).join(" "),s=[];let i="",r=!1;for(const o of t)o==='"'?(r&&(s.push(i),i=""),r=!r):r&&(i+=o);return s.join(" ")}c(D,"parseTxtValue");function $(e){const n=/;\s*auto\s*$/.test(e),s=e.replace(/;\s*auto\s*$/,"").trim().match(/^\$FJALL-DELEGATE\s+(\S+)\s+TO\s+(\S+)$/i);if(s)return{subdomain:s[1],targetAccount:s[2],auto:n}}c($,"parseDelegateDirective");function S(e){if(e.length<2)return;const n=e[1],t=e.slice(2);return{domainName:n,subjectAlternativeNames:t}}c(S,"parseCertDirective");function j(e){const n=[];let t="",s=!1;for(const i of e)i==='"'?(s=!s,t+=i):/\s/.test(i)&&!s?t.length>0&&(n.push(t),t=""):t+=i;return t.length>0&&n.push(t),n}c(j,"tokenise");function w(e){if(e.length<2)return;let n=0;const t=e[n++];let s,i;for(;n<e.length&&i===void 0;){const o=e[n].toUpperCase();if(o==="IN")n++;else if(L(o))i=o,n++;else if(/^\d+$/.test(e[n]))s=parseInt(e[n],10),n++;else return}if(!i)return;const r=e.slice(n);switch(i){case"MX":{if(r.length<2)return;const o=parseInt(r[0],10),f=r.slice(1).join(" ");return{name:t,type:i,ttl:s,value:f,priority:o}}case"SRV":{if(r.length<4)return;const o=parseInt(r[0],10),f=parseInt(r[1],10),l=parseInt(r[2],10),p=r[3];return{name:t,type:i,ttl:s,value:p,priority:o,weight:f,port:l}}case"TXT":{const o=D(e,n);return{name:t,type:i,ttl:s,value:o}}case"CAA":{const o=r.join(" ");return{name:t,type:i,ttl:s,value:o}}case"A":case"AAAA":{if(r.length===0)return;if(r[0].toUpperCase()==="ALIAS"){if(r.length<2)return;const f=r.slice(1).join(" ");return{name:t,type:i,ttl:s,value:`${E}${f}`}}return{name:t,type:i,ttl:s,value:r[0]}}default:return r.length===0?void 0:{name:t,type:i,ttl:s,value:r[0]}}}c(w,"parseRecord");function U(e){const n=e.split(`
2
+ `);let t,s=300;const i=[],r=[],o=[];for(const f of n){const l=f.trim();if(l===""||l.startsWith(";"))continue;if(l.toUpperCase().startsWith(d.FJALL_DELEGATE)){const a=$(l);a&&r.push(a);continue}const p=R(l);if(p==="")continue;const u=j(p);if(u.length===0)continue;const h=u[0].toUpperCase();if(h===d.ORIGIN){if(u.length<2)continue;t=C(u[1]);continue}if(h===d.TTL){if(u.length<2)continue;s=parseInt(u[1],10);continue}if(h===d.FJALL_CERT){const a=S(u);a&&o.push(a);continue}const g=w(u);g&&i.push(g)}return t?A({origin:t,ttl:s,records:i,delegations:r,certificates:o}):I(new Error("Missing $ORIGIN directive"))}c(U,"parseZoneFile");function _(e,n){if(!e.startsWith("fjall:"))return;const t=e.split(":");if(t.length<3)return;const s=t[1],i=t[2],r=`${s}:${i}`;return n.get(r)??n.get(e)}c(_,"resolveAlias");export{U as parseZoneFile,_ as resolveAlias};
@@ -1,3 +1,3 @@
1
- var u=Object.defineProperty;var $=(t,n)=>u(t,"name",{value:n,configurable:!0});import{BIND_DIRECTIVES as i,ALIAS_PREFIX as l}from"./types.js";function f(t,n){return t.length>=n?t:t+" ".repeat(n-t.length)}$(f,"padRight");function p(t,n){const s=f(t.name,24),e=t.ttl!==void 0&&t.ttl!==n?`${t.ttl} `:"";switch(t.type){case"MX":return`${s} ${e}IN MX ${t.priority??10} ${t.value}`;case"SRV":return`${s} ${e}IN SRV ${t.priority??0} ${t.weight??0} ${t.port??0} ${t.value}`;case"TXT":return`${s} ${e}IN TXT "${t.value}"`;case"CAA":return`${s} ${e}IN CAA ${t.value}`;default:return t.type==="A"&&t.value.startsWith(l)?`${s} ${e}IN A ${t.value}`:`${s} ${e}IN ${t.type} ${t.value}`}}$(p,"formatRecord");function g(t){const n=[];if(n.push("; zone.bind \u2014 managed by fjall"),n.push(`${i.ORIGIN} ${t.origin}.`),n.push(`${i.TTL} ${t.ttl}`),n.push(""),t.certificates.length>0){for(const s of t.certificates){const a=[s.domainName,...s.subjectAlternativeNames];n.push(`${i.FJALL_CERT} ${a.join(" ")}`)}n.push("")}if(t.delegations.length>0){for(const s of t.delegations){const a=s.auto?" ; auto":"";n.push(`${i.FJALL_DELEGATE} ${s.subdomain} TO ${s.targetAccount}${a}`)}n.push("")}for(const s of t.records)n.push(p(s,t.ttl));return n.join(`
1
+ var u=Object.defineProperty;var i=(t,n)=>u(t,"name",{value:n,configurable:!0});import{BIND_DIRECTIVES as $}from"./types.js";function l(t,n){return t.length>=n?t:t+" ".repeat(n-t.length)}i(l,"padRight");function o(t,n){const s=l(t.name,24),e=t.ttl!==void 0&&t.ttl!==n?`${t.ttl} `:"";switch(t.type){case"MX":return`${s} ${e}IN MX ${t.priority??10} ${t.value}`;case"SRV":return`${s} ${e}IN SRV ${t.priority??0} ${t.weight??0} ${t.port??0} ${t.value}`;case"TXT":return`${s} ${e}IN TXT "${t.value}"`;case"CAA":return`${s} ${e}IN CAA ${t.value}`;default:return`${s} ${e}IN ${t.type} ${t.value}`}}i(o,"formatRecord");function h(t){const n=[];if(n.push("; zone.bind \u2014 managed by fjall"),n.push(`${$.ORIGIN} ${t.origin}.`),n.push(`${$.TTL} ${t.ttl}`),n.push(""),t.certificates.length>0){for(const s of t.certificates){const a=[s.domainName,...s.subjectAlternativeNames];n.push(`${$.FJALL_CERT} ${a.join(" ")}`)}n.push("")}if(t.delegations.length>0){for(const s of t.delegations){const a=s.auto?" ; auto":"";n.push(`${$.FJALL_DELEGATE} ${s.subdomain} TO ${s.targetAccount}${a}`)}n.push("")}for(const s of t.records)n.push(o(s,t.ttl));return n.join(`
2
2
  `)+`
3
- `}$(g,"generateZoneFile");export{g as generateZoneFile};
3
+ `}i(h,"generateZoneFile");export{h as generateZoneFile};
@@ -2,6 +2,7 @@ import { z } from "zod";
2
2
  export declare const TypedFjallTargetSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
3
3
  kind: z.ZodLiteral<"ecs">;
4
4
  appName: z.ZodString;
5
+ computeName: z.ZodOptional<z.ZodString>;
5
6
  }, z.core.$strict>, z.ZodObject<{
6
7
  kind: z.ZodLiteral<"cdn">;
7
8
  appName: z.ZodString;
@@ -65,6 +66,7 @@ export declare const ParsedAliasRecordSchema: z.ZodObject<{
65
66
  target: z.ZodDiscriminatedUnion<[z.ZodObject<{
66
67
  kind: z.ZodLiteral<"ecs">;
67
68
  appName: z.ZodString;
69
+ computeName: z.ZodOptional<z.ZodString>;
68
70
  }, z.core.$strict>, z.ZodObject<{
69
71
  kind: z.ZodLiteral<"cdn">;
70
72
  appName: z.ZodString;
@@ -102,6 +104,7 @@ export declare const ParsedDnsRecordSchema: z.ZodDiscriminatedUnion<[z.ZodObject
102
104
  target: z.ZodDiscriminatedUnion<[z.ZodObject<{
103
105
  kind: z.ZodLiteral<"ecs">;
104
106
  appName: z.ZodString;
107
+ computeName: z.ZodOptional<z.ZodString>;
105
108
  }, z.core.$strict>, z.ZodObject<{
106
109
  kind: z.ZodLiteral<"cdn">;
107
110
  appName: z.ZodString;
@@ -160,6 +163,7 @@ export declare const ParsedDomainRecordsSchema: z.ZodObject<{
160
163
  target: z.ZodDiscriminatedUnion<[z.ZodObject<{
161
164
  kind: z.ZodLiteral<"ecs">;
162
165
  appName: z.ZodString;
166
+ computeName: z.ZodOptional<z.ZodString>;
163
167
  }, z.core.$strict>, z.ZodObject<{
164
168
  kind: z.ZodLiteral<"cdn">;
165
169
  appName: z.ZodString;
@@ -1 +1 @@
1
- import{z as e}from"zod";const r=e.discriminatedUnion("kind",[e.object({kind:e.literal("ecs"),appName:e.string()}).strict(),e.object({kind:e.literal("cdn"),appName:e.string()}).strict(),e.object({kind:e.literal("bucket"),bucketName:e.string()}).strict(),e.object({kind:e.literal("custom"),dnsName:e.string(),hostedZoneId:e.string()}).strict()]),m=r.options.map(t=>t.shape.kind.value),a=e.enum(["A","AAAA"]),n=e.enum(["route53","external-delegated","external-records"]),g=e.enum(["zone","full"]),o=e.object({kind:e.literal("standard"),type:e.enum(["A","AAAA","CNAME","MX","TXT","NS","SRV","CAA"]),name:e.string(),value:e.union([e.string(),e.array(e.string())]),ttl:e.number().int().positive().optional()}).strict(),i=e.object({kind:e.literal("alias"),type:a,name:e.string(),target:r}).strict(),s=e.discriminatedUnion("kind",[o,i]),d=e.object({domainName:e.string(),subjectAlternativeNames:e.array(e.string()).optional(),transparencyLogging:e.boolean().optional(),cloudFront:e.boolean().optional()}).strict(),c=e.object({subdomain:e.string(),toAccount:e.string(),auto:e.boolean().optional()}).strict(),p=e.object({zoneName:e.string(),registrar:n,hostedZoneId:e.string().optional(),delegatedSubdomain:e.string().optional(),adoptedNameServers:e.array(e.string().min(1)).min(1).optional(),records:e.array(s),certificates:e.array(d),delegations:e.array(c)}).strict().refine(t=>t.registrar!=="external-delegated"||t.delegatedSubdomain!==void 0,{message:"external-delegated requires delegatedSubdomain"}).refine(t=>t.registrar!=="external-records"||t.delegations.length===0,{message:"external-records forbids delegations"}).refine(t=>t.registrar==="external-delegated"||t.adoptedNameServers===void 0,{message:"adoptedNameServers requires registrar external-delegated"}).refine(t=>t.registrar!=="external-delegated"||t.hostedZoneId===void 0==(t.adoptedNameServers===void 0),{message:"external-delegated adoption requires hostedZoneId and adoptedNameServers together (both-or-neither)"});export{a as AliasRecordTypeSchema,g as DomainDeployPhaseSchema,n as DomainRegistrarSchema,i as ParsedAliasRecordSchema,d as ParsedCertificateSchema,s as ParsedDnsRecordSchema,p as ParsedDomainRecordsSchema,o as ParsedStandardRecordSchema,c as ParsedSubdomainDelegationSchema,m as TYPED_FJALL_TARGET_KINDS,r as TypedFjallTargetSchema};
1
+ import{z as e}from"zod";const r=e.discriminatedUnion("kind",[e.object({kind:e.literal("ecs"),appName:e.string(),computeName:e.string().min(1).optional()}).strict(),e.object({kind:e.literal("cdn"),appName:e.string()}).strict(),e.object({kind:e.literal("bucket"),bucketName:e.string()}).strict(),e.object({kind:e.literal("custom"),dnsName:e.string(),hostedZoneId:e.string()}).strict()]),m=r.options.map(t=>t.shape.kind.value),a=e.enum(["A","AAAA"]),n=e.enum(["route53","external-delegated","external-records"]),g=e.enum(["zone","full"]),o=e.object({kind:e.literal("standard"),type:e.enum(["A","AAAA","CNAME","MX","TXT","NS","SRV","CAA"]),name:e.string(),value:e.union([e.string(),e.array(e.string())]),ttl:e.number().int().positive().optional()}).strict(),i=e.object({kind:e.literal("alias"),type:a,name:e.string(),target:r}).strict(),s=e.discriminatedUnion("kind",[o,i]),d=e.object({domainName:e.string(),subjectAlternativeNames:e.array(e.string()).optional(),transparencyLogging:e.boolean().optional(),cloudFront:e.boolean().optional()}).strict(),c=e.object({subdomain:e.string(),toAccount:e.string(),auto:e.boolean().optional()}).strict(),p=e.object({zoneName:e.string(),registrar:n,hostedZoneId:e.string().optional(),delegatedSubdomain:e.string().optional(),adoptedNameServers:e.array(e.string().min(1)).min(1).optional(),records:e.array(s),certificates:e.array(d),delegations:e.array(c)}).strict().refine(t=>t.registrar!=="external-delegated"||t.delegatedSubdomain!==void 0,{message:"external-delegated requires delegatedSubdomain"}).refine(t=>t.registrar!=="external-records"||t.delegations.length===0,{message:"external-records forbids delegations"}).refine(t=>t.registrar==="external-delegated"||t.adoptedNameServers===void 0,{message:"adoptedNameServers requires registrar external-delegated"}).refine(t=>t.registrar!=="external-delegated"||t.hostedZoneId===void 0==(t.adoptedNameServers===void 0),{message:"external-delegated adoption requires hostedZoneId and adoptedNameServers together (both-or-neither)"});export{a as AliasRecordTypeSchema,g as DomainDeployPhaseSchema,n as DomainRegistrarSchema,i as ParsedAliasRecordSchema,d as ParsedCertificateSchema,s as ParsedDnsRecordSchema,p as ParsedDomainRecordsSchema,o as ParsedStandardRecordSchema,c as ParsedSubdomainDelegationSchema,m as TYPED_FJALL_TARGET_KINDS,r as TypedFjallTargetSchema};
@@ -3,6 +3,7 @@
3
3
  *
4
4
  * Shared helper functions used across all generation modules.
5
5
  */
6
+ import type { ProjectedProp } from "../projection/types.js";
6
7
  import type { IdentifierValue, ExpressionValue, CallValue, SpecialValue } from "../schemas/resourceSchemas.js";
7
8
  export type { IdentifierValue, ExpressionValue, CallValue, SpecialValue };
8
9
  export { toPascalCase, toKebab, toValidDatabaseName } from "@fjall/util";
@@ -76,6 +77,12 @@ export declare function resolveResourceVariable(plan: {
76
77
  * Simple objects (few primitive values) are kept on one line.
77
78
  */
78
79
  export declare function formatValue(value: unknown, baseIndent?: string): string;
80
+ /**
81
+ * Render projected construct props as the body of an object literal —
82
+ * `\n<indent>key: value` per prop, comma-separated, no trailing comma. The
83
+ * caller supplies the surrounding braces and whatever it appends after.
84
+ */
85
+ export declare function emitProjectedProps(props: ReadonlyArray<ProjectedProp>, indent?: string): string;
79
86
  type PropertyFormat = "raw" | "string" | "object" | "boolean-or-object";
80
87
  /**
81
88
  * Build a property string for code generation.
@@ -1,7 +1,8 @@
1
- var b=Object.defineProperty;var n=(r,e)=>b(r,"name",{value:e,configurable:!0});import{toPascalCase as O,toKebab as T,toValidDatabaseName as h}from"@fjall/util";function c(r){return JSON.stringify(r)}n(c,"escapeStringLiteral");function y(r){return r.map(c).join(", ")}n(y,"formatStringArray");const u="import:SharedAlarmTopicArn";function _(r=" "){return`
2
- ${r}...(getConfig().environment === "production" ? { alertsTopic: ${c(u)} } : {}),`}n(_,"emitProductionAlertsTopicSpread");function l(r){if(typeof r!="object"||r===null)return!1;const e=r;return typeof e.__identifier=="string"||typeof e.__expression=="string"||typeof e.__call=="string"}n(l,"isSpecialValue");function p(r){return r.replace(/[^a-zA-Z0-9]/g," ").split(" ").map((e,t)=>t===0?e.charAt(0).toLowerCase()+e.slice(1):e.charAt(0).toUpperCase()+e.slice(1)).join("")}n(p,"toVariableName");function x(r){return r.variableName??p(r.name)}n(x,"getVariableName");function $(r,e){for(const t of r.database)if(t.name===e&&t.variableName)return t.variableName;for(const t of r.s3)if(t.name===e&&t.variableName)return t.variableName;for(const t of r.compute)if(t.name===e&&t.variableName)return t.variableName;for(const t of r.dynamodb??[])if(t.name===e&&t.variableName)return t.variableName;for(const t of r.sqs??[])if(t.name===e&&t.variableName)return t.variableName;return p(e)}n($,"resolveResourceVariable");function d(r){const e=Object.entries(r);return e.length===0?!0:e.length>1?!1:e.every(([,t])=>typeof t=="string"||typeof t=="number"||typeof t=="boolean"||t===null)}n(d,"isSimpleObject");function f(r,e=" "){if(r==null)return"undefined";if(typeof r=="string")return JSON.stringify(r);if(typeof r=="number"||typeof r=="boolean")return String(r);if(l(r)){if("__identifier"in r)return r.__identifier;if("__expression"in r)return r.__expression;if("__call"in r)return r.__call}if(Array.isArray(r))return`[${r.map(t=>f(t,e)).join(", ")}]`;if(typeof r=="object"){const t=Object.entries(r).filter(([,o])=>o!==void 0);if(d(r)){const o=t.map(([s,m])=>`${s}: ${f(m,e)}`).join(", ");return o?`{ ${o} }`:"{}"}const a=e+" ",i=t.map(([o,s])=>`${a}${o}: ${f(s,a)}`).join(`,
1
+ var u=Object.defineProperty;var n=(e,t)=>u(e,"name",{value:t,configurable:!0});import{toPascalCase as P,toKebab as T,toValidDatabaseName as h}from"@fjall/util";function c(e){return JSON.stringify(e)}n(c,"escapeStringLiteral");function g(e){return e.map(c).join(", ")}n(g,"formatStringArray");const b="import:SharedAlarmTopicArn";function _(e=" "){return`
2
+ ${e}...(getConfig().environment === "production" ? { alertsTopic: ${c(b)} } : {}),`}n(_,"emitProductionAlertsTopicSpread");function l(e){if(typeof e!="object"||e===null)return!1;const t=e;return typeof t.__identifier=="string"||typeof t.__expression=="string"||typeof t.__call=="string"}n(l,"isSpecialValue");function m(e){return e.replace(/[^a-zA-Z0-9]/g," ").split(" ").map((t,r)=>r===0?t.charAt(0).toLowerCase()+t.slice(1):t.charAt(0).toUpperCase()+t.slice(1)).join("")}n(m,"toVariableName");function $(e){return e.variableName??m(e.name)}n($,"getVariableName");function x(e,t){for(const r of e.database)if(r.name===t&&r.variableName)return r.variableName;for(const r of e.s3)if(r.name===t&&r.variableName)return r.variableName;for(const r of e.compute)if(r.name===t&&r.variableName)return r.variableName;for(const r of e.dynamodb??[])if(r.name===t&&r.variableName)return r.variableName;for(const r of e.sqs??[])if(r.name===t&&r.variableName)return r.variableName;return m(t)}n(x,"resolveResourceVariable");function d(e){const t=Object.entries(e);return t.length===0?!0:t.length>1?!1:t.every(([,r])=>typeof r=="string"||typeof r=="number"||typeof r=="boolean"||r===null)}n(d,"isSimpleObject");function f(e,t=" "){if(e==null)return"undefined";if(typeof e=="string")return JSON.stringify(e);if(typeof e=="number"||typeof e=="boolean")return String(e);if(l(e)){if("__identifier"in e)return e.__identifier;if("__expression"in e)return e.__expression;if("__call"in e)return e.__call}if(Array.isArray(e))return`[${e.map(r=>f(r,t)).join(", ")}]`;if(typeof e=="object"){const r=Object.entries(e).filter(([,a])=>a!==void 0);if(d(e)){const a=r.map(([s,p])=>`${s}: ${f(p,t)}`).join(", ");return a?`{ ${a} }`:"{}"}const o=t+" ",i=r.map(([a,s])=>`${o}${a}: ${f(s,o)}`).join(`,
3
3
  `);return i?`{
4
4
  ${i}
5
- ${e}}`:"{}"}return JSON.stringify(r)}n(f,"formatValue");function j(r,e,t,a="raw"){if(!r)return"";let i;switch(a){case"string":i=c(String(t));break;case"object":i=f(t);break;case"boolean-or-object":i=t===!1?"false":f(t);break;default:i=String(t)}return`
6
- ${e}: ${i},`}n(j,"buildProperty");function N(r,e=" "){return r?.length?r.map(t=>`
7
- ${e}${t.key}: ${t.sourceText},`).join(""):""}n(N,"emitExtraProperties");export{u as PRODUCTION_ALERTS_TOPIC_IMPORT,j as buildProperty,N as emitExtraProperties,_ as emitProductionAlertsTopicSpread,c as escapeStringLiteral,y as formatStringArray,f as formatValue,x as getVariableName,l as isSpecialValue,$ as resolveResourceVariable,T as toKebab,O as toPascalCase,h as toValidDatabaseName,p as toVariableName};
5
+ ${t}}`:"{}"}return JSON.stringify(e)}n(f,"formatValue");function j(e,t=" "){return e.map(r=>{const o=r.value.kind==="expression"?r.value.source:f(r.value.value,t);return`
6
+ ${t}${r.key}: ${o}`}).join(",")}n(j,"emitProjectedProps");function N(e,t,r,o="raw"){if(!e)return"";let i;switch(o){case"string":i=c(String(r));break;case"object":i=f(r);break;case"boolean-or-object":i=r===!1?"false":f(r);break;default:i=String(r)}return`
7
+ ${t}: ${i},`}n(N,"buildProperty");function S(e,t=" "){return e?.length?e.map(r=>`
8
+ ${t}${r.key}: ${r.sourceText},`).join(""):""}n(S,"emitExtraProperties");export{b as PRODUCTION_ALERTS_TOPIC_IMPORT,N as buildProperty,S as emitExtraProperties,_ as emitProductionAlertsTopicSpread,j as emitProjectedProps,c as escapeStringLiteral,g as formatStringArray,f as formatValue,$ as getVariableName,l as isSpecialValue,x as resolveResourceVariable,T as toKebab,P as toPascalCase,h as toValidDatabaseName,m as toVariableName};
@@ -1,50 +1,44 @@
1
- var g=Object.defineProperty;var s=(e,t)=>g(e,"name",{value:t,configurable:!0});import{buildProperty as o,getVariableName as u,emitExtraProperties as l,emitProductionAlertsTopicSpread as $,escapeStringLiteral as r}from"./common.js";function b(e){let t="";return t+=o(e.bucketName!==void 0,"bucketName",e.bucketName,"string"),t+=o(e.stackPlacement!==void 0&&e.stackPlacement!=="storage","stackPlacement",e.stackPlacement,"string"),t+=o(e.publicReadAccess===!0,"publicReadAccess",!0),t+=o(e.websiteHosting!==void 0,"websiteHosting",e.websiteHosting,"object"),t+=o(e.backupVaultTier!==void 0,"backupVaultTier",e.backupVaultTier,"string"),t+=o(e.versioned!==void 0,"versioned",e.versioned),t+=o(e.encryption!==void 0,"encryption",e.encryption,"string"),t+=o(e.kmsKeyArn!==void 0,"kmsKeyArn",e.kmsKeyArn,"string"),t+=o(e.cors!==void 0&&e.cors.length>0,"cors",e.cors,"object"),t+=o(e.deployment!==void 0,"deployment",e.deployment,"object"),t+=o(e.retain===!0,"retain",!0),t}s(b,"generateS3BucketProps");function x(e,t){return!!(t.compute.some(i=>i.connectedStorage?.includes(e.name))||t.cdn&&(t.cdn.defaultOriginRef===e.name||t.cdn.behaviours?.some(i=>i.originRef===e.name)))}s(x,"s3NeedsVariable");function h(e){if(e.s3.length===0)return"";let t="";for(let n=0;n<e.s3.length;n++){const i=e.s3[n],d=u(i),a=x(i,e),m=e.database.length>0||n>0?`
2
- `:"",y=b(i),f=a?`const ${d} = `:"",p=l(i.extraProperties);y||p?t+=`${m}${f}app.addStorage(
3
- StorageFactory.build(${r(i.name)}, {${y}${p}
1
+ var g=Object.defineProperty;var s=(e,t)=>g(e,"name",{value:t,configurable:!0});import{projectPlanToConstructProps as $}from"../projection/index.js";import{buildProperty as i,getVariableName as m,emitExtraProperties as u,emitProductionAlertsTopicSpread as b,emitProjectedProps as P,escapeStringLiteral as o}from"./common.js";function x(e){let t="";return t+=i(e.bucketName!==void 0,"bucketName",e.bucketName,"string"),t+=i(e.stackPlacement!==void 0&&e.stackPlacement!=="storage","stackPlacement",e.stackPlacement,"string"),t+=i(e.publicReadAccess===!0,"publicReadAccess",!0),t+=i(e.websiteHosting!==void 0,"websiteHosting",e.websiteHosting,"object"),t+=i(e.backupVaultTier!==void 0,"backupVaultTier",e.backupVaultTier,"string"),t+=i(e.versioned!==void 0,"versioned",e.versioned),t+=i(e.encryption!==void 0,"encryption",e.encryption,"string"),t+=i(e.kmsKeyArn!==void 0,"kmsKeyArn",e.kmsKeyArn,"string"),t+=i(e.cors!==void 0&&e.cors.length>0,"cors",e.cors,"object"),t+=i(e.deployment!==void 0,"deployment",e.deployment,"object"),t+=i(e.retain===!0,"retain",!0),t}s(x,"generateS3BucketProps");function K(e,t){return!!(t.compute.some(r=>r.connectedStorage?.includes(e.name))||t.cdn&&(t.cdn.defaultOriginRef===e.name||t.cdn.behaviours?.some(r=>r.originRef===e.name)))}s(K,"s3NeedsVariable");function R(e){if(e.s3.length===0)return"";let t="";for(let n=0;n<e.s3.length;n++){const r=e.s3[n],c=m(r),a=K(r,e),l=e.database.length>0||n>0?`
2
+ `:"",p=x(r),y=a?`const ${c} = `:"",f=u(r.extraProperties);p||f?t+=`${l}${y}app.addStorage(
3
+ StorageFactory.build(${o(r.name)}, {${p}${f}
4
4
  })
5
5
  );
6
- `:t+=`${m}${f}app.addStorage(
7
- StorageFactory.build(${r(i.name)}, {})
6
+ `:t+=`${l}${y}app.addStorage(
7
+ StorageFactory.build(${o(r.name)}, {})
8
8
  );
9
- `}return t}s(h,"generateS3Code");function N(e){if(!e.dynamodb||e.dynamodb.length===0)return"";let t="";for(const n of e.dynamodb){const i=u(n);if(t+=`
10
- const ${i} = app.addDatabase(
11
- DatabaseFactory.build(${r(n.name)}, {
9
+ `}return t}s(R,"generateS3Code");function T(e){if(!e.dynamodb||e.dynamodb.length===0)return"";let t="";for(const n of e.dynamodb){const r=m(n);if(t+=`
10
+ const ${r} = app.addDatabase(
11
+ DatabaseFactory.build(${o(n.name)}, {
12
12
  type: "DynamoDB",
13
13
  partitionKey: {
14
- name: ${r(n.partitionKey.name)},
15
- type: ${r(n.partitionKey.type)},
14
+ name: ${o(n.partitionKey.name)},
15
+ type: ${o(n.partitionKey.type)},
16
16
  }`,n.sortKey&&(t+=`,
17
17
  sortKey: {
18
- name: ${r(n.sortKey.name)},
19
- type: ${r(n.sortKey.type)},
20
- }`),n.globalSecondaryIndexes&&n.globalSecondaryIndexes.length>0){const d=n.globalSecondaryIndexes.map(a=>{let c=`{
21
- indexName: ${r(a.indexName)},
18
+ name: ${o(n.sortKey.name)},
19
+ type: ${o(n.sortKey.type)},
20
+ }`),n.globalSecondaryIndexes&&n.globalSecondaryIndexes.length>0){const c=n.globalSecondaryIndexes.map(a=>{let d=`{
21
+ indexName: ${o(a.indexName)},
22
22
  partitionKey: {
23
- name: ${r(a.partitionKey.name)},
24
- type: ${r(a.partitionKey.type)},
25
- },`;return a.sortKey&&(c+=`
23
+ name: ${o(a.partitionKey.name)},
24
+ type: ${o(a.partitionKey.type)},
25
+ },`;return a.sortKey&&(d+=`
26
26
  sortKey: {
27
- name: ${r(a.sortKey.name)},
28
- type: ${r(a.sortKey.type)},
29
- },`),c+=`
30
- }`,c}).join(`,
27
+ name: ${o(a.sortKey.name)},
28
+ type: ${o(a.sortKey.type)},
29
+ },`),d+=`
30
+ }`,d}).join(`,
31
31
  `);t+=`,
32
32
  globalSecondaryIndexes: [
33
- ${d}
33
+ ${c}
34
34
  ]`}n.ttlAttribute&&(t+=`,
35
- ttlAttribute: ${r(n.ttlAttribute)}`),n.stream&&(t+=`,
36
- stream: true`),t+=l(n.extraProperties),t+=`
35
+ ttlAttribute: ${o(n.ttlAttribute)}`),n.stream&&(t+=`,
36
+ stream: true`),t+=u(n.extraProperties),t+=`
37
37
  })
38
38
  );
39
- `}return t}s(N,"generateDynamoDBCode");function P(e,t){return t.compute.some(n=>n.connectedMessaging?.includes(e.name))}s(P,"sqsNeedsVariable");function v(e){if(!e.sqs||e.sqs.length===0)return"";let t="";for(const n of e.sqs){const i=u(n),a=P(n,e)?`const ${i} = `:"";t+=`
39
+ `}return t}s(T,"generateDynamoDBCode");function S(e,t){return t.compute.some(n=>n.connectedMessaging?.includes(e.name))}s(S,"sqsNeedsVariable");function V(e){if(!e.sqs||e.sqs.length===0)return"";let t="";for(const n of e.sqs){const r=m(n),a=S(n,e)?`const ${r} = `:"",{props:d}=$("messaging",{queueType:n.queueType,visibilityTimeout:n.visibilityTimeout,retentionPeriod:n.retentionPeriod,...n.contentBasedDeduplication===!0&&{contentBasedDeduplication:!0},removalPolicy:n.removalPolicy});t+=`
40
40
  ${a}app.addMessaging(
41
- MessagingFactory.build(${r(n.name)}, {
42
- type: "queue",
43
- queueType: ${r(n.queueType)}`,n.visibilityTimeout!==void 0&&(t+=`,
44
- visibilityTimeout: ${n.visibilityTimeout}`),n.retentionPeriod!==void 0&&(t+=`,
45
- messageRetentionPeriod: ${n.retentionPeriod}`),n.contentBasedDeduplication&&(t+=`,
46
- contentBasedDeduplication: true`),n.removalPolicy!==void 0&&(t+=`,
47
- removalPolicy: ${r(n.removalPolicy)}`),t+=",",t+=l(n.extraProperties),t+=$(),t+=`
41
+ MessagingFactory.build(${o(n.name)}, {${P(d)}`,t+=",",t+=u(n.extraProperties),t+=b(),t+=`
48
42
  })
49
43
  );
50
- `}return t}s(v,"generateSQSCode");export{N as generateDynamoDBCode,h as generateS3Code,v as generateSQSCode,x as s3NeedsVariable,P as sqsNeedsVariable};
44
+ `}return t}s(V,"generateSQSCode");export{T as generateDynamoDBCode,R as generateS3Code,V as generateSQSCode,K as s3NeedsVariable,S as sqsNeedsVariable};
@@ -1,4 +1,4 @@
1
- export { planApplicationResources, toUserServiceConfigs, type GenerationOptions, generateInfrastructureFromPlan, } from "./resourcePlanning.js";
1
+ export { planApplicationResources, planServiceFromTierPreset, toUserServiceConfigs, type GenerationOptions, generateInfrastructureFromPlan, } from "./resourcePlanning.js";
2
2
  export { type OpenNextResourceOptions, planOpenNextResources, } from "./openNextPlanning.js";
3
3
  export { type StaticSiteResourceOptions, planStaticSiteResources, } from "./staticSitePlanning.js";
4
4
  export { type ConnectionType, applyComputeConnections, applyServiceConnections, } from "./resourceConnections.js";
@@ -1 +1 @@
1
- import{planApplicationResources as r,toUserServiceConfigs as t,generateInfrastructureFromPlan as n}from"./resourcePlanning.js";import{planOpenNextResources as p}from"./openNextPlanning.js";import{planStaticSiteResources as c}from"./staticSitePlanning.js";import{applyComputeConnections as l,applyServiceConnections as u}from"./resourceConnections.js";import{addResourceToPlan as m,validateResourceAddition as x,listAvailableResources as R}from"./resourceAddition.js";import{generateResourceChange as C}from"./generateResourceChange.js";export{m as addResourceToPlan,l as applyComputeConnections,u as applyServiceConnections,n as generateInfrastructureFromPlan,C as generateResourceChange,R as listAvailableResources,r as planApplicationResources,p as planOpenNextResources,c as planStaticSiteResources,t as toUserServiceConfigs,x as validateResourceAddition};
1
+ import{planApplicationResources as o,planServiceFromTierPreset as t,toUserServiceConfigs as n,generateInfrastructureFromPlan as a}from"./resourcePlanning.js";import{planOpenNextResources as s}from"./openNextPlanning.js";import{planStaticSiteResources as c}from"./staticSitePlanning.js";import{applyComputeConnections as u,applyServiceConnections as m}from"./resourceConnections.js";import{addResourceToPlan as x,validateResourceAddition as R,listAvailableResources as d}from"./resourceAddition.js";import{generateResourceChange as C}from"./generateResourceChange.js";export{x as addResourceToPlan,u as applyComputeConnections,m as applyServiceConnections,a as generateInfrastructureFromPlan,C as generateResourceChange,d as listAvailableResources,o as planApplicationResources,s as planOpenNextResources,t as planServiceFromTierPreset,c as planStaticSiteResources,n as toUserServiceConfigs,R as validateResourceAddition};
@@ -1,6 +1,6 @@
1
- import { type UserServiceConfig, type AppType } from "../presets/tierPresets.js";
1
+ import { type TierEcsServiceConfig, type UserServiceConfig, type AppType } from "../presets/tierPresets.js";
2
2
  import { type Result } from "../types/Result.js";
3
- import type { ApplicationResourcePlan } from "../schemas/resourceSchemas.js";
3
+ import type { ApplicationResourcePlan, EcsServiceConfig } from "../schemas/resourceSchemas.js";
4
4
  import type { ApplicationServiceConfig } from "../schemas/computeSchemas.js";
5
5
  /**
6
6
  * Adapt the wire-level service config (`ApplicationServiceConfig`, validated by
@@ -14,6 +14,18 @@ export declare function planApplicationResources(appName: string, appType: AppTy
14
14
  snapshotIdentifier?: string;
15
15
  snapshotUsername?: string;
16
16
  }): ApplicationResourcePlan;
17
+ /**
18
+ * The one translation from a tier preset's service entry to the plan shape.
19
+ *
20
+ * The two differ in exactly one place: the preset carries `minCapacity` /
21
+ * `maxCapacity` flat, the plan nests them under `scaling`. Every other key
22
+ * passes through, so a new preset field reaches the plan without touching this
23
+ * function. Exported because anything deriving a plan from a tier — the app
24
+ * planner below, the dogfood deploy-test suites — must apply the same rule, and
25
+ * a second copy of it would drift silently: an unnested `minCapacity` is an
26
+ * excess property the plan schema rejects only at parse time.
27
+ */
28
+ export declare function planServiceFromTierPreset(tierService: TierEcsServiceConfig): EcsServiceConfig;
17
29
  export interface GenerationOptions {
18
30
  /** Resource name mapping from old names to new names (for custom code repositioning) */
19
31
  resourceMapping?: Map<string, string>;
@@ -1 +1 @@
1
- var b=Object.defineProperty;var a=(e,n)=>b(e,"name",{value:n,configurable:!0});import{TIER_PRESETS as l,getDefaultDatabaseTypeForTier as k,applyTierDefaultsToServices as P}from"../presets/tierPresets.js";import{COMPUTE_TYPE as D,DEFAULT_CONTAINER_PORT as T}from"../schemas/constants.js";import{success as f,failure as h}from"../types/Result.js";import{injectCustomCodeBlocks as p}from"../ast/mutation/astCodeInjection.js";import{toVariableName as m,toValidDatabaseName as v,generateImports as E,generateAppInit as R,generateTags as S,generateNetworkCode as C,generateDatabaseCode as y,generateClickHouseCode as I,generateS3Code as w,generateDynamoDBCode as A,generateSQSCode as B,generateComputeCode as U,generateCDNCode as x,collectCdnReferencedResources as j,usesPatternApproach as _,generatePatternCodeWithComments as $}from"../generation/index.js";function G(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}}))}a(G,"toUserServiceConfigs");function J(e,n,r=!0,c,t){const i={appName:e,type:n,database:[],s3:[],compute:[]};if(n==="custom")return i;const s=n,o=l[s];return{...i,database:F(e,o,s,r,t),compute:V(e,o,s,r,c),network:o.network,backup:o.backup}}a(J,"planApplicationResources");function F(e,n,r,c,t){const i=k(r),s=n.database[i];return!c||s===null?[]:[{name:e,type:i,databaseName:v(e),variableName:`${m(e)}Database`,...s,...t?.snapshotIdentifier!==void 0&&{snapshotIdentifier:t.snapshotIdentifier},...t?.snapshotUsername!==void 0&&{snapshotUsername:t.snapshotUsername}}]}a(F,"buildDatabasePlan");function N(e,n){if(!(e===void 0&&n===void 0))return{scaling:{...e!==void 0&&{minCapacity:e},...n!==void 0&&{maxCapacity:n}}}}a(N,"buildScalingConfig");function H(e,n){const{minCapacity:r,maxCapacity:c,...t}=e,i=n?.serviceType==="worker",s=n?.containerPort??T,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}],...N(r,c)}}a(H,"buildServiceEntry");function M(e,n){return n||e?.directAccess===!0?e:{...e,loadBalancer:!1}}a(M,"resolveClusterConfig");function V(e,n,r,c,t){const i=n.compute.ecs,o=(t&&t.length>0?P(r,t):i.services.map((u,d)=>({...u,name:d===0?"api":`service-${d+1}`}))).map((u,d)=>H(u,t?.[d])),g=o.some(u=>u.containers?.some(d=>d.port!==void 0));return[{name:e,type:D.ECS,needsConnection:c,connectedDatabase:c?[e]:void 0,variableName:`${m(e)}Compute`,cluster:M(i.cluster,g),services:o}]}a(V,"buildComputePlan");function K(e,n){const r=[E(e),R(e),S(e)];if(_(e))r.push($(e),C(e));else{const t=j(e);r.push(C(e),y(e),I(e),w(e),A(e),B(e),U(e,t),x(e))}const c=r.join("");if(e.customCodeBlocks&&e.customCodeBlocks.length>0){const t=p(c,e.customCodeBlocks,n?.resourceMapping);return t.success?f(t.content):h(new Error(`Custom code injection failed: ${t.error??"unknown error"}`))}return f(c)}a(K,"generateInfrastructureFromPlan");export{K as generateInfrastructureFromPlan,J as planApplicationResources,G as toUserServiceConfigs};
1
+ var b=Object.defineProperty;var i=(e,n)=>b(e,"name",{value:n,configurable:!0});import{TIER_PRESETS as l,getDefaultDatabaseTypeForTier as P,applyTierDefaultsToServices as k}from"../presets/tierPresets.js";import{COMPUTE_TYPE as D,DEFAULT_CONTAINER_PORT as T}from"../schemas/constants.js";import{success as f,failure as h}from"../types/Result.js";import{injectCustomCodeBlocks as p}from"../ast/mutation/astCodeInjection.js";import{toVariableName as m,toValidDatabaseName as v,generateImports as S,generateAppInit as E,generateTags as R,generateNetworkCode as C,generateDatabaseCode as y,generateClickHouseCode as I,generateS3Code as w,generateDynamoDBCode as x,generateSQSCode as A,generateComputeCode as B,generateCDNCode as U,collectCdnReferencedResources as j,usesPatternApproach as F,generatePatternCodeWithComments as _}from"../generation/index.js";function J(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}}))}i(J,"toUserServiceConfigs");function K(e,n,r=!0,c,t){const o={appName:e,type:n,database:[],s3:[],compute:[]};if(n==="custom")return o;const s=n,a=l[s];return{...o,database:$(e,a,s,r,t),compute:W(e,a,s,r,c),network:a.network,backup:a.backup}}i(K,"planApplicationResources");function $(e,n,r,c,t){const o=P(r),s=n.database[o];return!c||s===null?[]:[{name:e,type:o,databaseName:v(e),variableName:`${m(e)}Database`,...s,...t?.snapshotIdentifier!==void 0&&{snapshotIdentifier:t.snapshotIdentifier},...t?.snapshotUsername!==void 0&&{snapshotUsername:t.snapshotUsername}}]}i($,"buildDatabasePlan");function N(e,n){if(!(e===void 0&&n===void 0))return{scaling:{...e!==void 0&&{minCapacity:e},...n!==void 0&&{maxCapacity:n}}}}i(N,"buildScalingConfig");function H(e){const{minCapacity:n,maxCapacity:r,...c}=e;return{...c,...N(n,r)}}i(H,"planServiceFromTierPreset");function M(e,n){const r=H(e),c=n?.serviceType==="worker",t=n?.containerPort??T,o=n?.docker;return{...r,...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:c?[{}]:[{port:t}]}}i(M,"buildServiceEntry");function V(e,n){return n||e?.directAccess===!0?e:{...e,loadBalancer:!1}}i(V,"resolveClusterConfig");function W(e,n,r,c,t){const o=n.compute.ecs,a=(t&&t.length>0?k(r,t):o.services.map((u,d)=>({...u,name:d===0?"api":`service-${d+1}`}))).map((u,d)=>M(u,t?.[d])),g=a.some(u=>u.containers?.some(d=>d.port!==void 0));return[{name:e,type:D.ECS,needsConnection:c,connectedDatabase:c?[e]:void 0,variableName:`${m(e)}Compute`,cluster:V(o.cluster,g),services:a}]}i(W,"buildComputePlan");function O(e,n){const r=[S(e),E(e),R(e)];if(F(e))r.push(_(e),C(e));else{const t=j(e);r.push(C(e),y(e),I(e),w(e),x(e),A(e),B(e,t),U(e))}const c=r.join("");if(e.customCodeBlocks&&e.customCodeBlocks.length>0){const t=p(c,e.customCodeBlocks,n?.resourceMapping);return t.success?f(t.content):h(new Error(`Custom code injection failed: ${t.error??"unknown error"}`))}return f(c)}i(O,"generateInfrastructureFromPlan");export{O as generateInfrastructureFromPlan,K as planApplicationResources,H as planServiceFromTierPreset,J as toUserServiceConfigs};
@@ -0,0 +1,3 @@
1
+ export { projectPlanToConstructProps } from "./project.js";
2
+ export { isProjectableType, TYPE_PROJECTIONS, type ProjectableType, } from "./tables.js";
3
+ export type { PlanKeyRule, Projection, ProjectionContext, ProjectedProp, ProjectedValue, TypeProjection, UnprojectableProp, } from "./types.js";
@@ -0,0 +1 @@
1
+ import{projectPlanToConstructProps as e}from"./project.js";import{isProjectableType as p,TYPE_PROJECTIONS as P}from"./tables.js";export{P as TYPE_PROJECTIONS,p as isProjectableType,e as projectPlanToConstructProps};
@@ -0,0 +1,22 @@
1
+ import { type ProjectableType } from "./tables.js";
2
+ import type { Projection, ProjectionContext } from "./types.js";
3
+ /**
4
+ * Project a resource-plan fragment onto its construct's props.
5
+ *
6
+ * Keys with no rule pass through under their own name — the two vocabularies
7
+ * agree far more often than they disagree, and enumerating the agreements
8
+ * would be a second inventory to keep in step with the schemas.
9
+ *
10
+ * `undefined` values are skipped rather than emitted: a construct prop
11
+ * explicitly set to `undefined` is not the same as an absent one for a
12
+ * `.strict()` Zod props schema, and the plan's optional keys arrive as
13
+ * `undefined` routinely.
14
+ *
15
+ * A fragment key landing on a constant's construct key REPLACES it, in the
16
+ * constant's position. Constants exist to supply what the plan vocabulary
17
+ * cannot say; a caller who says it anyway (a hand-written `type: "queue"`,
18
+ * a round-tripped statement) is not disagreeing with the projection, and
19
+ * emitting the key twice would be a syntax-level duplicate that the last
20
+ * writer silently wins.
21
+ */
22
+ export declare function projectPlanToConstructProps(type: ProjectableType, fragment: Readonly<Record<string, unknown>>, context?: ProjectionContext): Projection;
@@ -0,0 +1 @@
1
+ var k=Object.defineProperty;var f=(o,s)=>k(o,"name",{value:s,configurable:!0});import{TYPE_PROJECTIONS as y}from"./tables.js";function O(o,s,r={}){const u=y[o],l=r.editingExisting===!0?[]:u.constants??[],t=new Map(l.map(n=>[n.key,n])),i=[];for(const[n,c]of Object.entries(s)){if(c===void 0)continue;const e=u.keys?.[n];if(e===void 0||e.kind==="prop"){const d=e?.as??n;t.set(d,{key:d,value:{kind:"literal",value:c}});continue}if(e.kind==="planOnly"){i.push({key:n,reason:e.reason});continue}const a=e.bind(c,r);if(a===void 0){i.push({key:n,reason:e.reason});continue}const p=e.as??n;t.set(p,{key:p,value:{kind:"expression",source:a}})}return{props:[...t.values()],unprojectable:i}}f(O,"projectPlanToConstructProps");export{O as projectPlanToConstructProps};
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Per-type plan→construct projections.
3
+ *
4
+ * Every entry here was, before this module, a `silentlyDropped` /
5
+ * `requiresLiveValue` rule in `codemod/registry.ts` describing a translation
6
+ * the scaffold generator performed and the codemod could not. The reasons are
7
+ * carried over verbatim where they still apply, because they record what was
8
+ * actually observed to happen at synth — not what the vocabulary suggests.
9
+ *
10
+ * Two plan keys recur on nearly every type and are declared once:
11
+ * `variableName` (the `const <var> =` binding the scaffold emits) and
12
+ * `extraProperties` (round-trip preservation the scaffold flattens into
13
+ * sibling properties). Neither is a construct prop anywhere.
14
+ *
15
+ * `compute`, `cdn`, `pattern` and `vpc-peer` are deliberately ABSENT. Their
16
+ * disagreements are not renames: a CDN origin needs the live `IBucket` or
17
+ * load balancer its sibling resource became, and a compute's four connection
18
+ * keys expand into environment variables plus a whole second statement
19
+ * (`app.addSchedule(...)`). Both need a projection that can carry bindings
20
+ * and emit more than one statement, which is the next increment; until then
21
+ * they keep their `emitGuard` tables and a type is projected or guarded,
22
+ * never both.
23
+ */
24
+ import type { TypeProjection } from "./types.js";
25
+ export declare const TYPE_PROJECTIONS: {
26
+ readonly messaging: TypeProjection;
27
+ readonly storage: TypeProjection;
28
+ readonly database: TypeProjection;
29
+ readonly network: TypeProjection;
30
+ };
31
+ export type ProjectableType = keyof typeof TYPE_PROJECTIONS;
32
+ export declare function isProjectableType(value: string): value is ProjectableType;
@@ -0,0 +1 @@
1
+ var s=Object.defineProperty;var a=(n,t)=>s(n,"name",{value:t,configurable:!0});const r={kind:"planOnly",reason:"`variableName` is a plan-only round-trip key naming the `const <var> =` binding the scaffold emits; no construct reads it."},o={kind:"planOnly",reason:"`extraProperties` is a plan-only round-trip key: the scaffold flattens each `{ key, sourceText }` entry into a sibling property, and no construct reads the array."},e={variableName:r,extraProperties:o},i={constants:[{key:"type",value:{kind:"literal",value:"queue"}}],keys:{retentionPeriod:{kind:"prop",as:"messageRetentionPeriod"},...e}},l={keys:{...e}},p={keys:{engineExpression:{kind:"planOnly",reason:"`engineExpression` carries a raw CDK engine expression for the scaffold to inline; the construct reads `databaseEngine` instead, so a cluster pinned to `DatabaseClusterEngine.auroraMysql(...)` still deploys as aurora-postgresql."},...e}},c={keys:{...e}},y={messaging:i,storage:l,database:p,network:c};function u(n){return Object.prototype.hasOwnProperty.call(y,n)}a(u,"isProjectableType");export{y as TYPE_PROJECTIONS,u as isProjectableType};
@@ -0,0 +1,108 @@
1
+ /**
2
+ * The plan→construct projection vocabulary.
3
+ *
4
+ * A resource PLAN and a CDK construct's PROPS are two different vocabularies
5
+ * for the same resource. They agree on most keys and disagree on a handful,
6
+ * and every disagreement has been, until now, encoded twice: once in the
7
+ * scaffold generator (which translates on the way out) and once in the
8
+ * codemod's `emitGuard` tables (which refuse what they cannot translate).
9
+ * Two encodings of one fact is drift waiting to happen — and it happened, in
10
+ * the direction that hurts: the guards are what stop `fjall add messaging`
11
+ * and `fjall add cdn` working at all.
12
+ *
13
+ * This module is that encoding, and the codemod reads it for every type in
14
+ * TYPE_PROJECTIONS. The scaffold does NOT yet, except for `messaging`
15
+ * (generation/storage.ts) — storage, database and network still emit their
16
+ * props by hand there, so for those three this is one of two encodings still.
17
+ * Converging the scaffold's remaining emitters is what makes the "single"
18
+ * claim true; until then, a table entry proves the codemod's behaviour and
19
+ * only documents the scaffold's.
20
+ */
21
+ /**
22
+ * A construct prop's value. `literal` is a plain JS value the emitter
23
+ * serialises; `expression` is TypeScript source spliced in verbatim, which
24
+ * only a caller that can supply live bindings may ask for.
25
+ */
26
+ export type ProjectedValue = {
27
+ kind: "literal";
28
+ value: unknown;
29
+ } | {
30
+ kind: "expression";
31
+ source: string;
32
+ };
33
+ /** One construct prop, in construct vocabulary. */
34
+ export interface ProjectedProp {
35
+ key: string;
36
+ value: ProjectedValue;
37
+ }
38
+ /**
39
+ * A plan key this context cannot turn into a construct prop, and why. The
40
+ * scaffold ignores these — it consumes such keys through its own paths. The
41
+ * codemod refuses the whole statement, because writing the key would either
42
+ * take synth down or deploy something other than what was asked for.
43
+ */
44
+ export interface UnprojectableProp {
45
+ key: string;
46
+ reason: string;
47
+ }
48
+ export interface Projection {
49
+ props: ProjectedProp[];
50
+ unprojectable: UnprojectableProp[];
51
+ }
52
+ /**
53
+ * What the caller can offer beyond the plan fragment itself.
54
+ *
55
+ * `resolveBinding` is the whole difference between the two emission paths: the
56
+ * scaffold knows the identifier it bound each planned resource to, so it can
57
+ * answer; a codemod appending to a file someone else wrote generally cannot,
58
+ * and a key needing a live sibling is unprojectable for it.
59
+ */
60
+ export interface ProjectionContext {
61
+ resolveBinding?: (planResourceName: string) => string | undefined;
62
+ /**
63
+ * The fragment is an EDIT to an existing statement rather than a whole
64
+ * resource. Constants describe the statement, so an edit must not carry
65
+ * them: `fjall modify messaging --retentionPeriod` asked to change the
66
+ * retention, not to write a `type` discriminator its author never mentioned.
67
+ */
68
+ editingExisting?: boolean;
69
+ }
70
+ /**
71
+ * How one plan key becomes (or fails to become) a construct prop.
72
+ *
73
+ * - `prop` — carried through as a literal, under `as` when the two
74
+ * vocabularies name it differently.
75
+ * - `planOnly` — never a construct prop. The scaffold consumes it (a
76
+ * `const <var> =` binding, flattened extra properties); anywhere else it is
77
+ * inert, so it is reported rather than silently dropped.
78
+ * - `live` — the construct wants an object, not a value. `bind` gets the plan
79
+ * value and the context and returns the source text of an expression, or
80
+ * undefined when this context cannot produce one.
81
+ */
82
+ export type PlanKeyRule = {
83
+ kind: "prop";
84
+ as?: string;
85
+ } | {
86
+ kind: "planOnly";
87
+ reason: string;
88
+ } | {
89
+ kind: "live";
90
+ as?: string;
91
+ reason: string;
92
+ bind: (value: unknown, context: ProjectionContext) => string | undefined;
93
+ };
94
+ /**
95
+ * One resource type's projection.
96
+ *
97
+ * `constants` are props every statement of the type carries no matter what
98
+ * the plan says — the discriminators the constructs switch on and the plan
99
+ * vocabulary never carried.
100
+ *
101
+ * `keys` is consulted per plan key; a key with no entry passes through under
102
+ * its own name, which is the common case and is why the tables stay short
103
+ * enough to read as the specification they are.
104
+ */
105
+ export interface TypeProjection {
106
+ constants?: ProjectedProp[];
107
+ keys?: Record<string, PlanKeyRule>;
108
+ }
File without changes
@@ -1 +1 @@
1
- export declare const GENERATOR_VERSION = "7.2.0";
1
+ export declare const GENERATOR_VERSION = "8.0.0";
@@ -1 +1 @@
1
- const E="7.2.0";export{E as GENERATOR_VERSION};
1
+ const E="8.0.0";export{E as GENERATOR_VERSION};