@fjall/generator 14.1.0 → 14.3.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 (86) hide show
  1. package/dist/.build-source-hash +50 -45
  2. package/dist/.minified +1 -1
  3. package/dist/src/ast/astTestHelpers.d.ts +2 -0
  4. package/dist/src/ast/domain/astDomainParser.d.ts +24 -0
  5. package/dist/src/ast/domain/astDomainParser.js +1 -1
  6. package/dist/src/ast/index.d.ts +1 -1
  7. package/dist/src/ast/index.js +1 -1
  8. package/dist/src/ast/parsers/resources/astCdnParser.js +1 -1
  9. package/dist/src/ast/parsers/resources/astComputeParser.js +1 -1
  10. package/dist/src/codemod/drift/index.d.ts +1 -1
  11. package/dist/src/codemod/drift/index.js +1 -1
  12. package/dist/src/codemod/drift/snapshot.d.ts +33 -1
  13. package/dist/src/codemod/drift/snapshot.js +1 -1
  14. package/dist/src/codemod/drift/types.d.ts +16 -1
  15. package/dist/src/codemod/drift/types.js +1 -1
  16. package/dist/src/codemod/edits/addResource/propertyBuilder.d.ts +8 -0
  17. package/dist/src/codemod/edits/addResource/propertyBuilder.js +1 -1
  18. package/dist/src/codemod/edits/addResource/siblingEmission.d.ts +61 -0
  19. package/dist/src/codemod/edits/addResource/siblingEmission.js +1 -0
  20. package/dist/src/codemod/edits/addResource.js +1 -1
  21. package/dist/src/codemod/edits/connectResourceToCompute.js +1 -1
  22. package/dist/src/codemod/edits/ensureImports.d.ts +18 -0
  23. package/dist/src/codemod/edits/ensureImports.js +1 -1
  24. package/dist/src/codemod/edits/modifyResource.js +1 -1
  25. package/dist/src/codemod/edits/resourceStatementLocator.d.ts +3 -0
  26. package/dist/src/codemod/edits/resourceStatementLocator.js +1 -1
  27. package/dist/src/codemod/edits/siblingBindingResolution.d.ts +54 -1
  28. package/dist/src/codemod/edits/siblingBindingResolution.js +1 -1
  29. package/dist/src/codemod/emitGuard.d.ts +2 -30
  30. package/dist/src/codemod/emitGuard.js +1 -1
  31. package/dist/src/codemod/emitProjection.d.ts +31 -2
  32. package/dist/src/codemod/emitProjection.js +1 -1
  33. package/dist/src/codemod/fileRewriter/builders.d.ts +18 -0
  34. package/dist/src/codemod/fileRewriter/builders.js +1 -1
  35. package/dist/src/codemod/fileRewriter/index.d.ts +1 -1
  36. package/dist/src/codemod/fileRewriter/index.js +1 -1
  37. package/dist/src/codemod/index.d.ts +3 -2
  38. package/dist/src/codemod/index.js +1 -1
  39. package/dist/src/codemod/llmFallback/index.d.ts +1 -1
  40. package/dist/src/codemod/llmFallback/index.js +1 -1
  41. package/dist/src/codemod/llmFallback/shouldTryFallback.d.ts +9 -0
  42. package/dist/src/codemod/llmFallback/shouldTryFallback.js +1 -1
  43. package/dist/src/codemod/registry.d.ts +26 -27
  44. package/dist/src/codemod/registry.js +1 -1
  45. package/dist/src/codemod/validationGate/gates/projection.js +1 -1
  46. package/dist/src/dns/domainFileGenerator.js +8 -3
  47. package/dist/src/dns/domainRecords.d.ts +30 -0
  48. package/dist/src/dns/domainRecords.js +1 -1
  49. package/dist/src/dns/tsEmitter.js +9 -9
  50. package/dist/src/generation/common.js +8 -8
  51. package/dist/src/generation/connectionWiring.d.ts +83 -0
  52. package/dist/src/generation/connectionWiring.js +1 -0
  53. package/dist/src/generation/database.d.ts +3 -34
  54. package/dist/src/generation/database.js +20 -20
  55. package/dist/src/generation/index.d.ts +1 -0
  56. package/dist/src/generation/index.js +1 -1
  57. package/dist/src/generation/infrastructure.d.ts +11 -0
  58. package/dist/src/generation/infrastructure.js +38 -28
  59. package/dist/src/generation/messagingConnections.d.ts +1 -4
  60. package/dist/src/generation/messagingConnections.js +1 -1
  61. package/dist/src/generation/storageConnections.d.ts +1 -12
  62. package/dist/src/generation/storageConnections.js +1 -1
  63. package/dist/src/planning/resourceAddition.d.ts +3 -0
  64. package/dist/src/planning/resourceAddition.js +1 -1
  65. package/dist/src/projection/compute.d.ts +31 -0
  66. package/dist/src/projection/compute.js +1 -0
  67. package/dist/src/projection/index.d.ts +3 -2
  68. package/dist/src/projection/index.js +1 -1
  69. package/dist/src/projection/project.d.ts +16 -1
  70. package/dist/src/projection/project.js +1 -1
  71. package/dist/src/projection/roundTripKeys.d.ts +12 -0
  72. package/dist/src/projection/roundTripKeys.js +1 -0
  73. package/dist/src/projection/tables.d.ts +13 -9
  74. package/dist/src/projection/tables.js +1 -1
  75. package/dist/src/projection/types.d.ts +204 -4
  76. package/dist/src/projection/unresolved.d.ts +17 -0
  77. package/dist/src/projection/unresolved.js +1 -0
  78. package/dist/src/schemas/applicationSchemas.d.ts +2 -0
  79. package/dist/src/schemas/cdnSchemas.d.ts +4 -0
  80. package/dist/src/schemas/cdnSchemas.js +1 -1
  81. package/dist/src/schemas/computeSchemas.js +1 -1
  82. package/dist/src/validation/validationMessages.d.ts +1 -0
  83. package/dist/src/validation/validationMessages.js +1 -1
  84. package/dist/src/version.d.ts +1 -1
  85. package/dist/src/version.js +1 -1
  86. 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{setContainerSecrets as E}from"./edits/setContainerSecrets.js";import{connectResourceToCompute as l}from"./edits/connectResourceToCompute.js";import{addVpcPeer as u,modifyVpcPeer as f,removeVpcPeer as T}from"./edits/vpcPeer.js";import{addVpcPeerAccepter as R,modifyVpcPeerAccepter as x,removeVpcPeerAccepter as S}from"./edits/vpcPeerAccepter.js";import{addCrossPlanConnection as v,modifyCrossPlanConnection as C,removeCrossPlanConnection as N}from"./edits/crossPlanConnection.js";import{resolveDriftPolicy as b}from"./edits/driftPolicy.js";import{listResources as y}from"./listResources.js";import{resolveConstructByLiteralProperty as G}from"./semanticIndex/index.js";import{parse as I}from"./fileRewriter/parse.js";import{CrossPlanConnectionResourcePlanSchema as F,VpcPeerAccepterResourcePlanSchema as L,VpcPeerResourcePlanSchema as U}from"../schemas/index.js";import{detectDrift as k,mergeProperties as B,snapshotProperties as M}from"./drift/index.js";import{computeLinesDelta as Y}from"./_internal.js";import{ResourceNameSchema as q,StatementTypeSchema as w}from"./types.js";import{REGISTERED_STATEMENT_TYPES as H,STATEMENT_REGISTRY as J}from"./registry.js";import{evaluateEmitGuard as W,UNRESOLVED as X}from"./emitGuard.js";import{CODEMOD_ERROR_KINDS as $}from"./telemetry/errorKinds.js";import{buildEgressBlockedEvent as re,buildFiredEvent as oe,buildGateFailedEvent as te,buildGatePassedEvent as ce,buildRejectedEvent as pe,buildSucceededEvent as me,buildTimeoutEvent as ae,estimateCostUsd as se,FALLBACK_EVENTS as ne,GATE_EVENTS as Ee,gateFallbackOutput as de,PARSE_GATE as le,RUNTIME_GATE as ie,runFallback as ue,shouldTryFallback as fe,UNATTRIBUTED_ORGANISATION as Te}from"./llmFallback/index.js";export{$ as CODEMOD_ERROR_KINDS,F as CrossPlanConnectionResourcePlanSchema,ne as FALLBACK_EVENTS,Ee as GATE_EVENTS,le as PARSE_GATE,H as REGISTERED_STATEMENT_TYPES,ie as RUNTIME_GATE,q as ResourceNameSchema,J as STATEMENT_REGISTRY,w as StatementTypeSchema,Te as UNATTRIBUTED_ORGANISATION,X as UNRESOLVED,L as VpcPeerAccepterResourcePlanSchema,U as VpcPeerResourcePlanSchema,v as addCrossPlanConnection,o as addResource,u as addVpcPeer,R as addVpcPeerAccepter,s as appendAccountToStage,re as buildEgressBlockedEvent,oe as buildFiredEvent,te as buildGateFailedEvent,ce as buildGatePassedEvent,pe as buildRejectedEvent,me as buildSucceededEvent,ae as buildTimeoutEvent,Y as computeLinesDelta,l as connectResourceToCompute,k as detectDrift,se as estimateCostUsd,W as evaluateEmitGuard,de as gateFallbackOutput,y as listResources,B as mergeProperties,C as modifyCrossPlanConnection,m as modifyResource,f as modifyVpcPeer,x as modifyVpcPeerAccepter,I as parse,N as removeCrossPlanConnection,c as removeResource,T as removeVpcPeer,S as removeVpcPeerAccepter,G as resolveConstructByLiteralProperty,b as resolveDriftPolicy,ue as runFallback,E as setContainerSecrets,fe as shouldTryFallback,M as snapshotProperties};
