@stacksjs/cloud 0.75.72 → 0.75.73
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/helpers.d.ts +223 -15
- package/dist/index.js +4 -13
- package/package.json +14 -14
package/dist/helpers.d.ts
CHANGED
|
@@ -1,28 +1,181 @@
|
|
|
1
|
+
import { config } from '@stacksjs/config';
|
|
2
|
+
import { EC2Client, LambdaClient, Route53DomainsClient, S3Client, SSMClient } from '@stacksjs/ts-cloud';
|
|
3
|
+
import type { ContactInfo } from '@stacksjs/types';
|
|
1
4
|
import type { CountryCode } from '@stacksjs/ts-cloud';
|
|
2
5
|
import type { Result } from '@stacksjs/error-handling';
|
|
6
|
+
/**
|
|
7
|
+
* The `tsCloud` export of the app's `config/cloud.ts`, which is what
|
|
8
|
+
* `buddy deploy` generates the stack from. An app without the file deploys
|
|
9
|
+
* with ts-cloud's defaults, so it reads as empty; a file that fails to load
|
|
10
|
+
* is an error, not an empty config.
|
|
11
|
+
*/
|
|
12
|
+
export declare function loadCloudStackConfig(): Promise<CloudStackConfig>;
|
|
13
|
+
/**
|
|
14
|
+
* The environment a deploy targets, resolved the way `buddy deploy` and
|
|
15
|
+
* `cloud:remove` resolve it.
|
|
16
|
+
*/
|
|
17
|
+
export declare function cloudEnvironment(): string;
|
|
18
|
+
/**
|
|
19
|
+
* The CloudFormation stack this app's AWS resources belong to: the one
|
|
20
|
+
* `buddy deploy` creates and `cloud:remove` deletes, `<project.name>-cloud`.
|
|
21
|
+
*
|
|
22
|
+
* Both of those now ask this function, so the name has one owner. It used to
|
|
23
|
+
* be `stacks-cloud-<env>`, a name nothing has created since the CDK deploy was
|
|
24
|
+
* replaced, so every lookup through it - the jump box, `isFirstDeployment`,
|
|
25
|
+
* `isFailedState` - asked AWS about a stack that does not exist.
|
|
26
|
+
*/
|
|
27
|
+
export declare function stacksCloudName(cloud?: CloudStackConfig): Promise<string>;
|
|
28
|
+
/**
|
|
29
|
+
* The region the app's stack is deployed to.
|
|
30
|
+
*
|
|
31
|
+
* `AWS_REGION` wins, as it always has for `buddy deploy`. Without it, the
|
|
32
|
+
* region `config/cloud.ts` declares for the environment, then the project's -
|
|
33
|
+
* the same values ts-cloud places the stack's subnets in. The fallback used to
|
|
34
|
+
* be a literal `us-east-1`, here and in the deploy, so an app configured for
|
|
35
|
+
* any other region was deployed and looked up in the wrong one.
|
|
36
|
+
*/
|
|
37
|
+
export declare function stacksCloudRegion(cloud?: CloudStackConfig, environment?: string): Promise<string>;
|
|
3
38
|
export declare function getSecurityGroupId(securityGroupName: string): Promise<Result<string | undefined, string>>;
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
39
|
+
/**
|
|
40
|
+
* The purchase options `config/dns.ts`'s `contactInfo` describes.
|
|
41
|
+
*
|
|
42
|
+
* Countries stay ts-cloud's ISO `CountryCode` union rather than a `string`
|
|
43
|
+
* alias, so a typo in the config fails the typecheck instead of reaching AWS.
|
|
44
|
+
*
|
|
45
|
+
* The admin and tech contacts default to the registrant, field by field.
|
|
46
|
+
* Privacy and auto-renew default to on, but only when unset: they were
|
|
47
|
+
* written `value || fallback || true`, which is `true` whatever the value, so
|
|
48
|
+
* `privacy: false` - which some TLDs require - could not be expressed.
|
|
49
|
+
*/
|
|
50
|
+
export declare function purchaseOptionsFromContactInfo(c: Partial<ContactInfo>): PurchaseOptions;
|
|
51
|
+
/**
|
|
52
|
+
* Lay the command line over the options config produced.
|
|
53
|
+
*
|
|
54
|
+
* The registrant flags are spelled for the person typing them -
|
|
55
|
+
* `--first-name`, `--email` - and arrive as `firstName`, `email`, which no
|
|
56
|
+
* purchase option is called, so every one of them was silently ignored. The
|
|
57
|
+
* parser also hands everything over as strings: `--years 2` was `'2'`, and
|
|
58
|
+
* `'false'` is the only way `--no-privacy` survives the trip to an action.
|
|
59
|
+
*/
|
|
60
|
+
export declare function applyPurchaseFlags(base: PurchaseOptions, flags: Record<string, unknown>): PurchaseOptions;
|
|
61
|
+
/**
|
|
62
|
+
* Register a domain through Route 53 Domains.
|
|
63
|
+
*
|
|
64
|
+
* Awaited, and its outcome returned. This used to hand back `ok(<the pending
|
|
65
|
+
* request>)`, so a caller could only see that the request had been built: the
|
|
66
|
+
* domain action then printed "Domain purchased successfully." and exited the
|
|
67
|
+
* process while the request was still in flight, and an AWS rejection - a
|
|
68
|
+
* taken name, an unsupported TLD, a bad contact - surfaced nowhere.
|
|
69
|
+
*
|
|
70
|
+
* Registration itself completes asynchronously at AWS. The operation id is
|
|
71
|
+
* what Route 53 gives back to follow it.
|
|
72
|
+
*/
|
|
73
|
+
export declare function purchaseDomain(domain: string, options: PurchaseOptions, registrar?: DomainRegistrar): Promise<Result<{ OperationId: string }, Error>>;
|
|
74
|
+
/**
|
|
75
|
+
* Whether the config asks for a jump box - `true`, or an object whose
|
|
76
|
+
* `enabled` is not `false` - exactly as ts-cloud's `generateJumpBox()` reads it.
|
|
77
|
+
*/
|
|
78
|
+
export declare function declaresJumpBox(cloud: CloudStackConfig): boolean;
|
|
79
|
+
/**
|
|
80
|
+
* Reads the jump box from the deployed stack.
|
|
81
|
+
*
|
|
82
|
+
* The jump box is a resource of the app's stack: `infrastructure.jumpBox` in
|
|
83
|
+
* `config/cloud.ts` makes ts-cloud generate the instance, its security group
|
|
84
|
+
* and its SSM role, and publish the instance id as the `JumpBoxInstanceId`
|
|
85
|
+
* output. This reads that output. It used to search EC2 for a `Name` tag of
|
|
86
|
+
* `<stack>/JumpBox`, which neither the generator nor the old `addJumpBox()`
|
|
87
|
+
* (`<stack>-jump-box`) ever wrote, always in us-east-1.
|
|
88
|
+
*/
|
|
89
|
+
export declare function getJumpBoxState(options?: JumpBoxOptions): Promise<Result<JumpBoxState, Error>>;
|
|
90
|
+
/**
|
|
91
|
+
* The deployed jump box's instance id, or undefined when the stack has none.
|
|
92
|
+
* Throws when the stack cannot be read, so a credentials or network failure
|
|
93
|
+
* is not reported as "no jump box".
|
|
94
|
+
*/
|
|
95
|
+
export declare function getJumpBoxInstanceId(options?: JumpBoxOptions): Promise<string | undefined>;
|
|
96
|
+
/**
|
|
97
|
+
* Reports how to get a jump box. It does not create one.
|
|
98
|
+
*
|
|
99
|
+
* The instance belongs to the stack, so making it outside CloudFormation would
|
|
100
|
+
* leave a resource the next deploy does not know about. This used to call
|
|
101
|
+
* RunInstances itself, and could never get there: it refused when a jump box
|
|
102
|
+
* existed, then read the security group from the existing jump box. Past
|
|
103
|
+
* that, it named one account's subnet and AMI, in us-east-1, and cloned the
|
|
104
|
+
* framework repository over the app's EFS mount.
|
|
105
|
+
*/
|
|
106
|
+
export declare function addJumpBox(options?: JumpBoxOptions): Promise<Result<JumpBoxChange, string>>;
|
|
107
|
+
/**
|
|
108
|
+
* Reports how to remove the jump box. It does not terminate it.
|
|
109
|
+
*
|
|
110
|
+
* Terminating a stack-owned instance directly leaves CloudFormation describing
|
|
111
|
+
* an instance that is gone, and the next update fails or recreates it. Removing
|
|
112
|
+
* it from the config and deploying deletes it, with its security group and role.
|
|
113
|
+
*/
|
|
114
|
+
export declare function deleteJumpBox(options?: JumpBoxOptions): Promise<Result<JumpBoxChange, string>>;
|
|
8
115
|
export declare function deleteIamUsers(): Promise<Result<string, string>>;
|
|
9
|
-
export declare function deleteStacksBuckets(): Promise<Result<string, string | Error>>;
|
|
10
|
-
|
|
116
|
+
export declare function deleteStacksBuckets(options?: RegionalOptions<S3Client>): Promise<Result<string, string | Error>>;
|
|
117
|
+
/**
|
|
118
|
+
* Deletes the app's retained Lambda functions: in the stack's region, and in
|
|
119
|
+
* us-east-1, where Lambda@Edge functions have to live and where CloudFront
|
|
120
|
+
* leaves its replicas behind after the stack is gone. It looked only in
|
|
121
|
+
* us-east-1, so an app deployed anywhere else kept its regional functions.
|
|
122
|
+
*/
|
|
123
|
+
export declare function deleteStacksFunctions(options?: RegionalOptions<Pick<LambdaClient, 'listFunctions' | 'deleteFunction'>>): Promise<Result<string, string>>;
|
|
11
124
|
export declare function deleteLogGroups(): Promise<Result<string, Error>>;
|
|
12
|
-
export declare function deleteParameterStore(): Promise<Result<string, string>>;
|
|
13
|
-
export declare function deleteVpcs(): Promise<Result<string, Error>>;
|
|
125
|
+
export declare function deleteParameterStore(options?: RegionalOptions<Pick<SSMClient, 'describeParameters' | 'deleteParameter'>>): Promise<Result<string, string>>;
|
|
126
|
+
export declare function deleteVpcs(options?: Ec2CleanupOptions): Promise<Result<string, Error>>;
|
|
14
127
|
export declare function deleteCdkRemnants(): Promise<Result<string, Error>>;
|
|
15
|
-
export declare function deleteSubnets(): Promise<Result<string, Error>>;
|
|
16
|
-
export declare function hasBeenDeployed(): Promise<Result<boolean, Error>>;
|
|
17
|
-
export declare function getJumpBoxInstanceProfileName(): Promise<Result<string, string>>;
|
|
18
|
-
export declare function addJumpBox(stackName?: string): Promise<Result<string, string>>;
|
|
19
|
-
export declare function getJumpBoxSecurityGroupName(): Promise<Result<string | undefined, string>>;
|
|
20
|
-
export declare function getSecurityGroupFromInstanceId(instanceId: string): Promise<string | undefined>;
|
|
128
|
+
export declare function deleteSubnets(options?: Ec2CleanupOptions): Promise<Result<string, Error>>;
|
|
129
|
+
export declare function hasBeenDeployed(options?: RegionalOptions<Pick<S3Client, 'listBuckets'>>): Promise<Result<boolean, Error>>;
|
|
21
130
|
export declare function isFirstDeployment(): Promise<boolean>;
|
|
131
|
+
/**
|
|
132
|
+
* Whether the app's stack is in a failed state.
|
|
133
|
+
*
|
|
134
|
+
* True when it is listed among the failed statuses. This returned the
|
|
135
|
+
* negation - "not among the failed stacks" - so a failed stack read as
|
|
136
|
+
* healthy and a healthy one as failed.
|
|
137
|
+
*/
|
|
22
138
|
export declare function isFailedState(): Promise<boolean>;
|
|
23
|
-
|
|
139
|
+
/**
|
|
140
|
+
* Compares a freshly generated template with the one deployed.
|
|
141
|
+
*
|
|
142
|
+
* `buddy cloud --diff` and `cloud:diff` asked for the stack
|
|
143
|
+
* `<project.slug>-<env>` in AWS_REGION or us-east-1; `buddy deploy` creates
|
|
144
|
+
* `<project.name>-cloud` in the configured region, so the diff never found it
|
|
145
|
+
* and reported the whole template as new. Any error read as "not deployed",
|
|
146
|
+
* credentials included. And it compared text, so the deploy's compact JSON
|
|
147
|
+
* never equalled the generator's indented JSON even when nothing had changed.
|
|
148
|
+
*/
|
|
149
|
+
export declare function diffStackTemplate(localTemplate: string, options?: RegionalOptions<TemplateReader>): Promise<Result<StackTemplateDiff, Error>>;
|
|
150
|
+
export declare function getOrCreateTimestamp(options?: RegionalOptions<Pick<SSMClient, 'getParameter' | 'putParameter'>>): Promise<string>;
|
|
24
151
|
// get the CloudFront distribution ID of the current stack
|
|
25
152
|
export declare function getCloudFrontDistributionId(): Promise<string>;
|
|
153
|
+
/** The stack output ts-cloud's generator gives the jump box's instance id. */
|
|
154
|
+
export declare const JUMP_BOX_OUTPUT: 'JumpBoxInstanceId';
|
|
155
|
+
/**
|
|
156
|
+
* The part of `config/cloud.ts`'s `tsCloud` export this package reads: what
|
|
157
|
+
* names the stack, where it lives, and whether it declares a jump box.
|
|
158
|
+
*
|
|
159
|
+
* `buddy deploy` hands the whole `tsCloud` object to ts-cloud's
|
|
160
|
+
* `InfrastructureGenerator`; this is a structural slice of it, so a test can
|
|
161
|
+
* pass a literal.
|
|
162
|
+
*/
|
|
163
|
+
export declare interface CloudStackConfig {
|
|
164
|
+
project?: { name?: string, region?: string }
|
|
165
|
+
environments?: Partial<Record<string, { region?: string } | undefined>>
|
|
166
|
+
infrastructure?: { jumpBox?: boolean | { enabled?: boolean } }
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Where a cleanup helper looks, and what it looks with. Both default to the
|
|
170
|
+
* app's: the region its stack is in, and ts-cloud's client. Tests pass both.
|
|
171
|
+
*/
|
|
172
|
+
export declare interface RegionalOptions<Client> {
|
|
173
|
+
config?: CloudStackConfig
|
|
174
|
+
client?: (region: string) => Client
|
|
175
|
+
}
|
|
176
|
+
export declare interface Ec2CleanupOptions extends RegionalOptions<Pick<EC2Client, 'describeVpcs' | 'describeSubnets' | 'terminateInstances'>> {
|
|
177
|
+
request?: Ec2Request
|
|
178
|
+
}
|
|
26
179
|
export declare interface PurchaseOptions {
|
|
27
180
|
domain: string
|
|
28
181
|
years: number
|
|
@@ -67,3 +220,58 @@ export declare interface PurchaseOptions {
|
|
|
67
220
|
contactType: 'PERSON' | 'COMPANY' | 'ASSOCIATION' | 'PUBLIC_BODY' | 'RESELLER'
|
|
68
221
|
verbose: boolean
|
|
69
222
|
}
|
|
223
|
+
/** The one Route 53 Domains call a purchase makes. Injectable, so a purchase can be tested without AWS. */
|
|
224
|
+
export declare interface DomainRegistrar {
|
|
225
|
+
registerDomain: (input: Parameters<Route53DomainsClient['registerDomain']>[0]) => Promise<{ OperationId?: string }>
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* The CloudFormation calls the jump-box helpers make. ts-cloud's client by
|
|
229
|
+
* default; a test passes a fake, as `purchaseDomain()` takes its registrar.
|
|
230
|
+
*/
|
|
231
|
+
export declare interface StackDescriber {
|
|
232
|
+
describeStacks: (options: { stackName: string }) => Promise<{
|
|
233
|
+
Stacks?: Array<{ StackStatus?: string, Outputs?: Array<{ OutputKey?: string, OutputValue?: string }> }>
|
|
234
|
+
}>
|
|
235
|
+
}
|
|
236
|
+
export declare interface JumpBoxOptions {
|
|
237
|
+
config?: CloudStackConfig
|
|
238
|
+
cloudFormation?: (region: string) => StackDescriber
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Where the app's jump box stands: what `config/cloud.ts` declares, and what
|
|
242
|
+
* the deployed stack has.
|
|
243
|
+
*/
|
|
244
|
+
export declare interface JumpBoxState {
|
|
245
|
+
stack: string
|
|
246
|
+
region: string
|
|
247
|
+
declared: boolean
|
|
248
|
+
deployed: boolean
|
|
249
|
+
instanceId?: string
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* What `cloud:add --jump-box` and `cloud:remove --jump-box` found.
|
|
253
|
+
*
|
|
254
|
+
* `done` is true when the stack is already in the state asked for. Otherwise
|
|
255
|
+
* `message` says what to change, since the change is a deploy.
|
|
256
|
+
*/
|
|
257
|
+
export declare interface JumpBoxChange {
|
|
258
|
+
done: boolean
|
|
259
|
+
message: string
|
|
260
|
+
state: JumpBoxState
|
|
261
|
+
}
|
|
262
|
+
/** The CloudFormation call `buddy cloud --diff` makes. */
|
|
263
|
+
export declare interface TemplateReader {
|
|
264
|
+
getTemplate: (stackName: string) => Promise<{ TemplateBody?: string }>
|
|
265
|
+
}
|
|
266
|
+
/** How the generated template compares with the deployed stack's. */
|
|
267
|
+
export declare interface StackTemplateDiff {
|
|
268
|
+
stack: string
|
|
269
|
+
region: string
|
|
270
|
+
deployed: boolean
|
|
271
|
+
changed: boolean
|
|
272
|
+
deployedBytes: number
|
|
273
|
+
localBytes: number
|
|
274
|
+
}
|
|
275
|
+
/** A raw EC2 Query API call, for actions EC2Client does not expose. */
|
|
276
|
+
export type Ec2Request = (region: string, action: string, params?: Record<string, string>) => Promise<Record<string, unknown>>;
|
|
277
|
+
declare type ContactType = PurchaseOptions['contactType'];
|
package/dist/index.js
CHANGED
|
@@ -1,14 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{config as B}from"@stacksjs/config";import{InfrastructureGenerator as j}from"@stacksjs/ts-cloud";class G{generator;cloudConfig;props;constructor(e,t){this.cloudConfig=e,this.props=t;let n=(t.appEnv==="local"?"development":t.appEnv)||"production";this.generator=new j({config:this.cloudConfig,environment:n})}generate(){return this.generator.generate().toJSON()}shouldDeployApi(){return B.cloud.api?.deploy??!1}}import{AWSClient as R,AWSCloudFormationClient as L,CloudWatchLogsClient as V,EC2Client as y,IAMClient as x,LambdaClient as K,Route53DomainsClient as z,S3Client as O,SSMClient as M}from"@stacksjs/ts-cloud";import{config as w}from"@stacksjs/config";import{err as c,handleError as p,ok as d}from"@stacksjs/error-handling";import{log as g}from"@stacksjs/logging";import{path as E}from"@stacksjs/path";import{slug as q}from"@stacksjs/strings";var J=w.app.env==="local"?"dev":w.app.env,P=`stacks-cloud-${J}`;async function k(e,t={}){let n=new R,r={Action:e,Version:"2016-11-15",...t};return await n.request({service:"ec2",region:"us-east-1",method:"POST",path:"/",queryParams:r})}async function _(e,t,n){return await new R().request({service:"logs",region:e,method:"POST",path:"/",headers:{"Content-Type":"application/x-amz-json-1.1","X-Amz-Target":`Logs_20140328.${t}`},body:JSON.stringify(n)})}async function W(e,t,n){return await new R().request({service:"elasticfilesystem",region:"us-east-1",method:t,path:n})}async function H(e){let t=new y("us-east-1"),{SecurityGroups:n}=await t.describeSecurityGroups({Filters:[{Name:"group-name",Values:[e]}]});if(!n)return c(`Security group ${e} not found`);if(n[0])return d(n[0].GroupId);return c(`Security group ${e} not found`)}function le(e,t){let n=new z,r=t.contactType.toUpperCase()||"PERSON",s=(a)=>a.toString().includes("+")?a.toString():`+${a.toString()}`;try{return d(n.registerDomain({DomainName:e,DurationInYears:t.years||1,AutoRenew:t.autoRenew||!0,AdminContact:{FirstName:t.adminFirstName,LastName:t.adminLastName,ContactType:r,OrganizationName:t.adminOrganization,AddressLine1:t.adminAddressLine1,AddressLine2:t.adminAddressLine2,City:t.adminCity,State:t.adminState,CountryCode:t.adminCountry,ZipCode:t.adminZip.toString(),PhoneNumber:s(t.adminPhone),Email:t.adminEmail},RegistrantContact:{FirstName:t.registrantFirstName,LastName:t.registrantLastName,ContactType:r,OrganizationName:t.registrantOrganization,AddressLine1:t.registrantAddressLine1,AddressLine2:t.registrantAddressLine2,City:t.registrantCity,State:t.registrantState,CountryCode:t.registrantCountry,ZipCode:t.registrantZip.toString(),PhoneNumber:s(t.registrantPhone),Email:t.registrantEmail},TechContact:{FirstName:t.techFirstName,LastName:t.techLastName,ContactType:r,OrganizationName:t.techOrganization,AddressLine1:t.techAddressLine1,AddressLine2:t.techAddressLine2,City:t.techCity,State:t.techState,CountryCode:t.techCountry,ZipCode:t.techZip.toString(),PhoneNumber:s(t.techPhone),Email:t.techEmail},PrivacyProtectAdminContact:t.privacyAdmin||t.privacy||!0,PrivacyProtectRegistrantContact:t.privacyRegistrant||t.privacy||!0,PrivacyProtectTechContact:t.privacyTech||t.privacy||!0}))}catch(a){return c(a)}}async function A(e){if(!e)e=`${P}/JumpBox`;let n=await new y("us-east-1").describeInstances({Filters:[{Name:"tag:Name",Values:[e]}]});if(n.Reservations?.[0]?.Instances?.[0])return n.Reservations[0].Instances[0].InstanceId;return}async function Z(e,t){if(!t)t=P;if(!e)return c(`Instance ${e} not found`);return await new y("us-east-1").terminateInstances([e]),d(`Instance ${e} is being terminated`)}async function me(e){if(!e)e=P;let t=await A();if(!t)return c("Jump-box not found");return g.info(`Deleting jump-box ${t}...`),await Z(t,e)}async function ge(){let e=new x("us-east-1"),t=await e.listUsers(),n=q(w.team.name),r=t.Users?.filter((a)=>{let i=a.UserName?.toLowerCase();return i!=="stacks"&&i!==n.toLowerCase()&&i?.includes(n.toLowerCase())})||[];if(!r||r.length===0)return d(`No Stacks IAM users found for team ${n}`);let s=r.map(async(a)=>{let i=a.UserName||"";g.info(`Deleting IAM user: ${i}`);let o=await e.listAttachedUserPolicies({UserName:i});await Promise.all(o.AttachedPolicies?.map((f)=>{let h=f;return e.detachUserPolicy({UserName:i,PolicyArn:h.PolicyArn||""})})||[]);let l=await e.listAccessKeys({UserName:i});return await Promise.all(l.AccessKeyMetadata?.map((f)=>{let h=f;return e.deleteAccessKey({UserName:i,AccessKeyId:h.AccessKeyId||""})})||[]),e.deleteUser({UserName:i})});try{await Promise.all(s)}catch(a){return console.error(a),c(p("Error deleting Stacks IAM users").message)}return d(`Stacks IAM users deleted for team ${n}`)}async function fe(){try{let e=new O("us-east-1"),n=(await e.listBuckets()).Buckets?.filter((s)=>s.Name?.includes("stacks"));if(!n)return c("No stacks buckets found");let r=n.map(async(s)=>{let a=s.Name||"";g.info(`Deleting bucket ${a}...`);let u,i=!0;while(i){let o=await e.listObjects({bucket:a,continuationToken:u});if(o.objects&&o.objects.length>0)g.info(`Deleting ${o.objects.length} objects from bucket ${a}...`),await Promise.all(o.objects.map((l)=>{let f=l;return e.deleteObject(a,f.Key||"")})).catch((l)=>{throw g.error(`Failed to delete objects from bucket ${a}:`,l),l});i=!!o.nextContinuationToken,u=o.nextContinuationToken}g.info(`Finished deleting objects from bucket ${a}`),g.info(`Deleting bucket ${a} versions...`);try{let o,l,f=!0;while(f){let m=await e.listObjectVersions({bucket:a,keyMarker:o,versionIdMarker:l});if(m.versions&&m.versions.length>0)await Promise.all(m.versions.map((S)=>{let v=S;return e.deleteObject(a,v.Key||"")})).catch((S)=>p(S)),g.info(`Deleted ${m.versions.length} versions from bucket ${a}`);if(m.deleteMarkers&&m.deleteMarkers.length>0)await Promise.all(m.deleteMarkers.map((S)=>{let v=S;return e.deleteObject(a,v.Key||"")})).catch((S)=>p(S)),g.info(`Deleted ${m.deleteMarkers.length} delete markers from bucket ${a}`);f=!!m.nextKeyMarker,o=m.nextKeyMarker,l=m.nextVersionIdMarker}g.info(`Finished deleting all versions from bucket ${a}`);let h=await e.listMultipartUploads(a);if(h&&h.length>0)g.info("Aborting bucket multipart uploads..."),await Promise.all(h.map((m)=>{let S=m;return e.abortMultipartUpload(a,S.Key||"",S.UploadId||"")})).catch((m)=>p(m)),g.info(`Finished aborting multipart uploads from bucket ${a}`);await e.deleteBucket(a).catch((m)=>p(m)),g.info(`Bucket ${a} deleted`)}catch(o){g.info(`Error listing bucket ${a} versions`,o)}});return await Promise.all(r).catch((s)=>(console.error(s),c(p("Error deleting stacks buckets")))),d("Stacks buckets deleted")}catch(e){return c(p("Error deleting stacks buckets",e))}}async function pe(){let e=new K("us-east-1"),n=(await e.listFunctions()).Functions?.filter((s)=>s.FunctionName?.includes("stacks"))||[];if(!n||n.length===0)return d("No stacks functions found");let r=n.map((s)=>{let a=s;return e.deleteFunction(a.FunctionName||"")});try{await Promise.all(r)}catch(s){let a=s;if(a.message.includes("it is a replicated function"))return g.info("Function is replicated, skipping..."),d("CloudFront is still deleting the some functions. Try again later.");return c(p("Error deleting stacks functions",a).message)}return d("Stacks functions deleted")}async function he(){try{let e=await k("DescribeRegions"),n=e.regionInfo?.item??e.Regions??e.regionSet??[],r=[];if(Array.isArray(n))for(let s of n){let a=s.regionName??s.RegionName;if(a)r.push(a)}for(let s of r){let u=await new V(s).describeLogGroups();if(u?.logGroups)for(let i of u.logGroups){let o=w.app.name?.toLocaleLowerCase()||"stacks";if(i.logGroupName?.includes(o))await _(s,"DeleteLogGroup",{logGroupName:i.logGroupName})}}return d("Log groups deleted in all regions")}catch(e){return c(p("Error deleting log groups",e))}}async function Se(){let e=new M("us-east-1"),t=await e.describeParameters();if(!t.Parameters)return d("No parameters found");let n=w.app.name?.toLocaleLowerCase()||"stacks",r=t.Parameters.filter((a)=>a.Name?.includes(n))||[];if(!r||r.length===0)return d("No stacks parameters found");let s=r.map((a)=>{let u=a;return e.deleteParameter({Name:u.Name||""})});try{await Promise.all(s)}catch(a){return c(p("Error deleting parameter store",a).message)}return d("Parameter store deleted")}async function we(){let e=new y("us-east-1"),t=w.app.name?`${w.app.name.toLowerCase()}-`:"stacks-";try{let{Vpcs:n}=await e.describeVpcs();if(!n||n.length===0)return d("No VPCs found");let r=n.filter((s)=>s.Tags?.some((i)=>i.Key==="Name"&&i.Value===t));if(r.length===0)return d(`No VPCs found matching the pattern: ${t}`);for(let s of r)if(s.VpcId)await k("DeleteVpc",{VpcId:s.VpcId}),g.info(`Deleted VPC: ${s.VpcId} (${t})`);return d(`Deleted ${r.length} VPCs matching the pattern: ${t}`)}catch(n){return c(p(`Error deleting VPCs: ${n}`))}}async function ye(){try{return await Bun.$`rm -rf ${E.cloudPath("cdk.out/")} ${E.cloudPath("cdk.context.json")}`.text(),d("CDK remnants deleted")}catch(e){return c(p("Error deleting CDK remnants",e))}}async function ke(){let e=new y("us-east-1"),t=w.app.name?`${w.app.name.toLowerCase()}-`:"stacks-";try{let{Subnets:n}=await e.describeSubnets();if(!n||n.length===0)return d("No subnets found");let r=n.filter((s)=>s.Tags?.some((i)=>i.Key==="Name"&&i.Value?.startsWith(t)));if(r.length===0)return d(`No subnets found matching the pattern: ${t}`);for(let s of r)if(s.SubnetId){let i=(await k("DescribeNetworkInterfaces",{"Filter.1.Name":"subnet-id","Filter.1.Value.1":s.SubnetId})).networkInterfaceSet?.item??[];for(let o of Array.isArray(i)?i:[]){let l=o.networkInterfaceId;if(l){let f=o.attachment;if(f?.instanceId)await e.terminateInstances([f.instanceId]),g.info(`Terminated instance: ${f.instanceId}`),await new Promise((h)=>setTimeout(h,60000));if(f?.attachmentId)await k("DetachNetworkInterface",{AttachmentId:f.attachmentId,Force:"true"}),g.info(`Detached network interface: ${l}`),await new Promise((h)=>setTimeout(h,1e4));await k("DeleteNetworkInterface",{NetworkInterfaceId:l}),g.info(`Deleted network interface: ${l}`)}}await k("DeleteSubnet",{SubnetId:s.SubnetId}),g.info(`Deleted subnet: ${s.SubnetId} (${s.Tags?.find((o)=>o.Key==="Name")?.Value})`)}return d(`Deleted ${r.length} subnets matching the pattern: ${t}`)}catch(n){return c(p(`Error deleting subnets: ${n}`))}}async function Pe(){let e=new O("us-east-1");try{let t=await e.listBuckets();return d(t.Buckets?.some((n)=>n.Name?.includes(w.app.name?.toLocaleLowerCase()||"stacks"))||!1)}catch(t){return console.error(t),c(p("Error checking if the app has been deployed"))}}async function Y(){let r=(await new x("us-east-1").listInstanceProfiles()).InstanceProfiles?.find((s)=>s.InstanceProfileName?.includes("JumpBox"))?.InstanceProfileName;if(!r)return c("Jump-box IAM instance profile not found");return d(r)}async function Ce(e){if(!e)e=P;if(await A())return c("The jump-box you are trying to add already exists. Please remove it & wait until it finished terminating.");let t=new y("us-east-1"),n=await Q();if(n.isErr)return c(n.error);if(!n.value)return c("Security group not found when adding jump-box");let r=await H(n.value);if(r.isErr)return c(r.error);let s=r.value;if(!s)return c("Security group not found when adding jump-box");let u=(await W("DescribeFileSystems","GET","/2015-02-01/file-systems")).FileSystems??[],i=`stacks-${w.app.env}-efs`,o=u.find((U)=>U.Name===i),l=o?.FileSystemId;if(!o||!l)return c(`EFS file system ${i} not found`);let f=`
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
yum install -y git
|
|
7
|
-
yum install -y https://s3.us-east-1.amazonaws.com/amazon-ssm-us-east-1/latest/linux_amd64/amazon-ssm-agent.rpm
|
|
8
|
-
mkdir /mnt/efs
|
|
9
|
-
mount -t efs ${l}:/ /mnt/efs
|
|
10
|
-
git clone https://github.com/stacksjs/stacks.git /mnt/efs
|
|
11
|
-
`,h=btoa(f),m=await Y();if(m.isErr)return c(m.error);let S=m.value;if(!S)return c("Jump-box IAM instance profile not found");let T=(await k("RunInstances",{ImageId:"ami-03a6eaae9938c858c",InstanceType:"t2.micro",MaxCount:"1",MinCount:"1","SecurityGroupId.1":s,SubnetId:"subnet-004c5f196358b00f0","TagSpecification.1.ResourceType":"instance","TagSpecification.1.Tag.1.Key":"Name","TagSpecification.1.Tag.1.Value":`${P}-jump-box`,UserData:h,"IamInstanceProfile.Name":S})).instancesSet?.item??[],N=Array.isArray(T)?T[0]:void 0;return N?d(`Jump-box created with id ${N.instanceId}`):c("Jump-box creation failed")}async function Q(){let e=await A();if(!e)return c("Jump-box not found");let n=await new y("us-east-1").describeInstances({InstanceIds:[e]});if(n.Reservations?.[0]?.Instances?.[0]){let s=n.Reservations[0].Instances[0].SecurityGroups;if(s?.[0])return d(s[0].GroupName)}return c("Security group not found")}async function be(e){let n=await new y("us-east-1").describeInstances({InstanceIds:[e]});if(n.Reservations?.[0]?.Instances?.[0]){let s=n.Reservations[0].Instances[0].SecurityGroups;if(s?.[0])return s[0].GroupId}return}async function ve(){let e=P;return!(await new L("us-east-1").listStacks(["CREATE_COMPLETE","UPDATE_COMPLETE"])).StackSummaries?.some((s)=>s.StackName===e)}async function Ie(){return!(await new L("us-east-1").listStacks(["CREATE_FAILED","UPDATE_FAILED","ROLLBACK_COMPLETE","UPDATE_ROLLBACK_COMPLETE"])).StackSummaries?.some((r)=>r.StackName===P)}async function Re(){let t=new M("us-east-1");try{let n=await t.getParameter({Name:"/stacks/timestamp"}),r=n.Parameter?n.Parameter.Value:void 0;if(!r)throw Error("Timestamp parameter not found");return r}catch(n){let r=new Date().getTime().toString();return g.debug(`Creating timestamp parameter /stacks/timestamp with value ${r}`,n),await t.putParameter({Name:"/stacks/timestamp",Value:r,Type:"String"}),r}}async function Ae(){return""}import*as F from"net";import*as I from"tls";import*as C from"fs";import*as b from"crypto";import{S3Client as X,SESClient as ee}from"@stacksjs/ts-cloud";class D{config;ses;s3;server;tlsServer;sessions=new Map;constructor(e){if(this.config={port:587,tlsPort:465,host:"0.0.0.0",...e},this.ses=new ee(e.region||"us-east-1"),e.sentBucket)this.s3=new X(e.region||"us-east-1")}async start(){if(this.server=F.createServer((e)=>{this.handleConnection(e,!1)}),this.server.listen(this.config.port,this.config.host,()=>{console.log(`SMTP server listening on ${this.config.host}:${this.config.port} (STARTTLS)`)}),this.config.tls?.key&&this.config.tls?.cert){let e={key:C.readFileSync(this.config.tls.key),cert:C.readFileSync(this.config.tls.cert)};this.tlsServer=I.createServer(e,(t)=>{this.handleConnection(t,!0)}),this.tlsServer.listen(this.config.tlsPort,this.config.host,()=>{console.log(`SMTP server listening on ${this.config.host}:${this.config.tlsPort} (TLS)`)})}}async stop(){if(this.server)this.server.close();if(this.tlsServer)this.tlsServer.close();for(let e of this.sessions.values())e.socket.destroy();this.sessions.clear()}handleConnection(e,t){let n=b.randomUUID(),r={id:n,socket:e,secure:t,state:"greeting",authenticated:!1,rcptTo:[],dataBuffer:"",tlsUpgraded:t};this.sessions.set(n,r),console.log(`SMTP connection from ${e.remoteAddress} (session: ${n.slice(0,8)})`),this.send(r,`220 ${this.config.domain} ESMTP Mail Server`),r.state="ready";let s="";e.on("data",async(a)=>{s+=a.toString();let u;while((u=s.indexOf(`\r
|
|
12
|
-
`))!==-1){let i=s.slice(0,u);if(s=s.slice(u+2),r.state==="data")await this.handleDataLine(r,i);else await this.handleCommand(r,i)}}),e.on("close",()=>{console.log(`SMTP session ${n.slice(0,8)} closed`),this.sessions.delete(n)}),e.on("error",(a)=>{console.error(`SMTP session ${n.slice(0,8)} error:`,a.message),this.sessions.delete(n)})}send(e,t){if(!e.socket.destroyed)e.socket.write(`${t}\r
|
|
13
|
-
`)}async handleCommand(e,t){let n=t.trim();if(!n)return;let r=n.split(" ")[0]?.toUpperCase();if(!r)return;let s=n.slice(r.length).trim();switch(console.log(`SMTP CMD [${e.username||"anon"}]: ${r} ${s.includes("AUTH")?"***":s}`),r){case"EHLO":case"HELO":await this.handleEhlo(e,s);break;case"STARTTLS":await this.handleStartTls(e);break;case"AUTH":await this.handleAuth(e,s);break;case"MAIL":await this.handleMailFrom(e,s);break;case"RCPT":await this.handleRcptTo(e,s);break;case"DATA":await this.handleData(e);break;case"RSET":this.resetSession(e),this.send(e,"250 OK");break;case"NOOP":this.send(e,"250 OK");break;case"QUIT":this.send(e,`221 ${this.config.domain} closing connection`),e.socket.end();break;default:this.send(e,"500 Unrecognized command")}}async handleEhlo(e,t){let n=[`250-${this.config.domain} Hello ${t}`,"250-SIZE 26214400","250-8BITMIME","250-PIPELINING"];if(!e.secure&&this.config.tls?.key)n.push("250-STARTTLS");n.push("250-AUTH PLAIN LOGIN"),n.push("250 OK");for(let r of n)this.send(e,r)}async handleStartTls(e){if(e.secure||e.tlsUpgraded){this.send(e,"503 TLS already active");return}if(!this.config.tls?.key||!this.config.tls?.cert){this.send(e,"454 TLS not available");return}this.send(e,"220 Ready to start TLS");let t={key:C.readFileSync(this.config.tls.key),cert:C.readFileSync(this.config.tls.cert),isServer:!0},n=new I.TLSSocket(e.socket,t);e.socket=n,e.secure=!0,e.tlsUpgraded=!0,this.resetSession(e)}async handleAuth(e,t){let n=t.split(" "),r=n[0]?.toUpperCase();if(!r){this.send(e,"504 Authentication mechanism required");return}if(r==="PLAIN")if(n[1])await this.handleAuthPlain(e,n[1]);else this.send(e,"334 "),e.state="ready";else if(r==="LOGIN"){this.send(e,"334 VXNlcm5hbWU6");let s=e.socket.listeners("data")[0];e.socket.removeAllListeners("data");let a="username",u="";e.socket.on("data",async(i)=>{try{let o=i.toString().trim();if(a==="username")u=Buffer.from(o,"base64").toString("utf-8"),a="password",this.send(e,"334 UGFzc3dvcmQ6");else if(a==="password"){let l=Buffer.from(o,"base64").toString("utf-8");e.socket.removeAllListeners("data"),e.socket.on("data",s),await this.authenticateUser(e,u,l)}}catch(o){e.socket.removeAllListeners("data"),e.socket.on("data",s),this.send(e,"535 Authentication failed"),console.error(`SMTP AUTH LOGIN error: ${o.message}`)}})}else this.send(e,"504 Unrecognized authentication mechanism")}async handleAuthPlain(e,t){try{let r=Buffer.from(t,"base64").toString("utf-8").split("\x00"),s=r.length===3?r[1]:r[0],a=r.length===3?r[2]:r[1];if(!s||a===void 0)throw Error("Malformed AUTH PLAIN credentials");await this.authenticateUser(e,s,a)}catch(n){this.send(e,"535 Authentication failed")}}async authenticateUser(e,t,n){let r=t.includes("@")?t.split("@")[0]??"":t,s=this.config.users[r],a=s?(()=>{try{let u=Buffer.from(s.password,"utf-8"),i=Buffer.from(n,"utf-8");if(u.length!==i.length){let o=Math.max(u.length,i.length),l=Buffer.alloc(o),f=Buffer.alloc(o);return l.set(u),f.set(i),b.timingSafeEqual(l,f),!1}return b.timingSafeEqual(u,i)}catch{return!1}})():!1;if(s&&a)e.authenticated=!0,e.username=r,e.email=s.email,this.send(e,"235 Authentication successful"),console.log(`SMTP AUTH success: ${r}`);else this.send(e,"535 Authentication failed"),console.log(`SMTP AUTH failed: ${t}`)}async handleMailFrom(e,t){if(!e.authenticated){this.send(e,"530 Authentication required");return}let n=t.match(/FROM:\s*<([^>]*)>/i);if(!n){this.send(e,"501 Syntax error in MAIL FROM");return}let r=n[1];if(!r){this.send(e,"501 Syntax error in MAIL FROM");return}if(!r.endsWith(`@${this.config.domain}`)){this.send(e,`553 Sender address must be from @${this.config.domain}`);return}e.mailFrom=r,e.state="mail",this.send(e,"250 OK")}async handleRcptTo(e,t){if(!e.authenticated){this.send(e,"530 Authentication required");return}if(!e.mailFrom){this.send(e,"503 MAIL FROM required first");return}let n=t.match(/TO:\s*<([^>]*)>/i);if(!n){this.send(e,"501 Syntax error in RCPT TO");return}let r=n[1];if(!r){this.send(e,"501 Syntax error in RCPT TO");return}e.rcptTo.push(r),e.state="rcpt",this.send(e,"250 OK")}async handleData(e){if(!e.authenticated){this.send(e,"530 Authentication required");return}if(e.rcptTo.length===0){this.send(e,"503 RCPT TO required first");return}e.state="data",e.dataBuffer="",this.send(e,"354 Start mail input; end with <CRLF>.<CRLF>")}async handleDataLine(e,t){if(t===".")await this.sendEmail(e);else{let n=t.startsWith(".")?t.slice(1):t;e.dataBuffer+=`${n}\r
|
|
14
|
-
`}}async sendEmail(e){try{let t=e.dataBuffer,n=await this.ses.sendRawEmail({source:e.mailFrom,destinations:e.rcptTo,rawMessage:t});if(console.log(`SMTP: Email sent via SES, MessageId: ${n.MessageId}`),this.s3&&this.config.sentBucket)try{let r=`${this.config.sentPrefix||"sent/"}${e.email}/${Date.now()}-${n.MessageId}`;await this.s3.putObject({bucket:this.config.sentBucket,key:r,body:t,contentType:"message/rfc822"}),console.log(`SMTP: Email stored in S3: ${r}`)}catch(r){console.error("SMTP: Failed to store sent email in S3 (email was sent successfully):",r.message)}this.send(e,`250 OK Message accepted, ID: ${n.MessageId}`),this.resetSession(e)}catch(t){console.error("SMTP: Failed to send email:",t.message),this.send(e,`451 Failed to send: ${t.message}`),this.resetSession(e)}}resetSession(e){e.state="ready",e.mailFrom=void 0,e.rcptTo=[],e.dataBuffer=""}}async function Ee(e){let t=new D(e);return await t.start(),t}import{AWSClient as De,S3Client as Ue,SecretsManagerClient as Be}from"@stacksjs/ts-cloud";import{buildQueryParams as Ge}from"@stacksjs/ts-cloud/aws";export{De as AWSClient,G as Cloud,Ue as S3Client,Be as SecretsManagerClient,D as SmtpServer,Ce as addJumpBox,Ge as buildQueryParams,ye as deleteCdkRemnants,Z as deleteEc2Instance,ge as deleteIamUsers,me as deleteJumpBox,he as deleteLogGroups,Se as deleteParameterStore,fe as deleteStacksBuckets,pe as deleteStacksFunctions,ke as deleteSubnets,we as deleteVpcs,Ae as getCloudFrontDistributionId,A as getJumpBoxInstanceId,Y as getJumpBoxInstanceProfileName,Q as getJumpBoxSecurityGroupName,Re as getOrCreateTimestamp,be as getSecurityGroupFromInstanceId,H as getSecurityGroupId,Pe as hasBeenDeployed,Ie as isFailedState,ve as isFirstDeployment,le as purchaseDomain,Ee as startSmtpServer};
|
|
2
|
+
import{config as V}from"@stacksjs/config";import{InfrastructureGenerator as K}from"@stacksjs/ts-cloud";class z{generator;cloudConfig;props;constructor(e,t){this.cloudConfig=e,this.props=t;let n=(t.appEnv==="local"?"development":t.appEnv)||"production";this.generator=new K({config:this.cloudConfig,environment:n})}generate(){return this.generator.generate().toJSON()}shouldDeployApi(){return V.cloud.api?.deploy??!1}}import{existsSync as J}from"fs";import A from"process";import{AWSClient as M,AWSCloudFormationClient as T,CloudWatchLogsClient as q,EC2Client as x,IAMClient as G,LambdaClient as _,Route53DomainsClient as W,S3Client as F,SSMClient as D}from"@stacksjs/ts-cloud";import{config as w}from"@stacksjs/config";import{err as p,handleError as h,ok as c}from"@stacksjs/error-handling";import{log as g}from"@stacksjs/logging";import{path as L}from"@stacksjs/path";import{slug as H}from"@stacksjs/strings";async function b(){let e=L.projectPath("config/cloud.ts");if(!J(e))return{};return(await import(e)).tsCloud??{}}function Z(){return A.env.APP_ENV||A.env.NODE_ENV||"production"}async function N(e){let{project:t}=e??await b();return`${t?.name||"stacks"}-cloud`}async function S(e,t=Z()){let{project:n,environments:r}=e??await b();return A.env.AWS_REGION||r?.[t]?.region||n?.region||"us-east-1"}async function I(e,t,n={}){let r=new M,a={Action:t,Version:"2016-11-15",...n};return await r.request({service:"ec2",region:e,method:"POST",path:"/",queryParams:a})}async function X(e,t,n){return await new M().request({service:"logs",region:e,method:"POST",path:"/",headers:{"Content-Type":"application/x-amz-json-1.1","X-Amz-Target":`Logs_20140328.${t}`},body:JSON.stringify(n)})}async function fe(e){let t=new x(await S()),{SecurityGroups:n}=await t.describeSecurityGroups({Filters:[{Name:"group-name",Values:[e]}]});if(!n)return p(`Security group ${e} not found`);if(n[0])return c(n[0].GroupId);return p(`Security group ${e} not found`)}function he(e){let t=e.admin??{},n=e.tech??{},r=e.privacy??!0,a=String(e.contactType||"PERSON").toUpperCase();return{domain:"",years:1,privacy:r,autoRenew:!0,registrantFirstName:e.firstName??"",registrantLastName:e.lastName??"",registrantOrganization:e.organizationName??"",registrantAddressLine1:e.addressLine1??"",registrantAddressLine2:e.addressLine2??"",registrantCity:e.city??"",registrantState:e.state??"",registrantCountry:e.countryCode,registrantZip:e.zip??"",registrantPhone:e.phoneNumber??"",registrantEmail:e.email??"",adminFirstName:t.firstName||e.firstName||"",adminLastName:t.lastName||e.lastName||"",adminOrganization:t.organizationName||e.organizationName||"",adminAddressLine1:t.addressLine1||e.addressLine1||"",adminAddressLine2:t.addressLine2||e.addressLine2||"",adminCity:t.city||e.city||"",adminState:t.state||e.state||"",adminCountry:t.countryCode||e.countryCode,adminZip:t.zip||e.zip||"",adminPhone:t.phoneNumber||e.phoneNumber||"",adminEmail:t.email||e.email||"",techFirstName:n.firstName||e.firstName||"",techLastName:n.lastName||e.lastName||"",techOrganization:n.organizationName||e.organizationName||"",techAddressLine1:n.addressLine1||e.addressLine1||"",techAddressLine2:n.addressLine2||e.addressLine2||"",techCity:n.city||e.city||"",techState:n.state||e.state||"",techCountry:n.countryCode||e.countryCode,techZip:n.zip||e.zip||"",techPhone:n.phoneNumber||e.phoneNumber||"",techEmail:n.email||e.email||"",privacyAdmin:e.privacyAdmin??r,privacyTech:e.privacyTech??r,privacyRegistrant:e.privacyRegistrant??r,contactType:a,verbose:!1}}var Q={firstName:"registrantFirstName",lastName:"registrantLastName",organization:"registrantOrganization",addressLine1:"registrantAddressLine1",addressLine2:"registrantAddressLine2",city:"registrantCity",state:"registrantState",country:"registrantCountry",zip:"registrantZip",phone:"registrantPhone",email:"registrantEmail"};function ye(e,t){let n={...e};for(let[a,i]of Object.entries(t)){if(i===void 0||i===null||i==="")continue;n[Q[a]??a]=i}for(let a of["privacy","autoRenew","privacyAdmin","privacyTech","privacyRegistrant","verbose"])if(n[a]==="false")n[a]=!1;else if(n[a]==="true")n[a]=!0;if(t.privacy!==void 0){for(let a of["privacyAdmin","privacyTech","privacyRegistrant"])if(t[a]===void 0)n[a]=n.privacy}let r=Number(n.years);if(n.years=Number.isInteger(r)&&r>0?r:1,typeof n.contactType==="string")n.contactType=n.contactType.toUpperCase();return n}async function Se(e,t,n=new W){let r=String(t.contactType||"PERSON").toUpperCase(),a=(s)=>s.toString().includes("+")?s.toString():`+${s.toString()}`,i=(s)=>({FirstName:t[`${s}FirstName`],LastName:t[`${s}LastName`],ContactType:r,OrganizationName:t[`${s}Organization`],AddressLine1:t[`${s}AddressLine1`],AddressLine2:t[`${s}AddressLine2`],City:t[`${s}City`],State:t[`${s}State`],CountryCode:t[`${s}Country`],ZipCode:String(t[`${s}Zip`]??""),PhoneNumber:a(t[`${s}Phone`]??""),Email:t[`${s}Email`]});try{let s=await n.registerDomain({DomainName:e,DurationInYears:t.years||1,AutoRenew:t.autoRenew??!0,AdminContact:i("admin"),RegistrantContact:i("registrant"),TechContact:i("tech"),PrivacyProtectAdminContact:t.privacyAdmin??t.privacy??!0,PrivacyProtectRegistrantContact:t.privacyRegistrant??t.privacy??!0,PrivacyProtectTechContact:t.privacyTech??t.privacy??!0});if(!s?.OperationId)return p(Error(`Route 53 returned no operation id for ${e}, so the registration cannot be confirmed.`));return c({OperationId:s.OperationId})}catch(s){return p(s instanceof Error?s:Error(String(s)))}}var Y="JumpBoxInstanceId",ee="Set `infrastructure.jumpBox: true` in the `tsCloud` export of config/cloud.ts (or an object: `{ size, keyName, allowedCidrs, databaseTools, mountEfs }`), then run `buddy deploy`.";function te(e){let t=e.infrastructure?.jumpBox;if(!t)return!1;return t===!0||t.enabled!==!1}async function B(e={}){let t=e.config??await b(),n=await N(t),r=await S(t),a=(e.cloudFormation??((s)=>new T(s)))(r),i={stack:n,region:r,declared:te(t),deployed:!1};try{let{Stacks:s}=await a.describeStacks({stackName:n}),o=s?.[0];if(!o||o.StackStatus==="DELETE_COMPLETE")return c(i);return i.deployed=!0,i.instanceId=o.Outputs?.find((d)=>d.OutputKey===Y)?.OutputValue||void 0,c(i)}catch(s){let o=s instanceof Error?s:Error(String(s));if(/does not exist/i.test(o.message))return c(i);return p(o)}}async function ke(e={}){let t=await B(e);if(t.isErr)throw t.error;return t.value.instanceId}function C(e,t,n){return{done:e,state:t,message:n}}function P(e){return`the ${e.stack} stack (${e.region})`}async function we(e={}){let t=await B(e);if(t.isErr)return p(`Could not read the jump box from the deployed stack: ${t.error.message}`);let n=t.value;if(n.instanceId)return c(C(!0,n,`${P(n)} already has a jump box, ${n.instanceId}. Connect with \`buddy cloud --ssh\`.`));if(n.declared){let r=n.deployed?"has not been deployed with it yet":"is not deployed";return c(C(!1,n,`config/cloud.ts declares a jump box, but ${P(n)} ${r}. Run \`buddy deploy\` to create it.`))}return c(C(!1,n,`${P(n)} has no jump box. ${ee}`))}async function Ce(e={}){let t=await B(e);if(t.isErr)return p(`Could not read the jump box from the deployed stack: ${t.error.message}`);let n=t.value;if(!n.instanceId){let r=n.declared?" config/cloud.ts still declares one, so the next `buddy deploy` creates it; remove `infrastructure.jumpBox` to keep it gone.":"";return c(C(!0,n,`${P(n)} has no jump box.${r}`))}if(n.declared)return c(C(!1,n,`${P(n)} has a jump box, ${n.instanceId}. Remove \`infrastructure.jumpBox\` from the \`tsCloud\` export of config/cloud.ts (or set \`enabled: false\`), then run \`buddy deploy\`; CloudFormation deletes the instance, its security group and its role.`));return c(C(!1,n,`${P(n)} still has a jump box, ${n.instanceId}, though config/cloud.ts no longer declares one. Run \`buddy deploy\` to remove it.`))}async function Pe(){let e=new G("us-east-1"),t=await e.listUsers(),n=H(w.team.name),r=t.Users?.filter((i)=>{let o=i.UserName?.toLowerCase();return o!=="stacks"&&o!==n.toLowerCase()&&o?.includes(n.toLowerCase())})||[];if(!r||r.length===0)return c(`No Stacks IAM users found for team ${n}`);let a=r.map(async(i)=>{let o=i.UserName||"";g.info(`Deleting IAM user: ${o}`);let d=await e.listAttachedUserPolicies({UserName:o});await Promise.all(d.AttachedPolicies?.map((l)=>{let y=l;return e.detachUserPolicy({UserName:o,PolicyArn:y.PolicyArn||""})})||[]);let u=await e.listAccessKeys({UserName:o});return await Promise.all(u.AccessKeyMetadata?.map((l)=>{let y=l;return e.deleteAccessKey({UserName:o,AccessKeyId:y.AccessKeyId||""})})||[]),e.deleteUser({UserName:o})});try{await Promise.all(a)}catch(i){return console.error(i),p(h("Error deleting Stacks IAM users").message)}return c(`Stacks IAM users deleted for team ${n}`)}async function be(e={}){try{let t=(e.client??((i)=>new F(i)))(await S(e.config)),r=(await t.listBuckets()).Buckets?.filter((i)=>i.Name?.includes("stacks"));if(!r)return p("No stacks buckets found");let a=r.map(async(i)=>{let s=i.Name||"";g.info(`Deleting bucket ${s}...`);let o,d=!0;while(d){let u=await t.listObjects({bucket:s,continuationToken:o});if(u.objects&&u.objects.length>0)g.info(`Deleting ${u.objects.length} objects from bucket ${s}...`),await Promise.all(u.objects.map((l)=>{let y=l;return t.deleteObject(s,y.Key||"")})).catch((l)=>{throw g.error(`Failed to delete objects from bucket ${s}:`,l),l});d=!!u.nextContinuationToken,o=u.nextContinuationToken}g.info(`Finished deleting objects from bucket ${s}`),g.info(`Deleting bucket ${s} versions...`);try{let u,l,y=!0;while(y){let m=await t.listObjectVersions({bucket:s,keyMarker:u,versionIdMarker:l});if(m.versions&&m.versions.length>0)await Promise.all(m.versions.map((f)=>{let O=f;return t.deleteObject(s,O.Key||"")})).catch((f)=>h(f)),g.info(`Deleted ${m.versions.length} versions from bucket ${s}`);if(m.deleteMarkers&&m.deleteMarkers.length>0)await Promise.all(m.deleteMarkers.map((f)=>{let O=f;return t.deleteObject(s,O.Key||"")})).catch((f)=>h(f)),g.info(`Deleted ${m.deleteMarkers.length} delete markers from bucket ${s}`);y=!!m.nextKeyMarker,u=m.nextKeyMarker,l=m.nextVersionIdMarker}g.info(`Finished deleting all versions from bucket ${s}`);let k=await t.listMultipartUploads(s);if(k&&k.length>0)g.info("Aborting bucket multipart uploads..."),await Promise.all(k.map((m)=>{let f=m;return t.abortMultipartUpload(s,f.Key||"",f.UploadId||"")})).catch((m)=>h(m)),g.info(`Finished aborting multipart uploads from bucket ${s}`);await t.deleteBucket(s).catch((m)=>h(m)),g.info(`Bucket ${s} deleted`)}catch(u){g.info(`Error listing bucket ${s} versions`,u)}});return await Promise.all(a).catch((i)=>(console.error(i),p(h("Error deleting stacks buckets")))),c("Stacks buckets deleted")}catch(t){return p(h("Error deleting stacks buckets",t))}}async function ve(e={}){let t=e.client??((a)=>new _(a)),n=[...new Set([await S(e.config),"us-east-1"])],r=[];for(let a of n){let i=t(a),s=await i.listFunctions();for(let o of s.Functions??[]){let d=o.FunctionName;if(d?.includes("stacks"))r.push({lambda:i,name:d})}}if(r.length===0)return c("No stacks functions found");try{await Promise.all(r.map(({lambda:a,name:i})=>a.deleteFunction(i)))}catch(a){let i=a;if(i.message.includes("it is a replicated function"))return g.info("Function is replicated, skipping..."),c("CloudFront is still deleting the some functions. Try again later.");return p(h("Error deleting stacks functions",i).message)}return c("Stacks functions deleted")}async function Re(){try{let e=await I(await S(),"DescribeRegions"),n=e.regionInfo?.item??e.Regions??e.regionSet??[],r=[];if(Array.isArray(n))for(let a of n){let i=a.regionName??a.RegionName;if(i)r.push(i)}for(let a of r){let s=await new q(a).describeLogGroups();if(s?.logGroups)for(let o of s.logGroups){let d=w.app.name?.toLocaleLowerCase()||"stacks";if(o.logGroupName?.includes(d))await X(a,"DeleteLogGroup",{logGroupName:o.logGroupName})}}return c("Log groups deleted in all regions")}catch(e){return p(h("Error deleting log groups",e))}}async function Te(e={}){let t=(e.client??((s)=>new D(s)))(await S(e.config)),n=await t.describeParameters();if(!n.Parameters)return c("No parameters found");let r=w.app.name?.toLocaleLowerCase()||"stacks",a=n.Parameters.filter((s)=>s.Name?.includes(r))||[];if(!a||a.length===0)return c("No stacks parameters found");let i=a.map((s)=>{let o=s;return t.deleteParameter({Name:o.Name||""})});try{await Promise.all(i)}catch(s){return p(h("Error deleting parameter store",s).message)}return c("Parameter store deleted")}async function Ne(e={}){let t=await S(e.config),n=(e.client??((i)=>new x(i)))(t),r=e.request??I,a=w.app.name?`${w.app.name.toLowerCase()}-`:"stacks-";try{let{Vpcs:i}=await n.describeVpcs();if(!i||i.length===0)return c("No VPCs found");let s=i.filter((o)=>o.Tags?.some((l)=>l.Key==="Name"&&l.Value===a));if(s.length===0)return c(`No VPCs found matching the pattern: ${a}`);for(let o of s)if(o.VpcId)await r(t,"DeleteVpc",{VpcId:o.VpcId}),g.info(`Deleted VPC: ${o.VpcId} (${a})`);return c(`Deleted ${s.length} VPCs matching the pattern: ${a}`)}catch(i){return p(h(`Error deleting VPCs: ${i}`))}}async function Ee(){try{return await Bun.$`rm -rf ${L.cloudPath("cdk.out/")} ${L.cloudPath("cdk.context.json")}`.text(),c("CDK remnants deleted")}catch(e){return p(h("Error deleting CDK remnants",e))}}async function Oe(e={}){let t=await S(e.config),n=(e.client??((i)=>new x(i)))(t),r=e.request??I,a=w.app.name?`${w.app.name.toLowerCase()}-`:"stacks-";try{let{Subnets:i}=await n.describeSubnets();if(!i||i.length===0)return c("No subnets found");let s=i.filter((o)=>o.Tags?.some((l)=>l.Key==="Name"&&l.Value?.startsWith(a)));if(s.length===0)return c(`No subnets found matching the pattern: ${a}`);for(let o of s)if(o.SubnetId){let l=(await r(t,"DescribeNetworkInterfaces",{"Filter.1.Name":"subnet-id","Filter.1.Value.1":o.SubnetId})).networkInterfaceSet?.item??[];for(let y of Array.isArray(l)?l:[]){let k=y.networkInterfaceId;if(k){let m=y.attachment;if(m?.instanceId)await n.terminateInstances([m.instanceId]),g.info(`Terminated instance: ${m.instanceId}`),await new Promise((f)=>setTimeout(f,60000));if(m?.attachmentId)await r(t,"DetachNetworkInterface",{AttachmentId:m.attachmentId,Force:"true"}),g.info(`Detached network interface: ${k}`),await new Promise((f)=>setTimeout(f,1e4));await r(t,"DeleteNetworkInterface",{NetworkInterfaceId:k}),g.info(`Deleted network interface: ${k}`)}}await r(t,"DeleteSubnet",{SubnetId:o.SubnetId}),g.info(`Deleted subnet: ${o.SubnetId} (${o.Tags?.find((y)=>y.Key==="Name")?.Value})`)}return c(`Deleted ${s.length} subnets matching the pattern: ${a}`)}catch(i){return p(h(`Error deleting subnets: ${i}`))}}async function Ae(e={}){let t=(e.client??((n)=>new F(n)))(await S(e.config));try{let n=await t.listBuckets();return c(n.Buckets?.some((r)=>r.Name?.includes(w.app.name?.toLocaleLowerCase()||"stacks"))||!1)}catch(n){return console.error(n),p(h("Error checking if the app has been deployed"))}}async function Le(){let e=await b(),t=await N(e);return!(await new T(await S(e)).listStacks(["CREATE_COMPLETE","UPDATE_COMPLETE"])).StackSummaries?.some((i)=>i.StackName===t)}async function xe(){let e=await b(),t=await N(e),r=await new T(await S(e)).listStacks(["CREATE_FAILED","UPDATE_FAILED","ROLLBACK_COMPLETE","UPDATE_ROLLBACK_COMPLETE"]);return Boolean(r.StackSummaries?.some((a)=>a.StackName===t))}async function Ie(e,t={}){let n=t.config??await b(),r=await N(n),a=await S(n),i=(t.client??((u)=>new T(u)))(a),s;try{s=(await i.getTemplate(r)).TemplateBody}catch(u){let l=u instanceof Error?u:Error(String(u));if(!/does not exist/i.test(l.message))return p(l)}let o=typeof s==="string",d=!0;if(o)try{d=!Bun.deepEquals(JSON.parse(s),JSON.parse(e))}catch{d=s!==e}return c({stack:r,region:a,deployed:o,changed:d,deployedBytes:o?Buffer.byteLength(s):0,localBytes:Buffer.byteLength(e)})}async function $e(e={}){let n=(e.client??((r)=>new D(r)))(await S(e.config));try{let r=await n.getParameter({Name:"/stacks/timestamp"}),a=r.Parameter?r.Parameter.Value:void 0;if(!a)throw Error("Timestamp parameter not found");return a}catch(r){let a=new Date().getTime().toString();return g.debug(`Creating timestamp parameter /stacks/timestamp with value ${a}`,r),await n.putParameter({Name:"/stacks/timestamp",Value:a,Type:"String"}),a}}async function Be(){return""}import*as U from"net";import*as E from"tls";import*as v from"fs";import*as R from"crypto";import{S3Client as ne,SESClient as re}from"@stacksjs/ts-cloud";class j{config;ses;s3;server;tlsServer;sessions=new Map;constructor(e){if(this.config={port:587,tlsPort:465,host:"0.0.0.0",...e},this.ses=new re(e.region||"us-east-1"),e.sentBucket)this.s3=new ne(e.region||"us-east-1")}async start(){if(this.server=U.createServer((e)=>{this.handleConnection(e,!1)}),this.server.listen(this.config.port,this.config.host,()=>{console.log(`SMTP server listening on ${this.config.host}:${this.config.port} (STARTTLS)`)}),this.config.tls?.key&&this.config.tls?.cert){let e={key:v.readFileSync(this.config.tls.key),cert:v.readFileSync(this.config.tls.cert)};this.tlsServer=E.createServer(e,(t)=>{this.handleConnection(t,!0)}),this.tlsServer.listen(this.config.tlsPort,this.config.host,()=>{console.log(`SMTP server listening on ${this.config.host}:${this.config.tlsPort} (TLS)`)})}}async stop(){if(this.server)this.server.close();if(this.tlsServer)this.tlsServer.close();for(let e of this.sessions.values())e.socket.destroy();this.sessions.clear()}handleConnection(e,t){let n=R.randomUUID(),r={id:n,socket:e,secure:t,state:"greeting",authenticated:!1,rcptTo:[],dataBuffer:"",tlsUpgraded:t};this.sessions.set(n,r),console.log(`SMTP connection from ${e.remoteAddress} (session: ${n.slice(0,8)})`),this.send(r,`220 ${this.config.domain} ESMTP Mail Server`),r.state="ready";let a="";e.on("data",async(i)=>{a+=i.toString();let s;while((s=a.indexOf(`\r
|
|
3
|
+
`))!==-1){let o=a.slice(0,s);if(a=a.slice(s+2),r.state==="data")await this.handleDataLine(r,o);else await this.handleCommand(r,o)}}),e.on("close",()=>{console.log(`SMTP session ${n.slice(0,8)} closed`),this.sessions.delete(n)}),e.on("error",(i)=>{console.error(`SMTP session ${n.slice(0,8)} error:`,i.message),this.sessions.delete(n)})}send(e,t){if(!e.socket.destroyed)e.socket.write(`${t}\r
|
|
4
|
+
`)}async handleCommand(e,t){let n=t.trim();if(!n)return;let r=n.split(" ")[0]?.toUpperCase();if(!r)return;let a=n.slice(r.length).trim();switch(console.log(`SMTP CMD [${e.username||"anon"}]: ${r} ${a.includes("AUTH")?"***":a}`),r){case"EHLO":case"HELO":await this.handleEhlo(e,a);break;case"STARTTLS":await this.handleStartTls(e);break;case"AUTH":await this.handleAuth(e,a);break;case"MAIL":await this.handleMailFrom(e,a);break;case"RCPT":await this.handleRcptTo(e,a);break;case"DATA":await this.handleData(e);break;case"RSET":this.resetSession(e),this.send(e,"250 OK");break;case"NOOP":this.send(e,"250 OK");break;case"QUIT":this.send(e,`221 ${this.config.domain} closing connection`),e.socket.end();break;default:this.send(e,"500 Unrecognized command")}}async handleEhlo(e,t){let n=[`250-${this.config.domain} Hello ${t}`,"250-SIZE 26214400","250-8BITMIME","250-PIPELINING"];if(!e.secure&&this.config.tls?.key)n.push("250-STARTTLS");n.push("250-AUTH PLAIN LOGIN"),n.push("250 OK");for(let r of n)this.send(e,r)}async handleStartTls(e){if(e.secure||e.tlsUpgraded){this.send(e,"503 TLS already active");return}if(!this.config.tls?.key||!this.config.tls?.cert){this.send(e,"454 TLS not available");return}this.send(e,"220 Ready to start TLS");let t={key:v.readFileSync(this.config.tls.key),cert:v.readFileSync(this.config.tls.cert),isServer:!0},n=new E.TLSSocket(e.socket,t);e.socket=n,e.secure=!0,e.tlsUpgraded=!0,this.resetSession(e)}async handleAuth(e,t){let n=t.split(" "),r=n[0]?.toUpperCase();if(!r){this.send(e,"504 Authentication mechanism required");return}if(r==="PLAIN")if(n[1])await this.handleAuthPlain(e,n[1]);else this.send(e,"334 "),e.state="ready";else if(r==="LOGIN"){this.send(e,"334 VXNlcm5hbWU6");let a=e.socket.listeners("data")[0];e.socket.removeAllListeners("data");let i="username",s="";e.socket.on("data",async(o)=>{try{let d=o.toString().trim();if(i==="username")s=Buffer.from(d,"base64").toString("utf-8"),i="password",this.send(e,"334 UGFzc3dvcmQ6");else if(i==="password"){let u=Buffer.from(d,"base64").toString("utf-8");e.socket.removeAllListeners("data"),e.socket.on("data",a),await this.authenticateUser(e,s,u)}}catch(d){e.socket.removeAllListeners("data"),e.socket.on("data",a),this.send(e,"535 Authentication failed"),console.error(`SMTP AUTH LOGIN error: ${d.message}`)}})}else this.send(e,"504 Unrecognized authentication mechanism")}async handleAuthPlain(e,t){try{let r=Buffer.from(t,"base64").toString("utf-8").split("\x00"),a=r.length===3?r[1]:r[0],i=r.length===3?r[2]:r[1];if(!a||i===void 0)throw Error("Malformed AUTH PLAIN credentials");await this.authenticateUser(e,a,i)}catch(n){this.send(e,"535 Authentication failed")}}async authenticateUser(e,t,n){let r=t.includes("@")?t.split("@")[0]??"":t,a=this.config.users[r],i=a?(()=>{try{let s=Buffer.from(a.password,"utf-8"),o=Buffer.from(n,"utf-8");if(s.length!==o.length){let d=Math.max(s.length,o.length),u=Buffer.alloc(d),l=Buffer.alloc(d);return u.set(s),l.set(o),R.timingSafeEqual(u,l),!1}return R.timingSafeEqual(s,o)}catch{return!1}})():!1;if(a&&i)e.authenticated=!0,e.username=r,e.email=a.email,this.send(e,"235 Authentication successful"),console.log(`SMTP AUTH success: ${r}`);else this.send(e,"535 Authentication failed"),console.log(`SMTP AUTH failed: ${t}`)}async handleMailFrom(e,t){if(!e.authenticated){this.send(e,"530 Authentication required");return}let n=t.match(/FROM:\s*<([^>]*)>/i);if(!n){this.send(e,"501 Syntax error in MAIL FROM");return}let r=n[1];if(!r){this.send(e,"501 Syntax error in MAIL FROM");return}if(!r.endsWith(`@${this.config.domain}`)){this.send(e,`553 Sender address must be from @${this.config.domain}`);return}e.mailFrom=r,e.state="mail",this.send(e,"250 OK")}async handleRcptTo(e,t){if(!e.authenticated){this.send(e,"530 Authentication required");return}if(!e.mailFrom){this.send(e,"503 MAIL FROM required first");return}let n=t.match(/TO:\s*<([^>]*)>/i);if(!n){this.send(e,"501 Syntax error in RCPT TO");return}let r=n[1];if(!r){this.send(e,"501 Syntax error in RCPT TO");return}e.rcptTo.push(r),e.state="rcpt",this.send(e,"250 OK")}async handleData(e){if(!e.authenticated){this.send(e,"530 Authentication required");return}if(e.rcptTo.length===0){this.send(e,"503 RCPT TO required first");return}e.state="data",e.dataBuffer="",this.send(e,"354 Start mail input; end with <CRLF>.<CRLF>")}async handleDataLine(e,t){if(t===".")await this.sendEmail(e);else{let n=t.startsWith(".")?t.slice(1):t;e.dataBuffer+=`${n}\r
|
|
5
|
+
`}}async sendEmail(e){try{let t=e.dataBuffer,n=await this.ses.sendRawEmail({source:e.mailFrom,destinations:e.rcptTo,rawMessage:t});if(console.log(`SMTP: Email sent via SES, MessageId: ${n.MessageId}`),this.s3&&this.config.sentBucket)try{let r=`${this.config.sentPrefix||"sent/"}${e.email}/${Date.now()}-${n.MessageId}`;await this.s3.putObject({bucket:this.config.sentBucket,key:r,body:t,contentType:"message/rfc822"}),console.log(`SMTP: Email stored in S3: ${r}`)}catch(r){console.error("SMTP: Failed to store sent email in S3 (email was sent successfully):",r.message)}this.send(e,`250 OK Message accepted, ID: ${n.MessageId}`),this.resetSession(e)}catch(t){console.error("SMTP: Failed to send email:",t.message),this.send(e,`451 Failed to send: ${t.message}`),this.resetSession(e)}}resetSession(e){e.state="ready",e.mailFrom=void 0,e.rcptTo=[],e.dataBuffer=""}}async function De(e){let t=new j(e);return await t.start(),t}import{AWSClient as qe,S3Client as Ge,SecretsManagerClient as _e}from"@stacksjs/ts-cloud";import{buildQueryParams as He}from"@stacksjs/ts-cloud/aws";export{qe as AWSClient,z as Cloud,Y as JUMP_BOX_OUTPUT,Ge as S3Client,_e as SecretsManagerClient,j as SmtpServer,we as addJumpBox,ye as applyPurchaseFlags,He as buildQueryParams,Z as cloudEnvironment,te as declaresJumpBox,Ee as deleteCdkRemnants,Pe as deleteIamUsers,Ce as deleteJumpBox,Re as deleteLogGroups,Te as deleteParameterStore,be as deleteStacksBuckets,ve as deleteStacksFunctions,Oe as deleteSubnets,Ne as deleteVpcs,Ie as diffStackTemplate,Be as getCloudFrontDistributionId,ke as getJumpBoxInstanceId,B as getJumpBoxState,$e as getOrCreateTimestamp,fe as getSecurityGroupId,Ae as hasBeenDeployed,xe as isFailedState,Le as isFirstDeployment,b as loadCloudStackConfig,Se as purchaseDomain,he as purchaseOptionsFromContactInfo,N as stacksCloudName,S as stacksCloudRegion,De as startSmtpServer};
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@stacksjs/cloud",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"sideEffects": false,
|
|
5
|
-
"version": "0.75.
|
|
5
|
+
"version": "0.75.73",
|
|
6
6
|
"description": "The Stacks cloud/serverless integration & implementation.",
|
|
7
7
|
"author": "Chris Breuer",
|
|
8
8
|
"contributors": [
|
|
@@ -59,22 +59,22 @@
|
|
|
59
59
|
"prepublishOnly": "bun run build"
|
|
60
60
|
},
|
|
61
61
|
"dependencies": {
|
|
62
|
-
"@stacksjs/config": "0.75.
|
|
63
|
-
"@stacksjs/error-handling": "0.75.
|
|
64
|
-
"@stacksjs/logging": "0.75.
|
|
65
|
-
"@stacksjs/path": "0.75.
|
|
66
|
-
"@stacksjs/strings": "0.75.
|
|
67
|
-
"@stacksjs/ts-cloud": "^0.16.
|
|
62
|
+
"@stacksjs/config": "0.75.73",
|
|
63
|
+
"@stacksjs/error-handling": "0.75.73",
|
|
64
|
+
"@stacksjs/logging": "0.75.73",
|
|
65
|
+
"@stacksjs/path": "0.75.73",
|
|
66
|
+
"@stacksjs/strings": "0.75.73",
|
|
67
|
+
"@stacksjs/ts-cloud": "^0.16.39",
|
|
68
68
|
"@stacksjs/ts-xml": "^0.1.2"
|
|
69
69
|
},
|
|
70
70
|
"devDependencies": {
|
|
71
|
-
"@stacksjs/cli": "0.75.
|
|
72
|
-
"@stacksjs/dns": "0.75.
|
|
73
|
-
"@stacksjs/env": "0.75.
|
|
74
|
-
"@stacksjs/router": "0.75.
|
|
75
|
-
"@stacksjs/storage": "0.75.
|
|
76
|
-
"@stacksjs/utils": "0.75.
|
|
77
|
-
"@stacksjs/validation": "0.75.
|
|
71
|
+
"@stacksjs/cli": "0.75.73",
|
|
72
|
+
"@stacksjs/dns": "0.75.73",
|
|
73
|
+
"@stacksjs/env": "0.75.73",
|
|
74
|
+
"@stacksjs/router": "0.75.73",
|
|
75
|
+
"@stacksjs/storage": "0.75.73",
|
|
76
|
+
"@stacksjs/utils": "0.75.73",
|
|
77
|
+
"@stacksjs/validation": "0.75.73",
|
|
78
78
|
"better-dx": "^0.2.24"
|
|
79
79
|
}
|
|
80
80
|
}
|