@fjall/generator 8.0.0 → 10.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.build-source-hash +32 -29
- package/dist/.minified +1 -1
- package/dist/src/ast/astTestHelpers.d.ts +1 -0
- package/dist/src/ast/parsers/resources/astComputeParserHelpers.js +1 -1
- package/dist/src/codemod/edits/addResource.js +1 -1
- package/dist/src/codemod/edits/appendAccountToStage.js +1 -1
- package/dist/src/codemod/edits/computeServiceLocator.d.ts +65 -0
- package/dist/src/codemod/edits/computeServiceLocator.js +1 -0
- package/dist/src/codemod/edits/connectResourceToCompute.d.ts +65 -0
- package/dist/src/codemod/edits/connectResourceToCompute.js +1 -0
- package/dist/src/codemod/edits/modifyResource.js +1 -1
- package/dist/src/codemod/edits/moduleConstResolver.d.ts +1 -0
- package/dist/src/codemod/edits/moduleConstResolver.js +1 -1
- package/dist/src/codemod/edits/objectGraph.d.ts +6 -0
- package/dist/src/codemod/edits/objectGraph.js +1 -1
- package/dist/src/codemod/edits/setContainerSecrets.js +1 -1
- package/dist/src/codemod/emitGuard.d.ts +5 -6
- package/dist/src/codemod/index.d.ts +1 -0
- package/dist/src/codemod/index.js +1 -1
- package/dist/src/codemod/registry.d.ts +28 -7
- package/dist/src/codemod/registry.js +1 -1
- package/dist/src/codemod/types.d.ts +9 -1
- package/dist/src/codemod/types.js +1 -1
- package/dist/src/codemod/validationGate/gates/schema.js +1 -1
- package/dist/src/generation/common.d.ts +15 -0
- package/dist/src/generation/common.js +6 -6
- package/dist/src/generation/compute/ecs.js +14 -13
- package/dist/src/generation/database.d.ts +20 -0
- package/dist/src/generation/database.js +18 -18
- package/dist/src/generation/messagingConnections.js +1 -1
- package/dist/src/generation/storageConnections.d.ts +9 -0
- package/dist/src/generation/storageConnections.js +1 -1
- package/dist/src/planning/index.d.ts +2 -1
- package/dist/src/planning/index.js +1 -1
- package/dist/src/planning/planBuilders.d.ts +48 -0
- package/dist/src/planning/planBuilders.js +1 -0
- package/dist/src/planning/resourceAddition.d.ts +3 -0
- package/dist/src/planning/resourceAddition.js +1 -1
- package/dist/src/planning/resourcePlanning.js +1 -1
- package/dist/src/schemas/applicationSchemas.d.ts +4 -0
- package/dist/src/schemas/computeSchemas.d.ts +13 -1
- package/dist/src/schemas/computeSchemas.js +1 -1
- package/dist/src/schemas/constants.d.ts +2 -0
- package/dist/src/schemas/constants.js +1 -1
- package/dist/src/version.d.ts +1 -1
- package/dist/src/version.js +1 -1
- 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
|
|
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 a}from"./edits/appendAccountToStage.js";import{setContainerSecrets as d}from"./edits/setContainerSecrets.js";import{connectResourceToCompute as i}from"./edits/connectResourceToCompute.js";import{addVpcPeer as f,modifyVpcPeer as u,removeVpcPeer as P}from"./edits/vpcPeer.js";import{addVpcPeerAccepter as R,modifyVpcPeerAccepter as T,removeVpcPeerAccepter as S}from"./edits/vpcPeerAccepter.js";import{addCrossPlanConnection as C,modifyCrossPlanConnection as A,removeCrossPlanConnection as V}from"./edits/crossPlanConnection.js";import{resolveDriftPolicy as y}from"./edits/driftPolicy.js";import{listResources as D}from"./listResources.js";import{resolveConstructByLiteralProperty as N}from"./semanticIndex/index.js";import{parse as F}from"./fileRewriter/parse.js";import{CrossPlanConnectionResourcePlanSchema as I,VpcPeerAccepterResourcePlanSchema as M,VpcPeerResourcePlanSchema as O}from"../schemas/index.js";import{detectDrift as k,mergeProperties as B,snapshotProperties as U}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 se,estimateCostUsd as ae,FALLBACK_EVENTS as ne,GATE_EVENTS as de,PARSE_GATE as Ee,RUNTIME_GATE as ie,runFallback as le,shouldTryFallback as fe}from"./llmFallback/index.js";export{$ as CODEMOD_ERROR_KINDS,I as CrossPlanConnectionResourcePlanSchema,ne as FALLBACK_EVENTS,de as GATE_EVENTS,Ee as PARSE_GATE,H as REGISTERED_STATEMENT_TYPES,ie as RUNTIME_GATE,q as ResourceNameSchema,J as STATEMENT_REGISTRY,w as StatementTypeSchema,X as UNRESOLVED,M as VpcPeerAccepterResourcePlanSchema,O as VpcPeerResourcePlanSchema,C as addCrossPlanConnection,o as addResource,f as addVpcPeer,R as addVpcPeerAccepter,a as appendAccountToStage,re as buildEgressBlockedEvent,oe as buildFiredEvent,te as buildGateFailedEvent,ce as buildGatePassedEvent,pe as buildRejectedEvent,me as buildSucceededEvent,se as buildTimeoutEvent,Y as computeLinesDelta,i as connectResourceToCompute,k as detectDrift,ae as estimateCostUsd,W as evaluateEmitGuard,D as listResources,B as mergeProperties,A as modifyCrossPlanConnection,m as modifyResource,u as modifyVpcPeer,T as modifyVpcPeerAccepter,F as parse,V as removeCrossPlanConnection,c as removeResource,P as removeVpcPeer,S as removeVpcPeerAccepter,N as resolveConstructByLiteralProperty,y as resolveDriftPolicy,le as runFallback,d as setContainerSecrets,fe as shouldTryFallback,U as snapshotProperties};
|
|
@@ -27,6 +27,27 @@ export interface StatementTypeEntry {
|
|
|
27
27
|
locator: StatementLocator;
|
|
28
28
|
generator: StatementGenerator;
|
|
29
29
|
schemaFragment: z.ZodObject<z.ZodRawShape>;
|
|
30
|
+
/**
|
|
31
|
+
* The ADD path's required-aware input contract: the plan schema minus
|
|
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.
|
|
36
|
+
*
|
|
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; `cdn.defaultOriginRef` likewise), so
|
|
42
|
+
* demanding them at the gate would be a catch-22 no invocation could
|
|
43
|
+
* satisfy. When an increment lands a type's projection and deletes its
|
|
44
|
+
* guard table, declare `addContract` in the same edit — the schema-gate
|
|
45
|
+
* XOR test pins the pairing.
|
|
46
|
+
*
|
|
47
|
+
* Absent = the schema gate applies `schemaFragment` to adds too
|
|
48
|
+
* (unknown-key and per-key-shape checks only, no required demand).
|
|
49
|
+
*/
|
|
50
|
+
addContract?: z.ZodObject<z.ZodRawShape>;
|
|
30
51
|
/**
|
|
31
52
|
* When present, the ADD path emits `app.<appMethod>(XFactory.build(...))`
|
|
32
53
|
* instead of the bare factory call. MANDATORY for any type whose factory
|
|
@@ -84,11 +105,12 @@ export interface StatementTypeEntry {
|
|
|
84
105
|
* @fjall/components-infrastructure.
|
|
85
106
|
*
|
|
86
107
|
* Deliberately NOT covered: INCOMPLETE input, where the vocabulary can
|
|
87
|
-
* express a working call and the operator has not yet
|
|
88
|
-
*
|
|
89
|
-
* buildkite` with no flags
|
|
90
|
-
*
|
|
91
|
-
*
|
|
108
|
+
* express a working call and the operator has not yet — that is
|
|
109
|
+
* `addContract`'s territory, refused at write time by the schema gate for
|
|
110
|
+
* guard-free types (`fjall add buildkite` with no flags is now refused
|
|
111
|
+
* naming `buildkiteQueue` + `buildkiteOrgSlug` instead of throwing
|
|
112
|
+
* `Buildkite: invalid props` at synth). Nor is this general schema
|
|
113
|
+
* validation: unknown keys and mistyped values are the schema gate's job.
|
|
92
114
|
*
|
|
93
115
|
* Absent = every expressible property shape for this type reaches a
|
|
94
116
|
* synthesising statement. That is a claim, not an oversight, and it is now
|
|
@@ -99,7 +121,7 @@ export interface StatementTypeEntry {
|
|
|
99
121
|
*/
|
|
100
122
|
emitGuard?: ReadonlyArray<EmitGuardRule>;
|
|
101
123
|
}
|
|
102
|
-
declare const FACTORY_IDENTIFIERS: {
|
|
124
|
+
export declare const FACTORY_IDENTIFIERS: {
|
|
103
125
|
readonly database: "DatabaseFactory";
|
|
104
126
|
readonly storage: "StorageFactory";
|
|
105
127
|
readonly compute: "ComputeFactory";
|
|
@@ -125,4 +147,3 @@ export declare const STATEMENT_REGISTRY: Record<StatementType, StatementTypeEntr
|
|
|
125
147
|
*/
|
|
126
148
|
export declare const REGISTERED_STATEMENT_TYPES: ReadonlyArray<StatementType>;
|
|
127
149
|
export declare function findTypeByIdentifier(identifier: string): StatementType | undefined;
|
|
128
|
-
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var N=Object.defineProperty;var a=(e,t)=>N(e,"name",{value:t,configurable:!0});import{z as p}from"zod";import{BuildkitePropsObjectSchema as y,CDNResourcePlanSchema as M,ComputeResourcePlanSchema as _,CrossPlanConnectionResourcePlanSchema as f,DatabaseResourcePlanSchema as b,NetworkResourcePlanSchema as C,NextJSPatternConfigSchema as D,OrganisationResourcePlanSchema as S,PayloadPatternConfigSchema as O,S3ResourcePlanSchema as P,SQSResourcePlanSchema as v,StaticSitePatternConfigSchema as x,VpcPeerAccepterResourcePlanSchema as R,VpcPeerResourcePlanSchema as W}from"../schemas/index.js";import{failure as G}from"../types/Result.js";import{isRecord as I}from"./_internal.js";import{AUTHOR_BY_HAND as d,requiresLiveValue as k,silentlyDropped as n,UNRESOLVED as l,whenAbsent as u}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 i(e){const{name:t,...s}=e.shape;return p.object(s).partial().strict()}a(i,"fragmentOf");function c(e){const{name:t,...s}=e.shape;return p.object(s).strict()}a(c,"completeFragmentOf");const j=i(b),B=i(P),L=(()=>{const{name:e,...t}=_.shape;return p.object(t).partial().strict()})(),V=i(v),Y=i(M),q=i(C),K=(()=>{const{name:e,type:t,cdn:s,...A}=O.shape,{name:re,type:oe,cdn:se,...E}=D.shape,{name:ie,type:ce,domain:de,cdn:F,...w}=x.shape;return p.object({...A,...E,...w,cdn:p.union([s,F])}).partial().strict()})(),U=i(W),z=i(R),H=i(f),Q=i(S),$=i(y);function h(e,t){return G({kind:"SemanticQueryError",reason:`StatementTypeEntry.${e} for ${t} is not wired; existing types dispatch through the shared locator/generator.`})}a(h,"notWiredError");function J(e){return{factoryIdentifier:e,findByShape:a(()=>h("locator.findByShape",e),"findByShape"),validateContext:a(()=>h("locator.validateContext",e),"validateContext")}}a(J,"createLocator");function X(e){return{build:a(()=>{const t=h("generator.build",e);throw new Error(t.success?"unreachable":t.error.reason)},"build")}}a(X,"createGenerator");const Z=n("variableName","`variableName` is a plan-only round-trip key naming the `const <var> =` binding the scaffold emits; no construct reads it."),T=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."),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.",ee=[{property:"deployment",refuseWhen:a(e=>(e.type==="lambda"||e.deployment!==void 0)&&e.deployment!=="container"&&e.code!==l,"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."),k("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."),k("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",m),n("connectedDatabase",m),n("connectedStorage",m),n("connectedMessaging",m),Z,T],te=[{property:"originType",refuseWhen:u("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. "+d},{property:"originType",refuseWhen:a(e=>e.originType==="s3"&&e.bucket!==l,"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. "+d},{property:"originType",refuseWhen:a(e=>e.originType==="alb"&&e.loadBalancer!==l,"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"`. '+d},{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. "+d},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."),T],ae=[{property:"name",refuseWhen:u("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. "+d},{property:"type",refuseWhen:u("type"),reason:"`PatternFactory.build` reads `PATTERN_REGISTRY[props.type]` before it even returns the thunk, and the pattern vocabulary carries no `type` discriminator. "+d}],ne=[{property:"peerAppName",refuseWhen:u("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:u("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,s={}){return{factoryIdentifier:e,locator:J(e),generator:X(e),schemaFragment:t,...s}}a(o,"createEntry");const g={database:o(r.database,j,{emitWrapper:{appMethod:"addDatabase"},addContract:c(b)}),storage:o(r.storage,B,{emitWrapper:{appMethod:"addStorage"},addContract:c(P)}),compute:o(r.compute,L,{emitWrapper:{appMethod:"addCompute"},emitGuard:ee}),messaging:o(r.messaging,V,{emitWrapper:{appMethod:"addMessaging"},addContract:c(v)}),cdn:o(r.cdn,Y,{emitWrapper:{appMethod:"addCdn"},emitGuard:te}),network:o(r.network,q,{emitWrapper:{appMethod:"addNetwork"},addContract:c(C)}),pattern:o(r.pattern,K,{emitWrapper:{appMethod:"addPattern"},emitGuard:ae}),"vpc-peer":o(r["vpc-peer"],U,{emitWrapper:{appMethod:"addVpcPeer"},emitGuard:ne}),"vpc-peer-accepter":o(r["vpc-peer-accepter"],z,{emitWrapper:{appMethod:"addVpcPeerAccepter"},addContract:c(R)}),"cross-plan-connection":o(r["cross-plan-connection"],H,{addContract:c(f)}),organisation:o(r.organisation,Q,{addContract:c(S)}),buildkite:o(r.buildkite,$,{emitWrapper:{appMethod:"addBuildkite",propsOverloadConstructId:"Buildkite"},addContract:c(y)})},ye=Object.keys(g);function fe(e){const t=Object.keys(g);for(const s of t)if(g[s].factoryIdentifier===e)return s}a(fe,"findTypeByIdentifier");export{r as FACTORY_IDENTIFIERS,ye as REGISTERED_STATEMENT_TYPES,g as STATEMENT_REGISTRY,fe as findTypeByIdentifier};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { ResourceNameSchema } from "../schemas/baseSchemas.js";
|
|
2
3
|
import type { GateId } from "./validationGate/types.js";
|
|
3
4
|
import type { EgressRiskReason } from "./llmFallback/egressGate.types.js";
|
|
4
5
|
export declare const DriftPolicySchema: z.ZodObject<{
|
|
@@ -26,7 +27,14 @@ export declare const StatementTypeSchema: z.ZodEnum<{
|
|
|
26
27
|
buildkite: "buildkite";
|
|
27
28
|
}>;
|
|
28
29
|
export type StatementType = z.infer<typeof StatementTypeSchema>;
|
|
29
|
-
|
|
30
|
+
/**
|
|
31
|
+
* The scaffold's shared resource-name vocabulary (lowercase-leading factory
|
|
32
|
+
* names included: interactive adds use `resourceName = databaseName`, the
|
|
33
|
+
* default is `${appName}Database`). Re-exported from the canonical schema so
|
|
34
|
+
* the codemod's add/modify/remove gates cannot drift from the generator's
|
|
35
|
+
* validation.
|
|
36
|
+
*/
|
|
37
|
+
export { ResourceNameSchema };
|
|
30
38
|
export type ResourceName = z.infer<typeof ResourceNameSchema>;
|
|
31
39
|
export declare const AddOptionsSchema: z.ZodObject<{
|
|
32
40
|
type: z.ZodEnum<{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{z as t}from"zod";import{
|
|
1
|
+
import{z as t}from"zod";import{ResourceNameSchema as e}from"../schemas/baseSchemas.js";const o=t.object({force:t.boolean().optional(),resolutionMap:t.record(t.string(),t.unknown()).optional()}).strict(),n=t.enum(["database","storage","compute","messaging","cdn","network","pattern","vpc-peer","vpc-peer-accepter","cross-plan-connection","organisation","buildkite"]),r=t.record(t.string(),t.unknown()),l=t.object({type:n,name:e,properties:r,filePath:t.string().optional(),driftPolicy:o.optional(),branch:t.string().optional()}).strict(),m=t.object({type:n,name:e,filePath:t.string().optional(),force:t.boolean().optional(),branch:t.string().optional()}).strict(),g=t.object({type:n,name:e,properties:r,filePath:t.string().optional(),driftPolicy:o.optional(),branch:t.string().optional()}).strict(),i=t.object({line:t.number().int().positive(),column:t.number().int().positive(),context:t.string()}).strict(),c=t.object({added:t.number().int().nonnegative(),removed:t.number().int().nonnegative()}).strict(),a=t.object({type:n,name:t.string(),filePath:t.string(),start:t.number().int().nonnegative(),length:t.number().int().nonnegative(),managed:t.literal(!1).optional()}).strict(),b=t.object({filePath:t.string(),resources:t.array(a)}).strict(),h=t.object({content:t.string(),linesChanged:c,references:t.array(i).optional(),warnings:t.array(t.string()).optional()}).strict(),u=t.object({property:t.string(),base:t.unknown().optional(),theirs:t.unknown(),ours:t.unknown(),verdict:t.enum(["clean","no-op","compatible","conflict"])}).strict();export{l as AddOptionsSchema,h as CodemodSuccessSchema,o as DriftPolicySchema,c as LinesChangedSchema,g as ModifyOptionsSchema,u as PropertyDeltaSchema,i as ReferenceLocationSchema,m as RemoveOptionsSchema,a as ResourceListingEntrySchema,b as ResourceListingSchema,e as ResourceNameSchema,n as StatementTypeSchema};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{success as c}from"../../../types/Result.js";const
|
|
1
|
+
var a=Object.defineProperty;var s=(e,r)=>a(e,"name",{value:r,configurable:!0});import{failure as p,success as c}from"../../../types/Result.js";import{STATEMENT_REGISTRY as d}from"../../registry.js";const h={id:"schema",run(e){const r=d[e.plan.type],n=(e.plan.op==="add"?r.addContract??r.schemaFragment:r.schemaFragment).safeParse(e.plan.properties);return n.success?c({action:"proceed"}):p(u(e,n.error))}};function u(e,r){const t=f(e,r);if(t.length>0){const o=t.map(i=>`\`${i}\``).join(", ");return{kind:"InvalidPropertyError",property:t[0]??"<unknown>",reason:`required for a new ${e.plan.type} and not provided (missing: ${o}). Nothing has been written.`}}const n=r.issues[0];if(n!==void 0&&n.code==="unrecognized_keys"){const o=n.keys.map(i=>`\`${i}\``).join(", ");return{kind:"InvalidPropertyError",property:n.keys[0]??"<unknown>",reason:`not a ${e.plan.type} property (unrecognised: ${o}). Nothing has been written.`}}return{kind:"InvalidPropertyError",property:n!==void 0&&n.path.length>0?String(n.path[0]):Object.keys(e.plan.properties)[0]??"<unknown>",reason:n?.message??"Schema validation failed"}}s(u,"toInvalidPropertyError");function f(e,r){const t=[];for(const n of r.issues){if(n.path.length!==1)continue;const o=n.path[0];typeof o=="string"&&(o in e.plan.properties||t.includes(o)||t.push(o))}return t}s(f,"missingRequiredKeys");export{h as schemaGate};
|
|
@@ -29,6 +29,21 @@ export declare function formatStringArray(values: readonly string[]): string;
|
|
|
29
29
|
*/
|
|
30
30
|
export declare const PRODUCTION_ALERTS_TOPIC_IMPORT = "import:SharedAlarmTopicArn";
|
|
31
31
|
export declare function emitProductionAlertsTopicSpread(indent?: string): string;
|
|
32
|
+
/**
|
|
33
|
+
* The `_N` connection env-key suffix scheme, shared by every connection
|
|
34
|
+
* emitter (database, storage, messaging) AND the codemod connection edit
|
|
35
|
+
* (`codemod/edits/connectResourceToCompute.ts`): the first connection of a
|
|
36
|
+
* type gets no suffix, the Nth gets `_N`. `index` is zero-based position.
|
|
37
|
+
* Drift between the two lanes silently desynchronises surgically-wired env
|
|
38
|
+
* keys from regenerated ones.
|
|
39
|
+
*/
|
|
40
|
+
export declare function connectionEnvSuffix(index: number): string;
|
|
41
|
+
/**
|
|
42
|
+
* Inverse of {@link connectionEnvSuffix}: the 1-based ordinal a key encodes
|
|
43
|
+
* for `base` (`DATABASE_HOST` → 1, `DATABASE_HOST_2` → 2), or `undefined`
|
|
44
|
+
* when the key does not belong to that base's suffix scheme.
|
|
45
|
+
*/
|
|
46
|
+
export declare function connectionKeyOrdinal(key: string, base: string): number | undefined;
|
|
32
47
|
/**
|
|
33
48
|
* Type guard to check if a value is a special code generation value
|
|
34
49
|
*/
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
var
|
|
2
|
-
${e}...(getConfig().environment === "production" ? { alertsTopic: ${c(
|
|
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
3
|
`);return i?`{
|
|
4
4
|
${i}
|
|
5
|
-
${
|
|
6
|
-
${
|
|
7
|
-
${
|
|
8
|
-
${
|
|
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,12 +1,12 @@
|
|
|
1
|
-
var O=Object.defineProperty;var u=(e,n)=>O(e,"name",{value:n,configurable:!0});import{formatValue as
|
|
2
|
-
ec2Config: ${
|
|
3
|
-
cluster: ${
|
|
1
|
+
var O=Object.defineProperty;var u=(e,n)=>O(e,"name",{value:n,configurable:!0});import{formatValue as S,emitExtraProperties as E,escapeStringLiteral as o,formatStringArray as k,emitProductionAlertsTopicSpread as R}from"../common.js";import{DATABASE_ENV_VARS as y,getConnectedDatabases as D,buildDatabaseEnvVars as N}from"../database.js";import{STORAGE_ENV_VARS as B,getConnectedStorage as j,buildStorageEnvVars as L,formatAllConnectionsCode as _}from"../storageConnections.js";import{MESSAGING_ENV_VARS as C,getConnectedMessaging as H,buildMessagingEnvVars as w}from"../messagingConnections.js";import{BASE_ENVIRONMENT_VARS as I,computeHasConnections as G,computeHasDatabaseConnections as P,computeHasMessagingConnections as M,computeHasStorageConnections as V,formatCompactOrExpandedObject as $,formatEnvBlock as x}from"./shared.js";function J(e){const n=[];if(e.instanceType!==void 0&&n.push(`instanceType: ${o(e.instanceType)}`),e.amiHardwareType!==void 0&&n.push(`amiHardwareType: ${o(e.amiHardwareType)}`),e.minCapacity!==void 0&&n.push(`minCapacity: ${e.minCapacity}`),e.maxCapacity!==void 0&&n.push(`maxCapacity: ${e.maxCapacity}`),e.memoryLimitMiB!==void 0&&n.push(`memoryLimitMiB: ${e.memoryLimitMiB}`),e.warmPool!==void 0&&n.push(`warmPool: ${S(e.warmPool," ")}`),e.extraProperties?.length)for(const t of e.extraProperties)n.push(`${t.key}: ${t.sourceText}`);return`
|
|
2
|
+
ec2Config: ${$(n," "," ")},`}u(J,"generateEcsServiceEc2ConfigCode");function K(e){if(!e.cluster)return"";const n=[];if(e.cluster.directAccess&&n.push("directAccess: true"),e.cluster.domain&&n.push(`domain: ${o(e.cluster.domain)}`),e.cluster.loadBalancer!==void 0&&n.push(e.cluster.loadBalancer===!1?"loadBalancer: false":`loadBalancer: ${o(e.cluster.loadBalancer)}`),e.cluster.extraProperties?.length)for(const t of e.cluster.extraProperties)n.push(`${t.key}: ${t.sourceText}`);return`
|
|
3
|
+
cluster: ${$(n," "," ")},`}u(K,"generateEcsClusterCode");function U(e,n,t,l,p,h){let i="";e.name&&(i+=`
|
|
4
4
|
name: ${o(e.name)},`),e.image&&(i+=`
|
|
5
5
|
image: ${o(e.image)},`),e.port!==void 0&&(i+=`
|
|
6
6
|
port: ${e.port},`),e.essential!==void 0&&(i+=`
|
|
7
7
|
essential: ${e.essential},`),e.command?.length&&(i+=`
|
|
8
8
|
command: ${JSON.stringify(e.command)},`),e.entryPoint?.length&&(i+=`
|
|
9
|
-
entryPoint: ${JSON.stringify(e.entryPoint)},`);const c=[y.HOST,y.PORT,y.NAME,y.SSL,y.USERNAME,y.PASSWORD,B.NAME,C.URL,C.ARN],r=u(a=>{if(!a)return a;const d={};for(const[m,g]of Object.entries(a))c.some(
|
|
9
|
+
entryPoint: ${JSON.stringify(e.entryPoint)},`);const c=[y.HOST,y.PORT,y.NAME,y.SSL,y.USERNAME,y.PASSWORD,B.NAME,C.URL,C.ARN],r=u(a=>{if(!a)return a;const d={};for(const[m,g]of Object.entries(a))c.some(v=>m===v||m.startsWith(`${v}_`))||(d[m]=g);return Object.keys(d).length>0?d:void 0},"stripConnectionEnv"),f=n?{...h,...t.env,...l.env,...p.env,...e.environment}:{...h,...r(e.environment)},s=n?{...t.secrets,...e.secretsImport}:r(e.secretsImport);return f&&Object.keys(f).length>0&&(i+=`
|
|
10
10
|
environment: {
|
|
11
11
|
${x(f," ")}
|
|
12
12
|
},`),s&&Object.keys(s).length>0&&(i+=`
|
|
@@ -14,29 +14,30 @@ ${x(f," ")}
|
|
|
14
14
|
${x(s," ")}
|
|
15
15
|
},`),e.ssmSecrets&&e.ssmSecrets.length>0&&(i+=`
|
|
16
16
|
secrets: [${k(e.ssmSecrets)}],`),e.healthCheck&&(i+=`
|
|
17
|
-
healthCheck: ${
|
|
17
|
+
healthCheck: ${S(e.healthCheck," ")},`),i+=E(e.extraProperties," "),i}u(U,"generateEcsContainerCode");function A(e,n){const t=[];return e.path&&t.push(`path: ${o(e.path)}`),e.host&&t.push(`host: ${o(e.host)}`),e.priority!==void 0&&t.push(`priority: ${e.priority}`),e.healthCheckPath&&t.push(`healthCheckPath: ${o(e.healthCheckPath)}`),$(t,n,`${n} `)}u(A,"formatRoutingRule");function W(e){const n=Array.isArray(e)?e:[e];return n.length===1?`
|
|
18
18
|
routing: ${A(n[0]," ")},`:`
|
|
19
19
|
routing: [
|
|
20
20
|
${n.map(l=>A(l," ")).join(`,
|
|
21
21
|
`)},
|
|
22
22
|
],`}u(W,"generateEcsServiceRoutingCode");function q(e){if(e===!1)return`
|
|
23
23
|
scaling: false,`;if(typeof e!="object"||!(e.minCapacity!==void 0||e.maxCapacity!==void 0||e.desiredCount!==void 0||e.scalingType!==void 0))return"";const t=[];return e.minCapacity!==void 0&&t.push(`minCapacity: ${e.minCapacity}`),e.maxCapacity!==void 0&&t.push(`maxCapacity: ${e.maxCapacity}`),e.desiredCount!==void 0&&t.push(`desiredCount: ${e.desiredCount}`),e.scalingType&&t.push(`scalingType: ${o(e.scalingType)}`),`
|
|
24
|
-
scaling: ${
|
|
24
|
+
scaling: ${$(t," "," ")},`}u(q,"generateEcsServiceScalingCode");function z(e,n,t){return{needsDb:e.needsDatabaseConnection!==void 0?e.needsDatabaseConnection:n&&P(t),needsStorage:e.needsStorageConnection!==void 0?e.needsStorageConnection:n&&V(t),needsMessaging:e.needsMessagingConnection!==void 0?e.needsMessagingConnection:n&&M(t)}}u(z,"deriveServiceConnectionNeeds");function F(e){const{service:n,isFirstService:t,hasConnections:l,dbEnvVars:p,storageEnvVars:h,messagingEnvVars:i,baseEnvVars:c,plan:r,compute:f}=e;let s=`
|
|
25
25
|
name: ${o(n.name)},`;s+=`
|
|
26
|
-
capacityProvider: ${o(n.capacityProvider)},`,n.
|
|
27
|
-
|
|
26
|
+
capacityProvider: ${o(n.capacityProvider)},`,n.serviceType!==void 0&&(s+=`
|
|
27
|
+
serviceType: ${o(n.serviceType)},`),n.ec2Config&&(s+=J(n.ec2Config)),n.docker&&(s+=`
|
|
28
|
+
docker: ${S(n.docker," ")},`),n.image&&(s+=`
|
|
28
29
|
image: ${o(n.image)},`),n.ssmSecretsPath&&(s+=`
|
|
29
30
|
ssmSecretsPath: ${o(n.ssmSecretsPath)},`);const a=z(n,t,f);if(n.containers?.length){s+=`
|
|
30
|
-
containers: [{`;for(let d=0;d<n.containers.length;d++){const m=n.containers[d];if(!m)continue;const g=d===0&&(a.needsDb||a.needsStorage||a.needsMessaging)&&l,b=a.needsDb?
|
|
31
|
-
}, {`),s+=U(m,g,b,
|
|
31
|
+
containers: [{`;for(let d=0;d<n.containers.length;d++){const m=n.containers[d];if(!m)continue;const g=d===0&&(a.needsDb||a.needsStorage||a.needsMessaging)&&l,b=a.needsDb?p:{env:{},secrets:{}},v=a.needsStorage?h:{env:{},secrets:{}},T=a.needsMessaging?i:{env:{},secrets:{}};d>0&&(s+=`
|
|
32
|
+
}, {`),s+=U(m,g,b,v,T,c)}s+=`
|
|
32
33
|
}],`}if(n.routing&&(s+=W(n.routing)),n.cpu!==void 0&&(s+=`
|
|
33
34
|
cpu: ${n.cpu},`),n.memoryLimitMiB!==void 0&&(s+=`
|
|
34
35
|
memoryLimitMiB: ${n.memoryLimitMiB},`),n.desiredCount!==void 0&&(s+=`
|
|
35
36
|
desiredCount: ${n.desiredCount},`),n.scaling!==void 0&&(s+=q(n.scaling)),n.alarms===!1?s+=`
|
|
36
37
|
alarms: false,`:typeof n.alarms=="object"&&(s+=`
|
|
37
|
-
alarms: ${
|
|
38
|
-
${_(d,m,g)}`)}return s}u(F,"generateEcsServiceCode");function te(e,n){const t=G(e),l={...I},
|
|
38
|
+
alarms: ${S(n.alarms," ")},`),s+=E(n.extraProperties," "),a.needsDb||a.needsStorage||a.needsMessaging){const d=a.needsDb?D(r,f):[],m=a.needsStorage?j(r,f):[],g=a.needsMessaging?H(r,f):[];(d.length>0||m.length>0||g.length>0)&&(s+=`
|
|
39
|
+
${_(d,m,g)}`)}return s}u(F,"generateEcsServiceCode");function te(e,n){const t=G(e),l={...I},p={env:{},secrets:{}};if(P(e)){const r=N(n,e);Object.assign(p.env,r.env),Object.assign(p.secrets,r.secrets)}const h={env:{},secrets:{}};if(V(e)){const r=L(n,e);Object.assign(h.env,r.env)}const i={env:{},secrets:{}};if(M(e)){const r=w(n,e);Object.assign(i.env,r.env)}let c=`
|
|
39
40
|
ecrRepository: app.getDefaultContainerRegistry(),`;if(c+=K(e),e.services?.length){c+=`
|
|
40
41
|
services: [{`;for(let r=0;r<e.services.length;r++){const f=e.services[r];f&&(r>0&&(c+=`
|
|
41
|
-
}, {`),c+=F({service:f,isFirstService:r===0,hasConnections:t,dbEnvVars:
|
|
42
|
+
}, {`),c+=F({service:f,isFirstService:r===0,hasConnections:t,dbEnvVars:p,storageEnvVars:h,messagingEnvVars:i,baseEnvVars:l,plan:n,compute:e}))}c+=`
|
|
42
43
|
}],`}return c+=E(e.extraProperties),c+=R(),c}u(te,"generateEcsCode");export{te as generateEcsCode};
|
|
@@ -17,6 +17,26 @@ export declare const CREDENTIAL_KEYS: Readonly<{
|
|
|
17
17
|
readonly USERNAME: "username";
|
|
18
18
|
readonly PASSWORD: "password";
|
|
19
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
|
+
}>;
|
|
20
40
|
export type DatabaseEnvVarEntry = {
|
|
21
41
|
key: string;
|
|
22
42
|
expression: string;
|
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
var
|
|
2
|
-
secondaryRegions: [${
|
|
3
|
-
`:""}${
|
|
4
|
-
DatabaseFactory.build(${
|
|
1
|
+
var $=Object.defineProperty;var c=(e,n)=>$(e,"name",{value:n,configurable:!0});import{buildProperty as o,connectionEnvSuffix as y,formatValue as S,getVariableName as p,emitExtraProperties as b,escapeStringLiteral as a,formatStringArray as R,emitProductionAlertsTopicSpread as m}from"./common.js";const l=Object.freeze({HOST:"DATABASE_HOST",PORT:"DATABASE_PORT",NAME:"DATABASE_NAME",SSL:"DATABASE_SSL",USERNAME:"DATABASE_USERNAME",PASSWORD:"DATABASE_PASSWORD"}),A=Object.freeze({USERNAME:"username",PASSWORD:"password"}),g="true",u=Object.freeze({HOST:"getHostEndpoint",PORT:"getHostPort",NAME:"getDatabaseName",CREDENTIALS:"getCredentials",IMPORT:"getImport"});function D(e,n){const r=n.connectedDatabase;return r?.length?e.database.filter(t=>r.includes(t.name)):[]}c(D,"getConnectedDatabases");function E(e,n){return`${e}.${u.CREDENTIALS}().${u.IMPORT}(${a(n)})`}c(E,"getCredentialExpression");function T(e){const n=[],r=c((t,d,s)=>{n.push({key:t,expression:d,isSecret:s})},"addEntry");if(e.length===1){const t=p(e[0]);r(l.HOST,`${t}.${u.HOST}()`,!1),r(l.PORT,`${t}.${u.PORT}()`,!1),r(l.NAME,`${t}.${u.NAME}()`,!1),r(l.SSL,a(g),!1),r(l.USERNAME,E(t,A.USERNAME),!0),r(l.PASSWORD,E(t,A.PASSWORD),!0)}else for(const[t,d]of e.entries()){const s=p(d),i=y(t);r(`${l.HOST}${i}`,`${s}.${u.HOST}()`,!1),r(`${l.PORT}${i}`,`${s}.${u.PORT}()`,!1),r(`${l.NAME}${i}`,`${s}.${u.NAME}()`,!1),r(`${l.SSL}${i}`,a(g),!1),r(`${l.USERNAME}${i}`,E(s,A.USERNAME),!0),r(`${l.PASSWORD}${i}`,E(s,A.PASSWORD),!0)}return n}c(T,"generateDatabaseEnvVarEntries");function j(e){return`connections: [${e.map(r=>p(r)).join(", ")}],`}c(j,"formatConnectionsCode");function h(e){return e.expression===a(g)?g:{__expression:e.expression}}c(h,"toDatabaseEnvVarValue");function _(e,n){const r={},t={};if(!n.needsConnection||!n.connectedDatabase?.length)return{env:r,secrets:t};const d=D(e,n),s=T(d);for(const i of s){const f=h(i);i.isSecret?t[i.key]={__expression:i.expression}:r[i.key]=f}return{env:r,secrets:t}}c(_,"buildDatabaseEnvVars");function x(e){let n="";return n+=o(e.port!==void 0,"port",e.port),n+=o(e.deletionProtection!==void 0,"deletionProtection",e.deletionProtection),n+=o(e.snapshotIdentifier!==void 0,"snapshotIdentifier",e.snapshotIdentifier,"string"),n+=o(e.snapshotUsername!==void 0,"snapshotUsername",e.snapshotUsername,"string"),n+=o(e.monitoringInterval!==void 0,"monitoringInterval",e.monitoringInterval),n}c(x,"generateDatabaseSharedProps");function N(e){if(e.type!=="Instance")return"";let n="";return n+=o(e.instanceType!==void 0,"instanceType",e.instanceType,"string"),n+=o(e.allocatedStorage!==void 0,"allocatedStorage",e.allocatedStorage),n+=o(e.multiAz!==void 0,"multiAz",e.multiAz),n+=o(e.publiclyAccessible!==void 0,"publiclyAccessible",e.publiclyAccessible),n+=o(e.encryption!==void 0,"encryption",e.encryption,"object"),n+=o(e.databaseInsights!==void 0,"databaseInsights",e.databaseInsights,"boolean-or-object"),n+=o(e.proxy!==void 0,"proxy",e.proxy,"boolean-or-object"),n+=o(e.readReplica!==void 0,"readReplica",e.readReplica,"boolean-or-object"),n+=o(e.credentials!==void 0,"credentials",e.credentials,"object"),n+=o(e.backupRetention!==void 0,"backupRetention",e.backupRetention),n}c(N,"generateDatabaseInstanceProps");function P(e){if(e.type!=="Aurora"&&e.type!=="GlobalAurora")return"";let n="";return n+=o(e.encryption!==void 0,"encryption",e.encryption,"object"),n+=o(e.databaseInsights!==void 0,"databaseInsights",e.databaseInsights,"boolean-or-object"),n+=o(e.proxy!==void 0,"proxy",e.proxy,"boolean-or-object"),n+=o(e.credentials!==void 0,"credentials",e.credentials,"object"),n+=o(e.writer!==void 0,"writer",e.writer,"object"),n+=o(e.readers!==void 0,"readers",e.readers,"boolean-or-object"),n+=o(e.backupRetention!==void 0,"backupRetention",e.backupRetention),n+=o(e.preferredMaintenanceWindow!==void 0,"preferredMaintenanceWindow",e.preferredMaintenanceWindow,"string"),n}c(P,"generateDatabaseAuroraProps");function O(e){if(e.type!=="GlobalAurora")return"";let n="";return n+=o(e.primaryRegion!==void 0,"primaryRegion",e.primaryRegion,"string"),e.secondaryRegions!==void 0&&e.secondaryRegions.length>0&&(n+=`
|
|
2
|
+
secondaryRegions: [${R(e.secondaryRegions)}],`),n+=o(e.globalClusterIdentifier!==void 0,"globalClusterIdentifier",e.globalClusterIdentifier,"string"),n+=o(e.enableGlobalWriteForwarding!==void 0,"enableGlobalWriteForwarding",e.enableGlobalWriteForwarding),n}c(O,"generateDatabaseGlobalAuroraProps");function I(e,n){return n.compute.some(r=>r.needsConnection&&r.connectedDatabase?.includes(e.name))}c(I,"databaseNeedsVariable");function w(e){if(e.database.length===0)return"";let n="";for(let r=0;r<e.database.length;r++){const t=e.database[r],d=p(t),s=I(t,e),i=r>0,f=s?`const ${d} = `:"";n+=`${i?`
|
|
3
|
+
`:""}${f}app.addDatabase(
|
|
4
|
+
DatabaseFactory.build(${a(t.name)}, {
|
|
5
5
|
vpc: app.getVpc(),
|
|
6
|
-
type: ${
|
|
7
|
-
databaseName: ${
|
|
6
|
+
type: ${a(t.type)},
|
|
7
|
+
databaseName: ${a(t.databaseName)},`,t.engineExpression?n+=`
|
|
8
8
|
engine: ${t.engineExpression},`:t.databaseEngine&&(n+=`
|
|
9
|
-
databaseEngine: ${
|
|
9
|
+
databaseEngine: ${a(t.databaseEngine)},`),n+=x(t),n+=N(t),n+=P(t),n+=O(t),n+=b(t.extraProperties),t.alarms===!1?n+=`
|
|
10
10
|
alarms: false,`:typeof t.alarms=="object"&&(n+=`
|
|
11
|
-
alarms: ${
|
|
11
|
+
alarms: ${S(t.alarms," ")},`),t.type!=="GlobalAurora"&&(n+=m()),n+=`
|
|
12
12
|
})
|
|
13
13
|
);
|
|
14
|
-
`}return n}
|
|
15
|
-
`:"",
|
|
16
|
-
DatabaseFactory.build(${
|
|
14
|
+
`}return n}c(w,"generateDatabaseCode");function W(e){if(!e.clickhouse||e.clickhouse.length===0)return"";let n="";for(let r=0;r<e.clickhouse.length;r++){const t=e.clickhouse[r],d=p(t),s=k(t,e),i=r>0?`
|
|
15
|
+
`:"",f=s?`const ${d} = `:"";n+=`${i}${f}app.addDatabase(
|
|
16
|
+
DatabaseFactory.build(${a(t.name)}, {
|
|
17
17
|
type: "ClickHouse",
|
|
18
|
-
databaseName: ${
|
|
19
|
-
instanceType: ${
|
|
20
|
-
coldTier: ${
|
|
21
|
-
optimiseSchedule: ${
|
|
22
|
-
backupSchedule: ${
|
|
23
|
-
backupRetentionDays: ${t.backupRetentionDays},`),n+=
|
|
18
|
+
databaseName: ${a(t.databaseName)},`,t.instanceType!==void 0&&(n+=`
|
|
19
|
+
instanceType: ${a(t.instanceType)},`),t.coldTier!==void 0&&(n+=`
|
|
20
|
+
coldTier: ${S(t.coldTier," ")},`),t.optimiseSchedule!==void 0&&(n+=`
|
|
21
|
+
optimiseSchedule: ${S(t.optimiseSchedule," ")},`),t.backupSchedule!==void 0&&(n+=`
|
|
22
|
+
backupSchedule: ${S(t.backupSchedule," ")},`),t.backupRetentionDays!==void 0&&(n+=`
|
|
23
|
+
backupRetentionDays: ${t.backupRetentionDays},`),n+=b(t.extraProperties),n+=`
|
|
24
24
|
})
|
|
25
25
|
);
|
|
26
|
-
`}return n}
|
|
26
|
+
`}return n}c(W,"generateClickHouseCode");function k(e,n){return n.compute.some(r=>r.connectedDatabase?.includes(e.name))}c(k,"clickhouseNeedsVariable");export{A as CREDENTIAL_KEYS,u as DATABASE_ACCESSORS,l as DATABASE_ENV_VARS,g as DATABASE_SSL_VALUE,_ as buildDatabaseEnvVars,I as databaseNeedsVariable,j as formatConnectionsCode,W as generateClickHouseCode,w as generateDatabaseCode,T as generateDatabaseEnvVarEntries,D as getConnectedDatabases,h as toDatabaseEnvVarValue};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var g=Object.defineProperty;var u=(s,e)=>g(s,"name",{value:e,configurable:!0});import{connectionEnvSuffix as p,getVariableName as f}from"./common.js";const i=Object.freeze({URL:"QUEUE_URL",ARN:"QUEUE_ARN"});function a(s,e){const{connectedMessaging:n}=e;return n?.length?(s.sqs??[]).filter(t=>n.includes(t.name)):[]}u(a,"getConnectedMessaging");function x(s){const e=[];if(s.length===1){const n=s[0];if(!n)return e;const t=f(n);e.push({key:i.URL,expression:`${t}.getQueueUrl()`}),e.push({key:i.ARN,expression:`${t}.getQueueArn()`})}else for(const[n,t]of s.entries()){const r=f(t),o=p(n);e.push({key:`${i.URL}${o}`,expression:`${r}.getQueueUrl()`}),e.push({key:`${i.ARN}${o}`,expression:`${r}.getQueueArn()`})}return e}u(x,"generateMessagingEnvVarEntries");function U(s,e){const n={},t={};if(!e.connectedMessaging?.length)return{env:n,secrets:t};const r=a(s,e),o=x(r);for(const c of o)n[c.key]={__expression:c.expression};return{env:n,secrets:t}}u(U,"buildMessagingEnvVars");export{i as MESSAGING_ENV_VARS,U as buildMessagingEnvVars,x as generateMessagingEnvVarEntries,a as getConnectedMessaging};
|
|
@@ -8,6 +8,15 @@ import type { S3ResourcePlan, SQSResourcePlan, ApplicationResourcePlan, ComputeR
|
|
|
8
8
|
export declare const STORAGE_ENV_VARS: Readonly<{
|
|
9
9
|
readonly NAME: "BUCKET_NAME";
|
|
10
10
|
}>;
|
|
11
|
+
/**
|
|
12
|
+
* Construct accessor methods the emitted connection wiring calls on a bound
|
|
13
|
+
* bucket variable. Shared with the codemod connection edit
|
|
14
|
+
* (`codemod/edits/connectResourceToCompute.ts`) — the two emitters must call
|
|
15
|
+
* identical methods or surgically-wired apps fail at synth.
|
|
16
|
+
*/
|
|
17
|
+
export declare const STORAGE_ACCESSORS: Readonly<{
|
|
18
|
+
readonly BUCKET_NAME: "getBucketName";
|
|
19
|
+
}>;
|
|
11
20
|
export type StorageEnvVarEntry = {
|
|
12
21
|
key: string;
|
|
13
22
|
expression: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var p=Object.defineProperty;var i=(t,e)=>p(t,"name",{value:e,configurable:!0});import{connectionEnvSuffix as g,getVariableName as a}from"./common.js";const u=Object.freeze({NAME:"BUCKET_NAME"}),E=Object.freeze({BUCKET_NAME:"getBucketName"});function l(t,e){const{connectedStorage:n}=e;return n?.length?t.s3.filter(r=>n.includes(r.name)):[]}i(l,"getConnectedStorage");function x(t){const e=[];if(t.length===1){const n=t[0];if(!n)return e;const r=a(n);e.push({key:u.NAME,expression:`${r}.${E.BUCKET_NAME}()`})}else for(const[n,r]of t.entries()){const o=a(r),s=g(n);e.push({key:`${u.NAME}${s}`,expression:`${o}.${E.BUCKET_NAME}()`})}return e}i(x,"generateStorageEnvVarEntries");function S(t,e){const n={},r={};if(!e.connectedStorage?.length)return{env:n,secrets:r};const o=l(t,e),s=x(o);for(const f of s)n[f.key]={__expression:f.expression};return{env:n,secrets:r}}i(S,"buildStorageEnvVars");function N(t,e,n=[]){const r=t.map(c=>a(c)),o=e.map(c=>a(c)),s=n.map(c=>a(c));return`connections: [${[...r,...o,...s].join(", ")}],`}i(N,"formatAllConnectionsCode");export{E as STORAGE_ACCESSORS,u as STORAGE_ENV_VARS,S as buildStorageEnvVars,N as formatAllConnectionsCode,x as generateStorageEnvVarEntries,l as getConnectedStorage};
|
|
@@ -2,5 +2,6 @@ export { planApplicationResources, planServiceFromTierPreset, toUserServiceConfi
|
|
|
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";
|
|
5
|
-
export { type AddableResourceType, type AddResourceOptions, type DatabaseAddOptions, type ProxyAddOptions, type S3AddOptions, type NetworkAddOptions, type EcsComputeAddOptions, type LambdaComputeAddOptions, type CdnAddOptions, type TunnelAddOptions, addResourceToPlan, validateResourceAddition, listAvailableResources, } from "./resourceAddition.js";
|
|
5
|
+
export { type AddableResourceType, type AddResourceOptions, type DatabaseAddOptions, type ProxyAddOptions, type S3AddOptions, type NetworkAddOptions, type EcsComputeAddOptions, type LambdaComputeAddOptions, type CdnAddOptions, type TunnelAddOptions, addResourceToPlan, validateResourceAddition, listAvailableResources, isResourceNameTaken, resourceNameTakenMessage, } from "./resourceAddition.js";
|
|
6
6
|
export { type ResourceChangeResult, generateResourceChange, } from "./generateResourceChange.js";
|
|
7
|
+
export { type RelationalDatabaseBuildOptions, type ClickHouseDatabaseBuildOptions, type S3BucketBuildOptions, type ProxyAdditionResolution, type ProxyPlanValue, buildRelationalResourcePlan, buildClickHouseResourcePlan, buildS3ResourcePlan, defaultRelationalDatabaseName, duplicateDatabaseNameMessage, resolveProxyAddition, pickDefined, } from "./planBuilders.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{planApplicationResources as
|
|
1
|
+
import{planApplicationResources as a,planServiceFromTierPreset as r,toUserServiceConfigs as s,generateInfrastructureFromPlan as t}from"./resourcePlanning.js";import{planOpenNextResources as i}from"./openNextPlanning.js";import{planStaticSiteResources as c}from"./staticSitePlanning.js";import{applyComputeConnections as u,applyServiceConnections as m}from"./resourceConnections.js";import{addResourceToPlan as R,validateResourceAddition as f,listAvailableResources as x,isResourceNameTaken as P,resourceNameTakenMessage as b}from"./resourceAddition.js";import{generateResourceChange as v}from"./generateResourceChange.js";import{buildRelationalResourcePlan as S,buildClickHouseResourcePlan as N,buildS3ResourcePlan as k,defaultRelationalDatabaseName as A,duplicateDatabaseNameMessage as T,resolveProxyAddition as y,pickDefined as D}from"./planBuilders.js";export{R as addResourceToPlan,u as applyComputeConnections,m as applyServiceConnections,N as buildClickHouseResourcePlan,S as buildRelationalResourcePlan,k as buildS3ResourcePlan,A as defaultRelationalDatabaseName,T as duplicateDatabaseNameMessage,t as generateInfrastructureFromPlan,v as generateResourceChange,P as isResourceNameTaken,x as listAvailableResources,D as pickDefined,a as planApplicationResources,i as planOpenNextResources,r as planServiceFromTierPreset,c as planStaticSiteResources,y as resolveProxyAddition,b as resourceNameTakenMessage,s as toUserServiceConfigs,f as validateResourceAddition};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure resource-plan builders shared by the CLI generator lane (full
|
|
3
|
+
* regeneration) and the surgical codemod lane. Both lanes MUST derive a new
|
|
4
|
+
* resource's plan shape from these builders — a second derivation would let
|
|
5
|
+
* preset expansion and option picking drift silently between the two paths.
|
|
6
|
+
*/
|
|
7
|
+
import type { z } from "zod";
|
|
8
|
+
import type { AddProxyGeneratorOptions, DatabaseGeneratorSchema } from "../schemas/databaseSchemas.js";
|
|
9
|
+
import type { S3GeneratorOptions } from "../schemas/storageSchemas.js";
|
|
10
|
+
import type { ClickHouseResourcePlan, DatabaseResourcePlan, S3ResourcePlan } from "../schemas/resourceSchemas.js";
|
|
11
|
+
export declare function pickDefined<T extends Record<string, unknown>>(source: T, ...keys: Array<keyof T>): Partial<Pick<T, (typeof keys)[number]>>;
|
|
12
|
+
type ValidatedDatabaseOptions = z.infer<typeof DatabaseGeneratorSchema>;
|
|
13
|
+
export type RelationalDatabaseBuildOptions = Extract<ValidatedDatabaseOptions, {
|
|
14
|
+
databaseType: "Instance" | "Aurora" | "GlobalAurora";
|
|
15
|
+
}>;
|
|
16
|
+
export type ClickHouseDatabaseBuildOptions = Extract<ValidatedDatabaseOptions, {
|
|
17
|
+
databaseType: "ClickHouse";
|
|
18
|
+
}>;
|
|
19
|
+
export type S3BucketBuildOptions = S3GeneratorOptions;
|
|
20
|
+
export declare function buildRelationalResourcePlan(resourceName: string, options: RelationalDatabaseBuildOptions): DatabaseResourcePlan;
|
|
21
|
+
/** Default construct name both lanes use for a relational database add. */
|
|
22
|
+
export declare function defaultRelationalDatabaseName(appName: string): string;
|
|
23
|
+
/** Duplicate-`databaseName` refusal both lanes surface verbatim. */
|
|
24
|
+
export declare function duplicateDatabaseNameMessage(databaseName: string, appName: string): string;
|
|
25
|
+
export type ProxyPlanValue = Partial<Pick<AddProxyGeneratorOptions, "maxConnections" | "maxIdleConnections" | "connectionBorrowTimeout" | "requireTLS">>;
|
|
26
|
+
export type ProxyAdditionResolution = {
|
|
27
|
+
ok: true;
|
|
28
|
+
database: DatabaseResourcePlan;
|
|
29
|
+
proxyValue: ProxyPlanValue;
|
|
30
|
+
} | {
|
|
31
|
+
ok: false;
|
|
32
|
+
message: string;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Shared proxy-addition core for both lanes: target lookup by construct or
|
|
36
|
+
* database name, the two refusal messages, and the proxy config value.
|
|
37
|
+
* Drift here would let the two `fjall add proxy` paths disagree on which
|
|
38
|
+
* databases are eligible or which options survive.
|
|
39
|
+
*/
|
|
40
|
+
export declare function resolveProxyAddition(databases: DatabaseResourcePlan[], validated: AddProxyGeneratorOptions): ProxyAdditionResolution;
|
|
41
|
+
export declare function buildClickHouseResourcePlan(resourceName: string, options: ClickHouseDatabaseBuildOptions): ClickHouseResourcePlan;
|
|
42
|
+
/**
|
|
43
|
+
* `existingBucketCount` feeds the scaffold's `bucket`/`bucket2`/… variable
|
|
44
|
+
* naming; the surgical lane strips `variableName` before emission (plan-only
|
|
45
|
+
* round-trip key) but passes the real count so both lanes stay one source.
|
|
46
|
+
*/
|
|
47
|
+
export declare function buildS3ResourcePlan(constructName: string, options: S3BucketBuildOptions, existingBucketCount: number): S3ResourcePlan;
|
|
48
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var c=Object.defineProperty;var t=(a,e)=>c(a,"name",{value:e,configurable:!0});import{STORAGE_PRESETS as u}from"../presets/storagePresets.js";function s(a,...e){const n={};for(const r of e)a[r]!==void 0&&(n[r]=a[r]);return n}t(s,"pickDefined");function b(a,e){const n={name:a,type:e.databaseType,databaseName:e.databaseName,...s(e,"databaseInsights","port","proxy","credentials","encryption","deletionProtection")};switch(e.databaseType){case"Instance":return{...n,...s(e,"instanceType","multiAz","readReplica","publiclyAccessible","backupRetention","allocatedStorage","snapshotIdentifier","snapshotUsername")};case"Aurora":return{...n,...s(e,"writer","readers","backupRetention","preferredMaintenanceWindow","monitoringInterval","snapshotIdentifier","snapshotUsername")};case"GlobalAurora":return{...n,primaryRegion:e.primaryRegion,...e.secondaryRegions&&e.secondaryRegions.length>0&&{secondaryRegions:e.secondaryRegions},...s(e,"globalClusterIdentifier","enableGlobalWriteForwarding","writer","readers","backupRetention","preferredMaintenanceWindow","monitoringInterval","snapshotIdentifier","snapshotUsername")};default:return e}}t(b,"buildRelationalResourcePlan");function m(a){return`${a}Database`}t(m,"defaultRelationalDatabaseName");function f(a,e){return`Database name '${a}' already exists in ${e}. Please choose a different database name.`}t(f,"duplicateDatabaseNameMessage");function p(a,e){const n=a.find(o=>o.name===e.databaseName||o.databaseName===e.databaseName);if(!n)return{ok:!1,message:`Database '${e.databaseName}' not found. Available databases: ${a.map(o=>o.name).join(", ")||"none"}`};if(n.proxy!==void 0&&n.proxy!==!1)return{ok:!1,message:`Database '${n.name}' already has RDS Proxy enabled.`};const r=s(e,"maxConnections","maxIdleConnections","connectionBorrowTimeout","requireTLS");return{ok:!0,database:n,proxyValue:Object.keys(r).length>0?r:{}}}t(p,"resolveProxyAddition");function y(a,e){return{name:a,type:"ClickHouse",databaseName:e.databaseName,...s(e,"instanceType","coldTier","optimiseSchedule","backupSchedule","backupRetentionDays")}}t(y,"buildClickHouseResourcePlan");function R(a,e,n){const r=e.storagePreset??"standard",o=u[r],i=n===0?"":`${n+1}`;return{name:a,bucketName:e.bucketName,variableName:`bucket${i}`,...o,...s(e,"publicReadAccess","websiteHosting","backupVaultTier","versioned","encryption","kmsKeyArn","cors")}}t(R,"buildS3ResourcePlan");export{y as buildClickHouseResourcePlan,b as buildRelationalResourcePlan,R as buildS3ResourcePlan,m as defaultRelationalDatabaseName,f as duplicateDatabaseNameMessage,s as pickDefined,p as resolveProxyAddition};
|
|
@@ -155,4 +155,7 @@ export declare function validateResourceAddition(plan: ApplicationResourcePlan,
|
|
|
155
155
|
* fields wire the new resource to existing compute resources in the plan.
|
|
156
156
|
*/
|
|
157
157
|
export declare function addResourceToPlan(plan: ApplicationResourcePlan, options: AddResourceOptions): Result<ApplicationResourcePlan, Error>;
|
|
158
|
+
export declare function isResourceNameTaken(plan: ApplicationResourcePlan, name: string): boolean;
|
|
159
|
+
/** Refusal message every lane surfaces verbatim when the gate fires. */
|
|
160
|
+
export declare function resourceNameTakenMessage(name: string): string;
|
|
158
161
|
export {};
|