1
+ import{addResource as o}from"./edits/addResource.js";import{removeResource as c}from"./edits/removeResource.js";import{modifyResource as a}from"./edits/modifyResource.js";import{appendAccountToStage as s}from"./edits/appendAccountToStage.js";import{setContainerSecrets as E}from"./edits/setContainerSecrets.js";import{connectResourceToCompute as d}from"./edits/connectResourceToCompute.js";import{addVpcPeer as u,modifyVpcPeer as f,removeVpcPeer as R}from"./edits/vpcPeer.js";import{addVpcPeerAccepter as T,modifyVpcPeerAccepter as P,removeVpcPeerAccepter as x}from"./edits/vpcPeerAccepter.js";import{addCrossPlanConnection as C,modifyCrossPlanConnection as v,removeCrossPlanConnection as N}from"./edits/crossPlanConnection.js";import{resolveDriftPolicy as V}from"./edits/driftPolicy.js";import{listResources as h}from"./listResources.js";import{resolveConstructByLiteralProperty as y}from"./semanticIndex/index.js";import{parse as G}from"./fileRewriter/parse.js";import{CrossPlanConnectionResourcePlanSchema as F,VpcPeerAccepterResourcePlanSchema as g,VpcPeerResourcePlanSchema as U}from"../schemas/index.js";import{detectDrift as L,mergeProperties as M,RESOURCE_SNAPSHOT_SCHEMA_VERSION as B,ResourceSnapshotSchema as j,snapshotProperties as H}from"./drift/index.js";import{computeLinesDelta as Y}from"./_internal.js";import{ResourceNameSchema as w,StatementTypeSchema as z}from"./types.js";import{REGISTERED_STATEMENT_TYPES as Q,STATEMENT_REGISTRY as W}from"./registry.js";import{evaluateEmitGuard as Z,UNRESOLVED as $}from"./emitGuard.js";import{projectionRefusals as re}from"./emitProjection.js";import{CODEMOD_ERROR_KINDS as te}from"./telemetry/errorKinds.js";import{buildEgressBlockedEvent as pe,buildFiredEvent as ae,buildGateFailedEvent as me,buildGatePassedEvent as se,buildRejectedEvent as ne,buildSucceededEvent as Ee,buildTimeoutEvent as le,estimateCostUsd as de,FALLBACK_EVENTS as ie,GATE_EVENTS as ue,gateFallbackOutput as fe,matchFallbackTrigger as Re,PARSE_GATE as Se,RUNTIME_GATE as Te,runFallback as Pe,shouldTryFallback as xe,UNATTRIBUTED_ORGANISATION as Ae}from"./llmFallback/index.js";export{te as CODEMOD_ERROR_KINDS,F as CrossPlanConnectionResourcePlanSchema,ie as FALLBACK_EVENTS,ue as GATE_EVENTS,Se as PARSE_GATE,Q as REGISTERED_STATEMENT_TYPES,B as RESOURCE_SNAPSHOT_SCHEMA_VERSION,Te as RUNTIME_GATE,w as ResourceNameSchema,j as ResourceSnapshotSchema,W as STATEMENT_REGISTRY,z as StatementTypeSchema,Ae as UNATTRIBUTED_ORGANISATION,$ as UNRESOLVED,g as VpcPeerAccepterResourcePlanSchema,U as VpcPeerResourcePlanSchema,C as addCrossPlanConnection,o as addResource,u as addVpcPeer,T as addVpcPeerAccepter,s as appendAccountToStage,pe as buildEgressBlockedEvent,ae as buildFiredEvent,me as buildGateFailedEvent,se as buildGatePassedEvent,ne as buildRejectedEvent,Ee as buildSucceededEvent,le as buildTimeoutEvent,Y as computeLinesDelta,d as connectResourceToCompute,L as detectDrift,de as estimateCostUsd,Z as evaluateEmitGuard,fe as gateFallbackOutput,h as listResources,Re as matchFallbackTrigger,M as mergeProperties,v as modifyCrossPlanConnection,a as modifyResource,f as modifyVpcPeer,P as modifyVpcPeerAccepter,G as parse,re as projectionRefusals,N as removeCrossPlanConnection,c as removeResource,R as removeVpcPeer,x as removeVpcPeerAccepter,y as resolveConstructByLiteralProperty,V as resolveDriftPolicy,Pe as runFallback,E as setContainerSecrets,xe as shouldTryFallback,H as snapshotProperties};
@@ -1,6 +1,6 @@
1
1
  export { runFallback, type FallbackClients, type RunFallbackInput, } from "./runFallback.js";
2
2
  export { gateFallbackOutput, type GateEventAction, type GateFallbackParams, } from "./gateFallbackOutput.js";
3
- export { shouldTryFallback, type FallbackDecision, type FallbackGuardConfig, } from "./shouldTryFallback.js";
3
+ export { matchFallbackTrigger, shouldTryFallback, type FallbackDecision, type FallbackGuardConfig, } from "./shouldTryFallback.js";
4
4
  export { buildEgressBlockedEvent, buildFiredEvent, buildGateFailedEvent, buildGatePassedEvent, buildRejectedEvent, buildSucceededEvent, buildTimeoutEvent, estimateCostUsd, FALLBACK_EVENTS, GATE_EVENTS, UNATTRIBUTED_ORGANISATION, type FallbackEgressBlockedEvent, type FallbackFiredEvent, type FallbackRejectedEvent, type FallbackSucceededEvent, type FallbackTelemetryEvent, type FallbackTimeoutEvent, type GateFailedEvent, type GatePassedEvent, type TelemetrySource, } from "./telemetryEvents.js";
5
5
  export { PARSE_GATE, RUNTIME_GATE } from "./types.js";
6
6
  export type { AnthropicClientProvider, AnthropicContentBlock, AnthropicResponse, ApplyResult, EgressStage, FallbackInput, FallbackIntent, FallbackOp, FallbackOutput, FallbackTelemetry, MorphClientProvider, MorphResponse, StrReplaceOp, TriggerReason, } from "./types.js";
@@ -1 +1 @@
1
- import{runFallback as E}from"./runFallback.js";import{gateFallbackOutput as l}from"./gateFallbackOutput.js";import{shouldTryFallback as r}from"./shouldTryFallback.js";import{buildEgressBlockedEvent as a,buildFiredEvent as T,buildGateFailedEvent as i,buildGatePassedEvent as b,buildRejectedEvent as A,buildSucceededEvent as n,buildTimeoutEvent as s,estimateCostUsd as c,FALLBACK_EVENTS as m,GATE_EVENTS as v,UNATTRIBUTED_ORGANISATION as p}from"./telemetryEvents.js";import{PARSE_GATE as G,RUNTIME_GATE as N}from"./types.js";export{m as FALLBACK_EVENTS,v as GATE_EVENTS,G as PARSE_GATE,N as RUNTIME_GATE,p as UNATTRIBUTED_ORGANISATION,a as buildEgressBlockedEvent,T as buildFiredEvent,i as buildGateFailedEvent,b as buildGatePassedEvent,A as buildRejectedEvent,n as buildSucceededEvent,s as buildTimeoutEvent,c as estimateCostUsd,l as gateFallbackOutput,E as runFallback,r as shouldTryFallback};
1
+ import{runFallback as l}from"./runFallback.js";import{gateFallbackOutput as d}from"./gateFallbackOutput.js";import{matchFallbackTrigger as a,shouldTryFallback as o}from"./shouldTryFallback.js";import{buildEgressBlockedEvent as T,buildFiredEvent as i,buildGateFailedEvent as b,buildGatePassedEvent as c,buildRejectedEvent as A,buildSucceededEvent as m,buildTimeoutEvent as n,estimateCostUsd as s,FALLBACK_EVENTS as v,GATE_EVENTS as F,UNATTRIBUTED_ORGANISATION as p}from"./telemetryEvents.js";import{PARSE_GATE as N,RUNTIME_GATE as f}from"./types.js";export{v as FALLBACK_EVENTS,F as GATE_EVENTS,N as PARSE_GATE,f as RUNTIME_GATE,p as UNATTRIBUTED_ORGANISATION,T as buildEgressBlockedEvent,i as buildFiredEvent,b as buildGateFailedEvent,c as buildGatePassedEvent,A as buildRejectedEvent,m as buildSucceededEvent,n as buildTimeoutEvent,s as estimateCostUsd,d as gateFallbackOutput,a as matchFallbackTrigger,l as runFallback,o as shouldTryFallback};
@@ -11,3 +11,12 @@ export type FallbackDecision = {
11
11
  shouldTry: false;
12
12
  };
13
13
  export declare function shouldTryFallback(error: CodemodError, config: FallbackGuardConfig): FallbackDecision;
