@ts-cloud/core 0.7.118 → 0.7.120
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/drivers/types.d.ts +7 -0
- package/dist/index.js +70 -22
- package/dist/modules/sftp.d.ts +26 -5
- package/dist/types.d.ts +98 -6
- package/package.json +2 -2
package/dist/drivers/types.d.ts
CHANGED
|
@@ -57,6 +57,13 @@ export interface FindComputeTargetsOptions {
|
|
|
57
57
|
slug: string;
|
|
58
58
|
environment: EnvironmentType;
|
|
59
59
|
role?: string;
|
|
60
|
+
/**
|
|
61
|
+
* Region to search, for drivers that have one. Defaults to the driver's own.
|
|
62
|
+
* A driver method that resolved a region from config passes it here, so the
|
|
63
|
+
* lookup and whatever is done with the results cannot disagree about where
|
|
64
|
+
* the instances are.
|
|
65
|
+
*/
|
|
66
|
+
region?: string;
|
|
60
67
|
/**
|
|
61
68
|
* Project stack name (`resolveProjectStackName(config, environment)`), used
|
|
62
69
|
* by drivers that can pin targets from local state when label/tag scans
|
package/dist/index.js
CHANGED
|
@@ -10647,11 +10647,45 @@ function normalizeHomeDirectory(value, username) {
|
|
|
10647
10647
|
throw new Error(`sftp: invalid homeDirectory for user ${username}`);
|
|
10648
10648
|
return path;
|
|
10649
10649
|
}
|
|
10650
|
+
function resolveStorage(options) {
|
|
10651
|
+
const storage = options.storage;
|
|
10652
|
+
if (storage?.type === "efs") {
|
|
10653
|
+
const fileSystemId = "fileSystemId" in storage ? storage.fileSystemId : undefined;
|
|
10654
|
+
if (!fileSystemId || typeof fileSystemId === "string" && !fileSystemId.trim())
|
|
10655
|
+
throw new Error("sftp: EFS storage requires fileSystemId, or a fileSystem name defined in infrastructure.fileSystem");
|
|
10656
|
+
return { type: "efs", fileSystemId, posixProfile: storage.posixProfile };
|
|
10657
|
+
}
|
|
10658
|
+
const bucket = (storage?.type === "s3" ? storage.bucket ?? options.bucket : options.bucket)?.trim();
|
|
10659
|
+
if (!bucket)
|
|
10660
|
+
throw new Error("sftp: S3 storage requires bucket, or a storageBucket name defined in infrastructure.storage");
|
|
10661
|
+
return { type: "s3", bucket };
|
|
10662
|
+
}
|
|
10663
|
+
function posixProfileFor(username, user, fallback) {
|
|
10664
|
+
const profile = user.posixProfile ?? fallback;
|
|
10665
|
+
if (!profile)
|
|
10666
|
+
throw new Error(`sftp: user ${username} requires a posixProfile (uid/gid) on an EFS-backed server`);
|
|
10667
|
+
for (const id of [profile.uid, profile.gid, ...profile.secondaryGids ?? []]) {
|
|
10668
|
+
if (!Number.isInteger(id) || id < 0 || id > 4294967295)
|
|
10669
|
+
throw new Error(`sftp: user ${username} has an invalid posixProfile id ${id}`);
|
|
10670
|
+
}
|
|
10671
|
+
return {
|
|
10672
|
+
Uid: profile.uid,
|
|
10673
|
+
Gid: profile.gid,
|
|
10674
|
+
...profile.secondaryGids?.length ? { SecondaryGids: profile.secondaryGids } : {}
|
|
10675
|
+
};
|
|
10676
|
+
}
|
|
10677
|
+
function efsHomeDirectory(fileSystemId, home) {
|
|
10678
|
+
return typeof fileSystemId === "string" ? `/${fileSystemId}/${home}` : { "Fn::Sub": [`/\${FileSystemId}/${home}`, { FileSystemId: fileSystemId }] };
|
|
10679
|
+
}
|
|
10680
|
+
function efsFileSystemArn(fileSystemId) {
|
|
10681
|
+
const template = "arn:aws:elasticfilesystem:${AWS::Region}:${AWS::AccountId}:file-system/${FileSystemId}";
|
|
10682
|
+
return typeof fileSystemId === "string" ? { "Fn::Sub": template.replace("${FileSystemId}", fileSystemId) } : { "Fn::Sub": [template, { FileSystemId: fileSystemId }] };
|
|
10683
|
+
}
|
|
10650
10684
|
|
|
10651
10685
|
class Sftp {
|
|
10652
10686
|
static create(options) {
|
|
10653
|
-
|
|
10654
|
-
|
|
10687
|
+
const storage = resolveStorage(options);
|
|
10688
|
+
const domain = storage.type === "efs" ? "EFS" : "S3";
|
|
10655
10689
|
const endpointType = options.endpointType ?? "PUBLIC";
|
|
10656
10690
|
if (endpointType === "VPC" && (!options.endpointDetails?.vpcId || !options.endpointDetails.subnetIds.length))
|
|
10657
10691
|
throw new Error("sftp: VPC endpoints require endpointDetails.vpcId and at least one subnet");
|
|
@@ -10697,7 +10731,7 @@ class Sftp {
|
|
|
10697
10731
|
resources[serverLogicalId] = {
|
|
10698
10732
|
Type: "AWS::Transfer::Server",
|
|
10699
10733
|
Properties: {
|
|
10700
|
-
Domain:
|
|
10734
|
+
Domain: domain,
|
|
10701
10735
|
EndpointType: endpointType,
|
|
10702
10736
|
IdentityProviderType: "SERVICE_MANAGED",
|
|
10703
10737
|
Protocols: ["SFTP"],
|
|
@@ -10729,7 +10763,35 @@ class Sftp {
|
|
|
10729
10763
|
let roleArn = user.roleArn;
|
|
10730
10764
|
if (!roleArn) {
|
|
10731
10765
|
const roleLogicalId = `${prefix}${userPart}Role`;
|
|
10732
|
-
|
|
10766
|
+
let statements;
|
|
10767
|
+
if (storage.type === "efs") {
|
|
10768
|
+
statements = [
|
|
10769
|
+
{
|
|
10770
|
+
Effect: "Allow",
|
|
10771
|
+
Action: [
|
|
10772
|
+
"elasticfilesystem:ClientMount",
|
|
10773
|
+
"elasticfilesystem:ClientWrite",
|
|
10774
|
+
"elasticfilesystem:DescribeMountTargets"
|
|
10775
|
+
],
|
|
10776
|
+
Resource: efsFileSystemArn(storage.fileSystemId)
|
|
10777
|
+
}
|
|
10778
|
+
];
|
|
10779
|
+
} else {
|
|
10780
|
+
const bucketArn = `arn:aws:s3:::${storage.bucket}`;
|
|
10781
|
+
statements = [
|
|
10782
|
+
{
|
|
10783
|
+
Effect: "Allow",
|
|
10784
|
+
Action: ["s3:ListBucket", "s3:GetBucketLocation"],
|
|
10785
|
+
Resource: bucketArn,
|
|
10786
|
+
Condition: { StringLike: { "s3:prefix": [home, `${home}/*`] } }
|
|
10787
|
+
},
|
|
10788
|
+
{
|
|
10789
|
+
Effect: "Allow",
|
|
10790
|
+
Action: ["s3:GetObject", "s3:PutObject", "s3:DeleteObject", "s3:GetObjectVersion"],
|
|
10791
|
+
Resource: `${bucketArn}/${home}/*`
|
|
10792
|
+
}
|
|
10793
|
+
];
|
|
10794
|
+
}
|
|
10733
10795
|
resources[roleLogicalId] = {
|
|
10734
10796
|
Type: "AWS::IAM::Role",
|
|
10735
10797
|
Properties: {
|
|
@@ -10742,22 +10804,7 @@ class Sftp {
|
|
|
10742
10804
|
Policies: [
|
|
10743
10805
|
{
|
|
10744
10806
|
PolicyName: "SftpHomeDirectory",
|
|
10745
|
-
PolicyDocument: {
|
|
10746
|
-
Version: "2012-10-17",
|
|
10747
|
-
Statement: [
|
|
10748
|
-
{
|
|
10749
|
-
Effect: "Allow",
|
|
10750
|
-
Action: ["s3:ListBucket", "s3:GetBucketLocation"],
|
|
10751
|
-
Resource: bucketArn,
|
|
10752
|
-
Condition: { StringLike: { "s3:prefix": [home, `${home}/*`] } }
|
|
10753
|
-
},
|
|
10754
|
-
{
|
|
10755
|
-
Effect: "Allow",
|
|
10756
|
-
Action: ["s3:GetObject", "s3:PutObject", "s3:DeleteObject", "s3:GetObjectVersion"],
|
|
10757
|
-
Resource: `${bucketArn}/${home}/*`
|
|
10758
|
-
}
|
|
10759
|
-
]
|
|
10760
|
-
}
|
|
10807
|
+
PolicyDocument: { Version: "2012-10-17", Statement: statements }
|
|
10761
10808
|
}
|
|
10762
10809
|
]
|
|
10763
10810
|
}
|
|
@@ -10772,12 +10819,13 @@ class Sftp {
|
|
|
10772
10819
|
UserName: username,
|
|
10773
10820
|
Role: roleArn,
|
|
10774
10821
|
HomeDirectoryType: "PATH",
|
|
10775
|
-
HomeDirectory: `/${
|
|
10822
|
+
HomeDirectory: storage.type === "efs" ? efsHomeDirectory(storage.fileSystemId, home) : `/${storage.bucket}/${home}`,
|
|
10823
|
+
...storage.type === "efs" ? { PosixProfile: posixProfileFor(username, user, storage.posixProfile) } : {},
|
|
10776
10824
|
SshPublicKeys: user.sshPublicKeys
|
|
10777
10825
|
}
|
|
10778
10826
|
};
|
|
10779
10827
|
}
|
|
10780
|
-
return { resources, serverLogicalId };
|
|
10828
|
+
return { resources, serverLogicalId, domain };
|
|
10781
10829
|
}
|
|
10782
10830
|
}
|
|
10783
10831
|
// src/modules/ai.ts
|
package/dist/modules/sftp.d.ts
CHANGED
|
@@ -1,12 +1,33 @@
|
|
|
1
|
-
import type { EnvironmentType, SftpConfig } from '../types';
|
|
1
|
+
import type { EnvironmentType, SftpConfig, SftpPosixProfile } from '../types';
|
|
2
2
|
export interface SftpResources {
|
|
3
3
|
resources: Record<string, any>;
|
|
4
4
|
serverLogicalId: string;
|
|
5
|
+
/** Storage backend the server was built with. */
|
|
6
|
+
domain: 'S3' | 'EFS';
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* An EFS file system ID: either a literal `fs-…` or a CloudFormation intrinsic
|
|
10
|
+
* (`{ Ref: '…' }`) pointing at a file system created in the same stack.
|
|
11
|
+
*/
|
|
12
|
+
export type SftpFileSystemRef = string | Record<string, any>;
|
|
13
|
+
/**
|
|
14
|
+
* Storage the module resolved down to a concrete backend. The generator turns
|
|
15
|
+
* `storageBucket`/`fileSystem` references into these before calling `create`.
|
|
16
|
+
*/
|
|
17
|
+
export type ResolvedSftpStorage = {
|
|
18
|
+
type: 's3';
|
|
19
|
+
bucket: string;
|
|
20
|
+
} | {
|
|
21
|
+
type: 'efs';
|
|
22
|
+
fileSystemId: SftpFileSystemRef;
|
|
23
|
+
posixProfile?: SftpPosixProfile;
|
|
24
|
+
};
|
|
25
|
+
export interface SftpCreateOptions extends Omit<SftpConfig, 'storage'> {
|
|
26
|
+
slug: string;
|
|
27
|
+
environment: EnvironmentType;
|
|
28
|
+
storage?: SftpConfig['storage'] | ResolvedSftpStorage;
|
|
5
29
|
}
|
|
6
30
|
/** Build an AWS Transfer Family SFTP server with service-managed users. */
|
|
7
31
|
export declare class Sftp {
|
|
8
|
-
static create(options:
|
|
9
|
-
slug: string;
|
|
10
|
-
environment: EnvironmentType;
|
|
11
|
-
}): SftpResources;
|
|
32
|
+
static create(options: SftpCreateOptions): SftpResources;
|
|
12
33
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -984,6 +984,35 @@ export interface SiteConfig {
|
|
|
984
984
|
* Example: ['bun install --frozen-lockfile', 'bun run build']
|
|
985
985
|
*/
|
|
986
986
|
preStart?: string[];
|
|
987
|
+
/**
|
|
988
|
+
* systemd `MemoryHigh` for this site's app unit — the soft limit at which
|
|
989
|
+
* the kernel starts reclaiming the service's own memory, throttling it
|
|
990
|
+
* rather than letting pressure build box-wide.
|
|
991
|
+
*
|
|
992
|
+
* This is the same containment the rpx gateway has carried for a while, and
|
|
993
|
+
* app units are where it was missing. On a shared box a single tenant that
|
|
994
|
+
* leaks takes down every other tenant: memory fills, swap fills, and the
|
|
995
|
+
* kernel's OOM killer starts picking arbitrary victims. Squeezing the
|
|
996
|
+
* offender's own cgroup first keeps the blast radius on the service that
|
|
997
|
+
* actually grew.
|
|
998
|
+
*
|
|
999
|
+
* Accepts systemd size values (`512M`, `2G`, …), or `'infinity'` to opt a
|
|
1000
|
+
* site out. Applies to the app unit only; queue workers have their own
|
|
1001
|
+
* `--memory` restart threshold. @default '2G'
|
|
1002
|
+
*/
|
|
1003
|
+
memoryHigh?: string;
|
|
1004
|
+
/**
|
|
1005
|
+
* systemd `MemoryMax` for this site's app unit — the hard limit. Crossing it
|
|
1006
|
+
* invokes the OOM killer INSIDE this service's cgroup, so the unit's
|
|
1007
|
+
* `Restart=always` brings it straight back rather than the kernel killing a
|
|
1008
|
+
* co-tenant.
|
|
1009
|
+
*
|
|
1010
|
+
* Unset by default, deliberately: a hard cap turns a slow leak into a
|
|
1011
|
+
* restart loop for an app that legitimately needs the memory, and the
|
|
1012
|
+
* default has to be safe for workloads nobody has measured. Set it once you
|
|
1013
|
+
* know a site's real ceiling. Should be higher than {@link memoryHigh}.
|
|
1014
|
+
*/
|
|
1015
|
+
memoryMax?: string;
|
|
987
1016
|
/**
|
|
988
1017
|
* SSR only. tar `--exclude` patterns applied when packaging the release
|
|
989
1018
|
* tarball. Keep host-specific / heavy paths out of the artifact — most
|
|
@@ -1507,13 +1536,65 @@ export interface CdnConfig {
|
|
|
1507
1536
|
customDomain?: string;
|
|
1508
1537
|
certificateArn?: string;
|
|
1509
1538
|
}
|
|
1539
|
+
/**
|
|
1540
|
+
* POSIX identity a user is mapped to on an EFS-backed server.
|
|
1541
|
+
* Files the user writes are owned by this uid/gid.
|
|
1542
|
+
*/
|
|
1543
|
+
export interface SftpPosixProfile {
|
|
1544
|
+
uid: number;
|
|
1545
|
+
gid: number;
|
|
1546
|
+
secondaryGids?: number[];
|
|
1547
|
+
}
|
|
1548
|
+
/** Files live in an S3 bucket. */
|
|
1549
|
+
export interface SftpS3Storage {
|
|
1550
|
+
type: 's3';
|
|
1551
|
+
/** Physical bucket name of an existing bucket. */
|
|
1552
|
+
bucket?: string;
|
|
1553
|
+
/**
|
|
1554
|
+
* Key from `infrastructure.storage`. ts-cloud points the server at the
|
|
1555
|
+
* bucket it generates for that entry, so the bucket is created with the stack.
|
|
1556
|
+
*/
|
|
1557
|
+
storageBucket?: string;
|
|
1558
|
+
}
|
|
1559
|
+
/**
|
|
1560
|
+
* Files live on an EFS file system attached to the server, so users get a real
|
|
1561
|
+
* POSIX filesystem (directories, renames, symlinks) instead of object storage.
|
|
1562
|
+
*/
|
|
1563
|
+
export interface SftpEfsStorage {
|
|
1564
|
+
type: 'efs';
|
|
1565
|
+
/**
|
|
1566
|
+
* Directory served on box providers (Hetzner, local), where storage on the
|
|
1567
|
+
* server is a directory rather than an EFS file system.
|
|
1568
|
+
* Defaults to `/var/sftp/<slug>`.
|
|
1569
|
+
*/
|
|
1570
|
+
path?: string;
|
|
1571
|
+
/** File system ID (`fs-…`) of an existing EFS file system. */
|
|
1572
|
+
fileSystemId?: string;
|
|
1573
|
+
/**
|
|
1574
|
+
* Key from `infrastructure.fileSystem`. ts-cloud points the server at the
|
|
1575
|
+
* file system it generates for that entry, so storage is created with the stack.
|
|
1576
|
+
*/
|
|
1577
|
+
fileSystem?: string;
|
|
1578
|
+
/** Default POSIX identity for users that do not set their own. */
|
|
1579
|
+
posixProfile?: SftpPosixProfile;
|
|
1580
|
+
}
|
|
1581
|
+
export type SftpStorageConfig = SftpS3Storage | SftpEfsStorage;
|
|
1582
|
+
export interface SftpUserConfig {
|
|
1583
|
+
sshPublicKeys: string[];
|
|
1584
|
+
homeDirectory?: string;
|
|
1585
|
+
roleArn?: string;
|
|
1586
|
+
/** POSIX identity for this user. Required on EFS-backed servers. */
|
|
1587
|
+
posixProfile?: SftpPosixProfile;
|
|
1588
|
+
}
|
|
1510
1589
|
export interface SftpConfig {
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
}
|
|
1590
|
+
/**
|
|
1591
|
+
* Where uploaded files are stored: an EFS file system on the server
|
|
1592
|
+
* (`{ type: 'efs' }`) or an S3 bucket (`{ type: 's3' }`).
|
|
1593
|
+
*/
|
|
1594
|
+
storage?: SftpStorageConfig;
|
|
1595
|
+
/** Shorthand for `storage: { type: 's3', bucket }`. */
|
|
1596
|
+
bucket?: string;
|
|
1597
|
+
users: Record<string, SftpUserConfig>;
|
|
1517
1598
|
endpointType?: 'PUBLIC' | 'VPC';
|
|
1518
1599
|
endpointDetails?: {
|
|
1519
1600
|
vpcId: string;
|
|
@@ -1523,6 +1604,17 @@ export interface SftpConfig {
|
|
|
1523
1604
|
};
|
|
1524
1605
|
securityPolicyName?: string;
|
|
1525
1606
|
logging?: boolean;
|
|
1607
|
+
/**
|
|
1608
|
+
* Port the server listens on. Box providers only — AWS Transfer Family is
|
|
1609
|
+
* always reached on port 22. Defaults to 2222, since sshd owns 22 on a box.
|
|
1610
|
+
*/
|
|
1611
|
+
port?: number;
|
|
1612
|
+
/** Reject every write. Box providers only. */
|
|
1613
|
+
readOnly?: boolean;
|
|
1614
|
+
/** ts-sftp version installed on the box. Defaults to the latest release. */
|
|
1615
|
+
version?: string;
|
|
1616
|
+
/** System account the box server runs as. Defaults to `ts-sftp`. */
|
|
1617
|
+
serviceUser?: string;
|
|
1526
1618
|
}
|
|
1527
1619
|
export interface DnsConfig {
|
|
1528
1620
|
domain?: string;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ts-cloud/core",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.7.
|
|
4
|
+
"version": "0.7.120",
|
|
5
5
|
"description": "Core CloudFormation generation library for ts-cloud",
|
|
6
6
|
"author": "Chris Breuer <chris@stacksjs.com>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"typecheck": "tsc --noEmit"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@ts-cloud/aws-types": "0.7.
|
|
34
|
+
"@ts-cloud/aws-types": "0.7.120"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"typescript": "^7.0.2"
|