@tremho/mist-lift 2.2.8 → 2.4.0
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 +9 -1
- package/build/commands/actions/updateDeployedPermissions.js +109 -0
- package/build/commands/actions/updateDeployedPermissions.js.map +1 -0
- package/build/commands/builtin/ApiDocMaker.js +18 -10
- package/build/commands/builtin/ApiDocMaker.js.map +1 -1
- package/build/commands/builtin/BuiltInHandler.js +6 -3
- package/build/commands/builtin/BuiltInHandler.js.map +1 -1
- package/build/commands/builtin/ExportWebroot.js +242 -0
- package/build/commands/builtin/ExportWebroot.js.map +1 -0
- package/build/commands/builtin/StageWebrootZip.js +10 -6
- package/build/commands/builtin/StageWebrootZip.js.map +1 -1
- package/build/commands/builtin/prebuilt-zips/API.zip +0 -0
- package/build/commands/builtin/prebuilt-zips/FileServe.zip +0 -0
- package/build/commands/builtin/prebuilt-zips/Webroot.zip +0 -0
- package/build/commands/builtin/webroot-export/s3webroot.js +117 -0
- package/build/commands/builtin/webroot-export/s3webroot.js.map +1 -0
- package/build/commands/deploy.js +6 -4
- package/build/commands/deploy.js.map +1 -1
- package/build/commands/package.js +31 -1
- package/build/commands/package.js.map +1 -1
- package/build/commands/publish.js +40 -13
- package/build/commands/publish.js.map +1 -1
- package/build/commands/start.js +2 -1
- package/build/commands/start.js.map +1 -1
- package/build/commands/update.js +1 -0
- package/build/commands/update.js.map +1 -1
- package/build/expressRoutes/all.js +1 -0
- package/build/expressRoutes/all.js.map +1 -1
- package/build/expressRoutes/functionBinder.js +159 -17
- package/build/expressRoutes/functionBinder.js.map +1 -1
- package/build/lib/DirectoryUtils.js +2 -1
- package/build/lib/DirectoryUtils.js.map +1 -1
- package/build/lib/IdSrc.js +29 -5
- package/build/lib/IdSrc.js.map +1 -1
- package/build/lib/TypeCheck.js +1204 -0
- package/build/lib/TypeCheck.js.map +1 -0
- package/build/lib/executeCommand.js +1 -1
- package/build/lib/executeCommand.js.map +1 -1
- package/build/lib/openAPI/openApiConstruction.js +238 -54
- package/build/lib/openAPI/openApiConstruction.js.map +1 -1
- package/build/lift.js +1 -1
- package/build/lift.js.map +1 -1
- package/package.json +5 -2
- package/src/commands/actions/updateDeployedPermissions.ts +80 -0
- package/src/commands/builtin/ApiDocMaker.ts +17 -10
- package/src/commands/builtin/BuiltInHandler.ts +7 -2
- package/src/commands/builtin/ExportWebroot.ts +195 -0
- package/src/commands/builtin/StageWebrootZip.ts +13 -5
- package/src/commands/builtin/prebuilt-zips/API.zip +0 -0
- package/src/commands/builtin/prebuilt-zips/FileServe.zip +0 -0
- package/src/commands/builtin/prebuilt-zips/Webroot.zip +0 -0
- package/src/commands/builtin/webroot-export/s3webroot.ts +78 -0
- package/src/commands/deploy.ts +6 -4
- package/src/commands/package.ts +33 -2
- package/src/commands/publish.ts +37 -12
- package/src/commands/start.ts +2 -1
- package/src/commands/update.ts +1 -0
- package/src/expressRoutes/all.ts +1 -0
- package/src/expressRoutes/functionBinder.ts +152 -16
- package/src/lib/DirectoryUtils.ts +2 -1
- package/src/lib/IdSrc.ts +17 -4
- package/src/lib/TypeCheck.ts +1168 -0
- package/src/lib/executeCommand.ts +1 -1
- package/src/lib/openAPI/openApiConstruction.ts +225 -41
- package/src/lift.ts +1 -1
- package/templateData/function-main-ts +8 -1
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import * as ac from 'ansi-colors'
|
|
2
|
+
|
|
3
|
+
import path from 'path'
|
|
4
|
+
import fs from 'fs'
|
|
5
|
+
import { recurseDirectory } from '../../lib/DirectoryUtils'
|
|
6
|
+
import { decoratedName, getAccountId } from '../../lib/IdSrc'
|
|
7
|
+
import { getAWSCredentials, getSettings } from '../../lib/LiftConfig'
|
|
8
|
+
import { resolvePaths } from '../../lib/pathResolve'
|
|
9
|
+
import { LambdaClient, AddPermissionCommand } from '@aws-sdk/client-lambda'
|
|
10
|
+
|
|
11
|
+
// let projectPaths: { basePath: string, buildPath: string, functionPath: string, packagePath: string, verified: boolean }
|
|
12
|
+
|
|
13
|
+
export default async function updateDeployedPermissions (apiId: string): Promise<boolean | number | undefined> {
|
|
14
|
+
const projectPaths = resolvePaths()
|
|
15
|
+
if (!projectPaths.verified) {
|
|
16
|
+
console.log(ac.bold.magenta('current directory is not at project root'))
|
|
17
|
+
return -1
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const funcsToDeploy: string[] = []
|
|
21
|
+
let firstDepth = 0
|
|
22
|
+
recurseDirectory(projectPaths.functionPath, (filepath, stats) => {
|
|
23
|
+
const depth = filepath.split(path.sep).length
|
|
24
|
+
if (firstDepth === 0) firstDepth = depth
|
|
25
|
+
if (stats.isDirectory() && depth === firstDepth) {
|
|
26
|
+
funcsToDeploy.push(path.basename(filepath))
|
|
27
|
+
}
|
|
28
|
+
return false
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
const accountId: string = await getAccountId()
|
|
32
|
+
const region: string = getSettings().awsPreferredRegion ?? ''
|
|
33
|
+
|
|
34
|
+
const client = new LambdaClient(getAWSCredentials())
|
|
35
|
+
|
|
36
|
+
for (const funcName of funcsToDeploy) {
|
|
37
|
+
// read the def file and get the method from there
|
|
38
|
+
const defPath = path.join(projectPaths.functionPath, funcName, 'src', 'definition.json')
|
|
39
|
+
const def = JSON.parse(fs.readFileSync(defPath).toString())
|
|
40
|
+
const method: string = def.method
|
|
41
|
+
const pathMap: string = def.pathMap
|
|
42
|
+
|
|
43
|
+
const arn = generateSourceArnForApiGateway(region, accountId, apiId, method, pathMap)
|
|
44
|
+
const dname = decoratedName(funcName)
|
|
45
|
+
console.log(ac.grey.italic('update permissions for resource ' + arn))
|
|
46
|
+
const command: any = new AddPermissionCommand({
|
|
47
|
+
FunctionName: dname,
|
|
48
|
+
StatementId: 'InvokePermission',
|
|
49
|
+
Action: 'lambda:invokeFunction',
|
|
50
|
+
Principal: 'apigateway.amazonaws.com',
|
|
51
|
+
SourceArn: arn
|
|
52
|
+
})
|
|
53
|
+
await client.send(command)
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Generates the correct SourceArn to authorize API Gateway to invoke a Lambda function.
|
|
59
|
+
*
|
|
60
|
+
* @param region - The AWS region, e.g., 'us-west-1'
|
|
61
|
+
* @param accountId - Your AWS account ID
|
|
62
|
+
* @param apiId - The API Gateway ID, e.g., 'sfr7yltmc3'
|
|
63
|
+
* @param method - The HTTP method, e.g., 'POST'
|
|
64
|
+
* @param routePath - The API route path, e.g., '/upstart/{artistId}/{id}'
|
|
65
|
+
* @returns The complete SourceArn string
|
|
66
|
+
*/
|
|
67
|
+
export function generateSourceArnForApiGateway (
|
|
68
|
+
region: string,
|
|
69
|
+
accountId: string,
|
|
70
|
+
apiId: string,
|
|
71
|
+
method: string,
|
|
72
|
+
routePath: string
|
|
73
|
+
): string {
|
|
74
|
+
// Clean leading slashes and replace path params with wildcards
|
|
75
|
+
const cleanedPath = routePath
|
|
76
|
+
.replace(/^\/+/, '') // remove leading slashes
|
|
77
|
+
.replace(/{[^}]+}/g, '*') // replace path params with *
|
|
78
|
+
|
|
79
|
+
return `arn:aws:execute-api:${region}:${accountId}:${apiId}/*/${method.toUpperCase()}/${cleanedPath}`
|
|
80
|
+
}
|
|
@@ -5,6 +5,7 @@ import { GetWebrootServePaths } from '../../lib/openAPI/WebrootFileSupport'
|
|
|
5
5
|
import path from 'path'
|
|
6
6
|
// import * as ac from 'ansi-colors'
|
|
7
7
|
import { decoratedName } from '../../lib/IdSrc'
|
|
8
|
+
import { getWebrootSettings } from './ExportWebroot'
|
|
8
9
|
|
|
9
10
|
export async function MakePublicApiDoc
|
|
10
11
|
(
|
|
@@ -22,29 +23,32 @@ export async function MakeBuiltinApiDoc
|
|
|
22
23
|
const defs = gatherFunctionDefinitions()
|
|
23
24
|
// console.log(ac.gray.dim('>> after gatherfunctions'), defs)
|
|
24
25
|
// console.log(ac.gray.dim('>>> addBuiltInDefinitions '))
|
|
25
|
-
|
|
26
|
+
const wrs = await getWebrootSettings()
|
|
27
|
+
const withWebroot = (wrs.webrootMethod ?? 'SELF') === 'SELF'
|
|
28
|
+
// console.log("wrs.webrootMethod=",wrs.webrootMethod)
|
|
29
|
+
addBuiltInDefinitions(defs, withWebroot)
|
|
26
30
|
// console.log(ac.gray.dim('>> after addBuiltIns'), defs)
|
|
27
31
|
// console.log(ac.gray.dim('>>> buildOpenApi '))
|
|
28
|
-
return await buildOpenApi(defs,
|
|
32
|
+
return await buildOpenApi(defs, true, true, yamlFile)
|
|
29
33
|
}
|
|
30
34
|
|
|
31
|
-
export function addBuiltInDefinitions (defs: any[]): void {
|
|
35
|
+
export function addBuiltInDefinitions (defs: any[], withWebroot: boolean): void {
|
|
32
36
|
// console.warn("NOT ADDING ANY BUILTIN API INTEGRATIONS")
|
|
33
37
|
// console.log("ADDING apiDef");
|
|
34
38
|
// console.log(ac.gray.dim('>>>> pushing apiDef '), apiDef)
|
|
35
39
|
defs.push(apiDef)
|
|
40
|
+
// console.log("withWebroot = "+withWebroot)
|
|
36
41
|
// console.log(ac.gray.dim('>>>> pushing webrootDef '), webrootDef)
|
|
37
|
-
defs.push(webrootDef)
|
|
42
|
+
defs.push(webrootDef) // we need to do this to support index or anything else.
|
|
38
43
|
|
|
39
44
|
// console.log(ac.gray.dim('>>>> Adding webroot literals '))
|
|
40
45
|
// console.warn("Adding webroot literals");
|
|
41
46
|
// do just /docs and see how that goes
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
fsdef.
|
|
45
|
-
fsdef
|
|
46
|
-
|
|
47
|
-
*/
|
|
47
|
+
// const fsdef = Object.assign({}, fileServeDef) // copy
|
|
48
|
+
// fsdef.name = decoratedName('fileserve_docs')
|
|
49
|
+
// fsdef.pathMap = '/docs/{path}'
|
|
50
|
+
// defs.push(fsdef)
|
|
51
|
+
// }
|
|
48
52
|
const roots = GetWebrootServePaths()
|
|
49
53
|
// console.log("roots", roots)
|
|
50
54
|
// console.log(ac.gray.dim('>>>> roots here: '), roots)
|
|
@@ -55,6 +59,9 @@ export function addBuiltInDefinitions (defs: any[]): void {
|
|
|
55
59
|
let rootName = rootPath
|
|
56
60
|
// console.log(ac.gray.dim('>> rootName = '+rootName))
|
|
57
61
|
while (rootName.includes('/')) rootName = rootName.replace('/', '').toLowerCase().trim()
|
|
62
|
+
// TODO: Trying to exclude here seems to remove our ability to get anything from root (webroot, should be there already)
|
|
63
|
+
// console.log('fileserve '+ rootName)
|
|
64
|
+
// if(!withWebroot && rootName !== 'docs') continue; // only copy docs for non-self export types
|
|
58
65
|
// console.log(ac.gray.dim('>> past stupid error = '+rootName))
|
|
59
66
|
const fileserve = Object.assign({}, fileServeDef) // copy
|
|
60
67
|
fileserve.name = decoratedName('fileserve_' + rootName)
|
|
@@ -9,11 +9,16 @@ import path from 'path'
|
|
|
9
9
|
|
|
10
10
|
export async function DeployWebrootBuiltIn
|
|
11
11
|
(
|
|
12
|
+
externalizedFolders: boolean = true
|
|
12
13
|
): Promise<void> {
|
|
13
14
|
// console.warn(">> DeployWebrootBuiltIn")
|
|
15
|
+
// const withRoot = externalizedFolders
|
|
16
|
+
// const withFolders = true
|
|
14
17
|
const wrZip = await StageWebrootZip()
|
|
15
|
-
|
|
16
|
-
|
|
18
|
+
const wrName = decoratedName('Webroot')
|
|
19
|
+
// console.log(">> Deploy Webroot Builtin from "+wrZip+" as "+wrName)
|
|
20
|
+
|
|
21
|
+
await DeployBuiltInZip(wrName, wrZip)
|
|
17
22
|
// remove temp zip when done
|
|
18
23
|
// console.warn("a.zip is left behind")
|
|
19
24
|
fs.rmSync(wrZip, { recursive: true })
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import * as path from 'path'
|
|
2
|
+
import * as fs from 'fs'
|
|
3
|
+
import * as ac from 'ansi-colors'
|
|
4
|
+
import { resolvePaths } from '../../lib/pathResolve'
|
|
5
|
+
import { recurseDirectory } from '../../lib/DirectoryUtils'
|
|
6
|
+
// import { isNewer } from '../../lib/fileCompare'
|
|
7
|
+
import { executeCommand } from '../../lib/executeCommand'
|
|
8
|
+
// import { mkdirSync } from 'fs'
|
|
9
|
+
import { DeployRootFileserves, DeployWebrootBuiltIn } from './BuiltInHandler'
|
|
10
|
+
// import { ServiceSettingsData } from '@tremho/inverse-y'
|
|
11
|
+
import { exportWebrootToS3, getS3Prefix } from './webroot-export/s3webroot'
|
|
12
|
+
|
|
13
|
+
/*
|
|
14
|
+
Here we want to handle exporting the webroot to other serving sources according to configuration.
|
|
15
|
+
|
|
16
|
+
- Read the config options
|
|
17
|
+
- enumerate the webroot and find recent changes
|
|
18
|
+
- write these file paths to a temp file
|
|
19
|
+
- per config, call the handler that will do this
|
|
20
|
+
- to S3
|
|
21
|
+
- to script
|
|
22
|
+
later:
|
|
23
|
+
- to Blob ?
|
|
24
|
+
-
|
|
25
|
+
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
/*
|
|
29
|
+
Script will be called with comma delimited list of files as arg 1, and options (string) as arg2
|
|
30
|
+
*/
|
|
31
|
+
export class WebrootScriptOptions {
|
|
32
|
+
public scriptName = '' // name of script to call (relative to project root)
|
|
33
|
+
public options = '' // options passed as second parameter to script (see comment above)
|
|
34
|
+
}
|
|
35
|
+
export class WebrootS3Options {
|
|
36
|
+
public unused = '' // empty (lint)
|
|
37
|
+
}
|
|
38
|
+
export class WebrootDefaultOptions {
|
|
39
|
+
public unused = '' // empty (lint)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export type WebrootOptions = WebrootDefaultOptions | WebrootScriptOptions | WebrootS3Options
|
|
43
|
+
|
|
44
|
+
/*
|
|
45
|
+
For non-SELF types, only the files *not* in subdirectories will be packaged to the deployed webroot
|
|
46
|
+
*/
|
|
47
|
+
export enum WebrootExportType {
|
|
48
|
+
SELF = 'SELF', // Webroot is packaged and deployed per existing implementation, including all subdirectories
|
|
49
|
+
SCRIPT = 'SCRIPT', // a build-time script is called to copy all updated files to their target
|
|
50
|
+
S3 = 'S3' // built-in function (instead of script) is called for an S3 target
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/*
|
|
54
|
+
This is what webrootConfig.json looks like
|
|
55
|
+
*/
|
|
56
|
+
export class WebrootExportConfig {
|
|
57
|
+
public type: WebrootExportType = WebrootExportType.SELF
|
|
58
|
+
public options: WebrootOptions = new WebrootDefaultOptions()
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
let basePath = ''
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Exports the webroot according to configuration
|
|
65
|
+
*/
|
|
66
|
+
export async function ExportWebroot (): Promise<any> {
|
|
67
|
+
const projectPaths = resolvePaths()
|
|
68
|
+
basePath = projectPaths.basePath
|
|
69
|
+
const webrootConfig = readWebrootConfig(path.join(basePath, 'webrootConfig.json'))
|
|
70
|
+
// console.log(">> ExportWebroot", {webrootConfig})
|
|
71
|
+
|
|
72
|
+
const fla = await getUpdatedExportFileList()
|
|
73
|
+
switch (webrootConfig.type) {
|
|
74
|
+
case WebrootExportType.SELF:
|
|
75
|
+
await exportSelf()
|
|
76
|
+
break
|
|
77
|
+
case WebrootExportType.S3:
|
|
78
|
+
await exportWebrootToS3(fla, webrootConfig.options as WebrootS3Options)
|
|
79
|
+
break
|
|
80
|
+
case WebrootExportType.SCRIPT:
|
|
81
|
+
await exportScript(fla, webrootConfig.options as WebrootScriptOptions)
|
|
82
|
+
break
|
|
83
|
+
default: {
|
|
84
|
+
throw new Error(`UNSUPPORTED WEBROOT EXPORT ${WebrootExportType[webrootConfig.type]}`)
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
export async function getWebrootSettings (): Promise<{ webrootMethod: string, webrootBaseUrl: string }> {
|
|
89
|
+
const projectPaths = resolvePaths()
|
|
90
|
+
basePath = projectPaths.basePath
|
|
91
|
+
const webrootConfig = readWebrootConfig(path.join(basePath, 'webrootConfig.json'))
|
|
92
|
+
let baseUrl = ''
|
|
93
|
+
switch (webrootConfig.type) {
|
|
94
|
+
case WebrootExportType.SELF:
|
|
95
|
+
baseUrl = ''
|
|
96
|
+
break
|
|
97
|
+
case WebrootExportType.S3:
|
|
98
|
+
baseUrl = await getS3Prefix()
|
|
99
|
+
break
|
|
100
|
+
case WebrootExportType.SCRIPT: {
|
|
101
|
+
const options = webrootConfig.options as WebrootScriptOptions
|
|
102
|
+
const scriptPath = path.join(basePath, options.scriptName)
|
|
103
|
+
const out = await executeCommand(scriptPath, ['--prefix'], basePath, false)
|
|
104
|
+
baseUrl = out.stdStr.trim()
|
|
105
|
+
break
|
|
106
|
+
}
|
|
107
|
+
default: {
|
|
108
|
+
const unreachable: never = webrootConfig.type
|
|
109
|
+
throw new Error(`UNSUPPORTED WEBROOT EXPORT ${unreachable}`)
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return {
|
|
113
|
+
webrootMethod: webrootConfig.type.toString(),
|
|
114
|
+
webrootBaseUrl: baseUrl
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
let warned = false
|
|
119
|
+
function readWebrootConfig (configPath: string): WebrootExportConfig {
|
|
120
|
+
let conf = new WebrootExportConfig()
|
|
121
|
+
let content = ''
|
|
122
|
+
// console.log("... reading from "+configPath)
|
|
123
|
+
try {
|
|
124
|
+
// console.log(" >> readWebrootConfig")
|
|
125
|
+
content = fs.readFileSync(configPath).toString()
|
|
126
|
+
conf = JSON.parse(content)
|
|
127
|
+
} catch (e: any) {
|
|
128
|
+
if (!warned) {
|
|
129
|
+
warned = true
|
|
130
|
+
console.error(ac.yellow.bold('Warning: Failed to read or parse ' + configPath))
|
|
131
|
+
console.warn(ac.yellow.bold.dim("Falling back to 'self' publish mode"))
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return conf
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
async function exportSelf (): Promise<void> {
|
|
139
|
+
// zip up everything
|
|
140
|
+
// console.log(">> exportSelf")
|
|
141
|
+
// console.log(" >> deployWebrootBuiltIn")
|
|
142
|
+
await DeployWebrootBuiltIn(false)
|
|
143
|
+
// console.log(" >> deployRootFileserves")
|
|
144
|
+
await DeployRootFileserves()
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
async function exportScript (fla: string[], options: WebrootScriptOptions) {
|
|
148
|
+
// console.log(">> exportScript")
|
|
149
|
+
// console.log(" >> DeployWebrootBuiltIn")
|
|
150
|
+
// await DeployWebrootBuiltIn(true)
|
|
151
|
+
console.log(ac.bold.green(`calling webroot exportScript ${options.scriptName}`))
|
|
152
|
+
// console.log("files", fla)
|
|
153
|
+
const fl = fla.join(',')
|
|
154
|
+
const args = [fl]
|
|
155
|
+
// args.unshift(options.options)
|
|
156
|
+
// console.log("args", args)
|
|
157
|
+
|
|
158
|
+
const scriptPath = path.join(basePath, options.scriptName)
|
|
159
|
+
// console.log("Executing script", scriptPath)
|
|
160
|
+
await executeCommand(scriptPath, args, basePath, true)
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
async function getUpdatedExportFileList (): Promise<string[]> {
|
|
164
|
+
// console.log(">> getUpdatedExportFileList")
|
|
165
|
+
// find the last published time from .published file
|
|
166
|
+
let lastPublished = 0
|
|
167
|
+
try {
|
|
168
|
+
const pubjson = JSON.parse(fs.readFileSync(path.join(basePath, '.published')).toString())
|
|
169
|
+
lastPublished = pubjson.time
|
|
170
|
+
// console.log("last published ", lastPublished)
|
|
171
|
+
} catch (e: any) {
|
|
172
|
+
console.warn(ac.yellow.italic.dim('no .published information available - full export'))
|
|
173
|
+
}
|
|
174
|
+
const outbin: string[] = []
|
|
175
|
+
// enumerate at webroot and files from all non-root directories
|
|
176
|
+
const folder = path.join(basePath, 'webroot')
|
|
177
|
+
const rootpathsteps = folder.split(path.sep).length
|
|
178
|
+
const enumerating = true
|
|
179
|
+
|
|
180
|
+
function gatherFiles (filepath: string, stats: fs.Stats): boolean {
|
|
181
|
+
// console.log(filepath, {steps:filepath.split(path.sep).length, rootpathsteps, isDir:stats.isDirectory()})
|
|
182
|
+
if (filepath.split(path.sep).length > rootpathsteps + 1) {
|
|
183
|
+
// console.log({filepath, mtime:stats.mtime.getTime(), lastPublished})
|
|
184
|
+
if (stats.mtime.getTime() >= lastPublished) {
|
|
185
|
+
filepath = '+' + filepath
|
|
186
|
+
// console.log("will update "+filepath)
|
|
187
|
+
}
|
|
188
|
+
outbin.push(filepath)
|
|
189
|
+
}
|
|
190
|
+
return false
|
|
191
|
+
}
|
|
192
|
+
// console.log("recursing folder ", folder)
|
|
193
|
+
await recurseDirectory(folder, gatherFiles)
|
|
194
|
+
return outbin
|
|
195
|
+
}
|
|
@@ -11,6 +11,8 @@ import { rmSync } from 'fs'
|
|
|
11
11
|
|
|
12
12
|
export async function StageWebrootZip
|
|
13
13
|
(
|
|
14
|
+
withRoot: boolean = true,
|
|
15
|
+
withFolders: boolean = true
|
|
14
16
|
): Promise<string> {
|
|
15
17
|
// console.log(">>>> staging webroot to zip")
|
|
16
18
|
const projectPaths = resolvePaths()
|
|
@@ -43,6 +45,7 @@ export async function StageWebrootZip
|
|
|
43
45
|
await fs.mkdirSync(zipFilesPath)
|
|
44
46
|
|
|
45
47
|
// todo: read the redirects.json file
|
|
48
|
+
// todo: Document as deprecated
|
|
46
49
|
let redirected: string[] = []
|
|
47
50
|
try {
|
|
48
51
|
const redir = JSON.parse(fs.readFileSync(path.join(webroot, 'redirects.json')).toString())
|
|
@@ -55,13 +58,18 @@ export async function StageWebrootZip
|
|
|
55
58
|
// console.log(">>>> enumerating "+webroot)
|
|
56
59
|
await recurseDirectory(webroot, (filepath, stats) => {
|
|
57
60
|
const relPath = filepath.substring(webroot.length)
|
|
58
|
-
if (stats.isDirectory()) {
|
|
61
|
+
if (stats.isDirectory() && withFolders) {
|
|
59
62
|
fs.mkdirSync(zipFilesPath + relPath, { recursive: true })
|
|
60
63
|
} else {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
64
|
+
if (
|
|
65
|
+
(relPath.includes(path.sep) && withFolders) ||
|
|
66
|
+
((!relPath.includes(path.sep)) && withRoot)
|
|
67
|
+
) {
|
|
68
|
+
// TODO: Deprecate redirection. we'll continue to supoort it here, though for now
|
|
69
|
+
if (!redirected.includes(relPath.substring(1))) {
|
|
70
|
+
// console.log(ac.grey.dim('>> copying...'))
|
|
71
|
+
fs.copyFileSync(filepath, zipFilesPath + relPath) // copy only if not in redirected list
|
|
72
|
+
}
|
|
65
73
|
}
|
|
66
74
|
}
|
|
67
75
|
return false
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { S3Client } from '@aws-sdk/client-s3'
|
|
2
|
+
import { s3ListObjects, s3CreateBucket, s3UploadFile, s3Delete, S3ActionsLog } from '@tremho/basic-s3-actions'
|
|
3
|
+
import * as fs from 'fs'
|
|
4
|
+
import * as ac from 'ansi-colors'
|
|
5
|
+
import { WebrootS3Options, WebrootScriptOptions } from '../ExportWebroot'
|
|
6
|
+
import { DeployRootFileserves, DeployWebrootBuiltIn } from '../BuiltInHandler'
|
|
7
|
+
|
|
8
|
+
export async function exportWebrootToS3 (exportFileList: string[], options?: WebrootS3Options) {
|
|
9
|
+
const bucketName = determineBucketName()
|
|
10
|
+
console.log(ac.green.bold('webroot export to s3 bucket name ' + bucketName))
|
|
11
|
+
let existing: string[] = []
|
|
12
|
+
try {
|
|
13
|
+
// console.log("fetching existing")
|
|
14
|
+
existing = await getExistingDeployedFileList(bucketName)
|
|
15
|
+
} catch (e: any) {
|
|
16
|
+
console.log(ac.blue.italic('creating webroot bucket ' + bucketName))
|
|
17
|
+
await s3CreateBucket(bucketName, true)
|
|
18
|
+
// console.log("bucket created")
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
console.log(ac.blue.italic('Deploying base webroot handling'))
|
|
22
|
+
await DeployWebrootBuiltIn(true)
|
|
23
|
+
await DeployRootFileserves()
|
|
24
|
+
|
|
25
|
+
// console.log("existing ", existing)
|
|
26
|
+
|
|
27
|
+
let update = false
|
|
28
|
+
for (let file of exportFileList) {
|
|
29
|
+
update = (file.charAt(0) == '+')
|
|
30
|
+
if (update) file = file.substring(1)
|
|
31
|
+
const i = file.indexOf('/webroot/') + 9
|
|
32
|
+
const sfile = file.substring(i)
|
|
33
|
+
if (!sfile) continue
|
|
34
|
+
if (sfile.substring(0, 4) === 'docs') continue // keep these in self-serve only
|
|
35
|
+
const xi = existing.indexOf(sfile)
|
|
36
|
+
let disp = 'created'
|
|
37
|
+
if (xi !== -1) {
|
|
38
|
+
existing.splice(xi, 1)
|
|
39
|
+
disp = 'updated'
|
|
40
|
+
}
|
|
41
|
+
if (update) {
|
|
42
|
+
// console.log(sfile+"...")
|
|
43
|
+
try {
|
|
44
|
+
await s3UploadFile(bucketName, file, sfile)
|
|
45
|
+
console.log(ac.green.italic(`${disp} ${sfile}`))
|
|
46
|
+
} catch (e: any) {
|
|
47
|
+
break
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
for (const leftover of existing) {
|
|
52
|
+
await s3Delete(bucketName, leftover)
|
|
53
|
+
console.log(ac.green.italic(`deleted ${leftover}`))
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function determineBucketName () {
|
|
58
|
+
let pkg: any = {}
|
|
59
|
+
try {
|
|
60
|
+
pkg = JSON.parse(fs.readFileSync('./package.json').toString())
|
|
61
|
+
} catch (e: any) {
|
|
62
|
+
console.error(ac.bold.red('Failed to read package.json ' + e.message))
|
|
63
|
+
}
|
|
64
|
+
return (pkg.author + '-' + pkg.name).toLowerCase()
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async function getExistingDeployedFileList (bucketName: string) {
|
|
68
|
+
// S3ActionsLog.setMinimumLevel('Console', 'trace')
|
|
69
|
+
// S3ActionsLog.Debug("Getting bucket list for "+bucketName)
|
|
70
|
+
const list = await s3ListObjects(bucketName)
|
|
71
|
+
// S3ActionsLog.setMinimumLevel('Console', 'error')
|
|
72
|
+
return list
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function getS3Prefix () {
|
|
76
|
+
const name = determineBucketName()
|
|
77
|
+
return `https://${name}.s3.us-west-1.amazonaws.com/`
|
|
78
|
+
}
|
package/src/commands/deploy.ts
CHANGED
|
@@ -106,11 +106,11 @@ export async function deployPackage (
|
|
|
106
106
|
try {
|
|
107
107
|
def = JSON.parse(fs.readFileSync(defFile).toString())
|
|
108
108
|
} catch (e: any) {
|
|
109
|
-
// hack for assigning a definition -- the defs from
|
|
110
|
-
if (funcName
|
|
109
|
+
// hack for assigning a definition -- the defs from the MistBuiltIn def file don't appear here
|
|
110
|
+
if (funcName.includes('Webroot')) {
|
|
111
111
|
def.name = 'Webroot'
|
|
112
112
|
def.timeoutSeconds = 8
|
|
113
|
-
def.memorySize =
|
|
113
|
+
def.memorySize = 8192
|
|
114
114
|
}
|
|
115
115
|
}
|
|
116
116
|
const timeout: number = def.timeoutSeconds ?? 0 // zero will mean default (3 seconds on AWS)
|
|
@@ -135,7 +135,9 @@ export async function deployPackage (
|
|
|
135
135
|
const response: any = await CreateCloudFunction(dFuncName, zipFile, timeout, memorySize)
|
|
136
136
|
const parts = response.FunctionArn.split(':')
|
|
137
137
|
const principal = parts[4]
|
|
138
|
-
|
|
138
|
+
if (dFuncName.includes('Webroot') || dFuncName.includes('FileServe')) {
|
|
139
|
+
await AddPermissions(client, dFuncName, principal)
|
|
140
|
+
}
|
|
139
141
|
let deployMsg: string = `Successfully deployed ${funcName}`
|
|
140
142
|
// console.log(ac.gray.dim('>> deploy trace 1'))
|
|
141
143
|
if (memorySize > 0 || timeout > 0) {
|
package/src/commands/package.ts
CHANGED
|
@@ -11,6 +11,8 @@ import { executeCommand } from '../lib/executeCommand'
|
|
|
11
11
|
import { isNewerFile } from '../lib/fileCompare'
|
|
12
12
|
import { doBuildAsync } from './build'
|
|
13
13
|
import { FolderToZip } from '../lib/utils'
|
|
14
|
+
import { getWebrootSettings } from './builtin/ExportWebroot'
|
|
15
|
+
import { getServiceSettings, setAws, setWebroot } from '@tremho/inverse-y'
|
|
14
16
|
|
|
15
17
|
// test then package
|
|
16
18
|
export async function doPackageAsync (
|
|
@@ -123,6 +125,8 @@ async function packageFunction (funcName: string): Promise<number> {
|
|
|
123
125
|
// - write out new package.json to workPath
|
|
124
126
|
// console.log("writing package.json", pkgjson)
|
|
125
127
|
fs.writeFileSync(path.join(workPath, 'package.json'), JSON.stringify(pkgjson, null, 2))
|
|
128
|
+
|
|
129
|
+
const webrootExport = await getWebrootSettings()
|
|
126
130
|
// - execute npm i at workpath, create node_modules
|
|
127
131
|
await executeCommand('npm i', [], workPath).then(() => {
|
|
128
132
|
// copy the lambda function
|
|
@@ -148,10 +152,37 @@ async function packageFunction (funcName: string): Promise<number> {
|
|
|
148
152
|
const runmainPath = path.join(workPath, 'runmain.mjs')
|
|
149
153
|
fs.writeFileSync(runmainPath, fs.readFileSync(templatePath))
|
|
150
154
|
|
|
155
|
+
// put svcsettings.json into place
|
|
156
|
+
|
|
157
|
+
// Get publish Url from existing .published file (if any).
|
|
158
|
+
// If we haven't published before, we won't have this, but I think that's okay for now at least
|
|
159
|
+
|
|
160
|
+
try {
|
|
161
|
+
// console.log("creating service settings file")
|
|
162
|
+
const pubsrc = path.join(workPath, '..', '.published')
|
|
163
|
+
let pubInfo: any = {}
|
|
164
|
+
// console.log("checking pubsrc at ", pubsrc)
|
|
165
|
+
if (fs.existsSync(pubsrc)) {
|
|
166
|
+
// console.log("found it")
|
|
167
|
+
pubInfo = JSON.parse(fs.readFileSync(pubsrc).toString())
|
|
168
|
+
// console.log({pubInfo})
|
|
169
|
+
}
|
|
170
|
+
const publishUrl = pubInfo.url ?? '/'
|
|
171
|
+
|
|
172
|
+
const stage = publishUrl.substring(publishUrl.lastIndexOf('/') + 1)
|
|
173
|
+
setWebroot(webrootExport.webrootMethod, webrootExport.webrootBaseUrl)
|
|
174
|
+
setAws(stage, publishUrl)
|
|
175
|
+
// console.log("getServiceSettings", getServiceSettings())
|
|
176
|
+
const settingsFile = path.join(projectPaths.basePath, '.package_temp', 'svcsettings.json')
|
|
177
|
+
fs.writeFileSync(settingsFile, JSON.stringify(getServiceSettings()))
|
|
178
|
+
// if (fs.existsSync(settingsFile)) console.log("file confirmed at ", settingsFile)
|
|
179
|
+
} catch (e: any) {
|
|
180
|
+
console.error(e)
|
|
181
|
+
}
|
|
182
|
+
// console.log("push to zip stack ", {zipFile})
|
|
151
183
|
all.push(FolderToZip(workPath, zipFile))
|
|
152
|
-
// console.log("now zip it")
|
|
153
184
|
})
|
|
154
|
-
|
|
185
|
+
// console.log("all", {all})
|
|
155
186
|
return await Promise.all(all).then(() => {
|
|
156
187
|
return error
|
|
157
188
|
})
|