@ts-cloud/core 0.5.1 → 0.5.2
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/index.js +78 -5
- package/dist/types.d.ts +87 -2
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -45522,11 +45522,16 @@ function composeServerlessAppTemplate(opts) {
|
|
|
45522
45522
|
...hasQueue ? { TSCLOUD_QUEUE: queueNames[0] } : {},
|
|
45523
45523
|
...app.env ?? {}
|
|
45524
45524
|
});
|
|
45525
|
+
const efsEnabled = Boolean(app.efs);
|
|
45526
|
+
const efsOpts = typeof app.efs === "object" ? app.efs : {};
|
|
45527
|
+
const efsMountPath = efsOpts.mountPath ?? "/mnt/local";
|
|
45528
|
+
const efsProvision = efsEnabled && !efsOpts.accessPointArn;
|
|
45529
|
+
const efsAccessPoint = efsOpts.accessPointArn ?? (efsProvision ? Fn2.getAtt("EfsAccessPoint", "Arn") : undefined);
|
|
45525
45530
|
const subnets = app.vpc?.subnets ?? [];
|
|
45526
45531
|
const hasVpc = subnets.length > 0;
|
|
45527
|
-
const needsDataVpc = app.cache?.driver === "elasticache" || app.database?.connection === "aurora-serverless" || Boolean(app.rdsProxy);
|
|
45532
|
+
const needsDataVpc = app.cache?.driver === "elasticache" || app.database?.connection === "aurora-serverless" || Boolean(app.rdsProxy) || efsEnabled;
|
|
45528
45533
|
if (needsDataVpc && !hasVpc) {
|
|
45529
|
-
throw new Error("serverless app: elasticache / aurora-serverless / rdsProxy require app.vpc.subnets (private subnets) to be set.");
|
|
45534
|
+
throw new Error("serverless app: elasticache / aurora-serverless / rdsProxy / efs require app.vpc.subnets (private subnets) to be set.");
|
|
45530
45535
|
}
|
|
45531
45536
|
const vpcConfig = hasVpc ? {
|
|
45532
45537
|
VpcConfig: {
|
|
@@ -45537,6 +45542,15 @@ function composeServerlessAppTemplate(opts) {
|
|
|
45537
45542
|
]
|
|
45538
45543
|
}
|
|
45539
45544
|
} : {};
|
|
45545
|
+
const efsDependsOn = efsProvision ? subnets.map((_, i) => `EfsMountTarget${i}`) : [];
|
|
45546
|
+
const efsConfig = efsEnabled ? { FileSystemConfigs: [{ Arn: efsAccessPoint, LocalMountPath: efsMountPath }] } : {};
|
|
45547
|
+
if (efsEnabled) {
|
|
45548
|
+
inlinePolicies[0].PolicyDocument.Statement.push({
|
|
45549
|
+
Effect: "Allow",
|
|
45550
|
+
Action: ["elasticfilesystem:ClientMount", "elasticfilesystem:ClientWrite", "elasticfilesystem:ClientRootAccess", "elasticfilesystem:DescribeMountTargets"],
|
|
45551
|
+
Resource: "*"
|
|
45552
|
+
});
|
|
45553
|
+
}
|
|
45540
45554
|
function addFunction(logicalId, name, handler8, mode, memory, timeout, reservedConcurrency, tmp = tmpStorage) {
|
|
45541
45555
|
resources[`${logicalId}LogGroup`] = {
|
|
45542
45556
|
Type: "AWS::Logs::LogGroup",
|
|
@@ -45554,7 +45568,7 @@ function composeServerlessAppTemplate(opts) {
|
|
|
45554
45568
|
};
|
|
45555
45569
|
resources[logicalId] = {
|
|
45556
45570
|
Type: "AWS::Lambda::Function",
|
|
45557
|
-
DependsOn: [`${logicalId}LogGroup
|
|
45571
|
+
DependsOn: [`${logicalId}LogGroup`, ...efsDependsOn],
|
|
45558
45572
|
Properties: {
|
|
45559
45573
|
FunctionName: name,
|
|
45560
45574
|
Architectures: [architecture],
|
|
@@ -45565,7 +45579,8 @@ function composeServerlessAppTemplate(opts) {
|
|
|
45565
45579
|
EphemeralStorage: { Size: tmp },
|
|
45566
45580
|
...codeProps,
|
|
45567
45581
|
...reservedConcurrency !== undefined ? { ReservedConcurrentExecutions: reservedConcurrency } : {},
|
|
45568
|
-
...vpcConfig
|
|
45582
|
+
...vpcConfig,
|
|
45583
|
+
...efsConfig
|
|
45569
45584
|
}
|
|
45570
45585
|
};
|
|
45571
45586
|
}
|
|
@@ -45814,10 +45829,37 @@ function composeServerlessAppTemplate(opts) {
|
|
|
45814
45829
|
DomainName: Fn2.getAtt("AssetsBucket", "RegionalDomainName"),
|
|
45815
45830
|
OriginAccessControlId: Fn2.ref("AssetsOAC"),
|
|
45816
45831
|
S3OriginConfig: { OriginAccessIdentity: "" }
|
|
45817
|
-
}]
|
|
45832
|
+
}],
|
|
45833
|
+
...app.assetDomain ? {
|
|
45834
|
+
Aliases: [app.assetDomain],
|
|
45835
|
+
ViewerCertificate: {
|
|
45836
|
+
AcmCertificateArn: app.assetCertificateArn,
|
|
45837
|
+
SslSupportMethod: "sni-only",
|
|
45838
|
+
MinimumProtocolVersion: "TLSv1.2_2021"
|
|
45839
|
+
}
|
|
45840
|
+
} : {}
|
|
45818
45841
|
}
|
|
45819
45842
|
}
|
|
45820
45843
|
};
|
|
45844
|
+
if (app.assetDomain) {
|
|
45845
|
+
if (!app.assetCertificateArn)
|
|
45846
|
+
throw new Error("serverless app: `assetDomain` requires `assetCertificateArn` (a us-east-1 ACM cert — CloudFront only accepts certs from us-east-1).");
|
|
45847
|
+
if (app.hostedZoneId) {
|
|
45848
|
+
resources.AssetsDomainRecord = {
|
|
45849
|
+
Type: "AWS::Route53::RecordSet",
|
|
45850
|
+
Properties: {
|
|
45851
|
+
HostedZoneId: app.hostedZoneId,
|
|
45852
|
+
Name: app.assetDomain,
|
|
45853
|
+
Type: "A",
|
|
45854
|
+
AliasTarget: {
|
|
45855
|
+
DNSName: Fn2.getAtt("AssetsDistribution", "DomainName"),
|
|
45856
|
+
HostedZoneId: "Z2FDTNDATAQYW2"
|
|
45857
|
+
}
|
|
45858
|
+
}
|
|
45859
|
+
};
|
|
45860
|
+
}
|
|
45861
|
+
outputs.AssetDomain = { Description: "Custom asset CDN host", Value: app.assetDomain };
|
|
45862
|
+
}
|
|
45821
45863
|
resources.AssetsBucketPolicy = {
|
|
45822
45864
|
Type: "AWS::S3::BucketPolicy",
|
|
45823
45865
|
Properties: {
|
|
@@ -45896,6 +45938,37 @@ function composeServerlessAppTemplate(opts) {
|
|
|
45896
45938
|
}
|
|
45897
45939
|
};
|
|
45898
45940
|
}
|
|
45941
|
+
if (efsProvision) {
|
|
45942
|
+
resources.EfsFileSystem = {
|
|
45943
|
+
Type: "AWS::EFS::FileSystem",
|
|
45944
|
+
Properties: {
|
|
45945
|
+
Encrypted: true,
|
|
45946
|
+
FileSystemTags: [{ Key: "Name", Value: `${slug}-${environment}-efs` }]
|
|
45947
|
+
}
|
|
45948
|
+
};
|
|
45949
|
+
subnets.forEach((subnetId, i) => {
|
|
45950
|
+
resources[`EfsMountTarget${i}`] = {
|
|
45951
|
+
Type: "AWS::EFS::MountTarget",
|
|
45952
|
+
Properties: {
|
|
45953
|
+
FileSystemId: Fn2.ref("EfsFileSystem"),
|
|
45954
|
+
SubnetId: subnetId,
|
|
45955
|
+
SecurityGroups: [Fn2.getAtt("DataSecurityGroup", "GroupId")]
|
|
45956
|
+
}
|
|
45957
|
+
};
|
|
45958
|
+
});
|
|
45959
|
+
resources.EfsAccessPoint = {
|
|
45960
|
+
Type: "AWS::EFS::AccessPoint",
|
|
45961
|
+
Properties: {
|
|
45962
|
+
FileSystemId: Fn2.ref("EfsFileSystem"),
|
|
45963
|
+
PosixUser: { Uid: 1001, Gid: 1001 },
|
|
45964
|
+
RootDirectory: {
|
|
45965
|
+
Path: "/lambda",
|
|
45966
|
+
CreationInfo: { OwnerUid: 1001, OwnerGid: 1001, Permissions: "0755" }
|
|
45967
|
+
}
|
|
45968
|
+
}
|
|
45969
|
+
};
|
|
45970
|
+
outputs.EfsFileSystemId = { Description: "EFS file system id", Value: Fn2.ref("EfsFileSystem") };
|
|
45971
|
+
}
|
|
45899
45972
|
if (app.cache?.driver === "elasticache") {
|
|
45900
45973
|
resources.CacheSubnetGroup = {
|
|
45901
45974
|
Type: "AWS::ElastiCache::SubnetGroup",
|
package/dist/types.d.ts
CHANGED
|
@@ -918,9 +918,10 @@ export interface SiteConfig {
|
|
|
918
918
|
queues?: QueueWorkerConfig[];
|
|
919
919
|
/**
|
|
920
920
|
* Run the Laravel scheduler for this site
|
|
921
|
-
* (`* * * * * php artisan schedule:run`).
|
|
921
|
+
* (`* * * * * php artisan schedule:run`). `true` enables it with defaults;
|
|
922
|
+
* pass a {@link SchedulerConfig} to attach heartbeat monitoring.
|
|
922
923
|
*/
|
|
923
|
-
scheduler?: boolean;
|
|
924
|
+
scheduler?: boolean | SchedulerConfig;
|
|
924
925
|
/** Arbitrary long-running processes to keep alive (systemd-managed). */
|
|
925
926
|
daemons?: DaemonConfig[];
|
|
926
927
|
/** TLS configuration for this site's nginx vhost. */
|
|
@@ -955,6 +956,29 @@ export interface SiteConfig {
|
|
|
955
956
|
* Composer/npm credentials feature).
|
|
956
957
|
*/
|
|
957
958
|
credentials?: SiteCredentialsConfig;
|
|
959
|
+
/**
|
|
960
|
+
* Custom nginx for this site's vhost (Forge's "Edit Nginx Configuration").
|
|
961
|
+
* Directives are injected into the generated `server { … }` block, so the
|
|
962
|
+
* managed root/locations/SSL still apply.
|
|
963
|
+
*/
|
|
964
|
+
nginx?: SiteNginxConfig;
|
|
965
|
+
}
|
|
966
|
+
/** Per-site nginx customization injected into the generated server block. */
|
|
967
|
+
export interface SiteNginxConfig {
|
|
968
|
+
/**
|
|
969
|
+
* Name of a reusable template defined in
|
|
970
|
+
* {@link ComputeConfig.nginxTemplates}. Its directive lines are injected into
|
|
971
|
+
* this site's server block.
|
|
972
|
+
*/
|
|
973
|
+
template?: string;
|
|
974
|
+
/**
|
|
975
|
+
* Raw nginx directive lines added to this site's server block (after the
|
|
976
|
+
* managed directives), e.g. `['gzip on;', 'location /metrics { deny all; }']`.
|
|
977
|
+
* Applied on top of {@link template} when both are set.
|
|
978
|
+
*/
|
|
979
|
+
serverSnippet?: string[];
|
|
980
|
+
/** `client_max_body_size` for this vhost (e.g. `'256M'`) for large uploads. */
|
|
981
|
+
clientMaxBodySize?: string;
|
|
958
982
|
}
|
|
959
983
|
/** Private package-registry credentials for a site's build. */
|
|
960
984
|
export interface SiteCredentialsConfig {
|
|
@@ -1050,6 +1074,22 @@ export interface SslDnsConfig {
|
|
|
1050
1074
|
/** Seconds to wait for DNS propagation before certbot asks the CA to verify. */
|
|
1051
1075
|
propagationSeconds?: number;
|
|
1052
1076
|
}
|
|
1077
|
+
/**
|
|
1078
|
+
* Laravel scheduler options for a site (Forge's scheduler + heartbeat
|
|
1079
|
+
* monitoring). The scheduler runs `php artisan schedule:run` every minute.
|
|
1080
|
+
*/
|
|
1081
|
+
export interface SchedulerConfig {
|
|
1082
|
+
/**
|
|
1083
|
+
* Heartbeat monitor URL pinged after each successful `schedule:run`
|
|
1084
|
+
* (healthchecks.io, Oh Dear, Better Uptime, …). If the scheduler stops, the
|
|
1085
|
+
* monitor stops receiving pings and alerts you.
|
|
1086
|
+
*/
|
|
1087
|
+
heartbeatUrl?: string;
|
|
1088
|
+
/**
|
|
1089
|
+
* HTTP method for the heartbeat ping. @default 'GET'
|
|
1090
|
+
*/
|
|
1091
|
+
heartbeatMethod?: 'GET' | 'POST' | 'HEAD';
|
|
1092
|
+
}
|
|
1053
1093
|
/**
|
|
1054
1094
|
* A Laravel queue worker (or Horizon supervisor) run as a systemd service.
|
|
1055
1095
|
* Mirrors Forge's queue configuration. See {@link SiteConfig.queues}.
|
|
@@ -1621,6 +1661,18 @@ export interface ServerlessAppConfig {
|
|
|
1621
1661
|
storage?: {
|
|
1622
1662
|
bucket?: string;
|
|
1623
1663
|
};
|
|
1664
|
+
/**
|
|
1665
|
+
* Mount a shared Elastic File System on the functions (Vapor's `/mnt/local`).
|
|
1666
|
+
* Requires a VPC. `true` provisions an EFS file system + access point;
|
|
1667
|
+
* otherwise attach an existing access point by ARN. The mount path defaults
|
|
1668
|
+
* to `/mnt/local`.
|
|
1669
|
+
*/
|
|
1670
|
+
efs?: boolean | {
|
|
1671
|
+
/** Existing EFS Access Point ARN to attach (skips provisioning). */
|
|
1672
|
+
accessPointArn?: string;
|
|
1673
|
+
/** Mount path inside the functions. @default '/mnt/local' */
|
|
1674
|
+
mountPath?: string;
|
|
1675
|
+
};
|
|
1624
1676
|
/** Managed WAF in front of the HTTP API / CloudFront. */
|
|
1625
1677
|
firewall?: WafConfig;
|
|
1626
1678
|
/** Custom domain(s) for the app's HTTP API (overrides {@link EnvironmentConfig.domain}). */
|
|
@@ -1636,6 +1688,19 @@ export interface ServerlessAppConfig {
|
|
|
1636
1688
|
hostedZoneId?: string;
|
|
1637
1689
|
/** Local directory whose contents are uploaded to S3/CloudFront as versioned assets. */
|
|
1638
1690
|
assets?: string;
|
|
1691
|
+
/**
|
|
1692
|
+
* Serve assets from a custom CDN host instead of the default CloudFront domain
|
|
1693
|
+
* (Vapor `asset-domain`). Requires a us-east-1 ACM cert via assetCertificateArn.
|
|
1694
|
+
*/
|
|
1695
|
+
assetDomain?: string;
|
|
1696
|
+
/** us-east-1 ACM certificate ARN for {@link assetDomain} (CloudFront requirement). */
|
|
1697
|
+
assetCertificateArn?: string;
|
|
1698
|
+
/** Include dotfiles when uploading assets (Vapor `dot-files-as-assets`). @default false */
|
|
1699
|
+
dotFilesAsAssets?: boolean;
|
|
1700
|
+
/** Serve assets from the app/root domain too (Vapor `serve_assets`). Injected as env. */
|
|
1701
|
+
serveAssets?: boolean;
|
|
1702
|
+
/** Redirect robots.txt to the asset CDN (Vapor `redirect_robots_txt`). Injected as env. @default true */
|
|
1703
|
+
redirectRobotsTxt?: boolean;
|
|
1639
1704
|
/** PHP version for the runtime layer. @default '8.3' */
|
|
1640
1705
|
phpVersion?: PhpVersion;
|
|
1641
1706
|
/** CPU architecture. @default 'x86_64' */
|
|
@@ -2141,6 +2206,13 @@ export interface ComputeConfig {
|
|
|
2141
2206
|
* @default 'nginx'
|
|
2142
2207
|
*/
|
|
2143
2208
|
webServer?: 'nginx' | 'rpx';
|
|
2209
|
+
/**
|
|
2210
|
+
* Reusable nginx config templates, keyed by name. A site references one via
|
|
2211
|
+
* `site.nginx.template`, and its directive lines are injected into that
|
|
2212
|
+
* site's server block — define a hardening/caching/proxy snippet once and
|
|
2213
|
+
* share it across sites (Forge's nginx templates).
|
|
2214
|
+
*/
|
|
2215
|
+
nginxTemplates?: Record<string, string[]>;
|
|
2144
2216
|
/**
|
|
2145
2217
|
* On-box managed services to install (Forge's single-server model): the
|
|
2146
2218
|
* database engine, cache, and search. Each may be `true` for defaults or an
|
|
@@ -2228,6 +2300,19 @@ export interface ComputePhpConfig {
|
|
|
2228
2300
|
* e.g. `['imagick', 'swoole']`.
|
|
2229
2301
|
*/
|
|
2230
2302
|
extensions?: string[];
|
|
2303
|
+
/**
|
|
2304
|
+
* Apply the production OPcache + php.ini tuning (Forge's "Optimize for
|
|
2305
|
+
* Production"): OPcache on with timestamp validation off, larger file/string
|
|
2306
|
+
* buffers, and a bigger realpath cache. Deploys restart php-fpm, so disabled
|
|
2307
|
+
* timestamp validation is safe. @default true
|
|
2308
|
+
*/
|
|
2309
|
+
optimizeForProduction?: boolean;
|
|
2310
|
+
/**
|
|
2311
|
+
* Extra `php.ini` directives merged on top of the production tuning (and
|
|
2312
|
+
* applied even when {@link optimizeForProduction} is false), e.g.
|
|
2313
|
+
* `{ memory_limit: '512M', upload_max_filesize: '128M' }`.
|
|
2314
|
+
*/
|
|
2315
|
+
ini?: Record<string, string>;
|
|
2231
2316
|
}
|
|
2232
2317
|
/**
|
|
2233
2318
|
* On-box managed services (database / cache / search) for a compute box.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ts-cloud/core",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Core CloudFormation generation library for ts-cloud",
|
|
6
6
|
"author": "Chris Breuer <chris@stacksjs.com>",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"typecheck": "tsc --noEmit"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@ts-cloud/aws-types": "0.5.
|
|
34
|
+
"@ts-cloud/aws-types": "0.5.2"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"typescript": "^5.9.3"
|