fjall 0.89.6 → 0.94.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/bin/.bundled +3 -0
- package/bin/.metafile.json +39155 -0
- package/bin/assets/generators/account/files/infrastructure.ts +17 -0
- package/bin/assets/generators/account/generator.d.ts +8 -0
- package/bin/assets/generators/account/generator.js +2 -0
- package/bin/assets/generators/account/index.d.ts +1 -0
- package/bin/assets/generators/account/index.js +1 -0
- package/bin/assets/generators/application/generator.d.ts +4 -0
- package/bin/assets/generators/application/generator.js +28 -0
- package/bin/assets/generators/application/index.d.ts +1 -0
- package/bin/assets/generators/application/index.js +1 -0
- package/bin/assets/generators/cdn/generator.d.ts +4 -0
- package/bin/assets/generators/cdn/generator.js +4 -0
- package/bin/assets/generators/cdn/index.d.ts +1 -0
- package/bin/assets/generators/cdn/index.js +1 -0
- package/bin/assets/generators/compute/computeIntegrationHelpers.d.ts +134 -0
- package/bin/assets/generators/compute/computeIntegrationHelpers.js +1 -0
- package/bin/assets/generators/compute/generator.d.ts +4 -0
- package/bin/assets/generators/compute/generator.js +1 -0
- package/bin/assets/generators/compute/index.d.ts +1 -0
- package/bin/assets/generators/compute/index.js +1 -0
- package/bin/assets/generators/compute/service/generator.d.ts +4 -0
- package/bin/assets/generators/compute/service/generator.js +1 -0
- package/bin/assets/generators/compute/service/index.d.ts +1 -0
- package/bin/assets/generators/compute/service/index.js +1 -0
- package/bin/assets/generators/database/databaseIntegrationTestUtils.d.ts +134 -0
- package/bin/assets/generators/database/databaseIntegrationTestUtils.js +1 -0
- package/bin/assets/generators/database/generator.d.ts +4 -0
- package/bin/assets/generators/database/generator.js +1 -0
- package/bin/assets/generators/database/index.d.ts +1 -0
- package/bin/assets/generators/database/index.js +1 -0
- package/bin/assets/generators/database/proxy/generator.d.ts +4 -0
- package/bin/assets/generators/database/proxy/generator.js +1 -0
- package/bin/assets/generators/database/proxy/index.d.ts +1 -0
- package/bin/assets/generators/database/proxy/index.js +1 -0
- package/bin/assets/generators/domain/files/infrastructure.ts.ejs +22 -0
- package/bin/assets/generators/domain/files/zone.bind.ejs +14 -0
- package/bin/assets/generators/domain/generator.d.ts +10 -0
- package/bin/assets/generators/domain/generator.js +2 -0
- package/bin/assets/generators/domain/index.d.ts +1 -0
- package/bin/assets/generators/domain/index.js +1 -0
- package/bin/assets/generators/messaging/index.d.ts +1 -0
- package/bin/assets/generators/messaging/index.js +0 -0
- package/bin/assets/generators/network/generator.d.ts +4 -0
- package/bin/assets/generators/network/generator.js +1 -0
- package/bin/assets/generators/network/index.d.ts +1 -0
- package/bin/assets/generators/network/index.js +1 -0
- package/bin/assets/generators/organisation/files/account/infrastructure.ts +25 -0
- package/bin/assets/generators/organisation/files/organisation/infrastructure.ts +46 -0
- package/bin/assets/generators/organisation/files/platform/infrastructure.ts +16 -0
- package/bin/assets/generators/organisation/generator.d.ts +4 -0
- package/bin/assets/generators/organisation/generator.js +2 -0
- package/bin/assets/generators/organisation/index.d.ts +1 -0
- package/bin/assets/generators/organisation/index.js +1 -0
- package/bin/assets/generators/shared/files/cdk.context.json +3 -0
- package/bin/assets/generators/shared/files/cdk.json +55 -0
- package/bin/assets/generators/shared/files/package.json +15 -0
- package/bin/assets/generators/shared/files/tsconfig.json +23 -0
- package/bin/assets/generators/storage/index.d.ts +1 -0
- package/bin/assets/generators/storage/index.js +1 -0
- package/bin/assets/generators/storage/s3/generator.d.ts +4 -0
- package/bin/assets/generators/storage/s3/generator.js +1 -0
- package/bin/assets/generators/tunnel/generator.d.ts +4 -0
- package/bin/assets/generators/tunnel/generator.js +1 -0
- package/bin/assets/generators/tunnel/index.d.ts +1 -0
- package/bin/assets/generators/tunnel/index.js +1 -0
- package/bin/assets/generators/utils/ast/astCodeModification.d.ts +23 -0
- package/bin/assets/generators/utils/ast/astCodeModification.js +1 -0
- package/bin/assets/generators/utils/ast/astDomainRewriter.d.ts +65 -0
- package/bin/assets/generators/utils/ast/astDomainRewriter.js +1 -0
- package/bin/assets/generators/utils/ast/astSurgicalModification.d.ts +2 -0
- package/bin/assets/generators/utils/ast/astSurgicalModification.js +1 -0
- package/bin/assets/generators/utils/ast/index.d.ts +3 -0
- package/bin/assets/generators/utils/ast/index.js +1 -0
- package/bin/assets/generators/utils/copySharedFiles.d.ts +10 -0
- package/bin/assets/generators/utils/copySharedFiles.js +1 -0
- package/bin/assets/generators/utils/index.d.ts +8 -0
- package/bin/assets/generators/utils/index.js +1 -0
- package/bin/assets/generators/utils/integrationTestUtils.d.ts +129 -0
- package/bin/assets/generators/utils/integrationTestUtils.js +2 -0
- package/bin/assets/generators/utils/mockTree.d.ts +30 -0
- package/bin/assets/generators/utils/mockTree.js +1 -0
- package/bin/assets/generators/utils/planning/generatorHelpers.d.ts +35 -0
- package/bin/assets/generators/utils/planning/generatorHelpers.js +2 -0
- package/bin/assets/generators/utils/planning/index.d.ts +1 -0
- package/bin/assets/generators/utils/planning/index.js +1 -0
- package/bin/assets/generators/utils/prompts.d.ts +4 -0
- package/bin/assets/generators/utils/prompts.js +6 -0
- package/bin/assets/generators/utils/renderEjs.d.ts +24 -0
- package/bin/assets/generators/utils/renderEjs.js +1 -0
- package/bin/assets/generators/utils/resources/connectionHelpers.d.ts +19 -0
- package/bin/assets/generators/utils/resources/connectionHelpers.js +1 -0
- package/bin/assets/generators/utils/resources/index.d.ts +4 -0
- package/bin/assets/generators/utils/resources/index.js +1 -0
- package/bin/assets/generators/utils/resources/promptValidation.d.ts +42 -0
- package/bin/assets/generators/utils/resources/promptValidation.js +1 -0
- package/bin/assets/generators/utils/resources/resourceDetection.d.ts +12 -0
- package/bin/assets/generators/utils/resources/resourceDetection.js +1 -0
- package/bin/assets/generators/utils/resources/resourceNaming.d.ts +6 -0
- package/bin/assets/generators/utils/resources/resourceNaming.js +1 -0
- package/bin/assets/generators/utils/tree.d.ts +25 -0
- package/bin/assets/generators/utils/tree.js +1 -0
- package/bin/assets/proto/buildkit.proto +126 -0
- package/bin/assets/proto/proto/buildkit.proto +126 -0
- package/bin/fjall.bundle.js +1138 -0
- package/bin/fjall.js +5 -1
- package/package.json +41 -4
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
App,
|
|
5
|
+
OrganisationFactory,
|
|
6
|
+
getConfig
|
|
7
|
+
} from "@fjall/components-infrastructure";
|
|
8
|
+
|
|
9
|
+
const config = getConfig();
|
|
10
|
+
|
|
11
|
+
if (config.environment !== "platform" && config.environment !== "root") {
|
|
12
|
+
const app = App.getInstance();
|
|
13
|
+
const buildAccount = OrganisationFactory.build("Account", {
|
|
14
|
+
type: "account"
|
|
15
|
+
});
|
|
16
|
+
buildAccount(app);
|
|
17
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type Tree } from "@nx/devkit";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
export declare const AccountGeneratorSchema: z.ZodObject<{
|
|
4
|
+
primaryRegion: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
5
|
+
}, z.core.$strict>;
|
|
6
|
+
export type AccountGeneratorOptions = z.infer<typeof AccountGeneratorSchema>;
|
|
7
|
+
export declare function accountGenerator(tree: Tree, options: AccountGeneratorOptions): Promise<void>;
|
|
8
|
+
export default accountGenerator;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{join as i}from"path";import{renderEjsTemplates as m}from"../utils/renderEjs.js";import{copySharedCdkFiles as s}from"../utils/copySharedFiles.js";import{getOrganisationComponentPath as p}from"../../src/util/pathHelpers.js";import{z as a}from"zod";import{getZodErrorMessage as c,DEFAULT_REGION as f}from"@fjall/generator";const g=import.meta.dirname,d=a.object({primaryRegion:a.string().optional().default(f)}).strict();async function l(o,n){const r=d.safeParse(n);if(!r.success)throw new Error(`Invalid account generator options:
|
|
2
|
+
${c(r.error)}`);const t=p("account"),e={primaryRegion:r.data.primaryRegion};m(o,i(g,"files"),t,e),s(o,t,{...e,packageName:"infra-app"})}var x=l;export{d as AccountGeneratorSchema,l as accountGenerator,x as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { accountGenerator, AccountGeneratorSchema, type AccountGeneratorOptions } from "./generator.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{accountGenerator as r,AccountGeneratorSchema as c}from"./generator.js";export{c as AccountGeneratorSchema,r as accountGenerator};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import{join as m}from"path";import{copySharedCdkFiles as u}from"../utils/copySharedFiles.js";import{getInfrastructurePath as d,getAppPath as l}from"../../src/util/pathHelpers.js";import{planApplicationResources as f,planOpenNextResources as g,generateInfrastructureFromPlan as b,ApplicationGeneratorSchema as w,getZodErrorMessage as h}from"@fjall/generator";import{z as y}from"zod";async function C(n,r){let e;try{e=w.parse(r)}catch(t){throw t instanceof y.ZodError?new Error(`Invalid application generator options:
|
|
2
|
+
${h(t)}`):t}let o;if(e.pattern){const t=e.includeDatabase??!0,a=e.patternTier||"standard",c=t?a==="custom"&&e.customDatabase?{type:e.customDatabase.type,instanceType:e.customDatabase.instanceType,databaseName:e.databaseName,backupRetention:e.customDatabase.backupRetention,deletionProtection:e.customDatabase.deletionProtection,encryption:e.customDatabase.encryption}:{databaseName:e.databaseName}:void 0,p=a==="custom"&&e.customCompute?{memorySize:e.customCompute.memorySize,timeout:e.customCompute.timeout}:void 0,i=g(e.name,e.pattern,{tier:a,domain:e.patternDomain,database:c,compute:p});if(!i.success)throw new Error(i.error.message);o=i.data}else if(e.type==="custom")o=await k(e);else{const t=e.services?.map(a=>({name:a.name,dockerfilePath:a.dockerfilePath,containerPort:a.containerPort,needsDatabaseConnection:a.needsDatabaseConnection,routing:a.routing}));o=f(e.name,e.type,e.includeDatabase??!0,t,{snapshotIdentifier:e.snapshotIdentifier,snapshotUsername:e.snapshotUsername})}e.owner&&(o.owner=e.owner),e.vpcId&&(o.vpcId=e.vpcId),e.network!==void 0&&(o.network=e.network===!1?void 0:e.network);const s=b(o);if(!s.success)throw new Error(s.error.message);if(n.write(d(e.name),s.data),e.pattern==="payload"||e.pattern==="nextjs"){const t=m(l(e.name),"open-next.config.ts");n.write(t,D())}u(n,e.name,{name:e.name,type:e.type,packageName:e.name})}async function k(n){const r=n.network||void 0;return{appName:n.name,type:"custom",owner:n.owner,network:r,database:[],s3:[],compute:[]}}function D(){return`// OpenNext configuration - Generated by Fjall CLI
|
|
3
|
+
const sharpInstallConfig = {
|
|
4
|
+
packages: ["sharp@0.34.2", "typescript@5.7.3"],
|
|
5
|
+
arch: "arm64" as const,
|
|
6
|
+
nodeVersion: "20.0.0",
|
|
7
|
+
libc: "glibc" as const,
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
const config = {
|
|
11
|
+
default: {
|
|
12
|
+
install: sharpInstallConfig,
|
|
13
|
+
override: {
|
|
14
|
+
wrapper: "aws-lambda-streaming",
|
|
15
|
+
converter: "aws-apigw-v2",
|
|
16
|
+
incrementalCache: "s3-lite",
|
|
17
|
+
tagCache: "dynamodb-lite",
|
|
18
|
+
queue: "sqs-lite",
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
imageOptimization: {
|
|
22
|
+
loader: "s3",
|
|
23
|
+
install: sharpInstallConfig,
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export default config;
|
|
28
|
+
`}var R=C;export{C as applicationGenerator,R as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { applicationGenerator } from "./generator.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{applicationGenerator as a}from"./generator.js";export{a as applicationGenerator};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import{withInfrastructurePlan as g}from"../utils/planning/generatorHelpers.js";import{CdnGeneratorSchema as p,toPascalCase as w}from"@fjall/generator";import{promptForConnection as b}from"../utils/prompts.js";import s from"prompts";function R(o){const n=[];for(const e of o.s3)n.push({name:e.name,description:"S3 Storage"});for(const e of o.compute)e.type==="lambda"?e.functionUrl&&n.push({name:e.name,description:"Lambda"}):e.type==="ecs"&&n.push({name:e.name,description:"ECS with ALB"});return n}function d(o,n){if(!n.some(i=>i.name===o)){const i=n.map(t=>t.name).join(", ");throw new Error(`Origin "${o}" not found in infrastructure. Available origins: ${i}`)}}async function y(o,n){const e=R(o);if(e.length===0)throw new Error("No available CDN origins found. Add an S3 bucket or compute resource with ALB/function URL first.");if(n.defaultOriginRef){if(d(n.defaultOriginRef,e),n.behaviours)for(const r of n.behaviours)d(r.originRef,e);return{defaultOriginRef:n.defaultOriginRef,behaviours:n.behaviours,...n.customDomain&&{customDomain:n.customDomain}}}if(n.nameProvidedByFlag)throw new Error("Default origin must be specified in non-interactive mode");let i;if(e.length===1)i=e[0].name,process.stdout.write(`
|
|
2
|
+
Auto-selected origin: ${i}
|
|
3
|
+
`);else if(i=(await s([{type:"select",name:"origin",message:"Select the default origin:",choices:e.map(c=>({title:`${c.name} (${c.description})`,value:c.name}))}])).origin,!i)throw new Error("Origin selection cancelled");let t;const a=e.filter(r=>r.name!==i);if(a.length>0&&await b(a.length,"origin","Add path-based routing to another origin?","Add path-based routing to other origins?")){t=[];let c=!0;for(;c&&a.length>0;){const h=(await s([{type:"text",name:"pathPattern",message:"Path pattern (e.g., /static/*):"}])).pathPattern;if(!h)break;let m;if(a.length===1)m=a[0].name,process.stdout.write(` Auto-selected origin: ${m}
|
|
4
|
+
`);else if(m=(await s([{type:"select",name:"origin",message:"Origin for this path:",choices:a.map(f=>({title:`${f.name} (${f.description})`,value:f.name}))}])).origin,!m)break;const l=(await s([{type:"select",name:"cachePolicy",message:"Cache policy:",choices:[{title:"Caching Optimised",value:"CACHING_OPTIMIZED",description:"Best for static assets"},{title:"Caching Disabled",value:"CACHING_DISABLED",description:"Best for dynamic APIs"}]}])).cachePolicy;t.push({pathPattern:h,originRef:m,...l!==void 0&&{cachePolicy:l}}),c=(await s([{type:"confirm",name:"addMore",message:"Add another path route?",initial:!1}])).addMore}t.length===0&&(t=void 0)}let u;return(await s([{type:"confirm",name:"wantDomain",message:"Add a custom domain?",initial:!1}])).wantDomain&&(u=(await s([{type:"text",name:"domain",message:"Enter custom domain:"}])).domain||void 0),{defaultOriginRef:i,behaviours:t,...u!==void 0&&{customDomain:u}}}async function A(o,n){await g(o,p,n,"CDN",async({validated:e,plan:i})=>{if(i.cdn)throw new Error("A CDN is already configured for this application. Remove the existing CDN first.");const t=await y(i,e),a=e.name??`${w(e.appName)}Cdn`;return{...i,cdn:{name:a,defaultOriginRef:t.defaultOriginRef,...t.behaviours&&t.behaviours.length>0&&{behaviours:t.behaviours},...t.customDomain!==void 0&&{customDomain:t.customDomain},...e.certificateArn!==void 0&&{certificateArn:e.certificateArn},...e.accessGate!==void 0&&{accessGate:e.accessGate}}}})}var S=A;export{A as cdnGenerator,S as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { cdnGenerator } from "./generator.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{cdnGenerator as o}from"./generator.js";export{o as cdnGenerator};
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared helpers for compute integration tests.
|
|
3
|
+
*
|
|
4
|
+
* Extracted to allow splitting compute tests across multiple files
|
|
5
|
+
* for parallel execution without duplicating helper functions.
|
|
6
|
+
*/
|
|
7
|
+
import { type TierName, type EC2InstanceType, type EnvironmentValue } from "@fjall/generator";
|
|
8
|
+
import { FileSystemTree } from "../utils/tree.js";
|
|
9
|
+
import { type CfnTemplate, type ResourceEntry } from "../utils/integrationTestUtils.js";
|
|
10
|
+
export { CLI_ROOT } from "../utils/integrationTestUtils.js";
|
|
11
|
+
export declare function createTree(): FileSystemTree;
|
|
12
|
+
/**
|
|
13
|
+
* Create a test app with the application generator
|
|
14
|
+
*/
|
|
15
|
+
export declare function createTestApp(tree: FileSystemTree, appName: string, tier: TierName | "custom"): Promise<void>;
|
|
16
|
+
/**
|
|
17
|
+
* Add ECS compute to an existing app
|
|
18
|
+
*/
|
|
19
|
+
export declare function addEcsCompute(tree: FileSystemTree, appName: string, options: {
|
|
20
|
+
computeName: string;
|
|
21
|
+
capacityProvider?: "FARGATE" | "FARGATE_SPOT" | "EC2";
|
|
22
|
+
containerPort?: number;
|
|
23
|
+
containers?: Array<{
|
|
24
|
+
name: string;
|
|
25
|
+
image?: string;
|
|
26
|
+
port?: number;
|
|
27
|
+
environment?: Record<string, EnvironmentValue>;
|
|
28
|
+
essential?: boolean;
|
|
29
|
+
}>;
|
|
30
|
+
desiredCount?: number;
|
|
31
|
+
cpu?: number;
|
|
32
|
+
memoryLimitMiB?: number;
|
|
33
|
+
ec2Config?: {
|
|
34
|
+
instanceType?: string;
|
|
35
|
+
amiHardwareType?: "ARM" | "STANDARD";
|
|
36
|
+
minCapacity?: number;
|
|
37
|
+
maxCapacity?: number;
|
|
38
|
+
memoryLimitMiB?: number;
|
|
39
|
+
};
|
|
40
|
+
}): Promise<void>;
|
|
41
|
+
/**
|
|
42
|
+
* Add Lambda compute to an existing app
|
|
43
|
+
*/
|
|
44
|
+
export declare function addLambdaCompute(tree: FileSystemTree, appName: string, options: {
|
|
45
|
+
computeName: string;
|
|
46
|
+
timeout?: number;
|
|
47
|
+
memory?: number;
|
|
48
|
+
handler?: string;
|
|
49
|
+
runtime?: string;
|
|
50
|
+
}): Promise<void>;
|
|
51
|
+
/**
|
|
52
|
+
* Add ECS compute with multiple services to an existing app
|
|
53
|
+
*/
|
|
54
|
+
export declare function addMultiServiceEcsCompute(tree: FileSystemTree, appName: string, options: {
|
|
55
|
+
computeName: string;
|
|
56
|
+
capacityProvider?: "FARGATE" | "FARGATE_SPOT" | "EC2";
|
|
57
|
+
cluster?: {
|
|
58
|
+
domain?: string;
|
|
59
|
+
loadBalancer?: false | "public" | "internal";
|
|
60
|
+
directAccess?: boolean;
|
|
61
|
+
};
|
|
62
|
+
ec2Config?: {
|
|
63
|
+
instanceType?: string;
|
|
64
|
+
amiHardwareType?: "ARM" | "STANDARD";
|
|
65
|
+
minCapacity?: number;
|
|
66
|
+
maxCapacity?: number;
|
|
67
|
+
memoryLimitMiB?: number;
|
|
68
|
+
};
|
|
69
|
+
services: Array<{
|
|
70
|
+
name: string;
|
|
71
|
+
containers?: Array<{
|
|
72
|
+
name?: string;
|
|
73
|
+
port?: number;
|
|
74
|
+
image?: string;
|
|
75
|
+
ssmSecrets?: string[];
|
|
76
|
+
}>;
|
|
77
|
+
routing?: {
|
|
78
|
+
path?: string;
|
|
79
|
+
host?: string;
|
|
80
|
+
priority?: number;
|
|
81
|
+
} | Array<{
|
|
82
|
+
path?: string;
|
|
83
|
+
host?: string;
|
|
84
|
+
priority?: number;
|
|
85
|
+
}>;
|
|
86
|
+
cpu?: number;
|
|
87
|
+
memoryLimitMiB?: number;
|
|
88
|
+
desiredCount?: number;
|
|
89
|
+
ssmSecretsPath?: string;
|
|
90
|
+
capacityProvider?: "FARGATE" | "FARGATE_SPOT" | "EC2";
|
|
91
|
+
ec2Config?: {
|
|
92
|
+
instanceType?: string;
|
|
93
|
+
amiHardwareType?: "ARM" | "STANDARD";
|
|
94
|
+
minCapacity?: number;
|
|
95
|
+
maxCapacity?: number;
|
|
96
|
+
memoryLimitMiB?: number;
|
|
97
|
+
};
|
|
98
|
+
}>;
|
|
99
|
+
}): Promise<void>;
|
|
100
|
+
/**
|
|
101
|
+
* Add EC2 compute to an existing app
|
|
102
|
+
*/
|
|
103
|
+
export declare function addEc2Compute(tree: FileSystemTree, appName: string, options: {
|
|
104
|
+
computeName: string;
|
|
105
|
+
instanceType?: EC2InstanceType;
|
|
106
|
+
enableSSH?: boolean;
|
|
107
|
+
}): Promise<void>;
|
|
108
|
+
/**
|
|
109
|
+
* Expected configuration derived from tier preset
|
|
110
|
+
*/
|
|
111
|
+
export interface ExpectedEcsConfig {
|
|
112
|
+
capacityProvider: "FARGATE" | "FARGATE_SPOT" | "EC2";
|
|
113
|
+
cpu: string;
|
|
114
|
+
memory: string;
|
|
115
|
+
desiredCount: number;
|
|
116
|
+
isEc2Based: boolean;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Derive expected ECS configuration from tier preset
|
|
120
|
+
*/
|
|
121
|
+
export declare function getExpectedComputeConfigFromPreset(tier: TierName): ExpectedEcsConfig;
|
|
122
|
+
/**
|
|
123
|
+
* ECS tiers - all tiers support ECS
|
|
124
|
+
*/
|
|
125
|
+
export declare const ECS_TIER_SUPPORT: TierName[];
|
|
126
|
+
export declare function findEcsCluster(template: CfnTemplate): ResourceEntry | undefined;
|
|
127
|
+
export declare function findEcsService(template: CfnTemplate): ResourceEntry | undefined;
|
|
128
|
+
export declare function findEcsTaskDefinition(template: CfnTemplate): ResourceEntry | undefined;
|
|
129
|
+
export declare function findLoadBalancer(template: CfnTemplate): ResourceEntry | undefined;
|
|
130
|
+
export declare function findLambdaFunction(template: CfnTemplate): ResourceEntry | undefined;
|
|
131
|
+
export declare function findAutoScalingGroup(template: CfnTemplate): ResourceEntry | undefined;
|
|
132
|
+
export declare function findSecurityGroups(template: CfnTemplate): ResourceEntry[];
|
|
133
|
+
export declare function findTargetGroups(template: CfnTemplate): ResourceEntry[];
|
|
134
|
+
export declare function findListenerRules(template: CfnTemplate): ResourceEntry[];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{applicationGenerator as u}from"../application/generator.js";import{computeGenerator as o}from"./generator.js";import{getEcsPreset as m}from"@fjall/generator";import{FileSystemTree as d}from"../utils/tree.js";import{CLI_ROOT as p,findResourcesByType as n}from"../utils/integrationTestUtils.js";import{CLI_ROOT as h}from"../utils/integrationTestUtils.js";function g(){return new d(p)}async function S(t,r,e){await u(t,{name:r,type:e,includeDatabase:!1,network:{maxAzs:2,natGateways:{count:1},flowLogs:!1}})}async function v(t,r,e){const a=e.capacityProvider??"FARGATE";let c;e.containers?c=[{name:"TestService",capacityProvider:a,ec2Config:e.ec2Config,containers:e.containers,cpu:e.cpu,memoryLimitMiB:e.memoryLimitMiB,desiredCount:e.desiredCount}]:e.containerPort?c=[{name:"TestService",capacityProvider:a,ec2Config:e.ec2Config,containers:[{port:e.containerPort}],cpu:e.cpu,memoryLimitMiB:e.memoryLimitMiB,desiredCount:e.desiredCount}]:c=[{name:"TestService",capacityProvider:a,ec2Config:e.ec2Config}],await o(t,{appName:r,computeName:e.computeName,type:"ecs",nameProvidedByFlag:!0,connectionConfig:{connectToDatabase:[]},services:c})}async function E(t,r,e){await o(t,{appName:r,computeName:e.computeName,type:"lambda",nameProvidedByFlag:!0,connectionConfig:{connectToDatabase:[]},timeout:e.timeout,memory:e.memory,handler:e.handler,runtime:e.runtime})}async function T(t,r,e){const a=e.capacityProvider??"FARGATE",c=e.services.map(i=>({...i,capacityProvider:i.capacityProvider??a,ec2Config:i.ec2Config??(i.capacityProvider==="EC2"||!i.capacityProvider&&a==="EC2"?e.ec2Config:void 0)}));await o(t,{appName:r,computeName:e.computeName,type:"ecs",nameProvidedByFlag:!0,connectionConfig:{connectToDatabase:[]},cluster:e.cluster,services:c})}async function P(t,r,e){await o(t,{appName:r,computeName:e.computeName,type:"ec2",nameProvidedByFlag:!0,connectionConfig:{connectToDatabase:[]},instanceType:e.instanceType,enableSSH:e.enableSSH})}function x(t){const e=m(t).services[0];return{capacityProvider:e.capacityProvider,cpu:String(e.cpu??256),memory:String(e.memoryLimitMiB??512),desiredCount:e.desiredCount??1,isEc2Based:e.capacityProvider==="EC2"}}const A=["tinkerer","lightweight","standard","resilient","enterprise"];function L(t){return n(t,"AWS::ECS::Cluster")[0]}function B(t){return n(t,"AWS::ECS::Service")[0]}function b(t){return n(t,"AWS::ECS::TaskDefinition")[0]}function G(t){return n(t,"AWS::ElasticLoadBalancingV2::LoadBalancer")[0]}function w(t){return n(t,"AWS::Lambda::Function")[0]}function F(t){return n(t,"AWS::AutoScaling::AutoScalingGroup")[0]}function W(t){return n(t,"AWS::EC2::SecurityGroup")}function R(t){return n(t,"AWS::ElasticLoadBalancingV2::TargetGroup")}function N(t){return n(t,"AWS::ElasticLoadBalancingV2::ListenerRule")}export{h as CLI_ROOT,A as ECS_TIER_SUPPORT,P as addEc2Compute,v as addEcsCompute,E as addLambdaCompute,T as addMultiServiceEcsCompute,S as createTestApp,g as createTree,F as findAutoScalingGroup,L as findEcsCluster,B as findEcsService,b as findEcsTaskDefinition,w as findLambdaFunction,N as findListenerRules,G as findLoadBalancer,W as findSecurityGroups,R as findTargetGroups,x as getExpectedComputeConfigFromPreset};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{assertResourceNameUnique as o}from"../utils/resources/resourceDetection.js";import{withInfrastructurePlan as s}from"../utils/planning/generatorHelpers.js";import{ComputeGeneratorSchema as i}from"@fjall/generator";import{ensureUniqueResourceName as f}from"../utils/resources/resourceNaming.js";import{promptForConnection as y,selectResources as h}from"../utils/prompts.js";function p(r,e,n){const t=n.length>0;switch(e.type){case"ecs":return{name:r,type:"ecs",needsConnection:t,connectedDatabase:n,cluster:e.cluster,services:e.services,dockerfilePath:e.dockerfilePath};case"lambda":return{name:r,type:"lambda",needsConnection:t,connectedDatabase:n,timeout:e.timeout,memory:e.memory,handler:e.handler,runtime:e.runtime,environment:e.environment,secrets:e.secrets};case"ec2":return{name:r,type:"ec2",needsConnection:t,connectedDatabase:n,instanceType:e.instanceType,enableSSH:e.enableSSH,keyName:e.keyName,userData:e.userData,securityGroups:e.securityGroups};default:return e}}async function C(r,e){await s(r,i,e,"compute",async({tree:n,validated:t,plan:a})=>{t.nameProvidedByFlag||o(n,t.appName,t.computeName);const c=t.nameProvidedByFlag?f(n,t.appName,t.computeName):t.computeName,m=await b(t,a),u=p(c,t,m);return{...a,compute:[...a.compute,u]}})}async function b(r,e){return r.connectionConfig?r.connectionConfig.connectToDatabase??[]:e.database.length>0&&!r.nameProvidedByFlag&&await y(e.database.length,"database","Connect to existing database?","Found {count} databases. Configure connections?")?h(e.database,"Select databases to connect:",t=>`${t.type} - ${t.databaseName}`):[]}var w=C;export{C as computeGenerator,w as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { computeGenerator } from "./generator.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{computeGenerator as r}from"./generator.js";export{r as computeGenerator};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{AddServiceGeneratorSchema as g}from"@fjall/generator";import{withInfrastructurePlan as p,pickDefined as h}from"../../utils/planning/generatorHelpers.js";async function l(m,f){await p(m,g,f,"service",({validated:n,plan:o})=>{const t=o.compute.find(e=>e.name===n.clusterName&&e.type==="ecs");if(!t)throw new Error(`ECS cluster '${n.clusterName}' not found. Available clusters: ${o.compute.filter(e=>e.type==="ecs").map(e=>e.name).join(", ")||"none"}`);const c=t.services||[];if(c.some(e=>e.name===n.serviceName))throw new Error(`Service '${n.serviceName}' already exists in cluster '${n.clusterName}'`);const i={name:n.serviceName,capacityProvider:n.capacityProvider,...h(n,"dockerfilePath","dockerTarget","cpu","memoryLimitMiB","desiredCount","ec2Config","routing")};if(n.containerPort&&(i.containers=[{port:n.containerPort}]),n.connectionConfig?.connectToDatabase?.length){i.needsDatabaseConnection=!0;const e=t.connectedDatabase||[],r=n.connectionConfig.connectToDatabase.filter(a=>!e.includes(a));r.length>0&&(t.connectedDatabase=[...e,...r],t.needsConnection=!0)}t.services=[...c,i];const s=t.services.filter(e=>e.containers?.some(r=>r.port));if(s.length>1){const e=s.filter(r=>!(Array.isArray(r.routing)?r.routing:r.routing?[r.routing]:[]).some(u=>u.path||u.host));if(e.length>0)throw new Error(`Multiple services have container ports \u2014 all must have routing configuration. Services missing routing: ${e.map(r=>r.name).join(", ")}`)}return o})}var y=l;export{y as default,l as serviceGenerator};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { serviceGenerator, serviceGenerator as default } from "./generator.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{serviceGenerator as a,serviceGenerator as o}from"./generator.js";export{o as default,a as serviceGenerator};
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Database Integration Test Utilities
|
|
3
|
+
*
|
|
4
|
+
* Shared utilities for database integration tests.
|
|
5
|
+
* Extracted to enable parallel test execution across split test files.
|
|
6
|
+
*
|
|
7
|
+
* @see aiDocs/architecture/TESTING_STRATEGY.md
|
|
8
|
+
*/
|
|
9
|
+
import { type TierName } from "@fjall/generator";
|
|
10
|
+
import type { FileSystemTree } from "../utils/tree.js";
|
|
11
|
+
import { type CfnTemplate, type ResourceEntry } from "../utils/integrationTestUtils.js";
|
|
12
|
+
export { CLI_ROOT, findSecurityGroupByDescription } from "../utils/integrationTestUtils.js";
|
|
13
|
+
export type { TierName } from "@fjall/generator";
|
|
14
|
+
/**
|
|
15
|
+
* Assert that a security group has a self-referencing ingress rule,
|
|
16
|
+
* optionally checking the port matches.
|
|
17
|
+
*/
|
|
18
|
+
export declare function expectSecurityGroupSelfReferencing(template: CfnTemplate, description: string, options?: {
|
|
19
|
+
port?: number;
|
|
20
|
+
checkToPort?: boolean;
|
|
21
|
+
}): void;
|
|
22
|
+
/**
|
|
23
|
+
* Create a test app with the application generator
|
|
24
|
+
*/
|
|
25
|
+
export declare function createTestApp(tree: FileSystemTree, appName: string, tier: TierName | "custom"): Promise<void>;
|
|
26
|
+
/**
|
|
27
|
+
* Database options for addDatabase helper
|
|
28
|
+
*/
|
|
29
|
+
export interface AddDatabaseOptions {
|
|
30
|
+
databaseName: string;
|
|
31
|
+
databaseType: "Instance" | "Aurora" | "GlobalAurora";
|
|
32
|
+
resourceName: string;
|
|
33
|
+
tier?: TierName;
|
|
34
|
+
instanceType?: string;
|
|
35
|
+
multiAz?: boolean;
|
|
36
|
+
readReplica?: {
|
|
37
|
+
instanceType?: string;
|
|
38
|
+
} | false;
|
|
39
|
+
publiclyAccessible?: boolean;
|
|
40
|
+
readers?: {
|
|
41
|
+
count: number;
|
|
42
|
+
} | false;
|
|
43
|
+
backupRetention?: number;
|
|
44
|
+
primaryRegion?: string;
|
|
45
|
+
secondaryRegions?: string[];
|
|
46
|
+
enableGlobalWriteForwarding?: boolean;
|
|
47
|
+
port?: number;
|
|
48
|
+
proxy?: {
|
|
49
|
+
requireTLS?: boolean;
|
|
50
|
+
maxConnections?: number;
|
|
51
|
+
} | false;
|
|
52
|
+
credentials?: {
|
|
53
|
+
username?: string;
|
|
54
|
+
secretRotation?: {
|
|
55
|
+
automaticallyAfterDays?: number;
|
|
56
|
+
} | false;
|
|
57
|
+
};
|
|
58
|
+
databaseInsights?: {
|
|
59
|
+
mode?: "standard" | "advanced";
|
|
60
|
+
encryptionKey?: {
|
|
61
|
+
useCMK: true;
|
|
62
|
+
} | {
|
|
63
|
+
awsManaged: true;
|
|
64
|
+
};
|
|
65
|
+
} | false;
|
|
66
|
+
encryption?: {
|
|
67
|
+
storageKey?: {
|
|
68
|
+
useCMK: true;
|
|
69
|
+
} | {
|
|
70
|
+
awsManaged: true;
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Add a database to an existing app
|
|
76
|
+
*/
|
|
77
|
+
export declare function addDatabase(tree: FileSystemTree, appName: string, options: AddDatabaseOptions): Promise<void>;
|
|
78
|
+
/**
|
|
79
|
+
* Find the primary RDS Instance (not a read replica)
|
|
80
|
+
*/
|
|
81
|
+
export declare function findPrimaryDbInstance(template: CfnTemplate): ResourceEntry | undefined;
|
|
82
|
+
/**
|
|
83
|
+
* Find read replica RDS Instances
|
|
84
|
+
*/
|
|
85
|
+
export declare function findReadReplicas(template: CfnTemplate): ResourceEntry[];
|
|
86
|
+
/**
|
|
87
|
+
* Find Aurora DB Cluster
|
|
88
|
+
*/
|
|
89
|
+
export declare function findAuroraCluster(template: CfnTemplate): ResourceEntry | undefined;
|
|
90
|
+
/**
|
|
91
|
+
* Find Aurora DB Instances (writer + readers)
|
|
92
|
+
*/
|
|
93
|
+
export declare function findAuroraInstances(template: CfnTemplate): ResourceEntry[];
|
|
94
|
+
/**
|
|
95
|
+
* Find RDS Proxy resources
|
|
96
|
+
*/
|
|
97
|
+
export declare function findRdsProxy(template: CfnTemplate): ResourceEntry | undefined;
|
|
98
|
+
/**
|
|
99
|
+
* Find KMS Keys (for encryption validation)
|
|
100
|
+
*/
|
|
101
|
+
export declare function findKmsKeys(template: CfnTemplate): ResourceEntry[];
|
|
102
|
+
/**
|
|
103
|
+
* Find Security Groups
|
|
104
|
+
*/
|
|
105
|
+
export declare function findSecurityGroups(template: CfnTemplate): ResourceEntry[];
|
|
106
|
+
/**
|
|
107
|
+
* Extract security group logical ID from a CloudFormation reference
|
|
108
|
+
* Handles both { Ref: logicalId } and { "Fn::GetAtt": [logicalId, "GroupId"] }
|
|
109
|
+
*/
|
|
110
|
+
export declare function extractSecurityGroupRef(ref: unknown): string | undefined;
|
|
111
|
+
/**
|
|
112
|
+
* Find Security Group Ingress rules
|
|
113
|
+
* Returns rules that reference the given security group (self-referencing)
|
|
114
|
+
*/
|
|
115
|
+
export declare function findSelfReferencingIngressRules(template: CfnTemplate, securityGroupLogicalId: string): ResourceEntry[];
|
|
116
|
+
/**
|
|
117
|
+
* Expected database configuration interface
|
|
118
|
+
*/
|
|
119
|
+
export interface ExpectedDatabaseConfig {
|
|
120
|
+
port: number;
|
|
121
|
+
deletionProtection: boolean;
|
|
122
|
+
hasProxy: boolean;
|
|
123
|
+
proxyRequireTLS: boolean;
|
|
124
|
+
hasReadReplica: boolean;
|
|
125
|
+
multiAz: boolean;
|
|
126
|
+
storageEncrypted: boolean;
|
|
127
|
+
databaseInsightsEnabled: boolean;
|
|
128
|
+
backupRetentionPeriod: number;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Derive expected configuration from tier preset
|
|
132
|
+
* This ensures tests validate against the same source of truth as production code
|
|
133
|
+
*/
|
|
134
|
+
export declare function getExpectedConfigFromPreset(tier: TierName, databaseType: "Instance" | "Aurora" | "GlobalAurora"): ExpectedDatabaseConfig;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{applicationGenerator as R}from"../application/generator.js";import{databaseGenerator as x}from"./generator.js";import{DEFAULT_DATABASE_PORT as S,getDatabasePreset as u}from"@fjall/generator";import{expect as a}from"vitest";import{findResourcesByType as s,findSecurityGroupByDescription as A}from"../utils/integrationTestUtils.js";import{CLI_ROOT as K,findSecurityGroupByDescription as L}from"../utils/integrationTestUtils.js";function T(t,r,e){const n=b(t),i=A(n,r);a(i).toBeDefined();const o=m(t,i.logicalId);a(o.length).toBeGreaterThan(0),e?.port!==void 0&&(a(Number(o[0].properties.FromPort)).toBe(e.port),e.checkToPort&&a(Number(o[0].properties.ToPort)).toBe(e.port))}async function P(t,r,e){await R(t,{name:r,type:e,includeDatabase:!1,network:{maxAzs:2,natGateways:{count:1},flowLogs:!1}})}async function h(t,r,e){const n=e.tier?u(e.tier,e.databaseType):void 0,{tier:i,databaseName:o,databaseType:c,resourceName:f,...d}=e,l=n?{port:n.port,proxy:n.proxy,databaseInsights:n.databaseInsights,encryption:n.encryption,backupRetention:n.backupRetention,...c==="Instance"&&{instanceType:n.instanceType,multiAz:n.multiAz,readReplica:n.readReplica,publiclyAccessible:n.publiclyAccessible},...(c==="Aurora"||c==="GlobalAurora")&&{readers:n.readers}}:{},y={appName:r,databaseName:o,databaseType:c,resourceName:f,nameProvidedByFlag:!0,connectionConfig:{connectToCompute:[]},...l,...d};await x(t,y)}function C(t){return s(t,"AWS::RDS::DBInstance").find(e=>!e.properties.SourceDBInstanceIdentifier)}function E(t){return s(t,"AWS::RDS::DBInstance").filter(e=>e.properties.SourceDBInstanceIdentifier)}function W(t){return s(t,"AWS::RDS::DBCluster")[0]}function w(t){return s(t,"AWS::RDS::DBInstance").filter(e=>e.properties.DBClusterIdentifier)}function k(t){return s(t,"AWS::RDS::DBProxy")[0]}function F(t){return s(t,"AWS::KMS::Key")}function b(t){return s(t,"AWS::EC2::SecurityGroup")}function p(t){if(!t||typeof t!="object")return;const r=t;if(typeof r.Ref=="string")return r.Ref;const e=r["Fn::GetAtt"];if(Array.isArray(e)&&typeof e[0]=="string")return e[0]}function m(t,r){return s(t,"AWS::EC2::SecurityGroupIngress").filter(n=>{const i=p(n.properties.SourceSecurityGroupId),o=p(n.properties.GroupId);return i===r&&o===r})}function O(t,r){const e=u(t,r);if(!e)throw new Error(`No preset found for ${t}/${r}`);const n=e.port??S,i=e.proxy!==!1&&e.proxy!==void 0,o=i&&typeof e.proxy=="object"?e.proxy.requireTLS??!0:!0;return{port:n,deletionProtection:!0,hasProxy:i,proxyRequireTLS:o,hasReadReplica:r==="Instance"&&e.readReplica!==!1&&e.readReplica!==void 0,multiAz:e.multiAz!==!1,storageEncrypted:!0,databaseInsightsEnabled:e.databaseInsights!==!1,backupRetentionPeriod:e.backupRetention??14}}export{K as CLI_ROOT,h as addDatabase,P as createTestApp,T as expectSecurityGroupSelfReferencing,p as extractSecurityGroupRef,W as findAuroraCluster,w as findAuroraInstances,F as findKmsKeys,C as findPrimaryDbInstance,k as findRdsProxy,E as findReadReplicas,L as findSecurityGroupByDescription,b as findSecurityGroups,m as findSelfReferencingIngressRules,O as getExpectedConfigFromPreset};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{assertResourceNameUnique as u,databaseExists as m}from"../utils/resources/resourceDetection.js";import{pickDefined as s,withInfrastructurePlan as b}from"../utils/planning/generatorHelpers.js";import{DatabaseGeneratorSchema as p}from"@fjall/generator";import{handleResourceConnections as d}from"../utils/resources/connectionHelpers.js";function f(t,e){const r={name:t,type:e.databaseType,databaseName:e.databaseName,...s(e,"databaseInsights","port","proxy","credentials","encryption","deletionProtection")};switch(e.databaseType){case"Instance":return{...r,...s(e,"instanceType","multiAz","readReplica","publiclyAccessible","backupRetention","snapshotIdentifier","snapshotUsername")};case"Aurora":return{...r,...s(e,"writer","readers","backupRetention","preferredMaintenanceWindow","snapshotIdentifier","snapshotUsername")};case"GlobalAurora":return{...r,primaryRegion:e.primaryRegion,...e.secondaryRegions&&e.secondaryRegions.length>0&&{secondaryRegions:e.secondaryRegions},...s(e,"globalClusterIdentifier","enableGlobalWriteForwarding","writer","readers","backupRetention","preferredMaintenanceWindow","snapshotIdentifier","snapshotUsername")};default:return e}}async function l(t,e){await b(t,p,e,"database",async({tree:r,validated:a,plan:o})=>{const n=a.resourceName||`${a.appName}Database`;if(u(r,a.appName,n),m(r,a.appName,a.databaseName))throw new Error(`Database name '${a.databaseName}' already exists in ${a.appName}. Please choose a different database name.`);const i=f(n,a),c={...o,database:[...o.database,i]};return await d(c,a,n,"database",{singularPrompt:"Found an existing compute resource. Configure database access for it?",pluralPrompt:"Found {count} compute resources. Configure database access for them?"}),c})}var w=l;export{l as databaseGenerator,w as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { databaseGenerator } from "./generator.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{databaseGenerator as r}from"./generator.js";export{r as databaseGenerator};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{AddProxyGeneratorSchema as i}from"@fjall/generator";import{withInfrastructurePlan as m,pickDefined as b}from"../../utils/planning/generatorHelpers.js";async function f(t,s){await m(t,i,s,"proxy",({validated:e,plan:r})=>{const a=r.database.find(o=>o.name===e.databaseName||o.databaseName===e.databaseName);if(!a)throw new Error(`Database '${e.databaseName}' not found. Available databases: ${r.database.map(o=>o.name).join(", ")||"none"}`);if(a.proxy!==void 0&&a.proxy!==!1)throw new Error(`Database '${a.name}' already has RDS Proxy enabled.`);const n=b(e,"maxConnections","maxIdleConnections","connectionBorrowTimeout","requireTLS");return a.proxy=Object.keys(n).length>0?n:{},r})}var x=f;export{x as default,f as proxyGenerator};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { proxyGenerator, proxyGenerator as default } from "./generator.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{proxyGenerator as o,proxyGenerator as a}from"./generator.js";export{a as default,o as proxyGenerator};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import {
|
|
2
|
+
App,
|
|
3
|
+
Domain,
|
|
4
|
+
} from "@fjall/components-infrastructure";
|
|
5
|
+
|
|
6
|
+
// Fjall-managed domain — edit this file to add or change records.
|
|
7
|
+
// See docs/domains.md for the Domain construct API.
|
|
8
|
+
|
|
9
|
+
const app = App.getApp("<%= safeZoneName %>Domain");
|
|
10
|
+
|
|
11
|
+
new Domain(app, "<%= safeZoneName %>", {
|
|
12
|
+
registrar: "route53",
|
|
13
|
+
zoneName: "<%= domainName %>",
|
|
14
|
+
<% if (hostedZoneId) { -%>
|
|
15
|
+
hostedZoneId: "<%= hostedZoneId %>",
|
|
16
|
+
<% } -%>
|
|
17
|
+
certificates: [
|
|
18
|
+
{ domainName: "<%= domainName %>" },
|
|
19
|
+
],
|
|
20
|
+
records: [],
|
|
21
|
+
delegations: [],
|
|
22
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
; zone.bind — managed by fjall
|
|
2
|
+
; Edit this file and run 'fjall deploy domain' to apply changes
|
|
3
|
+
$ORIGIN <%= domainName %>.
|
|
4
|
+
$TTL 300
|
|
5
|
+
|
|
6
|
+
; Certificate for this domain
|
|
7
|
+
$FJALL-CERT <%= domainName %>
|
|
8
|
+
|
|
9
|
+
; Add your DNS records below
|
|
10
|
+
; Examples:
|
|
11
|
+
; @ IN A ALIAS fjall:cdn:my-app
|
|
12
|
+
; www IN CNAME <%= domainName %>.
|
|
13
|
+
; api IN A ALIAS fjall:ecs:my-api
|
|
14
|
+
; @ IN MX 10 mail.<%= domainName %>.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type Tree } from "@nx/devkit";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
export declare const DomainGeneratorSchema: z.ZodObject<{
|
|
4
|
+
domainName: z.ZodString;
|
|
5
|
+
hostedZoneId: z.ZodOptional<z.ZodString>;
|
|
6
|
+
infrastructureTs: z.ZodOptional<z.ZodString>;
|
|
7
|
+
}, z.core.$strict>;
|
|
8
|
+
export type DomainGeneratorOptions = z.infer<typeof DomainGeneratorSchema>;
|
|
9
|
+
export declare function domainGenerator(tree: Tree, options: DomainGeneratorOptions): Promise<void>;
|
|
10
|
+
export default domainGenerator;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{join as i}from"path";import{renderEjsTemplates as d}from"../utils/renderEjs.js";import{copySharedCdkFiles as p}from"../utils/copySharedFiles.js";import{getDomainComponentPath as c}from"../../src/util/pathHelpers.js";import{z as e}from"zod";import{VALIDATION_PATTERNS as f,VALIDATION_MESSAGES as l,getZodErrorMessage as u}from"@fjall/generator";import{toPascalCase as N}from"../../src/util/caseConversion.js";const g=import.meta.dirname,I=e.object({domainName:e.string().regex(f.DOMAIN,l.DOMAIN),hostedZoneId:e.string().optional(),infrastructureTs:e.string().optional()}).strict();async function h(t,s){const r=I.safeParse(s);if(!r.success)throw new Error(`Invalid domain generator options:
|
|
2
|
+
${u(r.error)}`);const o=r.data,m=N(o.domainName.split(".").join("")),a=c(o.domainName),n={domainName:o.domainName,safeZoneName:m,hostedZoneId:o.hostedZoneId??""};d(t,i(g,"files"),a,n),o.infrastructureTs!==void 0&&t.write(i(a,"infrastructure.ts"),o.infrastructureTs),p(t,a,{...n,packageName:`domain-${o.domainName}`})}var Z=h;export{I as DomainGeneratorSchema,Z as default,h as domainGenerator};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { domainGenerator, DomainGeneratorSchema, type DomainGeneratorOptions } from "./generator.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{domainGenerator as r,DomainGeneratorSchema as a}from"./generator.js";export{a as DomainGeneratorSchema,r as domainGenerator};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{pickDefined as a,withInfrastructurePlan as w}from"../utils/planning/generatorHelpers.js";import{NetworkGeneratorSchema as k}from"@fjall/generator";async function i(r,n){await w(r,k,n,"network",({validated:t,plan:o})=>{const e=a(t,"maxAzs","natGateways","flowLogs","vpcEndpoints");return t.networkName?{...o,additionalNetworks:[...o.additionalNetworks??[],{name:t.networkName,...e}]}:{...o,network:{...o.network??{},...e}}})}var c=i;export{c as default,i as networkGenerator};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { networkGenerator } from "./generator.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{networkGenerator as o}from"./generator.js";export{o as networkGenerator};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { App, OrganisationFactory, getConfig } from "@fjall/components-infrastructure";
|
|
4
|
+
|
|
5
|
+
const config = getConfig();
|
|
6
|
+
|
|
7
|
+
if (config.environment !== "platform" && config.environment !== "root") {
|
|
8
|
+
const app = App.getInstance();
|
|
9
|
+
const account = OrganisationFactory.build("Account", { type: "account" })(app);
|
|
10
|
+
<% if (security === "foundation" || security === "compliance" || security === "hardened") { -%>
|
|
11
|
+
|
|
12
|
+
account.enableGuardDuty();
|
|
13
|
+
account.enableSecurityHub();
|
|
14
|
+
account.enableConfigRecorder();
|
|
15
|
+
account.enableAccessAnalyser();
|
|
16
|
+
<% } -%>
|
|
17
|
+
<% if (security === "compliance") { -%>
|
|
18
|
+
account.enableInspector();
|
|
19
|
+
account.enableConfigRules({ preset: "essential" });
|
|
20
|
+
<% } -%>
|
|
21
|
+
<% if (security === "hardened") { -%>
|
|
22
|
+
account.enableInspector();
|
|
23
|
+
account.enableConfigRules({ preset: "production" });
|
|
24
|
+
<% } -%>
|
|
25
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { OrganisationFactory, getConfig, env } from "@fjall/components-infrastructure";
|
|
4
|
+
|
|
5
|
+
export const ACCOUNTS = {
|
|
6
|
+
security: [],
|
|
7
|
+
workloads: {
|
|
8
|
+
production: ["Production"],
|
|
9
|
+
staging: ["Staging"],
|
|
10
|
+
development: ["Development"],
|
|
11
|
+
compliance: ["BusinessContinuity"]
|
|
12
|
+
},
|
|
13
|
+
platform: "Platform",
|
|
14
|
+
suspended: []
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const config = getConfig();
|
|
18
|
+
|
|
19
|
+
const ALLOWED_REGIONS = env({
|
|
20
|
+
default: [] as string[]
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
if (config.environment === "root") {
|
|
24
|
+
const organisation = OrganisationFactory.build("Organisation", {
|
|
25
|
+
type: "organisation",
|
|
26
|
+
accounts: ACCOUNTS,
|
|
27
|
+
organisationName: "<%= name %>",
|
|
28
|
+
orgEmail: "<%= email %>"
|
|
29
|
+
});
|
|
30
|
+
<% if (security === "compliance") { -%>
|
|
31
|
+
|
|
32
|
+
organisation.enableScps({
|
|
33
|
+
preset: "standard",
|
|
34
|
+
rootId: organisation.node.tryGetContext("rootId"),
|
|
35
|
+
allowedRegions: ALLOWED_REGIONS
|
|
36
|
+
});
|
|
37
|
+
<% } -%>
|
|
38
|
+
<% if (security === "hardened") { -%>
|
|
39
|
+
|
|
40
|
+
organisation.enableScps({
|
|
41
|
+
preset: "hardened",
|
|
42
|
+
rootId: organisation.node.tryGetContext("rootId"),
|
|
43
|
+
allowedRegions: ALLOWED_REGIONS
|
|
44
|
+
});
|
|
45
|
+
<% } -%>
|
|
46
|
+
}
|