@pwrdrvr/microapps-publish 0.4.0-alpha.9 → 1.0.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/README.md +25 -25
- package/package.json +5 -52
- package/bin/run +0 -5
- package/dist/commands/delete.d.ts +0 -18
- package/dist/commands/delete.d.ts.map +0 -1
- package/dist/commands/delete.js +0 -125
- package/dist/commands/delete.js.map +0 -1
- package/dist/commands/nextjs-version-restore.d.ts +0 -14
- package/dist/commands/nextjs-version-restore.d.ts.map +0 -1
- package/dist/commands/nextjs-version-restore.js +0 -53
- package/dist/commands/nextjs-version-restore.js.map +0 -1
- package/dist/commands/nextjs-version.d.ts +0 -18
- package/dist/commands/nextjs-version.d.ts.map +0 -1
- package/dist/commands/nextjs-version.js +0 -103
- package/dist/commands/nextjs-version.js.map +0 -1
- package/dist/commands/preflight.d.ts +0 -19
- package/dist/commands/preflight.d.ts.map +0 -1
- package/dist/commands/preflight.js +0 -135
- package/dist/commands/preflight.js.map +0 -1
- package/dist/commands/publish-static.d.ts +0 -25
- package/dist/commands/publish-static.d.ts.map +0 -1
- package/dist/commands/publish-static.js +0 -361
- package/dist/commands/publish-static.js.map +0 -1
- package/dist/commands/publish.d.ts +0 -39
- package/dist/commands/publish.d.ts.map +0 -1
- package/dist/commands/publish.js +0 -565
- package/dist/commands/publish.js.map +0 -1
- package/dist/config/Application.d.ts +0 -26
- package/dist/config/Application.d.ts.map +0 -1
- package/dist/config/Application.js +0 -99
- package/dist/config/Application.js.map +0 -1
- package/dist/config/Config.d.ts +0 -18
- package/dist/config/Config.d.ts.map +0 -1
- package/dist/config/Config.js +0 -71
- package/dist/config/Config.js.map +0 -1
- package/dist/config/Deployer.d.ts +0 -10
- package/dist/config/Deployer.d.ts.map +0 -1
- package/dist/config/Deployer.js +0 -17
- package/dist/config/Deployer.js.map +0 -1
- package/dist/index.d.ts +0 -2
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -6
- package/dist/index.js.map +0 -1
- package/dist/lib/DeployClient.d.ts +0 -102
- package/dist/lib/DeployClient.d.ts.map +0 -1
- package/dist/lib/DeployClient.js +0 -233
- package/dist/lib/DeployClient.js.map +0 -1
- package/dist/lib/FilesExist.d.ts +0 -5
- package/dist/lib/FilesExist.d.ts.map +0 -1
- package/dist/lib/FilesExist.js +0 -26
- package/dist/lib/FilesExist.js.map +0 -1
- package/dist/lib/S3TransferUtility.d.ts +0 -19
- package/dist/lib/S3TransferUtility.d.ts.map +0 -1
- package/dist/lib/S3TransferUtility.js +0 -94
- package/dist/lib/S3TransferUtility.js.map +0 -1
- package/dist/lib/S3Uploader.d.ts +0 -27
- package/dist/lib/S3Uploader.d.ts.map +0 -1
- package/dist/lib/S3Uploader.js +0 -77
- package/dist/lib/S3Uploader.js.map +0 -1
- package/dist/lib/Versions.d.ts +0 -33
- package/dist/lib/Versions.d.ts.map +0 -1
- package/dist/lib/Versions.js +0 -76
- package/dist/lib/Versions.js.map +0 -1
- package/src/commands/delete.ts +0 -135
- package/src/commands/nextjs-version-restore.ts +0 -70
- package/src/commands/nextjs-version.ts +0 -123
- package/src/commands/preflight.ts +0 -148
- package/src/commands/publish-static.ts +0 -416
- package/src/commands/publish.ts +0 -662
- package/src/commands-deprecated/nextjs-docker-auto.skip +0 -590
- package/src/config/Application.ts +0 -98
- package/src/config/Config.ts +0 -81
- package/src/config/Deployer.ts +0 -17
- package/src/index.ts +0 -1
- package/src/lib/DeployClient.ts +0 -334
- package/src/lib/FilesExist.ts +0 -25
- package/src/lib/S3TransferUtility.spec.ts +0 -15
- package/src/lib/S3TransferUtility.ts +0 -113
- package/src/lib/S3Uploader.ts +0 -94
- package/src/lib/Versions.ts +0 -101
- package/src/lib/__snapshots__/S3TransferUtility.spec.ts.snap +0 -12
package/src/config/Config.ts
DELETED
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
import { url, ipaddress } from 'convict-format-with-validator';
|
|
2
|
-
import * as yaml from 'js-yaml';
|
|
3
|
-
import * as convict from 'ts-convict';
|
|
4
|
-
import { TSConvict } from 'ts-convict';
|
|
5
|
-
import { FilesExist } from '../lib/FilesExist';
|
|
6
|
-
import { ApplicationConfig, IApplicationConfig } from './Application';
|
|
7
|
-
import { DeployerConfig, IDeployerConfig } from './Deployer';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Represents a Config
|
|
11
|
-
*/
|
|
12
|
-
export interface IConfig {
|
|
13
|
-
deployer: IDeployerConfig;
|
|
14
|
-
app: IApplicationConfig;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
@convict.Config({
|
|
18
|
-
// optional default file to load, no errors if it doesn't exist
|
|
19
|
-
file: 'config.yml', // relative to NODE_PATH or cwd()
|
|
20
|
-
|
|
21
|
-
// optional parameter. Defaults to 'strict', can also be 'warn'
|
|
22
|
-
validationMethod: 'strict',
|
|
23
|
-
|
|
24
|
-
// optionally add parsers like yaml or toml
|
|
25
|
-
parser: {
|
|
26
|
-
extension: ['yml', 'yaml'],
|
|
27
|
-
parse: yaml.load,
|
|
28
|
-
},
|
|
29
|
-
|
|
30
|
-
//optional extra formats to use in validation
|
|
31
|
-
formats: {
|
|
32
|
-
url,
|
|
33
|
-
ipaddress,
|
|
34
|
-
},
|
|
35
|
-
})
|
|
36
|
-
export class Config implements IConfig {
|
|
37
|
-
public static configFiles(): string[] {
|
|
38
|
-
const possibleFiles = [
|
|
39
|
-
'./microapps.yaml',
|
|
40
|
-
'./microapps.yml',
|
|
41
|
-
`./microapps-${Config.envLevel}.yaml`,
|
|
42
|
-
`./microapps-${Config.envLevel}.yml`,
|
|
43
|
-
];
|
|
44
|
-
return FilesExist.getExistingFilesSync(possibleFiles);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
private static _instance: IConfig;
|
|
48
|
-
public static get instance(): IConfig {
|
|
49
|
-
if (Config._instance === undefined) {
|
|
50
|
-
const configLoader = new TSConvict<Config>(Config);
|
|
51
|
-
Config._instance = configLoader.load(Config.configFiles());
|
|
52
|
-
}
|
|
53
|
-
return Config._instance;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
public static get envLevel(): 'dev' | 'qa' | 'prod' | 'local' {
|
|
57
|
-
const nodeEnv = process.env.NODE_ENV || 'dev';
|
|
58
|
-
if (nodeEnv.startsWith('prod')) {
|
|
59
|
-
return 'prod';
|
|
60
|
-
} else if (nodeEnv === 'qa') {
|
|
61
|
-
return 'qa';
|
|
62
|
-
} else if (nodeEnv === 'local') {
|
|
63
|
-
return 'local';
|
|
64
|
-
}
|
|
65
|
-
return 'dev';
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// ts-convict will use the Typescript type if no format given
|
|
69
|
-
// @convict.Property({
|
|
70
|
-
// doc: 'The name of the thing',
|
|
71
|
-
// default: 'Convict',
|
|
72
|
-
// env: 'MY_CONFIG_NAME',
|
|
73
|
-
// })
|
|
74
|
-
// public name!: string;
|
|
75
|
-
|
|
76
|
-
@convict.Property(ApplicationConfig)
|
|
77
|
-
public app!: IApplicationConfig;
|
|
78
|
-
|
|
79
|
-
@convict.Property(DeployerConfig)
|
|
80
|
-
public deployer!: IDeployerConfig;
|
|
81
|
-
}
|
package/src/config/Deployer.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { Property } from 'ts-convict';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Represents a Deployer Config
|
|
5
|
-
*/
|
|
6
|
-
export interface IDeployerConfig {
|
|
7
|
-
lambdaName: string;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export class DeployerConfig implements IDeployerConfig {
|
|
11
|
-
@Property({
|
|
12
|
-
doc: 'Name of Deployer Lambda function',
|
|
13
|
-
default: 'microapps-deployer',
|
|
14
|
-
env: 'DEPLOYER_LAMBDA_NAME',
|
|
15
|
-
})
|
|
16
|
-
public lambdaName!: string;
|
|
17
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { run } from '@oclif/command';
|
package/src/lib/DeployClient.ts
DELETED
|
@@ -1,334 +0,0 @@
|
|
|
1
|
-
import * as lambda from '@aws-sdk/client-lambda';
|
|
2
|
-
import type {
|
|
3
|
-
ICreateApplicationRequest,
|
|
4
|
-
IDeployerResponse,
|
|
5
|
-
IDeployVersionPreflightRequest,
|
|
6
|
-
IDeployVersionPreflightResponse,
|
|
7
|
-
IDeployVersionRequest,
|
|
8
|
-
IDeleteVersionRequest,
|
|
9
|
-
ILambdaAliasRequest,
|
|
10
|
-
ILambdaAliasResponse,
|
|
11
|
-
} from '@pwrdrvr/microapps-deployer-lib';
|
|
12
|
-
import { IConfig } from '../config/Config';
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Represents a Deploy Version Preflight Result
|
|
16
|
-
*/
|
|
17
|
-
export interface IDeployVersionPreflightResult {
|
|
18
|
-
exists: boolean;
|
|
19
|
-
response: IDeployVersionPreflightResponse;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export type DeployVersionArgs = Parameters<typeof DeployClient.DeployVersionLite>[0];
|
|
23
|
-
|
|
24
|
-
export default class DeployClient {
|
|
25
|
-
static readonly _client = new lambda.LambdaClient({
|
|
26
|
-
maxAttempts: 8,
|
|
27
|
-
});
|
|
28
|
-
static readonly _decoder = new TextDecoder('utf-8');
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Create an application
|
|
32
|
-
* @param opts
|
|
33
|
-
*/
|
|
34
|
-
public static async CreateApp(opts: { config: IConfig }): Promise<void> {
|
|
35
|
-
const { config } = opts;
|
|
36
|
-
const request: ICreateApplicationRequest = {
|
|
37
|
-
type: 'createApp',
|
|
38
|
-
appName: config.app.name,
|
|
39
|
-
displayName: config.app.name,
|
|
40
|
-
};
|
|
41
|
-
const response = await this._client.send(
|
|
42
|
-
new lambda.InvokeCommand({
|
|
43
|
-
FunctionName: config.deployer.lambdaName,
|
|
44
|
-
Payload: Buffer.from(JSON.stringify(request)),
|
|
45
|
-
}),
|
|
46
|
-
);
|
|
47
|
-
|
|
48
|
-
if (response.$metadata.httpStatusCode === 200 && response.Payload !== undefined) {
|
|
49
|
-
const dResponse = JSON.parse(
|
|
50
|
-
Buffer.from(response.Payload).toString('utf-8'),
|
|
51
|
-
) as IDeployerResponse;
|
|
52
|
-
if (!(dResponse.statusCode === 201 || dResponse.statusCode === 200)) {
|
|
53
|
-
throw new Error(`App create failed: ${JSON.stringify(dResponse)}`);
|
|
54
|
-
}
|
|
55
|
-
} else {
|
|
56
|
-
throw new Error(`App Create - Lambda Invoke Failed: ${JSON.stringify(response)}`);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Delete version
|
|
62
|
-
* @param config
|
|
63
|
-
* @param output
|
|
64
|
-
* @returns
|
|
65
|
-
*/
|
|
66
|
-
public static async DeleteVersion(opts: {
|
|
67
|
-
config: IConfig;
|
|
68
|
-
output: (message: string) => void;
|
|
69
|
-
}): Promise<IDeployerResponse> {
|
|
70
|
-
const { config, output } = opts;
|
|
71
|
-
|
|
72
|
-
const request: IDeleteVersionRequest = {
|
|
73
|
-
type: 'deleteVersion',
|
|
74
|
-
appName: config.app.name,
|
|
75
|
-
semVer: config.app.semVer,
|
|
76
|
-
};
|
|
77
|
-
const response = await this._client.send(
|
|
78
|
-
new lambda.InvokeCommand({
|
|
79
|
-
FunctionName: config.deployer.lambdaName,
|
|
80
|
-
Payload: Buffer.from(JSON.stringify(request)),
|
|
81
|
-
}),
|
|
82
|
-
);
|
|
83
|
-
|
|
84
|
-
if (response.$metadata.httpStatusCode === 200 && response.Payload !== undefined) {
|
|
85
|
-
const dResponse = JSON.parse(
|
|
86
|
-
Buffer.from(response.Payload).toString('utf-8'),
|
|
87
|
-
) as IDeployerResponse;
|
|
88
|
-
if (dResponse.statusCode === 404) {
|
|
89
|
-
output(`App/Version does not exist: ${config.app.name}/${config.app.semVer}`);
|
|
90
|
-
return dResponse;
|
|
91
|
-
} else {
|
|
92
|
-
output(`App/Version deleted: ${config.app.name}/${config.app.semVer}`);
|
|
93
|
-
return dResponse;
|
|
94
|
-
}
|
|
95
|
-
} else {
|
|
96
|
-
throw new Error(`Lambda call to DeleteVersion failed: ${JSON.stringify(response)}`);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Check if version exists.
|
|
102
|
-
* Optionally get S3 creds for static asset upload.
|
|
103
|
-
* @param config
|
|
104
|
-
* @param output
|
|
105
|
-
* @returns
|
|
106
|
-
*/
|
|
107
|
-
public static async DeployVersionPreflight(opts: {
|
|
108
|
-
config: IConfig;
|
|
109
|
-
needS3Creds?: boolean;
|
|
110
|
-
overwrite: boolean;
|
|
111
|
-
output: (message: string) => void;
|
|
112
|
-
}): Promise<IDeployVersionPreflightResult> {
|
|
113
|
-
const { config, needS3Creds = true, overwrite, output } = opts;
|
|
114
|
-
|
|
115
|
-
const request: IDeployVersionPreflightRequest = {
|
|
116
|
-
type: 'deployVersionPreflight',
|
|
117
|
-
appName: config.app.name,
|
|
118
|
-
semVer: config.app.semVer,
|
|
119
|
-
overwrite,
|
|
120
|
-
needS3Creds,
|
|
121
|
-
};
|
|
122
|
-
const response = await this._client.send(
|
|
123
|
-
new lambda.InvokeCommand({
|
|
124
|
-
FunctionName: config.deployer.lambdaName,
|
|
125
|
-
Payload: Buffer.from(JSON.stringify(request)),
|
|
126
|
-
}),
|
|
127
|
-
);
|
|
128
|
-
|
|
129
|
-
if (response.$metadata.httpStatusCode === 200 && response.Payload !== undefined) {
|
|
130
|
-
const dResponse = JSON.parse(
|
|
131
|
-
Buffer.from(response.Payload).toString('utf-8'),
|
|
132
|
-
) as IDeployVersionPreflightResponse;
|
|
133
|
-
if (dResponse.statusCode === 404) {
|
|
134
|
-
output(`App/Version does not exist: ${config.app.name}/${config.app.semVer}`);
|
|
135
|
-
return { exists: false, response: dResponse };
|
|
136
|
-
} else if (dResponse.statusCode > 299) {
|
|
137
|
-
// @ts-expect-error remove awsCredentials from response
|
|
138
|
-
delete dResponse.awsCredentials;
|
|
139
|
-
output(`DeployVersionPreflight failed: ${JSON.stringify(dResponse)}`);
|
|
140
|
-
throw new Error('DeployVersionPreflight failed');
|
|
141
|
-
} else {
|
|
142
|
-
output(`App/Version exists: ${config.app.name}/${config.app.semVer}`);
|
|
143
|
-
return { exists: true, response: dResponse };
|
|
144
|
-
}
|
|
145
|
-
} else {
|
|
146
|
-
// @ts-expect-error remove awsCredentials from response
|
|
147
|
-
delete dResponse.awsCredentials;
|
|
148
|
-
throw new Error(`Lambda call to DeployVersionPreflight failed: ${JSON.stringify(response)}`);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* Create or update Lambda alias for specified Lambda version
|
|
154
|
-
* @param config
|
|
155
|
-
* @param output
|
|
156
|
-
* @returns
|
|
157
|
-
*/
|
|
158
|
-
public static async LambdaAlias(opts: {
|
|
159
|
-
appName: string;
|
|
160
|
-
semVer: string;
|
|
161
|
-
lambdaVersionArn: string;
|
|
162
|
-
overwrite: boolean;
|
|
163
|
-
deployerLambdaName: string;
|
|
164
|
-
output: (message: string) => void;
|
|
165
|
-
}): Promise<{ response: ILambdaAliasResponse }> {
|
|
166
|
-
const { appName, deployerLambdaName, lambdaVersionArn, overwrite, output, semVer } = opts;
|
|
167
|
-
|
|
168
|
-
const request: ILambdaAliasRequest = {
|
|
169
|
-
type: 'lambdaAlias',
|
|
170
|
-
appName,
|
|
171
|
-
semVer,
|
|
172
|
-
lambdaARN: lambdaVersionArn,
|
|
173
|
-
overwrite,
|
|
174
|
-
};
|
|
175
|
-
output(`Creating alias for version ARN: ${lambdaVersionArn}`);
|
|
176
|
-
const response = await this._client.send(
|
|
177
|
-
new lambda.InvokeCommand({
|
|
178
|
-
FunctionName: deployerLambdaName,
|
|
179
|
-
Payload: Buffer.from(JSON.stringify(request)),
|
|
180
|
-
}),
|
|
181
|
-
);
|
|
182
|
-
|
|
183
|
-
if (response.$metadata.httpStatusCode === 200 && response.Payload !== undefined) {
|
|
184
|
-
const dResponse = JSON.parse(
|
|
185
|
-
Buffer.from(response.Payload).toString('utf-8'),
|
|
186
|
-
) as ILambdaAliasResponse;
|
|
187
|
-
if (dResponse.statusCode > 299) {
|
|
188
|
-
output(`LambdaAlias failed: ${JSON.stringify(dResponse)}`);
|
|
189
|
-
throw new Error('LambdaAlias failed');
|
|
190
|
-
} else if (!dResponse.functionUrl) {
|
|
191
|
-
output(`LambdaAlias failed to return functionUrl: ${JSON.stringify(dResponse)}`);
|
|
192
|
-
throw new Error('LambdaAlias failed to return functionUrl');
|
|
193
|
-
} else if (dResponse.statusCode === 201) {
|
|
194
|
-
output(`Alias created: ${dResponse.lambdaAliasARN}`);
|
|
195
|
-
return { response: dResponse };
|
|
196
|
-
} else {
|
|
197
|
-
output(`Alias ${dResponse.actionTaken}: ${dResponse.lambdaAliasARN}`);
|
|
198
|
-
return { response: dResponse };
|
|
199
|
-
}
|
|
200
|
-
} else {
|
|
201
|
-
throw new Error(`Lambda call to LambdaAlias failed: ${JSON.stringify(response)}`);
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
/**
|
|
206
|
-
* Copy S3 static assets from staging to live bucket.
|
|
207
|
-
* Create API Gateway Integration for app (if needed).
|
|
208
|
-
* Give API Gateway permission to call the Lambda.
|
|
209
|
-
* Create API Gateway routes for this specific version.
|
|
210
|
-
* @param config
|
|
211
|
-
* @param task
|
|
212
|
-
*/
|
|
213
|
-
public static async DeployVersion(opts: {
|
|
214
|
-
appName: string;
|
|
215
|
-
semVer: string;
|
|
216
|
-
defaultFile?: string;
|
|
217
|
-
lambdaAliasArn?: string;
|
|
218
|
-
deployerLambdaName: string;
|
|
219
|
-
appType: 'lambda' | 'static' | 'lambda-url' | 'url';
|
|
220
|
-
startupType?: 'iframe' | 'direct';
|
|
221
|
-
url?: string;
|
|
222
|
-
overwrite: boolean;
|
|
223
|
-
output: (message: string) => void;
|
|
224
|
-
}): Promise<void> {
|
|
225
|
-
const {
|
|
226
|
-
appName,
|
|
227
|
-
semVer,
|
|
228
|
-
defaultFile,
|
|
229
|
-
lambdaAliasArn,
|
|
230
|
-
deployerLambdaName,
|
|
231
|
-
appType,
|
|
232
|
-
startupType = 'iframe',
|
|
233
|
-
url,
|
|
234
|
-
overwrite,
|
|
235
|
-
output,
|
|
236
|
-
} = opts;
|
|
237
|
-
const request: IDeployVersionRequest = {
|
|
238
|
-
type: 'deployVersion',
|
|
239
|
-
appType,
|
|
240
|
-
startupType,
|
|
241
|
-
appName,
|
|
242
|
-
semVer,
|
|
243
|
-
defaultFile: defaultFile,
|
|
244
|
-
url,
|
|
245
|
-
overwrite,
|
|
246
|
-
...(['lambda', 'lambda-url'].includes(appType) ? { lambdaARN: lambdaAliasArn } : {}),
|
|
247
|
-
};
|
|
248
|
-
const response = await this._client.send(
|
|
249
|
-
new lambda.InvokeCommand({
|
|
250
|
-
FunctionName: deployerLambdaName,
|
|
251
|
-
Payload: Buffer.from(JSON.stringify(request)),
|
|
252
|
-
}),
|
|
253
|
-
);
|
|
254
|
-
|
|
255
|
-
if (response.$metadata.httpStatusCode === 200 && response.Payload !== undefined) {
|
|
256
|
-
const dResponse = JSON.parse(
|
|
257
|
-
Buffer.from(response.Payload).toString('utf-8'),
|
|
258
|
-
) as IDeployerResponse;
|
|
259
|
-
if (dResponse.statusCode === 201) {
|
|
260
|
-
output(`Deploy succeeded: ${appName}/${semVer}`);
|
|
261
|
-
} else {
|
|
262
|
-
output(`Deploy failed with: ${dResponse.statusCode}`);
|
|
263
|
-
throw new Error(`Lambda call to DeployVersion failed with: ${dResponse.statusCode}`);
|
|
264
|
-
}
|
|
265
|
-
} else {
|
|
266
|
-
throw new Error(`Lambda call to DeployVersion failed: ${JSON.stringify(response)}`);
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
/**
|
|
271
|
-
* Copy S3 static assets from staging to live bucket.
|
|
272
|
-
* Create DB records.
|
|
273
|
-
* Proxied to parent account if needed.
|
|
274
|
-
*
|
|
275
|
-
* @param config
|
|
276
|
-
* @param task
|
|
277
|
-
*/
|
|
278
|
-
public static async DeployVersionLite(opts: {
|
|
279
|
-
appName: string;
|
|
280
|
-
semVer: string;
|
|
281
|
-
defaultFile?: string;
|
|
282
|
-
lambdaAliasArn?: string;
|
|
283
|
-
deployerLambdaName: string;
|
|
284
|
-
appType: 'lambda' | 'static' | 'lambda-url' | 'url';
|
|
285
|
-
startupType?: 'iframe' | 'direct';
|
|
286
|
-
url?: string;
|
|
287
|
-
overwrite: boolean;
|
|
288
|
-
output: (message: string) => void;
|
|
289
|
-
}): Promise<void> {
|
|
290
|
-
const {
|
|
291
|
-
appName,
|
|
292
|
-
semVer,
|
|
293
|
-
defaultFile,
|
|
294
|
-
lambdaAliasArn,
|
|
295
|
-
deployerLambdaName,
|
|
296
|
-
appType,
|
|
297
|
-
startupType = 'iframe',
|
|
298
|
-
url,
|
|
299
|
-
overwrite,
|
|
300
|
-
output,
|
|
301
|
-
} = opts;
|
|
302
|
-
const request: IDeployVersionRequest = {
|
|
303
|
-
type: 'deployVersionLite',
|
|
304
|
-
appType,
|
|
305
|
-
startupType,
|
|
306
|
-
appName,
|
|
307
|
-
semVer,
|
|
308
|
-
defaultFile: defaultFile,
|
|
309
|
-
url,
|
|
310
|
-
overwrite,
|
|
311
|
-
...(['lambda', 'lambda-url'].includes(appType) ? { lambdaARN: lambdaAliasArn } : {}),
|
|
312
|
-
};
|
|
313
|
-
const response = await this._client.send(
|
|
314
|
-
new lambda.InvokeCommand({
|
|
315
|
-
FunctionName: deployerLambdaName,
|
|
316
|
-
Payload: Buffer.from(JSON.stringify(request)),
|
|
317
|
-
}),
|
|
318
|
-
);
|
|
319
|
-
|
|
320
|
-
if (response.$metadata.httpStatusCode === 200 && response.Payload !== undefined) {
|
|
321
|
-
const dResponse = JSON.parse(
|
|
322
|
-
Buffer.from(response.Payload).toString('utf-8'),
|
|
323
|
-
) as IDeployerResponse;
|
|
324
|
-
if (dResponse.statusCode === 201) {
|
|
325
|
-
output(`Deploy succeeded: ${appName}/${semVer}`);
|
|
326
|
-
} else {
|
|
327
|
-
output(`Deploy failed with: ${dResponse.statusCode}`);
|
|
328
|
-
throw new Error(`Lambda call to DeployVersionLite failed with: ${dResponse.statusCode}`);
|
|
329
|
-
}
|
|
330
|
-
} else {
|
|
331
|
-
throw new Error(`Lambda call to DeployVersionLite failed: ${JSON.stringify(response)}`);
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
}
|
package/src/lib/FilesExist.ts
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { pathExists, pathExistsSync } from 'fs-extra';
|
|
2
|
-
|
|
3
|
-
export class FilesExist {
|
|
4
|
-
public static async getExistingFiles(filesToCheck: string[]): Promise<string[]> {
|
|
5
|
-
const existingFiles: string[] = [];
|
|
6
|
-
for (const file of filesToCheck) {
|
|
7
|
-
if (await pathExists(file)) {
|
|
8
|
-
existingFiles.push(file);
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
return existingFiles;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
public static getExistingFilesSync(filesToCheck: string[]): string[] {
|
|
16
|
-
const existingFiles: string[] = [];
|
|
17
|
-
for (const file of filesToCheck) {
|
|
18
|
-
if (pathExistsSync(file)) {
|
|
19
|
-
existingFiles.push(file);
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
return existingFiles;
|
|
24
|
-
}
|
|
25
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { S3TransferUtility } from './S3TransferUtility';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
|
|
4
|
-
describe('S3TransferUtility', () => {
|
|
5
|
-
it('collects the files', () => {
|
|
6
|
-
const testFilesRoot = path.join(__dirname, '../../tests/files');
|
|
7
|
-
const files = S3TransferUtility.GetFiles(path.join(__dirname, '../../tests/files'));
|
|
8
|
-
|
|
9
|
-
expect(files).toBeDefined();
|
|
10
|
-
expect(files).toHaveLength(6);
|
|
11
|
-
|
|
12
|
-
const relativeFiles = files.map((file) => path.relative(testFilesRoot, file));
|
|
13
|
-
expect(relativeFiles).toMatchSnapshot();
|
|
14
|
-
});
|
|
15
|
-
});
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// From: https://stackoverflow.com/a/65862128/878903
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
import { createReadStream, readdirSync } from 'fs';
|
|
6
|
-
import * as path from 'path';
|
|
7
|
-
import * as s3 from '@aws-sdk/client-s3';
|
|
8
|
-
import { Upload } from '@aws-sdk/lib-storage';
|
|
9
|
-
import type { IDeployVersionPreflightResponse } from '@pwrdrvr/microapps-deployer-lib';
|
|
10
|
-
import { contentType } from 'mime-types';
|
|
11
|
-
import pMap from 'p-map';
|
|
12
|
-
|
|
13
|
-
export class S3TransferUtility {
|
|
14
|
-
/**
|
|
15
|
-
* @deprecated 2021-11-27
|
|
16
|
-
*
|
|
17
|
-
* @param s3Path
|
|
18
|
-
* @param destPrefixPath
|
|
19
|
-
* @param bucketName
|
|
20
|
-
* @param preflightResponse
|
|
21
|
-
*/
|
|
22
|
-
public static async UploadDir(
|
|
23
|
-
s3Path: string,
|
|
24
|
-
destPrefixPath: string,
|
|
25
|
-
bucketName: string,
|
|
26
|
-
preflightResponse: IDeployVersionPreflightResponse,
|
|
27
|
-
): Promise<void> {
|
|
28
|
-
// Use temp credentials for S3
|
|
29
|
-
const s3Client = new s3.S3Client({
|
|
30
|
-
maxAttempts: 16,
|
|
31
|
-
credentials: {
|
|
32
|
-
accessKeyId: preflightResponse.awsCredentials.accessKeyId,
|
|
33
|
-
secretAccessKey: preflightResponse.awsCredentials.secretAccessKey,
|
|
34
|
-
sessionToken: preflightResponse.awsCredentials.sessionToken,
|
|
35
|
-
},
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
// console.log('Uploading files to S3');
|
|
39
|
-
const files = S3TransferUtility.GetFiles(s3Path);
|
|
40
|
-
// const pathWithoutAppAndVer = path.join(s3Path, destPrefixPath);
|
|
41
|
-
// for (const filePath of files) {
|
|
42
|
-
// const relFilePath = path.relative(pathWithoutAppAndVer, filePath);
|
|
43
|
-
// console.log(` ${relFilePath}`);
|
|
44
|
-
// }
|
|
45
|
-
|
|
46
|
-
// Use p-map to limit upload parallelism
|
|
47
|
-
await pMap(
|
|
48
|
-
files,
|
|
49
|
-
async (filePath) => {
|
|
50
|
-
// Use 4 multi-part parallel uploads for items > 5 MB
|
|
51
|
-
const upload = new Upload({
|
|
52
|
-
client: s3Client,
|
|
53
|
-
leavePartsOnError: false,
|
|
54
|
-
params: {
|
|
55
|
-
Bucket: bucketName,
|
|
56
|
-
Key: path.relative(s3Path, filePath),
|
|
57
|
-
Body: createReadStream(filePath),
|
|
58
|
-
ContentType: contentType(path.basename(filePath)) || 'application/octet-stream',
|
|
59
|
-
CacheControl: 'max-age=86400; public',
|
|
60
|
-
},
|
|
61
|
-
});
|
|
62
|
-
await upload.done();
|
|
63
|
-
},
|
|
64
|
-
{
|
|
65
|
-
concurrency: 10,
|
|
66
|
-
},
|
|
67
|
-
// await s3.send(
|
|
68
|
-
// new S3.PutObjectCommand({
|
|
69
|
-
// Key: path.relative(s3Path, filePath),
|
|
70
|
-
// Bucket: bucketName,
|
|
71
|
-
// Body: createReadStream(filePath),
|
|
72
|
-
// ContentType: contentType(path.basename(filePath)) || 'application/octet-stream',
|
|
73
|
-
// CacheControl: 'max-age=86400; public',
|
|
74
|
-
// }),
|
|
75
|
-
);
|
|
76
|
-
}
|
|
77
|
-
// Recursive getFiles from
|
|
78
|
-
// https://stackoverflow.com/a/45130990/831465
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Resursively enumerate the files to be uploaded
|
|
82
|
-
* @param dir
|
|
83
|
-
* @returns
|
|
84
|
-
*/
|
|
85
|
-
public static GetFiles(dir: string): string[] {
|
|
86
|
-
const dirents = readdirSync(dir, { withFileTypes: true });
|
|
87
|
-
const files: string[] = [];
|
|
88
|
-
const toScan = dirents.map((dirent) => ({
|
|
89
|
-
path: path.resolve(dir, dirent.name),
|
|
90
|
-
isDirectory: dirent.isDirectory(),
|
|
91
|
-
}));
|
|
92
|
-
|
|
93
|
-
// Iteratively collect all the files in the directories
|
|
94
|
-
// Do not use function call recursion
|
|
95
|
-
while (toScan.length > 0) {
|
|
96
|
-
const dirOrFile = toScan.pop();
|
|
97
|
-
|
|
98
|
-
if (dirOrFile.isDirectory) {
|
|
99
|
-
const direntsChild = readdirSync(dirOrFile.path, { withFileTypes: true });
|
|
100
|
-
const toScanChild = direntsChild.map((dirent) => ({
|
|
101
|
-
path: path.resolve(dirOrFile.path, dirent.name),
|
|
102
|
-
isDirectory: dirent.isDirectory(),
|
|
103
|
-
}));
|
|
104
|
-
Array.prototype.push.apply(toScan, toScanChild);
|
|
105
|
-
} else {
|
|
106
|
-
files.push(dirOrFile.path);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// Reverse the array so that the files are in the same order as the original
|
|
111
|
-
return files.reverse();
|
|
112
|
-
}
|
|
113
|
-
}
|
package/src/lib/S3Uploader.ts
DELETED
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
import * as path from 'path';
|
|
2
|
-
import type { IDeployVersionPreflightResponse } from '@pwrdrvr/microapps-deployer-lib';
|
|
3
|
-
import * as fs from 'fs-extra';
|
|
4
|
-
import { IConfig } from '../config/Config';
|
|
5
|
-
import { S3TransferUtility } from './S3TransferUtility';
|
|
6
|
-
|
|
7
|
-
export class S3Uploader {
|
|
8
|
-
/**
|
|
9
|
-
* Copy files to local upload directory
|
|
10
|
-
* @param config
|
|
11
|
-
* @param s3UploadPath
|
|
12
|
-
* @param preflightResponse
|
|
13
|
-
*/
|
|
14
|
-
public static async CopyToUploadDir(config: IConfig, s3UploadPath: string): Promise<void> {
|
|
15
|
-
const { destinationPrefix } = S3Uploader.ParseUploadPath(s3UploadPath);
|
|
16
|
-
|
|
17
|
-
// Make a local root dir for the upload
|
|
18
|
-
const tempUploadPath = path.join(S3Uploader._tempDir, destinationPrefix);
|
|
19
|
-
await S3Uploader.removeTempDirIfExists();
|
|
20
|
-
await fs.mkdir(tempUploadPath, { recursive: true });
|
|
21
|
-
|
|
22
|
-
// Copy the files in the source dir to the root dir
|
|
23
|
-
// Note: It would be faster to move the files, then move them back
|
|
24
|
-
await fs.copy(config.app.staticAssetsPath, tempUploadPath);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
public static ParseUploadPath(s3UploadPath: string): {
|
|
28
|
-
bucketName: string;
|
|
29
|
-
destinationPrefix: string;
|
|
30
|
-
} {
|
|
31
|
-
// Parse the S3 Source URI
|
|
32
|
-
const uri = new URL(s3UploadPath);
|
|
33
|
-
const bucketName = uri.host;
|
|
34
|
-
const destinationPrefix = uri.pathname.length >= 1 ? uri.pathname.slice(1) : '';
|
|
35
|
-
|
|
36
|
-
return { bucketName, destinationPrefix };
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Upload files to S3
|
|
41
|
-
* @deprecated 2021-11-27
|
|
42
|
-
* @param config
|
|
43
|
-
* @param s3UploadPath
|
|
44
|
-
* @param preflightResponse
|
|
45
|
-
*/
|
|
46
|
-
public static async Upload(
|
|
47
|
-
config: IConfig,
|
|
48
|
-
s3UploadPath: string,
|
|
49
|
-
preflightResponse: IDeployVersionPreflightResponse,
|
|
50
|
-
): Promise<void> {
|
|
51
|
-
try {
|
|
52
|
-
const { destinationPrefix, bucketName } = S3Uploader.ParseUploadPath(s3UploadPath);
|
|
53
|
-
|
|
54
|
-
// Make a local root dir for the upload
|
|
55
|
-
const tempUploadPath = path.join(S3Uploader._tempDir, destinationPrefix);
|
|
56
|
-
await S3Uploader.removeTempDirIfExists();
|
|
57
|
-
await fs.mkdir(tempUploadPath, { recursive: true });
|
|
58
|
-
|
|
59
|
-
// Copy the files in the source dir to the root dir
|
|
60
|
-
// Note: It would be faster to move the files, then move them back
|
|
61
|
-
// FIXME: Use p-map for controlled parallelism
|
|
62
|
-
await fs.copy(config.app.staticAssetsPath, tempUploadPath);
|
|
63
|
-
|
|
64
|
-
// Do the upload
|
|
65
|
-
await S3TransferUtility.UploadDir(
|
|
66
|
-
this._tempDir,
|
|
67
|
-
destinationPrefix,
|
|
68
|
-
bucketName,
|
|
69
|
-
preflightResponse,
|
|
70
|
-
);
|
|
71
|
-
} finally {
|
|
72
|
-
// Delete the directory, now that it's uploaded or if we failed
|
|
73
|
-
await S3Uploader.removeTempDirIfExists();
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
public static async removeTempDirIfExists(): Promise<void> {
|
|
78
|
-
try {
|
|
79
|
-
const stats = await fs.stat(S3Uploader._tempDir);
|
|
80
|
-
if (stats.isDirectory()) {
|
|
81
|
-
await fs.rm(S3Uploader._tempDir, { recursive: true });
|
|
82
|
-
}
|
|
83
|
-
} catch {
|
|
84
|
-
// Don't care
|
|
85
|
-
// fs.stat will throw if file/dir does not exist
|
|
86
|
-
// Since we want the directory deleted this is ok
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
private static readonly _tempDir = './deploytool-temp';
|
|
91
|
-
public static get TempDir(): string {
|
|
92
|
-
return S3Uploader._tempDir;
|
|
93
|
-
}
|
|
94
|
-
}
|