@ts-cloud/core 0.5.0 → 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 +139 -12
- package/dist/types.d.ts +173 -6
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -45517,15 +45517,21 @@ function composeServerlessAppTemplate(opts) {
|
|
|
45517
45517
|
TSCLOUD_LAMBDA_MODE: mode,
|
|
45518
45518
|
TSCLOUD_ENV: environment,
|
|
45519
45519
|
...app.octane ? { TSCLOUD_OCTANE: "1" } : {},
|
|
45520
|
+
...app.scheduler === "sub-minute" ? { TSCLOUD_SCHEDULER: "sub-minute" } : {},
|
|
45520
45521
|
...cacheEnabled ? { TSCLOUD_CACHE_TABLE: `${slug}-${environment}-cache` } : {},
|
|
45521
45522
|
...hasQueue ? { TSCLOUD_QUEUE: queueNames[0] } : {},
|
|
45522
45523
|
...app.env ?? {}
|
|
45523
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);
|
|
45524
45530
|
const subnets = app.vpc?.subnets ?? [];
|
|
45525
45531
|
const hasVpc = subnets.length > 0;
|
|
45526
|
-
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;
|
|
45527
45533
|
if (needsDataVpc && !hasVpc) {
|
|
45528
|
-
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.");
|
|
45529
45535
|
}
|
|
45530
45536
|
const vpcConfig = hasVpc ? {
|
|
45531
45537
|
VpcConfig: {
|
|
@@ -45536,7 +45542,16 @@ function composeServerlessAppTemplate(opts) {
|
|
|
45536
45542
|
]
|
|
45537
45543
|
}
|
|
45538
45544
|
} : {};
|
|
45539
|
-
|
|
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
|
+
}
|
|
45554
|
+
function addFunction(logicalId, name, handler8, mode, memory, timeout, reservedConcurrency, tmp = tmpStorage) {
|
|
45540
45555
|
resources[`${logicalId}LogGroup`] = {
|
|
45541
45556
|
Type: "AWS::Logs::LogGroup",
|
|
45542
45557
|
Properties: { LogGroupName: `/aws/lambda/${name}`, RetentionInDays: 14 }
|
|
@@ -45553,7 +45568,7 @@ function composeServerlessAppTemplate(opts) {
|
|
|
45553
45568
|
};
|
|
45554
45569
|
resources[logicalId] = {
|
|
45555
45570
|
Type: "AWS::Lambda::Function",
|
|
45556
|
-
DependsOn: [`${logicalId}LogGroup
|
|
45571
|
+
DependsOn: [`${logicalId}LogGroup`, ...efsDependsOn],
|
|
45557
45572
|
Properties: {
|
|
45558
45573
|
FunctionName: name,
|
|
45559
45574
|
Architectures: [architecture],
|
|
@@ -45561,17 +45576,18 @@ function composeServerlessAppTemplate(opts) {
|
|
|
45561
45576
|
Timeout: timeout,
|
|
45562
45577
|
Role: Fn2.getAtt("AppRole", "Arn"),
|
|
45563
45578
|
Environment: { Variables: baseEnv(mode) },
|
|
45564
|
-
EphemeralStorage: { Size:
|
|
45579
|
+
EphemeralStorage: { Size: tmp },
|
|
45565
45580
|
...codeProps,
|
|
45566
45581
|
...reservedConcurrency !== undefined ? { ReservedConcurrentExecutions: reservedConcurrency } : {},
|
|
45567
|
-
...vpcConfig
|
|
45582
|
+
...vpcConfig,
|
|
45583
|
+
...efsConfig
|
|
45568
45584
|
}
|
|
45569
45585
|
};
|
|
45570
45586
|
}
|
|
45571
|
-
addFunction("HttpFunction", functionNames.http, handlers.http, "http", app.memory ?? 1024, app.timeout ?? 28, app.concurrency);
|
|
45572
|
-
addFunction("CliFunction", functionNames.cli, handlers.cli, "cli", app.cliMemory ?? 1024, app.cliTimeout ?? 900);
|
|
45587
|
+
addFunction("HttpFunction", functionNames.http, handlers.http, "http", app.memory ?? 1024, app.timeout ?? 28, app.concurrency, tmpStorage);
|
|
45588
|
+
addFunction("CliFunction", functionNames.cli, handlers.cli, "cli", app.cliMemory ?? 1024, app.cliTimeout ?? 900, undefined, app.cliTmpStorage ?? tmpStorage);
|
|
45573
45589
|
if (hasQueue)
|
|
45574
|
-
addFunction("QueueFunction", functionNames.queue, handlers.queue, "queue", app.queueMemory ?? 1024, app.queueTimeout ?? 120);
|
|
45590
|
+
addFunction("QueueFunction", functionNames.queue, handlers.queue, "queue", app.queueMemory ?? 1024, app.queueTimeout ?? 120, undefined, app.queueTmpStorage ?? tmpStorage);
|
|
45575
45591
|
resources.HttpApi = {
|
|
45576
45592
|
Type: "AWS::ApiGatewayV2::Api",
|
|
45577
45593
|
Properties: {
|
|
@@ -45618,6 +45634,59 @@ function composeServerlessAppTemplate(opts) {
|
|
|
45618
45634
|
Value: Fn2.getAtt("HttpApi", "ApiEndpoint")
|
|
45619
45635
|
};
|
|
45620
45636
|
outputs.HttpApiId = { Description: "HTTP API id", Value: Fn2.ref("HttpApi") };
|
|
45637
|
+
const domains = (Array.isArray(app.domain) ? app.domain : app.domain ? [app.domain] : []).filter(Boolean);
|
|
45638
|
+
if (domains.length) {
|
|
45639
|
+
if (!app.certificateArn && !app.hostedZoneId) {
|
|
45640
|
+
throw new Error("serverless app: a custom `domain` needs either `certificateArn` (pre-issued, regional) or `hostedZoneId` (to auto-issue + validate an ACM cert).");
|
|
45641
|
+
}
|
|
45642
|
+
let certRef = app.certificateArn;
|
|
45643
|
+
if (!certRef) {
|
|
45644
|
+
resources.HttpCertificate = {
|
|
45645
|
+
Type: "AWS::CertificateManager::Certificate",
|
|
45646
|
+
Properties: {
|
|
45647
|
+
DomainName: domains[0],
|
|
45648
|
+
...domains.length > 1 ? { SubjectAlternativeNames: domains.slice(1) } : {},
|
|
45649
|
+
ValidationMethod: "DNS",
|
|
45650
|
+
DomainValidationOptions: domains.map((d) => ({ DomainName: d, HostedZoneId: app.hostedZoneId }))
|
|
45651
|
+
}
|
|
45652
|
+
};
|
|
45653
|
+
certRef = Fn2.ref("HttpCertificate");
|
|
45654
|
+
}
|
|
45655
|
+
domains.forEach((d, i) => {
|
|
45656
|
+
const dn = `HttpDomain${i}`;
|
|
45657
|
+
resources[dn] = {
|
|
45658
|
+
Type: "AWS::ApiGatewayV2::DomainName",
|
|
45659
|
+
Properties: {
|
|
45660
|
+
DomainName: d,
|
|
45661
|
+
DomainNameConfigurations: [{ CertificateArn: certRef, EndpointType: "REGIONAL" }]
|
|
45662
|
+
}
|
|
45663
|
+
};
|
|
45664
|
+
resources[`HttpApiMapping${i}`] = {
|
|
45665
|
+
Type: "AWS::ApiGatewayV2::ApiMapping",
|
|
45666
|
+
DependsOn: ["HttpStage"],
|
|
45667
|
+
Properties: { ApiId: Fn2.ref("HttpApi"), DomainName: Fn2.ref(dn), Stage: "$default" }
|
|
45668
|
+
};
|
|
45669
|
+
if (app.hostedZoneId) {
|
|
45670
|
+
resources[`HttpDomainRecord${i}`] = {
|
|
45671
|
+
Type: "AWS::Route53::RecordSet",
|
|
45672
|
+
Properties: {
|
|
45673
|
+
HostedZoneId: app.hostedZoneId,
|
|
45674
|
+
Name: d,
|
|
45675
|
+
Type: "A",
|
|
45676
|
+
AliasTarget: {
|
|
45677
|
+
DNSName: Fn2.getAtt(dn, "RegionalDomainName"),
|
|
45678
|
+
HostedZoneId: Fn2.getAtt(dn, "RegionalHostedZoneId")
|
|
45679
|
+
}
|
|
45680
|
+
}
|
|
45681
|
+
};
|
|
45682
|
+
}
|
|
45683
|
+
outputs[`CustomDomain${i}`] = { Description: `Custom domain ${d}`, Value: d };
|
|
45684
|
+
outputs[`CustomDomainTarget${i}`] = {
|
|
45685
|
+
Description: `Point ${d} (CNAME/alias) at this APIGW regional domain`,
|
|
45686
|
+
Value: Fn2.getAtt(dn, "RegionalDomainName")
|
|
45687
|
+
};
|
|
45688
|
+
});
|
|
45689
|
+
}
|
|
45621
45690
|
if (hasQueue) {
|
|
45622
45691
|
resources.AppQueueDlq = {
|
|
45623
45692
|
Type: "AWS::SQS::Queue",
|
|
@@ -45760,10 +45829,37 @@ function composeServerlessAppTemplate(opts) {
|
|
|
45760
45829
|
DomainName: Fn2.getAtt("AssetsBucket", "RegionalDomainName"),
|
|
45761
45830
|
OriginAccessControlId: Fn2.ref("AssetsOAC"),
|
|
45762
45831
|
S3OriginConfig: { OriginAccessIdentity: "" }
|
|
45763
|
-
}]
|
|
45764
|
-
|
|
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
|
+
} : {}
|
|
45841
|
+
}
|
|
45842
|
+
}
|
|
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
|
+
};
|
|
45765
45860
|
}
|
|
45766
|
-
|
|
45861
|
+
outputs.AssetDomain = { Description: "Custom asset CDN host", Value: app.assetDomain };
|
|
45862
|
+
}
|
|
45767
45863
|
resources.AssetsBucketPolicy = {
|
|
45768
45864
|
Type: "AWS::S3::BucketPolicy",
|
|
45769
45865
|
Properties: {
|
|
@@ -45842,6 +45938,37 @@ function composeServerlessAppTemplate(opts) {
|
|
|
45842
45938
|
}
|
|
45843
45939
|
};
|
|
45844
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
|
+
}
|
|
45845
45972
|
if (app.cache?.driver === "elasticache") {
|
|
45846
45973
|
resources.CacheSubnetGroup = {
|
|
45847
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. */
|
|
@@ -949,6 +950,46 @@ export interface SiteConfig {
|
|
|
949
950
|
* process.env.UI_PASSWORD }`. The htpasswd file is generated on the box.
|
|
950
951
|
*/
|
|
951
952
|
auth?: SiteAuthConfig;
|
|
953
|
+
/**
|
|
954
|
+
* Package-registry credentials written into the release before
|
|
955
|
+
* `composer install` / `npm install` so private packages resolve (Forge's
|
|
956
|
+
* Composer/npm credentials feature).
|
|
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;
|
|
982
|
+
}
|
|
983
|
+
/** Private package-registry credentials for a site's build. */
|
|
984
|
+
export interface SiteCredentialsConfig {
|
|
985
|
+
/**
|
|
986
|
+
* Composer `auth.json` contents — an object (serialized to JSON) or a
|
|
987
|
+
* ready-made JSON string. Written to the release root before `composer
|
|
988
|
+
* install` (e.g. `{ 'github-oauth': { 'github.com': '<token>' } }`).
|
|
989
|
+
*/
|
|
990
|
+
composerAuth?: Record<string, unknown> | string;
|
|
991
|
+
/** `.npmrc` contents written to the release root before `npm install`. */
|
|
992
|
+
npmrc?: string;
|
|
952
993
|
}
|
|
953
994
|
/** HTTP Basic auth for a site's nginx vhost. See {@link SiteConfig.auth}. */
|
|
954
995
|
export interface SiteAuthConfig {
|
|
@@ -1006,6 +1047,48 @@ export interface SiteSslConfig {
|
|
|
1006
1047
|
certPath?: string;
|
|
1007
1048
|
/** Path to the private key (PEM) when `provider: 'custom'`. */
|
|
1008
1049
|
keyPath?: string;
|
|
1050
|
+
/**
|
|
1051
|
+
* Issue a **wildcard** certificate (`*.<domain>` + `<domain>`). Requires
|
|
1052
|
+
* DNS-01 validation, so {@link dns} must be set. The nginx plugin can't do
|
|
1053
|
+
* wildcards (that needs HTTP-01 per host).
|
|
1054
|
+
*/
|
|
1055
|
+
wildcard?: boolean;
|
|
1056
|
+
/**
|
|
1057
|
+
* Use DNS-01 validation via a certbot DNS plugin instead of the nginx
|
|
1058
|
+
* (HTTP-01) challenge. Needed for wildcard certs and for issuing before the
|
|
1059
|
+
* domain resolves to the box. The plugin + credentials are wired on the box.
|
|
1060
|
+
*/
|
|
1061
|
+
dns?: SslDnsConfig;
|
|
1062
|
+
}
|
|
1063
|
+
/** certbot DNS-01 plugin configuration for DNS-validated / wildcard certs. */
|
|
1064
|
+
export interface SslDnsConfig {
|
|
1065
|
+
/** DNS provider whose certbot plugin handles the `_acme-challenge` records. */
|
|
1066
|
+
provider: 'cloudflare' | 'route53' | 'digitalocean' | 'google';
|
|
1067
|
+
/**
|
|
1068
|
+
* Provider credentials written to a root-only INI certbot reads
|
|
1069
|
+
* (`--dns-<provider>-credentials`). For route53, AWS env/instance-role creds
|
|
1070
|
+
* are used instead, so this may be omitted. Keys are provider-specific, e.g.
|
|
1071
|
+
* `{ dns_cloudflare_api_token: '…' }`.
|
|
1072
|
+
*/
|
|
1073
|
+
credentials?: Record<string, string>;
|
|
1074
|
+
/** Seconds to wait for DNS propagation before certbot asks the CA to verify. */
|
|
1075
|
+
propagationSeconds?: number;
|
|
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';
|
|
1009
1092
|
}
|
|
1010
1093
|
/**
|
|
1011
1094
|
* A Laravel queue worker (or Horizon supervisor) run as a systemd service.
|
|
@@ -1123,6 +1206,34 @@ export interface DatabaseConfig {
|
|
|
1123
1206
|
host?: string;
|
|
1124
1207
|
/** Port (defaults: mysql/mariadb 3306, postgres 5432). */
|
|
1125
1208
|
port?: number;
|
|
1209
|
+
/**
|
|
1210
|
+
* Additional database users to create beyond the app {@link username}
|
|
1211
|
+
* (the Forge Database Users feature). Each can be granted full or read-only
|
|
1212
|
+
* access to one or more databases. Created at provision time on the on-box
|
|
1213
|
+
* engine.
|
|
1214
|
+
*/
|
|
1215
|
+
users?: DatabaseUserConfig[];
|
|
1216
|
+
}
|
|
1217
|
+
/**
|
|
1218
|
+
* An extra database user provisioned on the on-box engine (per-user grants).
|
|
1219
|
+
* Beyond the application user, you can create reporting/read-only accounts or
|
|
1220
|
+
* service-specific logins with their own access scope.
|
|
1221
|
+
*/
|
|
1222
|
+
export interface DatabaseUserConfig {
|
|
1223
|
+
/** User name to create. */
|
|
1224
|
+
username: string;
|
|
1225
|
+
/** Password for the user. */
|
|
1226
|
+
password: string;
|
|
1227
|
+
/**
|
|
1228
|
+
* Databases this user may access. Defaults to the app database
|
|
1229
|
+
* ({@link DatabaseConfig.name}) when omitted.
|
|
1230
|
+
*/
|
|
1231
|
+
databases?: string[];
|
|
1232
|
+
/**
|
|
1233
|
+
* Access level granted on {@link databases}. `all` (default) is full
|
|
1234
|
+
* read/write; `readonly` grants SELECT only (plus connect on Postgres).
|
|
1235
|
+
*/
|
|
1236
|
+
access?: 'all' | 'readonly';
|
|
1126
1237
|
}
|
|
1127
1238
|
export interface CacheConfig {
|
|
1128
1239
|
type?: 'redis' | 'memcached';
|
|
@@ -1530,8 +1641,12 @@ export interface ServerlessAppConfig {
|
|
|
1530
1641
|
rdsProxy?: boolean | {
|
|
1531
1642
|
name?: string;
|
|
1532
1643
|
};
|
|
1533
|
-
/** Ephemeral
|
|
1644
|
+
/** Ephemeral storage in MB (512 to 10240) for the HTTP function. @default 512 */
|
|
1534
1645
|
tmpStorage?: number;
|
|
1646
|
+
/** Ephemeral storage in MB for the CLI function. @default tmpStorage */
|
|
1647
|
+
cliTmpStorage?: number;
|
|
1648
|
+
/** Ephemeral storage in MB for the queue function. @default tmpStorage */
|
|
1649
|
+
queueTmpStorage?: number;
|
|
1535
1650
|
/** Database attachment. */
|
|
1536
1651
|
database?: {
|
|
1537
1652
|
connection?: 'rds-proxy' | 'aurora-serverless' | 'rds';
|
|
@@ -1546,14 +1661,46 @@ export interface ServerlessAppConfig {
|
|
|
1546
1661
|
storage?: {
|
|
1547
1662
|
bucket?: string;
|
|
1548
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
|
+
};
|
|
1549
1676
|
/** Managed WAF in front of the HTTP API / CloudFront. */
|
|
1550
1677
|
firewall?: WafConfig;
|
|
1551
|
-
/** Custom domain for the app (overrides {@link EnvironmentConfig.domain}). */
|
|
1678
|
+
/** Custom domain(s) for the app's HTTP API (overrides {@link EnvironmentConfig.domain}). */
|
|
1552
1679
|
domain?: string | string[];
|
|
1553
|
-
/** Pre-issued ACM certificate ARN for the custom domain. */
|
|
1680
|
+
/** Pre-issued ACM certificate ARN for the custom domain (regional, same region). */
|
|
1554
1681
|
certificateArn?: string;
|
|
1682
|
+
/**
|
|
1683
|
+
* Route53 hosted zone ID for the custom domain. When set (and no
|
|
1684
|
+
* `certificateArn`), ts-cloud issues + DNS-validates an ACM cert and creates
|
|
1685
|
+
* the alias record automatically. Without it, supply `certificateArn` and
|
|
1686
|
+
* point your DNS at the API's regional domain (emitted as a stack output).
|
|
1687
|
+
*/
|
|
1688
|
+
hostedZoneId?: string;
|
|
1555
1689
|
/** Local directory whose contents are uploaded to S3/CloudFront as versioned assets. */
|
|
1556
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;
|
|
1557
1704
|
/** PHP version for the runtime layer. @default '8.3' */
|
|
1558
1705
|
phpVersion?: PhpVersion;
|
|
1559
1706
|
/** CPU architecture. @default 'x86_64' */
|
|
@@ -2059,6 +2206,13 @@ export interface ComputeConfig {
|
|
|
2059
2206
|
* @default 'nginx'
|
|
2060
2207
|
*/
|
|
2061
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[]>;
|
|
2062
2216
|
/**
|
|
2063
2217
|
* On-box managed services to install (Forge's single-server model): the
|
|
2064
2218
|
* database engine, cache, and search. Each may be `true` for defaults or an
|
|
@@ -2146,6 +2300,19 @@ export interface ComputePhpConfig {
|
|
|
2146
2300
|
* e.g. `['imagick', 'swoole']`.
|
|
2147
2301
|
*/
|
|
2148
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>;
|
|
2149
2316
|
}
|
|
2150
2317
|
/**
|
|
2151
2318
|
* On-box managed services (database / cache / search) for a compute box.
|
|
@@ -3191,7 +3358,7 @@ export interface RealtimeHooksConfig {
|
|
|
3191
3358
|
* })
|
|
3192
3359
|
*
|
|
3193
3360
|
* // Private channel
|
|
3194
|
-
* Echo.private(
|
|
3361
|
+
* Echo.private('user.' + userId).listen('notification', (e) => {
|
|
3195
3362
|
* console.log('Private notification:', e)
|
|
3196
3363
|
* })
|
|
3197
3364
|
*
|
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"
|