14
+ /**
15
+ * The trigger kind a failure would fall back under, or undefined when no
16
+ * amount of enablement could make the fallback attempt it.
17
+ *
18
+ * Pure and local — no config, no I/O. Consumers whose enablement lookup costs
19
+ * something (the CLI reads org config over the network) ask this first, so a
20
+ * failure the fallback can never handle stays free.
21
+ */
22
+ export declare function matchFallbackTrigger(error: CodemodError): TriggerReason | undefined;
@@ -1 +1 @@
1
- var o=Object.defineProperty;var n=(r,e)=>o(r,"name",{value:e,configurable:!0});const t={shouldTry:!1};function i(r,e){if(!e.envEnabled||!e.orgAllowsFallback)return t;const l=u(r);return l===void 0?t:{shouldTry:!0,trigger:l}}n(i,"shouldTryFallback");function u(r){switch(r.kind){case"TemplateLiteralNameError":return"template-literal-name";case"ResourceNotFoundError":return"resource-not-found";case"ControlFlowClassifierError":return r.reason==="anonymous-helper"?"control-flow-unclassifiable":void 0;case"DriftUnmergeableError":return"drift-unmergeable";default:return}}n(u,"matchTrigger");export{i as shouldTryFallback};
1
+ var o=Object.defineProperty;var n=(r,e)=>o(r,"name",{value:e,configurable:!0});const t={shouldTry:!1};function i(r,e){if(!e.envEnabled||!e.orgAllowsFallback)return t;const l=a(r);return l===void 0?t:{shouldTry:!0,trigger:l}}n(i,"shouldTryFallback");function a(r){switch(r.kind){case"TemplateLiteralNameError":return"template-literal-name";case"ResourceNotFoundError":return"resource-not-found";case"ControlFlowClassifierError":return r.reason==="anonymous-helper"?"control-flow-unclassifiable":void 0;case"DriftUnmergeableError":return"drift-unmergeable";default:return}}n(a,"matchFallbackTrigger");export{a as matchFallbackTrigger,i as shouldTryFallback};
@@ -30,18 +30,19 @@ export interface StatementTypeEntry {
30
30
  /**
31
31
  * The ADD path's required-aware input contract: the plan schema minus
32
32
  * `name`, WITHOUT `.partial()`, so a first-time add must carry every
33
- * required plan key (`database` demands `type` + `databaseName`) as well
34
- * as satisfying the per-key shapes. `schemaFragment` stays the partial
35
- * delta contract for MODIFY.
33
+ * required plan key (`database` demands `type` + `databaseName`; `compute`
34
+ * demands `type` + `needsConnection`) as well as satisfying the per-key
35
+ * shapes. `schemaFragment` stays the partial delta contract for MODIFY.
36
36
  *
37
37
  * Declared ONLY for guard-free types, and that is a rule, not a
38
- * convenience: a guarded type's required plan keys are exactly the
39
- * scaffold-consumed keys its own guard REFUSES to write
40
- * (`compute.needsConnection` is required by the plan schema and
41
- * `silentlyDropped` by the guard), so demanding them at the gate would be
42
- * a catch-22 no invocation could satisfy. When an increment lands a
43
- * type's projection and deletes its guard table, declare `addContract` in
44
- * the same edit — the schema-gate XOR test pins the pairing.
38
+ * convenience: a guarded type's required plan keys would be exactly the
39
+ * scaffold-consumed keys its own guard refuses to write — the catch-22
40
+ * `compute` sat in until its projection landed (its guard `silentlyDropped`
41
+ * the required `needsConnection`, so demanding it at the gate was
42
+ * unsatisfiable; the projection's expansion now CONSUMES it). When an
43
+ * increment lands a type's projection and deletes its guard table, declare
44
+ * `addContract` in the same edit — the schema-gate XOR test pins the
45
+ * pairing. `vpc-peer`, the one guarded type left, correctly declares none.
45
46
  *
46
47
  * Absent = the schema gate applies `schemaFragment` to adds too
47
48
  * (unknown-key and per-key-shape checks only, no required demand).
@@ -87,21 +88,19 @@ export interface StatementTypeEntry {
87
88
  * ONLY for types the plan→construct projection cannot describe. Where it
88
89
  * can (`src/projection/tables.ts`), the disagreement is TRANSLATED at
89
90
  * emission and no rule belongs here — `emitProjection.ts` reports what is
90
- * left from the projection's own `unprojectable` list, and a single live
91
- * sibling binding is now expressible through a `live` rule (`cdn`'s
92
- * origin). What survives is `compute`'s connection expansion (more than
93
- * one statement) and cross-key conditions no per-key table can state.
91
+ * left from the projection's own `unprojectable` list; a live sibling
92
+ * binding is expressible through a `live` rule (`cdn`'s origin), a second
93
+ * statement through a sibling projection (`compute`'s schedule), a merged
94
+ * prop through a fragment expansion (`compute`'s connection keys), and a
95
+ * key combination through a `crossKey` rule. What survives is `vpc-peer`
96
+ * alone: required-key conditions whose absence deploys silently wrong
97
+ * infrastructure.
94
98
  *
95
- * Rules cover exactly two classes, and nothing else:
96
- *
97
- * · UNTRANSLATABLE — the construct requires a value no CLI flag can
98
- * carry (a CDK `Code`/`Architecture`, an `IBucket`, a live sibling
99
- * construct). No invocation can ever synthesise, so writing one is
100
- * always wrong.
101
- * · SILENTLY DROPPED — the construct never reads the plan key, so the
102
- * resource deploys without the behaviour that was requested. Proven
103
- * per key: zero `props.<key>` reads anywhere in
104
- * @fjall/components-infrastructure.
99
+ * The one class rules still cover: a required key whose ABSENCE deploys
100
+ * silently wrong infrastructure — synth succeeds, the deploy is green, and
101
+ * the emitted resource points at garbage (`vpc-peer`'s two required
102
+ * members). Refusing at write time is the only net, because `cdk.json`
103
+ * runs `infrastructure.ts` through tsx, which does not typecheck.
105
104
  *
106
105
  * Deliberately NOT covered: INCOMPLETE input, where the vocabulary can
107
106
  * express a working call and the operator has not yet — that is
@@ -114,9 +113,9 @@ export interface StatementTypeEntry {
114
113
  * Absent = every expressible property shape for this type reaches a
115
114
  * synthesising statement. That is a claim, not an oversight, and it is now
116
115
  * true two ways: `network` and `buildkite` have outright plan/construct
117
- * parity, while `database`, `storage` and `messaging` reach it through the
118
- * projection. The components-infrastructure materialisation contract pins
119
- * both.
116
+ * parity, while `database`, `storage`, `messaging` and `compute` reach it
117
+ * through the projection. The components-infrastructure materialisation
118
+ * contract pins both.
120
119
  */
121
120
  emitGuard?: ReadonlyArray<EmitGuardRule>;
122
121
  /**
@@ -1 +1 @@
1
- var _=Object.defineProperty;var a=(e,t)=>_(e,"name",{value:t,configurable:!0});import{DEPLOYABLE_PATTERN_TYPES as w,PATTERN_TYPE_VALUES as x,isPatternType as M,patternConstructId as l}from"@fjall/util";import{z as d}from"zod";import{BuildkitePropsObjectSchema as h,CDNResourcePlanSchema as y,ComputeResourcePlanSchema as I,CrossPlanConnectionResourcePlanSchema as g,DatabaseResourcePlanSchema as f,NetworkResourcePlanSchema as S,NextJSPatternConfigSchema as O,OrganisationResourcePlanSchema as C,PayloadPatternConfigSchema as D,S3ResourcePlanSchema as P,SQSResourcePlanSchema as b,StaticSitePatternConfigSchema as W,VpcPeerAccepterResourcePlanSchema as E,VpcPeerResourcePlanSchema as L}from"../schemas/index.js";import{failure as j}from"../types/Result.js";import{requiresLiveValue as A,silentlyDropped as c,UNRESOLVED as G,whenAbsent as F}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,...n}=e.shape;return d.object(n).partial().strict()}a(s,"fragmentOf");function i(e){const{name:t,...n}=e.shape;return d.object(n).strict()}a(i,"completeFragmentOf");const V=s(f),B=s(P),Y=(()=>{const{name:e,...t}=I.shape;return d.object(t).partial().strict()})(),q=s(b),K=s(y),U=s(S),T=(()=>{const{name:e,type:t,cdn:n,...k}=D.shape,{name:se,type:ie,cdn:de,...v}=O.shape,{name:pe,type:me,domain:ue,cdn:N,...R}=W.shape;return{...k,...v,...R,cdn:d.union([n,N]),type:d.enum(w)}})(),z=d.object(T).partial().strict(),Q=d.object(T).partial().required({type:!0}).strict(),$={emitConstructId:a((e,t)=>M(t.type)?l(e,t.type):e,"emitConstructId"),locateCandidates:a(e=>[e,...x.map(t=>l(e,t))],"locateCandidates")},J=s(L),H=s(E),X=s(g),Z=s(C),ee=s(h);function u(e,t){return j({kind:"SemanticQueryError",reason:`StatementTypeEntry.${e} for ${t} is not wired; existing types dispatch through the shared locator/generator.`})}a(u,"notWiredError");function te(e){return{factoryIdentifier:e,findByShape:a(()=>u("locator.findByShape",e),"findByShape"),validateContext:a(()=>u("locator.validateContext",e),"validateContext")}}a(te,"createLocator");function ae(e){return{build:a(()=>{const t=u("generator.build",e);throw new Error(t.success?"unreachable":t.error.reason)},"build")}}a(ae,"createGenerator");const ne=c("variableName","`variableName` is a plan-only round-trip key naming the `const <var> =` binding the scaffold emits; no construct reads it."),re=c("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."),m="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.",oe=[{property:"deployment",refuseWhen:a(e=>(e.type==="lambda"||e.deployment!==void 0)&&e.deployment!=="container"&&e.code!==G,"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."},c("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."),A("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."),A("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."),c("memory","the Lambda construct reads `memorySize`, so `--memory 1024` deploys a function at the 128 MB default."),c("ssmSecrets","the Lambda construct reads `secrets`, so `--ssmSecrets` deploys a function with no SSM wiring and no secrets environment at all."),c("scheduleExpression","`scheduleExpression` is not a compute prop: the scaffold turns it into a SEPARATE `app.addSchedule(...)` statement, which this command cannot emit."),c("needsConnection",m),c("connectedDatabase",m),c("connectedStorage",m),c("connectedMessaging",m),ne,re],ce=[{property:"peerAppName",refuseWhen:F("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:F("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,n={}){return{factoryIdentifier:e,locator:te(e),generator:ae(e),schemaFragment:t,...n}}a(o,"createEntry");const p={database:o(r.database,V,{emitWrapper:{appMethod:"addDatabase"},addContract:i(f)}),storage:o(r.storage,B,{emitWrapper:{appMethod:"addStorage"},addContract:i(P)}),compute:o(r.compute,Y,{emitWrapper:{appMethod:"addCompute"},emitGuard:oe}),messaging:o(r.messaging,q,{emitWrapper:{appMethod:"addMessaging"},addContract:i(b)}),cdn:o(r.cdn,K,{emitWrapper:{appMethod:"addCdn"},addContract:i(y)}),network:o(r.network,U,{emitWrapper:{appMethod:"addNetwork"},addContract:i(S)}),pattern:o(r.pattern,z,{emitWrapper:{appMethod:"addPattern"},addContract:Q,statementIdentity:$}),"vpc-peer":o(r["vpc-peer"],J,{emitWrapper:{appMethod:"addVpcPeer"},emitGuard:ce}),"vpc-peer-accepter":o(r["vpc-peer-accepter"],H,{emitWrapper:{appMethod:"addVpcPeerAccepter"},addContract:i(E)}),"cross-plan-connection":o(r["cross-plan-connection"],X,{addContract:i(g)}),organisation:o(r.organisation,Z,{addContract:i(C)}),buildkite:o(r.buildkite,ee,{emitWrapper:{appMethod:"addBuildkite",propsOverloadConstructId:"Buildkite"},addContract:i(h)})},Ce=Object.keys(p);function Pe(e,t,n){return p[e].statementIdentity?.emitConstructId(t,n)??t}a(Pe,"constructIdFor");function be(e,t){return p[e].statementIdentity?.locateCandidates(t)??[t]}a(be,"locateNamesFor");function Ee(e){const t=Object.keys(p);for(const n of t)if(p[n].factoryIdentifier===e)return n}a(Ee,"findTypeByIdentifier");export{r as FACTORY_IDENTIFIERS,Ce as REGISTERED_STATEMENT_TYPES,p as STATEMENT_REGISTRY,Pe as constructIdFor,Ee as findTypeByIdentifier,be as locateNamesFor};
1
+ var R=Object.defineProperty;var r=(e,t)=>R(e,"name",{value:t,configurable:!0});import{DEPLOYABLE_PATTERN_TYPES as I,PATTERN_TYPE_VALUES as N,isPatternType as M,patternConstructId as m}from"@fjall/util";import{z as s}from"zod";import{BuildkitePropsObjectSchema as u,CDNResourcePlanSchema as l,ComputeResourcePlanSchema as g,CrossPlanConnectionResourcePlanSchema as h,DatabaseResourcePlanSchema as y,NetworkResourcePlanSchema as P,NextJSPatternConfigSchema as v,OrganisationResourcePlanSchema as S,PayloadPatternConfigSchema as w,S3ResourcePlanSchema as C,SQSResourcePlanSchema as f,StaticSitePatternConfigSchema as O,VpcPeerAccepterResourcePlanSchema as F,VpcPeerResourcePlanSchema as W}from"../schemas/index.js";import{failure as x}from"../types/Result.js";import{whenAbsent as b}from"./emitGuard.js";const n={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 c(e){const{name:t,...a}=e.shape;return s.object(a).partial().strict()}r(c,"fragmentOf");function p(e){const{name:t,...a}=e.shape;return s.object(a).strict()}r(p,"completeFragmentOf");const j=c(y),B=c(C),V=(()=>{const{name:e,...t}=g.shape;return s.object(t).partial().strict()})(),D=(()=>{const{name:e,...t}=g.shape;return s.object(t).strict()})(),Y=c(f),G=c(l),L=c(P),E=(()=>{const{name:e,type:t,cdn:a,...A}=w.shape,{name:te,type:re,cdn:ae,...T}=v.shape,{name:ne,type:oe,domain:ce,cdn:_,...k}=O.shape;return{...A,...T,...k,cdn:s.union([a,_]),type:s.enum(I)}})(),q=s.object(E).partial().strict(),Q=s.object(E).partial().required({type:!0}).strict(),U={emitConstructId:r((e,t)=>M(t.type)?m(e,t.type):e,"emitConstructId"),locateCandidates:r(e=>[e,...N.map(t=>m(e,t))],"locateCandidates")},$=c(W),z=c(F),J=c(h),H=c(S),K=c(u);function d(e,t){return x({kind:"SemanticQueryError",reason:`StatementTypeEntry.${e} for ${t} is not wired; existing types dispatch through the shared locator/generator.`})}r(d,"notWiredError");function X(e){return{factoryIdentifier:e,findByShape:r(()=>d("locator.findByShape",e),"findByShape"),validateContext:r(()=>d("locator.validateContext",e),"validateContext")}}r(X,"createLocator");function Z(e){return{build:r(()=>{const t=d("generator.build",e);throw new Error(t.success?"unreachable":t.error.reason)},"build")}}r(Z,"createGenerator");const ee=[{property:"peerAppName",refuseWhen:b("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:b("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,a={}){return{factoryIdentifier:e,locator:X(e),generator:Z(e),schemaFragment:t,...a}}r(o,"createEntry");const i={database:o(n.database,j,{emitWrapper:{appMethod:"addDatabase"},addContract:p(y)}),storage:o(n.storage,B,{emitWrapper:{appMethod:"addStorage"},addContract:p(C)}),compute:o(n.compute,V,{emitWrapper:{appMethod:"addCompute"},addContract:D}),messaging:o(n.messaging,Y,{emitWrapper:{appMethod:"addMessaging"},addContract:p(f)}),cdn:o(n.cdn,G,{emitWrapper:{appMethod:"addCdn"},addContract:p(l)}),network:o(n.network,L,{emitWrapper:{appMethod:"addNetwork"},addContract:p(P)}),pattern:o(n.pattern,q,{emitWrapper:{appMethod:"addPattern"},addContract:Q,statementIdentity:U}),"vpc-peer":o(n["vpc-peer"],$,{emitWrapper:{appMethod:"addVpcPeer"},emitGuard:ee}),"vpc-peer-accepter":o(n["vpc-peer-accepter"],z,{emitWrapper:{appMethod:"addVpcPeerAccepter"},addContract:p(F)}),"cross-plan-connection":o(n["cross-plan-connection"],J,{addContract:p(h)}),organisation:o(n.organisation,H,{addContract:p(S)}),buildkite:o(n.buildkite,K,{emitWrapper:{appMethod:"addBuildkite",propsOverloadConstructId:"Buildkite"},addContract:p(u)})},le=Object.keys(i);function ge(e,t,a){return i[e].statementIdentity?.emitConstructId(t,a)??t}r(ge,"constructIdFor");function he(e,t){return i[e].statementIdentity?.locateCandidates(t)??[t]}r(he,"locateNamesFor");function ye(e){const t=Object.keys(i);for(const a of t)if(i[a].factoryIdentifier===e)return a}r(ye,"findTypeByIdentifier");export{n as FACTORY_IDENTIFIERS,le as REGISTERED_STATEMENT_TYPES,i as STATEMENT_REGISTRY,ge as constructIdFor,ye as findTypeByIdentifier,he as locateNamesFor};
@@ -1 +1 @@
1
- var h=Object.defineProperty;var c=(n,t)=>h(n,"name",{value:t,configurable:!0});import{failure as u,success as a}from"../../../types/Result.js";import{isProjectableType as v,TYPE_PROJECTIONS as b}from"../../../projection/index.js";import{extractProgramBody as g}from"../../_internal.js";import{findConfigObject as j}from"../../drift/snapshot.js";import{astToLiteral as N,isNodeShape as P,NON_LITERAL as O,readKeyName as y}from"../../edits/modifyResource/literalConversion.js";import{parse as T}from"../../fileRewriter/parse.js";import{constructIdFor as $,STATEMENT_REGISTRY as k}from"../../registry.js";import{locateByShape as E}from"../../semanticIndex/locateByShape.js";function S(n){if(!v(n))return[];const t=b[n].keys??{};return Object.entries(t).flatMap(([e,r])=>r.kind==="live"?[{planKey:e,constructKey:r.as??e,reason:r.reason}]:[])}c(S,"liveConstructKeys");function m(n){return a({action:"reject",diagnostics:n})}c(m,"rejectOutcome");const q={id:"projection",run(n){const{type:t,name:e,op:r}=n.plan,o=S(t),f=r==="add"&&k[t].statementIdentity!==void 0;if(o.length===0&&!f)return a({action:"proceed"});const s=I(n);if(!s.success)return s;if(s.data===void 0)return m(`could not resolve the emitted config object for ${t} "${e}"; the output cannot be verified against the projection contract`);const{symbolName:p,configObject:l}=s.data;for(const d of o){const i=K(l,d.constructKey);if(i!==void 0&&(i.type==="StringLiteral"||i.type==="TemplateLiteral"))return u({kind:"InvalidPropertyError",property:d.constructKey,reason:`the ${t} construct reads a live binding here and the output wrote a ${i.type==="StringLiteral"?"string":"template"} literal; ${d.reason}`})}if(f){const d=L(l),i=$(t,e,d);if(p!==i)return m(`output writes construct id "${p}" where the ${t} identity derivation for "${e}" requires "${i}" \u2014 an id the deterministic lane never emits (the type declares an identity precisely because non-derived ids collide or go unaddressable at synth)`)}return a({action:"proceed"})}};function I(n){const t=E(n.content,{type:n.plan.type,name:n.plan.name});if(!t.success)return u(t.error);if(t.data===void 0)return a(void 0);const e=T(n.content,t.data.filePath);if(!e.success)return u(e.error);const r=g(e.data);if(r===void 0)return a(void 0);const o=j(r,{start:t.data.start,length:t.data.length});return o===void 0?a(void 0):a({symbolName:t.data.symbolName,configObject:o})}c(I,"locateEmittedStatement");function K(n,t){for(const e of n.properties)if(!(e.type!=="Property"&&e.type!=="ObjectProperty")&&!(e.shorthand===!0||e.computed===!0)&&y(e.key)===t&&e.value!==void 0&&P(e.value))return e.value}c(K,"readPropertyValueNode");function L(n){const t={};for(const e of n.properties){if(e.type!=="Property"&&e.type!=="ObjectProperty"||e.shorthand===!0||e.computed===!0)continue;const r=y(e.key);if(r===void 0||e.value===void 0)continue;const o=N(e.value);o!==O&&(t[r]=o)}return t}c(L,"literalPropertiesOf");export{q as projectionGate};
1
+ var N=Object.defineProperty;var d=(r,t)=>N(r,"name",{value:t,configurable:!0});import{failure as c,success as p}from"../../../types/Result.js";import{isProjectableType as v,TYPE_PROJECTIONS as k}from"../../../projection/index.js";import{extractProgramBody as O}from"../../_internal.js";import{findConfigObject as w}from"../../drift/snapshot.js";import{bodyCarriesSibling as E,siblingCallPropsObject as K}from"../../edits/addResource/siblingEmission.js";import{astToLiteral as S,isNodeShape as T,NON_LITERAL as x,readKeyName as j}from"../../edits/modifyResource/literalConversion.js";import{parse as M}from"../../fileRewriter/parse.js";import{constructIdFor as C,STATEMENT_REGISTRY as L}from"../../registry.js";import{locateByShape as R}from"../../semanticIndex/locateByShape.js";function _(r){if(!v(r))return[];const t=k[r].keys??{};return Object.entries(t).flatMap(([e,i])=>i.kind==="live"?[{planKey:e,constructKey:i.as??e,reason:i.reason,wants:"live binding"}]:i.kind==="structured"?[{planKey:e,constructKey:i.as??e,reason:i.reason,wants:"structured CDK expression"}]:[])}d(_,"shapeCheckedKeys");function u(r){return p({action:"reject",diagnostics:r})}d(u,"rejectOutcome");function A(r,t){if(r.plan.op!=="modify"||t?.expansion===void 0)return;const e=t.expansion;if(!e.keys.some(f=>r.plan.properties[f]!==void 0))return;const i=e.derive(r.plan.properties,{resourceName:r.plan.name,editingExisting:!0}),[o]=i.unprojectable;if(o!==void 0)return c({kind:"InvalidPropertyError",property:o.key,reason:o.reason})}d(A,"expansionModifyParity");const W={id:"projection",run(r){const{type:t,name:e,op:i}=r.plan,o=v(t)?k[t]:void 0,f=A(r,o);if(f!==void 0)return f;const I=o?.siblings!==void 0?o.siblings.keys.filter(n=>r.plan.properties[n]!==void 0):[];let y=[];if(I.length>0&&o?.siblings!==void 0){const n=o.siblings.derive(r.plan.properties,{resourceName:e}),[s]=n.unprojectable;if(s!==void 0)return c({kind:"InvalidPropertyError",property:s.key,reason:s.reason});const[a]=n.siblings;if(i!=="add"&&a!==void 0)return c({kind:"InvalidPropertyError",property:a.planKey,reason:`\`${a.planKey}\` expands into its own \`app.${a.appMethod}("${a.constructId}", \u2026)\` statement, and a modify edits exactly one statement \u2014 the deterministic lane refuses this edit and the fallback lane holds the same line.`});y=n.siblings}const m=_(t),h=i==="add"&&L[t].statementIdentity!==void 0;if(m.length===0&&!h&&y.length===0)return p({action:"proceed"});const l=B(r);if(!l.success)return l;if(l.data===void 0)return u(`could not resolve the emitted config object for ${t} "${e}"; the output cannot be verified against the projection contract`);const{symbolName:b,configObject:g,body:$}=l.data;for(const n of m){const s=P(g,n.constructKey);if(s!==void 0&&(s.type==="StringLiteral"||s.type==="TemplateLiteral"))return c({kind:"InvalidPropertyError",property:n.constructKey,reason:`the ${t} construct reads a ${n.wants} here and the output wrote a ${s.type==="StringLiteral"?"string":"template"} literal; ${n.reason}`})}for(const n of y){if(!E($,n))return u(`the \`${n.planKey}\` key expands into a second statement \`app.${n.appMethod}("${n.constructId}", \u2026)\` and the output does not carry it \u2014 the primary resource would deploy with the expansion silently missing`);if(n.props.length===0)continue;const s=K($,n);if(s===void 0)return u(`the \`${n.planKey}\` expansion statement \`app.${n.appMethod}("${n.constructId}", \u2026)\` carries no readable props object, so it cannot be verified against the props the projection derives (${n.props.map(a=>`\`${a.key}\``).join(", ")})`);for(const a of n.props)if(P(s,a.key)===void 0)return u(`the \`${n.planKey}\` expansion statement \`app.${n.appMethod}("${n.constructId}", \u2026)\` omits the derived prop \`${a.key}\` \u2014 the deterministic lane always emits it, and without it the expansion deploys wrong or incomplete infrastructure`)}if(h){const n=G(g),s=C(t,e,n);if(b!==s)return u(`output writes construct id "${b}" where the ${t} identity derivation for "${e}" requires "${s}" \u2014 an id the deterministic lane never emits (the type declares an identity precisely because non-derived ids collide or go unaddressable at synth)`)}return p({action:"proceed"})}};function B(r){const t=R(r.content,{type:r.plan.type,name:r.plan.name});if(!t.success)return c(t.error);if(t.data===void 0)return p(void 0);const e=M(r.content,t.data.filePath);if(!e.success)return c(e.error);const i=O(e.data);if(i===void 0)return p(void 0);const o=w(i,{start:t.data.start,length:t.data.length});return o===void 0?p(void 0):p({symbolName:t.data.symbolName,configObject:o,body:i})}d(B,"locateEmittedStatement");function P(r,t){for(const e of r.properties)if(!(e.type!=="Property"&&e.type!=="ObjectProperty")&&!(e.shorthand===!0||e.computed===!0)&&j(e.key)===t&&e.value!==void 0&&T(e.value))return e.value}d(P,"readPropertyValueNode");function G(r){const t={};for(const e of r.properties){if(e.type!=="Property"&&e.type!=="ObjectProperty"||e.shorthand===!0||e.computed===!0)continue;const i=j(e.key);if(i===void 0||e.value===void 0)continue;const o=S(e.value);o!==x&&(t[i]=o)}return t}d(G,"literalPropertiesOf");export{W as projectionGate};
@@ -1,4 +1,4 @@
1
- var p=Object.defineProperty;var o=(t,e)=>p(t,"name",{value:e,configurable:!0});import{getDomainStackName as g}from"@fjall/util";import{toPascalCase as w}from"../generation/common.js";import{GENERATOR_VERSION as d}from"../version.js";function I(t){const{domainName:e,hostedZoneId:r,records:n=[]}=t,a=t.basePath??`fjall/domains/${e}`;return[{path:`${a}/infrastructure.ts`,content:h({domainName:e,records:n,hostedZoneId:r})},{path:`${a}/package.json`,content:f(e)},{path:`${a}/tsconfig.json`,content:y},{path:`${a}/cdk.json`,content:N},{path:`${a}/cdk.context.json`,content:S},{path:`${a}/.gitignore`,content:k}]}o(I,"generateDomainFiles");function h(t){const{domainName:e,records:r,hostedZoneId:n}=t,a=w(e.split(".").join("")),i=g(e),c=r.map(s=>{const m=s.ttl!==void 0?`, ttl: ${s.ttl}`:"";return` { type: ${JSON.stringify(s.type)}, name: ${JSON.stringify(s.name)}, value: ${JSON.stringify(s.value)}${m} },`}),l=c.length>0?`[
1
+ var p=Object.defineProperty;var o=(t,e)=>p(t,"name",{value:e,configurable:!0});import{getDomainStackName as g}from"@fjall/util";import{toPascalCase as h}from"../generation/common.js";import{GENERATOR_VERSION as d}from"../version.js";function I(t){const{domainName:e,hostedZoneId:r,records:n=[]}=t,a=t.basePath??`fjall/domains/${e}`;return[{path:`${a}/infrastructure.ts`,content:w({domainName:e,records:n,hostedZoneId:r})},{path:`${a}/package.json`,content:f(e)},{path:`${a}/tsconfig.json`,content:y},{path:`${a}/cdk.json`,content:N},{path:`${a}/cdk.context.json`,content:S},{path:`${a}/.gitignore`,content:k}]}o(I,"generateDomainFiles");function w(t){const{domainName:e,records:r,hostedZoneId:n}=t,a=h(e.split(".").join("")),i=g(e),c=r.map(s=>{const m=s.ttl!==void 0?`, ttl: ${s.ttl}`:"";return` { type: ${JSON.stringify(s.type)}, name: ${JSON.stringify(s.name)}, value: ${JSON.stringify(s.value)}${m} },`}),l=c.length>0?`[
2
2
  ${c.join(`
3
3
  `)}
4
4
  ]`:"[]",u=n?` hostedZoneId: ${JSON.stringify(n)},
@@ -19,7 +19,12 @@ const stack = app.getStack(${JSON.stringify(i)}).getStack();
19
19
  new Domain(stack, ${JSON.stringify(a)}, {
20
20
  registrar: "route53",
21
21
  zoneName: ${JSON.stringify(e)},
22
- ${u} certificates: [
22
+ ${u} // Position-independent record logical IDs (fresh-zone default): records
23
+ // can be inserted, removed, or reordered freely. Never remove this line
24
+ // once the zone has deployed \u2014 flipping the mode renames every record's
25
+ // logical ID (a deliberate two-deploy migration, never a casual edit).
26
+ recordIds: "stable",
27
+ certificates: [
23
28
  { domainName: ${JSON.stringify(e)} },
24
29
  // Serving this zone through CloudFront (staticsite/cdn)? Add a viewer
25
30
  // certificate with cloudFront: true \u2014 it is minted in us-east-1 (the
@@ -39,7 +44,7 @@ ${u} certificates: [
39
44
  // and adoptedNameServers (both together) on the child Domain \u2014 the literals
40
45
  // feed the parent NS UPSERT because an imported zone exposes no name-server
41
46
  // attribute at synth.
42
- `}o(h,"generateDefaultInfrastructureTs");function f(t){return`{
47
+ `}o(w,"generateDefaultInfrastructureTs");function f(t){return`{
43
48
  "name": ${JSON.stringify(`domain-${t}`)},
44
49
  "version": "${d}",
45
50
  "type": "module",
@@ -40,6 +40,14 @@ export declare const DomainDeployPhaseSchema: z.ZodEnum<{
40
40
  full: "full";
41
41
  }>;
42
42
  export type DomainDeployPhase = z.infer<typeof DomainDeployPhaseSchema>;
43
+ /**
44
+ * Per-record construct-id override (`recordIds: "stable"` collision escape
45
+ * hatch) — mirrors `StandardRecord.id` / `AliasRecord.id` in
46
+ * @fjall/components-infrastructure, which validates the same shape (it
47
+ * becomes a CloudFormation logical-ID segment).
48
+ */
49
+ export declare const RecordConstructIdSchema: z.ZodString;
50
+ export type RecordConstructId = z.infer<typeof RecordConstructIdSchema>;
43
51
  export declare const ParsedStandardRecordSchema: z.ZodObject<{
44
52
  kind: z.ZodLiteral<"standard">;
45
53
  type: z.ZodEnum<{
@@ -55,6 +63,7 @@ export declare const ParsedStandardRecordSchema: z.ZodObject<{
55
63
  name: z.ZodString;
56
64
  value: z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>;
57
65
  ttl: z.ZodOptional<z.ZodNumber>;
66
+ id: z.ZodOptional<z.ZodString>;
58
67
  }, z.core.$strict>;
59
68
  export declare const ParsedAliasRecordSchema: z.ZodObject<{
60
69
  kind: z.ZodLiteral<"alias">;
@@ -78,6 +87,7 @@ export declare const ParsedAliasRecordSchema: z.ZodObject<{
78
87
  dnsName: z.ZodString;
79
88
  hostedZoneId: z.ZodString;
80
89
  }, z.core.$strict>], "kind">;
90
+ id: z.ZodOptional<z.ZodString>;
81
91
  }, z.core.$strict>;
82
92
  export declare const ParsedDnsRecordSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
83
93
  kind: z.ZodLiteral<"standard">;
@@ -94,6 +104,7 @@ export declare const ParsedDnsRecordSchema: z.ZodDiscriminatedUnion<[z.ZodObject
94
104
  name: z.ZodString;
95
105
  value: z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>;
96
106
  ttl: z.ZodOptional<z.ZodNumber>;
107
+ id: z.ZodOptional<z.ZodString>;
97
108
  }, z.core.$strict>, z.ZodObject<{
98
109
  kind: z.ZodLiteral<"alias">;
99
110
  type: z.ZodEnum<{
@@ -116,6 +127,7 @@ export declare const ParsedDnsRecordSchema: z.ZodDiscriminatedUnion<[z.ZodObject
116
127
  dnsName: z.ZodString;
117
128
  hostedZoneId: z.ZodString;
118
129
  }, z.core.$strict>], "kind">;
130
+ id: z.ZodOptional<z.ZodString>;
119
131
  }, z.core.$strict>], "kind">;
120
132
  export declare const ParsedCertificateSchema: z.ZodObject<{
121
133
  domainName: z.ZodString;
@@ -128,6 +140,18 @@ export declare const ParsedSubdomainDelegationSchema: z.ZodObject<{
128
140
  toAccount: z.ZodString;
129
141
  auto: z.ZodOptional<z.ZodBoolean>;
130
142
  }, z.core.$strict>;
143
+ /**
144
+ * Construct-id scheme for the records list — mirrors
145
+ * `DomainCommonProps.recordIds`. `"stable"` derives position-independent
146
+ * logical IDs (records can be inserted/removed/reordered freely);
147
+ * `"indexed"`/absent is the legacy position-coupled formula (append-only
148
+ * lists, byte-frozen for deployed stacks). Fresh imports emit `"stable"`.
149
+ */
150
+ export declare const RecordIdsModeSchema: z.ZodEnum<{
151
+ stable: "stable";
152
+ indexed: "indexed";
153
+ }>;
154
+ export type RecordIdsMode = z.infer<typeof RecordIdsModeSchema>;
131
155
  export declare const ParsedDomainRecordsSchema: z.ZodObject<{
132
156
  zoneName: z.ZodString;
133
157
  registrar: z.ZodEnum<{
@@ -135,6 +159,10 @@ export declare const ParsedDomainRecordsSchema: z.ZodObject<{
135
159
  "external-delegated": "external-delegated";
136
160
  "external-records": "external-records";
137
161
  }>;
162
+ recordIds: z.ZodOptional<z.ZodEnum<{
163
+ stable: "stable";
164
+ indexed: "indexed";
165
+ }>>;
138
166
  hostedZoneId: z.ZodOptional<z.ZodString>;
139
167
  delegatedSubdomain: z.ZodOptional<z.ZodString>;
140
168
  adoptedNameServers: z.ZodOptional<z.ZodArray<z.ZodString>>;
@@ -153,6 +181,7 @@ export declare const ParsedDomainRecordsSchema: z.ZodObject<{
153
181
  name: z.ZodString;
154
182
  value: z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>;
155
183
  ttl: z.ZodOptional<z.ZodNumber>;
184
+ id: z.ZodOptional<z.ZodString>;
156
185
  }, z.core.$strict>, z.ZodObject<{
157
186
  kind: z.ZodLiteral<"alias">;
158
187
  type: z.ZodEnum<{
@@ -175,6 +204,7 @@ export declare const ParsedDomainRecordsSchema: z.ZodObject<{
175
204
  dnsName: z.ZodString;
176
205
  hostedZoneId: z.ZodString;
177
206
  }, z.core.$strict>], "kind">;
207
+ id: z.ZodOptional<z.ZodString>;
178
208
  }, z.core.$strict>], "kind">>;
179
209
  certificates: z.ZodArray<z.ZodObject<{
180
210
  domainName: 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(),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};
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()]),p=r.options.map(t=>t.shape.kind.value),n=e.enum(["A","AAAA"]),o=e.enum(["route53","external-delegated","external-records"]),u=e.enum(["zone","full"]),a=e.string().regex(/^[A-Za-z][A-Za-z0-9]*$/),i=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(),id:a.optional()}).strict(),s=e.object({kind:e.literal("alias"),type:n,name:e.string(),target:r,id:a.optional()}).strict(),d=e.discriminatedUnion("kind",[i,s]),c=e.object({domainName:e.string(),subjectAlternativeNames:e.array(e.string()).optional(),transparencyLogging:e.boolean().optional(),cloudFront:e.boolean().optional()}).strict(),l=e.object({subdomain:e.string(),toAccount:e.string(),auto:e.boolean().optional()}).strict(),m=e.enum(["indexed","stable"]),x=e.object({zoneName:e.string(),registrar:o,recordIds:m.optional(),hostedZoneId:e.string().optional(),delegatedSubdomain:e.string().optional(),adoptedNameServers:e.array(e.string().min(1)).min(1).optional(),records:e.array(d),certificates:e.array(c),delegations:e.array(l)}).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{n as AliasRecordTypeSchema,u as DomainDeployPhaseSchema,o as DomainRegistrarSchema,s as ParsedAliasRecordSchema,c as ParsedCertificateSchema,d as ParsedDnsRecordSchema,x as ParsedDomainRecordsSchema,i as ParsedStandardRecordSchema,l as ParsedSubdomainDelegationSchema,a as RecordConstructIdSchema,m as RecordIdsModeSchema,p as TYPED_FJALL_TARGET_KINDS,r as TypedFjallTargetSchema};
@@ -1,14 +1,14 @@
1
- var A=Object.defineProperty;var o=(e,n)=>A(e,"name",{value:n,configurable:!0});import{getDomainStackName as k,toPascalCase as D}from"@fjall/util";const O=["A","AAAA","CNAME","MX","TXT","NS","SRV","CAA"],b=new Map(O.map((e,n)=>[e,n]));function C(e,n){return e==="@"&&n!=="@"?-1:e!=="@"&&n==="@"?1:e.localeCompare(n)}o(C,"compareName");function J(e,n){const t=Array.isArray(e)?e.join(`
2
- `):e,a=Array.isArray(n)?n.join(`
3
- `):n;return t.localeCompare(a)}o(J,"compareValue");function p(e){const n=e.kind==="standard"?0:1,t=b.get(e.type)??99;return[n,t,e.name]}o(p,"recordSortKey");function R(e){return[...e].sort((n,t)=>{const[a,c,m]=p(n),[s,d,f]=p(t);if(a!==s)return a-s;if(c!==d)return c-d;const u=C(m,f);return u!==0?u:n.kind==="standard"&&t.kind==="standard"?J(n.value,t.value):0})}o(R,"sortRecords");function P(e){return Array.isArray(e)?`[${e.map(t=>JSON.stringify(t)).join(", ")}]`:JSON.stringify(e)}o(P,"formatValue");function v(e){const n=[`type: ${JSON.stringify(e.type)}`,`name: ${JSON.stringify(e.name)}`,`value: ${P(e.value)}`];return e.ttl!==void 0&&n.push(`ttl: ${e.ttl}`),`{ ${n.join(", ")} }`}o(v,"emitStandardRecord");function I(e){switch(e.kind){case"ecs":return e.computeName===void 0?`fjallApp(${JSON.stringify(e.appName)})`:`fjallApp(${JSON.stringify(e.appName)}, ${JSON.stringify(e.computeName)})`;case"cdn":return`fjallCdn(${JSON.stringify(e.appName)})`;case"bucket":return`fjallBucket(${JSON.stringify(e.bucketName)})`;case"custom":return`aliasTo(${JSON.stringify(e.dnsName)}, ${JSON.stringify(e.hostedZoneId)})`}}o(I,"emitAliasTarget");function x(e){return`{ ${[`type: ${JSON.stringify(e.type)}`,`name: ${JSON.stringify(e.name)}`,`target: ${I(e.target)}`].join(", ")} }`}o(x,"emitAliasRecord");function T(e){return e.kind==="standard"?v(e):x(e)}o(T,"emitRecordObjectText");function w(e){return` ${T(e)},`}o(w,"emitRecord");function z(e){const n=[`domainName: ${JSON.stringify(e.domainName)}`];if(e.subjectAlternativeNames&&e.subjectAlternativeNames.length>0){const t=e.subjectAlternativeNames.map(a=>JSON.stringify(a)).join(", ");n.push(`subjectAlternativeNames: [${t}]`)}return e.transparencyLogging!==void 0&&n.push(`transparencyLogging: ${e.transparencyLogging}`),e.cloudFront!==void 0&&n.push(`cloudFront: ${e.cloudFront}`),` { ${n.join(", ")} },`}o(z,"emitCertificate");function B(e,n){if(n.length===0)return"";const t=["","// Delegations (D8 \u2014 child writes NS; no parent-side records here):"];for(const a of n)t.push(`// ${a.subdomain}.${e} \u2192 deploy a Domain { registrar: "external-delegated",`,`// zoneName: ${JSON.stringify(e)}, delegatedSubdomain: ${JSON.stringify(a.subdomain)} }`,`// in account ${JSON.stringify(a.toAccount)}; the CLI injects parentDelegationRoleArn`,"// (ManagedDomainBinding.delegationRoleArn) and the child UPSERTs its NS into this zone.");return t.join(`
1
+ var A=Object.defineProperty;var o=(e,n)=>A(e,"name",{value:n,configurable:!0});import{getDomainStackName as k,toPascalCase as D}from"@fjall/util";const O=["A","AAAA","CNAME","MX","TXT","NS","SRV","CAA"],J=new Map(O.map((e,n)=>[e,n]));function b(e,n){return e==="@"&&n!=="@"?-1:e!=="@"&&n==="@"?1:e.localeCompare(n)}o(b,"compareName");function C(e,n){const t=Array.isArray(e)?e.join(`
2
+ `):e,i=Array.isArray(n)?n.join(`
3
+ `):n;return t.localeCompare(i)}o(C,"compareValue");function p(e){const n=e.kind==="standard"?0:1,t=J.get(e.type)??99;return[n,t,e.name]}o(p,"recordSortKey");function R(e){return[...e].sort((n,t)=>{const[i,c,f]=p(n),[s,d,m]=p(t);if(i!==s)return i-s;if(c!==d)return c-d;const u=b(f,m);return u!==0?u:n.kind==="standard"&&t.kind==="standard"?C(n.value,t.value):0})}o(R,"sortRecords");function I(e){return Array.isArray(e)?`[${e.map(t=>JSON.stringify(t)).join(", ")}]`:JSON.stringify(e)}o(I,"formatValue");function P(e){const n=[`type: ${JSON.stringify(e.type)}`,`name: ${JSON.stringify(e.name)}`];return e.id!==void 0&&n.push(`id: ${JSON.stringify(e.id)}`),n.push(`value: ${I(e.value)}`),e.ttl!==void 0&&n.push(`ttl: ${e.ttl}`),`{ ${n.join(", ")} }`}o(P,"emitStandardRecord");function v(e){switch(e.kind){case"ecs":return e.computeName===void 0?`fjallApp(${JSON.stringify(e.appName)})`:`fjallApp(${JSON.stringify(e.appName)}, ${JSON.stringify(e.computeName)})`;case"cdn":return`fjallCdn(${JSON.stringify(e.appName)})`;case"bucket":return`fjallBucket(${JSON.stringify(e.bucketName)})`;case"custom":return`aliasTo(${JSON.stringify(e.dnsName)}, ${JSON.stringify(e.hostedZoneId)})`}}o(v,"emitAliasTarget");function x(e){const n=[`type: ${JSON.stringify(e.type)}`,`name: ${JSON.stringify(e.name)}`];return e.id!==void 0&&n.push(`id: ${JSON.stringify(e.id)}`),n.push(`target: ${v(e.target)}`),`{ ${n.join(", ")} }`}o(x,"emitAliasRecord");function T(e){return e.kind==="standard"?P(e):x(e)}o(T,"emitRecordObjectText");function w(e){return` ${T(e)},`}o(w,"emitRecord");function z(e){const n=[`domainName: ${JSON.stringify(e.domainName)}`];if(e.subjectAlternativeNames&&e.subjectAlternativeNames.length>0){const t=e.subjectAlternativeNames.map(i=>JSON.stringify(i)).join(", ");n.push(`subjectAlternativeNames: [${t}]`)}return e.transparencyLogging!==void 0&&n.push(`transparencyLogging: ${e.transparencyLogging}`),e.cloudFront!==void 0&&n.push(`cloudFront: ${e.cloudFront}`),` { ${n.join(", ")} },`}o(z,"emitCertificate");function B(e,n){if(n.length===0)return"";const t=["","// Delegations (D8 \u2014 child writes NS; no parent-side records here):"];for(const i of n)t.push(`// ${i.subdomain}.${e} \u2192 deploy a Domain { registrar: "external-delegated",`,`// zoneName: ${JSON.stringify(e)}, delegatedSubdomain: ${JSON.stringify(i.subdomain)} }`,`// in account ${JSON.stringify(i.toAccount)}; the CLI injects parentDelegationRoleArn`,"// (ManagedDomainBinding.delegationRoleArn) and the child UPSERTs its NS into this zone.");return t.join(`
4
4
  `)+`
5
5
  `}o(B,"emitDelegationGuidance");function F(e){const n={fjallApp:!1,fjallCdn:!1,fjallBucket:!1,aliasTo:!1};for(const t of e)if(t.kind==="alias")switch(t.target.kind){case"ecs":n.fjallApp=!0;break;case"cdn":n.fjallCdn=!0;break;case"bucket":n.fjallBucket=!0;break;case"custom":n.aliasTo=!0;break}return n}o(F,"computeUsedHelpers");function L(e){const n=["App","Domain"];return e.aliasTo&&n.push("aliasTo"),e.fjallApp&&n.push("fjallApp"),e.fjallBucket&&n.push("fjallBucket"),e.fjallCdn&&n.push("fjallCdn"),`import {
6
- ${n.map(a=>` ${a},`).join(`
6
+ ${n.map(i=>` ${i},`).join(`
7
7
  `)}
8
- } from "@fjall/components-infrastructure";`}o(L,"emitImports");function E(e){return D(e.split(".").join(""))}o(E,"safeZoneName");function g(e,n){if(e==="@")return e;const t=e.endsWith(".")?e.slice(0,-1):e;return t===n?"@":t.endsWith(`.${n}`)?t.slice(0,-(n.length+1)):e}o(g,"toRelativeRecordName");function Z(e){return e.registrar==="external-delegated"&&e.delegatedSubdomain?`${e.delegatedSubdomain}.${e.zoneName}`:e.zoneName}o(Z,"effectiveZoneName");function y(e,n,t){if(n.length===0)return` ${e}: [],`;const a=n.map(t).join(`
8
+ } from "@fjall/components-infrastructure";`}o(L,"emitImports");function E(e){return D(e.split(".").join(""))}o(E,"safeZoneName");function g(e,n){if(e==="@")return e;const t=e.endsWith(".")?e.slice(0,-1):e;return t===n?"@":t.endsWith(`.${n}`)?t.slice(0,-(n.length+1)):e}o(g,"toRelativeRecordName");function Z(e){return e.registrar==="external-delegated"&&e.delegatedSubdomain?`${e.delegatedSubdomain}.${e.zoneName}`:e.zoneName}o(Z,"effectiveZoneName");function y(e,n,t){if(n.length===0)return` ${e}: [],`;const i=n.map(t).join(`
9
9
  `);return` ${e}: [
10
- ${a}
11
- ],`}o(y,"emitBlock");function K(e,n={}){const t=k(n.componentName??e.zoneName),a=E(e.zoneName),c=F(e.records),m=L(c),s=Z(e),d=e.records.map(i=>i.kind==="standard"?{...i,name:g(i.name,s)}:{...i,name:g(i.name,s)}),f=R(d),u=[...e.certificates].sort((i,l)=>i.domainName.localeCompare(l.domainName)),h=[...e.delegations].sort((i,l)=>i.subdomain.localeCompare(l.subdomain)),r=[];if(e.hostedZoneId&&r.push(` hostedZoneId: ${JSON.stringify(e.hostedZoneId)},`),e.adoptedNameServers&&e.adoptedNameServers.length>0){const i=e.adoptedNameServers.map(l=>JSON.stringify(l)).join(", ");r.push(` adoptedNameServers: [${i}],`)}e.delegatedSubdomain&&r.push(` delegatedSubdomain: ${JSON.stringify(e.delegatedSubdomain)},`),e.registrar==="external-delegated"&&r.push(" // D8 child-writes delegation + two-phase deploy: both values arrive"," // via CDK context, injected by the Fjall CLI at deploy time (see the"," // reads above `new Domain`). Set a literal parentDelegationRoleArn"," // here only for out-of-band deploys.",' ...(domainDeployPhase === "zone" || domainDeployPhase === "full"'," ? { phase: domainDeployPhase }"," : {}),",' ...(typeof parentDelegationRoleArn === "string" &&',' parentDelegationRoleArn !== ""'," ? { parentDelegationRoleArn }"," : {}),");const N=y("certificates",u,z),S=y("records",f,w),$=e.registrar==="external-records"?"":B(e.zoneName,h),j=e.registrar==="external-delegated"?`
10
+ ${i}
11
+ ],`}o(y,"emitBlock");function K(e,n={}){const t=k(n.componentName??e.zoneName),i=E(n.componentName??e.zoneName),c=F(e.records),f=L(c),s=Z(e),d=e.records.map(a=>a.kind==="standard"?{...a,name:g(a.name,s)}:{...a,name:g(a.name,s)}),m=R(d),u=[...e.certificates].sort((a,l)=>a.domainName.localeCompare(l.domainName)),h=[...e.delegations].sort((a,l)=>a.subdomain.localeCompare(l.subdomain)),r=[];if(e.recordIds!==void 0&&r.push(` recordIds: ${JSON.stringify(e.recordIds)},`),e.hostedZoneId&&r.push(` hostedZoneId: ${JSON.stringify(e.hostedZoneId)},`),e.adoptedNameServers&&e.adoptedNameServers.length>0){const a=e.adoptedNameServers.map(l=>JSON.stringify(l)).join(", ");r.push(` adoptedNameServers: [${a}],`)}e.delegatedSubdomain&&r.push(` delegatedSubdomain: ${JSON.stringify(e.delegatedSubdomain)},`),e.registrar==="external-delegated"&&r.push(" // D8 child-writes delegation + two-phase deploy: both values arrive"," // via CDK context, injected by the Fjall CLI at deploy time (see the"," // reads above `new Domain`). Set a literal parentDelegationRoleArn"," // here only for out-of-band deploys.",' ...(domainDeployPhase === "zone" || domainDeployPhase === "full"'," ? { phase: domainDeployPhase }"," : {}),",' ...(typeof parentDelegationRoleArn === "string" &&',' parentDelegationRoleArn !== ""'," ? { parentDelegationRoleArn }"," : {}),");const N=y("certificates",u,z),S=y("records",m,w),$=e.registrar==="external-records"?"":B(e.zoneName,h),j=e.registrar==="external-delegated"?`
12
12
  // Injected by the Fjall CLI at deploy time (D8) \u2014 do not set these by hand.
13
13
  const domainDeployPhase: unknown = app.node.tryGetContext(
14
14
  "fjall:domainDeployPhase"
@@ -25,7 +25,7 @@ if (
25
25
  const parentDelegationRoleArn: unknown = app.node.tryGetContext(
26
26
  "fjall:parentDelegationRoleArn"
27
27
  );
28
- `:"";return`${m}
28
+ `:"";return`${f}
29
29
 
30
30
  // Fjall-managed domain \u2014 edit this file to add or change records. See https://docs.fjall.io/resources/networking/domain for the Domain construct API.
31
31
 
@@ -35,7 +35,7 @@ const app = App.getApp(${JSON.stringify(t)});
35
35
  // CloudFormation stack name. Do not rename it.
36
36
  const stack = app.getStack(${JSON.stringify(t)}).getStack();
37
37
  ${j}
38
- new Domain(stack, ${JSON.stringify(a)}, {
38
+ new Domain(stack, ${JSON.stringify(i)}, {
39
39
  registrar: ${JSON.stringify(e.registrar)},
40
40
  zoneName: ${JSON.stringify(e.zoneName)},
41
41
  ${r.length>0?r.join(`
@@ -1,8 +1,8 @@
1
- var m=Object.defineProperty;var n=(e,r)=>m(e,"name",{value:r,configurable:!0});import{toPascalCase as T,toKebab as V,toValidDatabaseName as C}from"@fjall/util";function c(e){return JSON.stringify(e)}n(c,"escapeStringLiteral");function _(e){return e.map(c).join(", ")}n(_,"formatStringArray");const l="import:SharedAlarmTopicArn";function $(e=" "){return`
2
- ${e}...(getConfig().environment === "production" ? { alertsTopic: ${c(l)} } : {}),`}n($,"emitProductionAlertsTopicSpread");function y(e){return e===0?"":`_${String(e+1)}`}n(y,"connectionEnvSuffix");function x(e,r){if(e===r)return 1;if(!e.startsWith(`${r}_`))return;const t=e.slice(r.length+1);return/^\d+$/.test(t)?parseInt(t,10):void 0}n(x,"connectionKeyOrdinal");function b(e){if(typeof e!="object"||e===null)return!1;const r=e;return typeof r.__identifier=="string"||typeof r.__expression=="string"||typeof r.__call=="string"}n(b,"isSpecialValue");function u(e){return e.replace(/[^a-zA-Z0-9]/g," ").split(" ").map((r,t)=>t===0?r.charAt(0).toLowerCase()+r.slice(1):r.charAt(0).toUpperCase()+r.slice(1)).join("")}n(u,"toVariableName");function j(e){return e.variableName??u(e.name)}n(j,"getVariableName");function S(e,r){for(const t of e.database)if(t.name===r&&t.variableName)return t.variableName;for(const t of e.s3)if(t.name===r&&t.variableName)return t.variableName;for(const t of e.compute)if(t.name===r&&t.variableName)return t.variableName;for(const t of e.dynamodb??[])if(t.name===r&&t.variableName)return t.variableName;for(const t of e.sqs??[])if(t.name===r&&t.variableName)return t.variableName;return u(r)}n(S,"resolveResourceVariable");function d(e){const r=Object.entries(e);return r.length===0?!0:r.length>1?!1:r.every(([,t])=>typeof t=="string"||typeof t=="number"||typeof t=="boolean"||t===null)}n(d,"isSimpleObject");function a(e,r=" "){if(e==null)return"undefined";if(typeof e=="string")return JSON.stringify(e);if(typeof e=="number"||typeof e=="boolean")return String(e);if(b(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(t=>a(t,r)).join(", ")}]`;if(typeof e=="object"){const t=Object.entries(e).filter(([,f])=>f!==void 0);if(d(e)){const f=t.map(([s,p])=>`${s}: ${a(p,r)}`).join(", ");return f?`{ ${f} }`:"{}"}const o=r+" ",i=t.map(([f,s])=>`${o}${f}: ${a(s,o)}`).join(`,
3
- `);return i?`{
4
- ${i}
5
- ${r}}`:"{}"}return JSON.stringify(e)}n(a,"formatValue");function N(e,r=" "){return e.map(t=>{const o=t.value.kind==="expression"?t.value.source:a(t.value.value,r);return`
6
- ${r}${t.key}: ${o}`}).join(",")}n(N,"emitProjectedProps");function O(e,r,t,o="raw"){if(!e)return"";let i;switch(o){case"string":i=c(String(t));break;case"object":i=a(t);break;case"boolean-or-object":i=t===!1?"false":a(t);break;default:i=String(t)}return`
7
- ${r}: ${i},`}n(O,"buildProperty");function A(e,r=" "){return e?.length?e.map(t=>`
8
- ${r}${t.key}: ${t.sourceText},`).join(""):""}n(A,"emitExtraProperties");export{l as PRODUCTION_ALERTS_TOPIC_IMPORT,O as buildProperty,y as connectionEnvSuffix,x as connectionKeyOrdinal,A as emitExtraProperties,$ as emitProductionAlertsTopicSpread,N as emitProjectedProps,c as escapeStringLiteral,_ as formatStringArray,a as formatValue,j as getVariableName,b as isSpecialValue,S as resolveResourceVariable,V as toKebab,T as toPascalCase,C as toValidDatabaseName,u as toVariableName};
1
+ var p=Object.defineProperty;var n=(e,t)=>p(e,"name",{value:t,configurable:!0});import{toPascalCase as T,toKebab as V,toValidDatabaseName as C}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 d="import:SharedAlarmTopicArn";function _(e=" "){return`
2
+ ${e}...(getConfig().environment === "production" ? { alertsTopic: ${c(d)} } : {}),`}n(_,"emitProductionAlertsTopicSpread");function $(e){return e===0?"":`_${String(e+1)}`}n($,"connectionEnvSuffix");function x(e,t){if(e===t)return 1;if(!e.startsWith(`${t}_`))return;const r=e.slice(t.length+1);return/^\d+$/.test(r)?parseInt(r,10):void 0}n(x,"connectionKeyOrdinal");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 u(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(u,"toVariableName");function j(e){return e.variableName??u(e.name)}n(j,"getVariableName");function S(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 u(t)}n(S,"resolveResourceVariable");function b(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(b,"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(b(e)){const a=r.map(([s,m])=>`${s}: ${f(m,t)}`).join(", ");return a?`{ ${a} }`:"{}"}const i=t+" ",o=r.map(([a,s])=>`${i}${a}: ${f(s,i)}`).join(`,
3
+ `);return o?`{
4
+ ${o}
5
+ ${t}}`:"{}"}return JSON.stringify(e)}n(f,"formatValue");function h(e,t=" "){return e.map(i=>{const o=r(i);return`
6
+ ${t}${i.key}: ${o}`}).join(",");function r(i){switch(i.value.kind){case"expression":return i.value.source;case"structured":throw new Error(`emitProjectedProps cannot render the structured value for "${i.key}" \u2014 structured expressions are emitted by the codemod's AST serialiser only.`);case"literal":return f(i.value.value,t)}}}n(h,"emitProjectedProps");function N(e,t,r,i="raw"){if(!e)return"";let o;switch(i){case"string":o=c(String(r));break;case"object":o=f(r);break;case"boolean-or-object":o=r===!1?"false":f(r);break;default:o=String(r)}return`
7
+ ${t}: ${o},`}n(N,"buildProperty");function A(e,t=" "){return e?.length?e.map(r=>`
8
+ ${t}${r.key}: ${r.sourceText},`).join(""):""}n(A,"emitExtraProperties");export{d as PRODUCTION_ALERTS_TOPIC_IMPORT,N as buildProperty,$ as connectionEnvSuffix,x as connectionKeyOrdinal,A as emitExtraProperties,_ as emitProductionAlertsTopicSpread,h as emitProjectedProps,c as escapeStringLiteral,g as formatStringArray,f as formatValue,j as getVariableName,l as isSpecialValue,S as resolveResourceVariable,V as toKebab,T as toPascalCase,C as toValidDatabaseName,u as toVariableName};
@@ -0,0 +1,83 @@
1
+ export declare const DATABASE_ENV_VARS: Readonly<{
2
+ readonly HOST: "DATABASE_HOST";
3
+ readonly PORT: "DATABASE_PORT";
4
+ readonly NAME: "DATABASE_NAME";
5
+ readonly SSL: "DATABASE_SSL";
6
+ readonly USERNAME: "DATABASE_USERNAME";
7
+ readonly PASSWORD: "DATABASE_PASSWORD";
8
+ }>;
9
+ export declare const CREDENTIAL_KEYS: Readonly<{
10
+ readonly USERNAME: "username";
11
+ readonly PASSWORD: "password";
12
+ }>;
13
+ /** The literal value emitted for `DATABASE_SSL`. */
14
+ export declare const DATABASE_SSL_VALUE = "true";
15
+ /**
16
+ * Construct accessor methods the emitted connection wiring calls on a bound
17
+ * database variable.
18
+ */
19
+ export declare const DATABASE_ACCESSORS: Readonly<{
20
+ readonly HOST: "getHostEndpoint";
21
+ readonly PORT: "getHostPort";
22
+ readonly NAME: "getDatabaseName";
23
+ readonly CREDENTIALS: "getCredentials";
24
+ readonly IMPORT: "getImport";
25
+ }>;
26
+ export declare const STORAGE_ENV_VARS: Readonly<{
27
+ readonly NAME: "BUCKET_NAME";
28
+ }>;
29
+ /**
30
+ * Construct accessor methods the emitted connection wiring calls on a bound
31
+ * bucket variable.
32
+ */
33
+ export declare const STORAGE_ACCESSORS: Readonly<{
34
+ readonly BUCKET_NAME: "getBucketName";
35
+ }>;
36
+ export declare const MESSAGING_ENV_VARS: Readonly<{
37
+ readonly URL: "QUEUE_URL";
38
+ readonly ARN: "QUEUE_ARN";
39
+ }>;
40
+ /**
41
+ * Construct accessor methods the emitted connection wiring calls on a bound
42
+ * queue variable.
43
+ */
44
+ export declare const MESSAGING_ACCESSORS: Readonly<{
45
+ readonly URL: "getQueueUrl";
46
+ readonly ARN: "getQueueArn";
47
+ }>;
48
+ /**
49
+ * Emission order for `connections: [...]` — databases, then storage, then
50
+ * messaging. `formatAllConnectionsCode` and the connect edit's insertion
51
+ * ranks both derive from this tuple so a surgical insert never reorders what
52
+ * a later full regeneration would emit.
53
+ */
54
+ export declare const CONNECTION_TYPE_ORDER: readonly ["database", "storage", "messaging"];
55
+ export type ConnectionResourceType = (typeof CONNECTION_TYPE_ORDER)[number];
56
+ /** How a wiring entry's value is produced from the bound resource variable. */
57
+ export type ConnectionWiringValue = {
58
+ kind: "accessor";
59
+ method: string;
60
+ } | {
61
+ kind: "credential";
62
+ credentialKey: string;
63
+ } | {
64
+ kind: "literal";
65
+ value: string;
66
+ };
67
+ export interface ConnectionWiringEntry {
68
+ key: string;
69
+ target: "environment" | "secretsImport";
70
+ value: ConnectionWiringValue;
71
+ }
72
+ /**
73
+ * The wiring entries a single connection of `resourceType` contributes, in
74
+ * canonical emission order. `suffix` is the `_N` scheme value for this
75
+ * connection's ordinal (`connectionEnvSuffix`).
76
+ */
77
+ export declare function buildConnectionWiringEntries(resourceType: ConnectionResourceType, suffix: string): ConnectionWiringEntry[];
78
+ /**
79
+ * Render a wiring value as generated source for the scaffold lane. The
80
+ * connect edit builds the equivalent AST nodes from the same
81
+ * {@link ConnectionWiringValue} shapes.
82
+ */
83
+ export declare function renderWiringValueSource(value: ConnectionWiringValue, variableName: string): string;
@@ -0,0 +1 @@
1
+ var N=Object.defineProperty;var r=(t,e)=>N(t,"name",{value:e,configurable:!0});import{escapeStringLiteral as o}from"./common.js";const E=Object.freeze({HOST:"DATABASE_HOST",PORT:"DATABASE_PORT",NAME:"DATABASE_NAME",SSL:"DATABASE_SSL",USERNAME:"DATABASE_USERNAME",PASSWORD:"DATABASE_PASSWORD"}),c=Object.freeze({USERNAME:"username",PASSWORD:"password"}),O="true",n=Object.freeze({HOST:"getHostEndpoint",PORT:"getHostPort",NAME:"getDatabaseName",CREDENTIALS:"getCredentials",IMPORT:"getImport"}),T=Object.freeze({NAME:"BUCKET_NAME"}),_=Object.freeze({BUCKET_NAME:"getBucketName"}),R=Object.freeze({URL:"QUEUE_URL",ARN:"QUEUE_ARN"}),s=Object.freeze({URL:"getQueueUrl",ARN:"getQueueArn"}),g=["database","storage","messaging"],A=r((t,e)=>({key:t,target:"environment",value:e}),"environmentEntry"),a=r((t,e)=>({key:t,target:"secretsImport",value:{kind:"credential",credentialKey:e}}),"secretEntry"),S=r(t=>({kind:"accessor",method:t}),"accessor");function D(t,e){switch(t){case"database":return[A(`${E.HOST}${e}`,S(n.HOST)),A(`${E.PORT}${e}`,S(n.PORT)),A(`${E.NAME}${e}`,S(n.NAME)),A(`${E.SSL}${e}`,{kind:"literal",value:O}),a(`${E.USERNAME}${e}`,c.USERNAME),a(`${E.PASSWORD}${e}`,c.PASSWORD)];case"storage":return[A(`${T.NAME}${e}`,S(_.BUCKET_NAME))];case"messaging":return[A(`${R.URL}${e}`,S(s.URL)),A(`${R.ARN}${e}`,S(s.ARN))]}}r(D,"buildConnectionWiringEntries");function M(t,e){switch(t.kind){case"accessor":return`${e}.${t.method}()`;case"credential":return`${e}.${n.CREDENTIALS}().${n.IMPORT}(${o(t.credentialKey)})`;case"literal":return o(t.value)}}r(M,"renderWiringValueSource");export{g as CONNECTION_TYPE_ORDER,c as CREDENTIAL_KEYS,n as DATABASE_ACCESSORS,E as DATABASE_ENV_VARS,O as DATABASE_SSL_VALUE,s as MESSAGING_ACCESSORS,R as MESSAGING_ENV_VARS,_ as STORAGE_ACCESSORS,T as STORAGE_ENV_VARS,D as buildConnectionWiringEntries,M as renderWiringValueSource};
@@ -5,38 +5,7 @@
5
5
  * RDS Instance, Aurora, and GlobalAurora configurations.
6
6
  */
7
7
  import type { DatabaseResourcePlan, ApplicationResourcePlan, ComputeResourcePlan } from "../schemas/resourceSchemas.js";
8
- export declare const DATABASE_ENV_VARS: Readonly<{
9
- readonly HOST: "DATABASE_HOST";
10
- readonly PORT: "DATABASE_PORT";
11
- readonly NAME: "DATABASE_NAME";
12
- readonly SSL: "DATABASE_SSL";
13
- readonly USERNAME: "DATABASE_USERNAME";
14
- readonly PASSWORD: "DATABASE_PASSWORD";
15
- }>;
16
- export declare const CREDENTIAL_KEYS: Readonly<{
17
- readonly USERNAME: "username";
18
- readonly PASSWORD: "password";
19
- }>;
20
- /**
21
- * The literal value emitted for `DATABASE_SSL`. Shared with the codemod
22
- * connection edit (`codemod/edits/connectResourceToCompute.ts`) — the two
23
- * emitters must write the same byte or surgically-wired apps diverge from
24
- * regenerated ones.
25
- */
26
- export declare const DATABASE_SSL_VALUE = "true";
27
- /**
28
- * Construct accessor methods the emitted connection wiring calls on a bound
29
- * database variable. Shared with the codemod connection edit
30
- * (`codemod/edits/connectResourceToCompute.ts`) — the two emitters must call
31
- * identical methods or surgically-wired apps fail at synth.
32
- */
33
- export declare const DATABASE_ACCESSORS: Readonly<{
34
- readonly HOST: "getHostEndpoint";
35
- readonly PORT: "getHostPort";
36
- readonly NAME: "getDatabaseName";
37
- readonly CREDENTIALS: "getCredentials";
38
- readonly IMPORT: "getImport";
39
- }>;
8
+ export { CREDENTIAL_KEYS, DATABASE_ACCESSORS, DATABASE_ENV_VARS, DATABASE_SSL_VALUE, } from "./connectionWiring.js";
40
9
  export type DatabaseEnvVarEntry = {
41
10
  key: string;
42
11
  expression: string;
@@ -51,8 +20,8 @@ export interface DatabaseEnvVars {
51
20
  */
52
21
  export declare function getConnectedDatabases(plan: ApplicationResourcePlan, compute: ComputeResourcePlan): DatabaseResourcePlan[];
53
22
  /**
54
- * Generate database environment variable entries for a list of connected databases.
55
- * Both ECS and Lambda use containerSecretsImport with getImport() for credentials.
23
+ * Generate database environment variable entries for a list of connected
24
+ * databases from the shared wiring vocabulary (`connectionWiring.ts`).
56
25
  * Credential entries are always marked as secrets (isSecret: true).
57
26
  */
58
27
  export declare function generateDatabaseEnvVarEntries(connectedDatabases: DatabaseResourcePlan[]): DatabaseEnvVarEntry[];