@voxgig/build 4.0.0 → 4.2.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.
Files changed (50) hide show
  1. package/build.ts +46 -0
  2. package/dist/build.d.ts +31 -1
  3. package/dist/build.js +33 -1
  4. package/dist/build.js.map +1 -1
  5. package/dist/env/env_gen.d.ts +16 -0
  6. package/dist/env/env_gen.js +143 -0
  7. package/dist/env/env_gen.js.map +1 -0
  8. package/dist/env/lambda/generate.d.ts +8 -1
  9. package/dist/env/lambda/generate.js +59 -0
  10. package/dist/env/lambda/generate.js.map +1 -1
  11. package/dist/env/lambda/res_yml.d.ts +1 -0
  12. package/dist/env/lambda/res_yml.js +12 -41
  13. package/dist/env/lambda/res_yml.js.map +1 -1
  14. package/dist/env/lambda/srv_handler.d.ts +1 -0
  15. package/dist/env/lambda/srv_handler.js +10 -21
  16. package/dist/env/lambda/srv_handler.js.map +1 -1
  17. package/dist/env/lambda/srv_yml.d.ts +1 -0
  18. package/dist/env/lambda/srv_yml.js +11 -9
  19. package/dist/env/lambda/srv_yml.js.map +1 -1
  20. package/env/env_gen.ts +165 -0
  21. package/env/lambda/generate.ts +112 -0
  22. package/env/lambda/res_yml.ts +140 -0
  23. package/env/lambda/srv_handler.ts +132 -0
  24. package/env/lambda/srv_yml.ts +201 -0
  25. package/package.json +6 -4
  26. package/tm/env/aws/README.md.frag +9 -0
  27. package/tm/env/aws/lambda.entry.ts.frag +89 -0
  28. package/tm/env/aws/serverless.yml.frag +23 -0
  29. package/tm/env/azure/README.md.frag +7 -0
  30. package/tm/env/azure/entry.ts.frag +49 -0
  31. package/tm/env/azure/host.json.frag +8 -0
  32. package/tm/env/basic/README.md.frag +7 -0
  33. package/tm/env/basic/backend.service.frag +14 -0
  34. package/tm/env/basic/deploy.sh.frag +13 -0
  35. package/tm/env/cloudflare/README.md.frag +7 -0
  36. package/tm/env/cloudflare/worker.ts.frag +13 -0
  37. package/tm/env/cloudflare/wrangler.toml.frag +7 -0
  38. package/tm/env/docker/Dockerfile.frag +10 -0
  39. package/tm/env/docker/README.md.frag +7 -0
  40. package/tm/env/docker/compose.yml.frag +10 -0
  41. package/tm/env/local/README.md.frag +7 -0
  42. package/tm/env/local/run.sh.frag +6 -0
  43. package/tm/env/server.entry.ts.frag +48 -0
  44. package/tm/env/vm/README.md.frag +5 -0
  45. package/tm/env/vm/cloud-init.yaml.frag +23 -0
  46. package/tm/lambda/res.queue.yml.frag +6 -0
  47. package/tm/lambda/res.role.yml.frag +35 -0
  48. package/tm/lambda/srv.yml.frag +6 -0
  49. package/tm/lambda/srv_handler.js.frag +17 -0
  50. package/tm/lambda/srv_handler.ts.frag +17 -0
@@ -0,0 +1,201 @@
1
+ /* Copyright © 2022-2026 Voxgig Ltd, MIT License. */
2
+
3
+ // gen/serverless/srv.yml template: one Serverless function definition per
4
+ // lambda-active service, derived from the model.
5
+
6
+ import Fs from 'fs'
7
+ import Path from 'path'
8
+
9
+ import { camelify } from '@voxgig/util'
10
+
11
+ import { CoreConfShape } from '../../shape/conf'
12
+
13
+ import { generate, empty, TM, loadFragment, renderFragment } from './generate'
14
+
15
+
16
+ const srv_yml = async (model: any, spec: {
17
+ folder: string
18
+ tm?: string
19
+ }) => {
20
+
21
+ const core = CoreConfShape(model.main.conf.core)
22
+
23
+ let appname = core.name
24
+ let AppName = camelify(appname)
25
+
26
+ const frag = loadFragment('srv.yml.frag', spec)
27
+
28
+ let srv_yml_prefix_path = Path.join(spec.folder, 'srv.prefix.yml')
29
+ let srv_yml_suffix_path = Path.join(spec.folder, 'srv.suffix.yml')
30
+
31
+ let prefixContent = Fs.existsSync(srv_yml_prefix_path) ?
32
+ Fs.readFileSync(srv_yml_prefix_path) : ''
33
+ let suffixContent = Fs.existsSync(srv_yml_suffix_path) ?
34
+ Fs.readFileSync(srv_yml_suffix_path) : ''
35
+
36
+ let content =
37
+
38
+ prefixContent +
39
+ Object
40
+ .entries(model.main.srv)
41
+ .filter((entry: any) => entry[1].env?.lambda?.active)
42
+ .map((entry: any) => {
43
+ const name = entry[0]
44
+ const srv = entry[1]
45
+
46
+ const lambda = srv.env.lambda
47
+ const handler = lambda.handler
48
+
49
+ // NOTE: gen.custom convention: allows for complete overwrite
50
+ // as a get-out-of-jail
51
+ if (srv.gen?.custom?.lambda?.srv_yml) {
52
+ return srv.gen.custom.lambda.srv_yml
53
+ }
54
+
55
+ const web = srv.api.web
56
+
57
+ let events = ''
58
+
59
+ let onEvents = srv.on
60
+
61
+ if (onEvents) {
62
+ Object.entries(onEvents).forEach((entry: any[]) => {
63
+ // let name = entry[0]
64
+ let spec = entry[1]
65
+
66
+ if ('aws' === spec.provider) {
67
+ spec.events.forEach((ev: any) => {
68
+ if ('s3' === ev.source) {
69
+ events += TM(`
70
+ - s3:
71
+ bucket: ${ev.bucket}
72
+ event: ${ev.event}
73
+ existing: true
74
+ `)
75
+ if (ev.rules) {
76
+ events += TM(`
77
+ rules:
78
+ `)
79
+ if (ev.rules.prefix) {
80
+ events += TM(`
81
+ - prefix: ${ev.rules.prefix}
82
+ `)
83
+ }
84
+
85
+ if (ev.rules.suffix) {
86
+ events += TM(`
87
+ - suffix: ${ev.rules.suffix}
88
+ `)
89
+ }
90
+ }
91
+ }
92
+ else if ('schedule' === ev.source) {
93
+ let entries =
94
+ 'string' === typeof ev.recur ? [ev.recur] : (ev.recur || [])
95
+ let recur = entries.map((entry: string) => {
96
+ let schedule = `
97
+ - schedule:
98
+ rate: ${entry}`
99
+ if (ev.msg) {
100
+ schedule += `
101
+ input:
102
+ msg: ${JSON.stringify(ev.msg)} `
103
+ }
104
+ return schedule
105
+ })
106
+
107
+ events += TM(`
108
+ ${recur}
109
+ `)
110
+
111
+ }
112
+ else if ('sqs' === ev.source) {
113
+ events += TM(`
114
+ - sqs:
115
+ arn:
116
+ Fn::GetAtt:
117
+ - ${ev.qrn}
118
+ - Arn
119
+ batchSize: 1
120
+ `)
121
+
122
+ }
123
+ })
124
+ }
125
+ })
126
+ }
127
+
128
+ // TODO: move to `on`
129
+ if (web.active) {
130
+ let prefix = web.path.prefix
131
+ let suffix = web.path.suffix
132
+ let area = web.path.area
133
+ let method = web.method
134
+ let corsflag = 'false'
135
+ let corsprops = ''
136
+
137
+ let methods = method.split(',')
138
+ // console.log('METHODS', methods)
139
+
140
+ if (web.cors.active) {
141
+ corsflag = 'true'
142
+ if (web.cors.props && !empty(web.cors.props)) {
143
+ corsflag = ''
144
+ corsprops = Object
145
+ .entries(web.cors.props)
146
+ .reduce(((a: any, nv: any) => (
147
+ a += ` ${nv[0]}: ${nv[1]}\n`
148
+ , a)), '')
149
+ }
150
+ }
151
+
152
+ if ('v2' === web.lambda?.gateway) {
153
+ for (let method of methods) {
154
+ events += TM(`
155
+ - httpApi:
156
+ path: "${prefix}${area}${name}${suffix}"
157
+ method: ${method}
158
+ `)
159
+ }
160
+ }
161
+ else {
162
+ for (let method of methods) {
163
+ events += TM(`
164
+ - http:
165
+ path: "${prefix}${area}${name}${suffix}"
166
+ method: ${method}
167
+ cors: ${corsflag}
168
+ ${corsprops}
169
+ `)
170
+ }
171
+ }
172
+ }
173
+
174
+
175
+
176
+ let eventsBlock = ''
177
+ if ('' !== events) {
178
+ eventsBlock = TM(`
179
+ events:
180
+ ${events}
181
+ `)
182
+ }
183
+
184
+ return renderFragment(frag, {
185
+ name,
186
+ handler: handler.path.prefix + name + handler.path.suffix,
187
+ AppName,
188
+ timeout: lambda.timeout,
189
+ memory: lambda.memory || 1024,
190
+ events: eventsBlock,
191
+ })
192
+ }).join('\n\n\n') +
193
+ suffixContent
194
+
195
+ await generate(spec.folder, [{ name: 'srv.yml', content }])
196
+ }
197
+
198
+
199
+ export {
200
+ srv_yml,
201
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voxgig/build",
3
- "version": "4.0.0",
3
+ "version": "4.2.0",
4
4
  "main": "dist/build.js",
5
5
  "type": "commonjs",
6
6
  "types": "dist/build.d.ts",
@@ -18,7 +18,7 @@
18
18
  "url": "git://github.com/voxgig/build.git"
19
19
  },
20
20
  "scripts": {
21
- "model-s01": "voxgig-model test/s01/model/model.jsonic",
21
+ "model-s01": "voxgig-model test/s01/model/model.aontu",
22
22
  "test": "jest --coverage",
23
23
  "test-some": "jest -t",
24
24
  "test-watch": "jest --coverage --watchAll",
@@ -42,7 +42,9 @@
42
42
  "lib",
43
43
  "dist",
44
44
  "bin",
45
- "LICENSE"
45
+ "LICENSE",
46
+ "tm",
47
+ "env"
46
48
  ],
47
49
  "dependencies": {
48
50
  "@voxgig/util": "0.5.4",
@@ -54,7 +56,7 @@
54
56
  "@types/jest": "^29.5.12",
55
57
  "@types/js-yaml": "^4.0.9",
56
58
  "@types/node": "26.1.2",
57
- "@voxgig/model": "^2.1.0",
59
+ "@voxgig/model": "^9.2.4",
58
60
  "@voxgig/system": "^1.2.0",
59
61
  "esbuild": "^0.23.0",
60
62
  "jest": "^29.7.0",
@@ -0,0 +1,9 @@
1
+ # $$Name$$ - aws environment (Serverless Framework)
2
+
3
+ cd backend && npm run build
4
+ cd gen/env/aws && npx serverless deploy --stage $$stage$$
5
+
6
+ serverless.yml composes the generated srv.yml (functions) and res.yml
7
+ (resources); both are regenerated by model-build. Provider settings
8
+ (region/stage/runtime) come from the model env entry - change them with
9
+ the model, or eject env/aws/serverless.yml.frag for structural edits.
@@ -0,0 +1,89 @@
1
+
2
+ // $$Name$$ backend - AWS Lambda environment bootstrap (generated once;
3
+ // this file is yours to edit). The generated handlers
4
+ // (src/handler/lambda/<srv>.ts) call getSeneca() for a ready Seneca
5
+ // instance wired for the Lambda + API Gateway path, configured by the
6
+ // shared setup (src/env/shared/basic.ts).
7
+
8
+ import Seneca from 'seneca'
9
+ import { Live } from '@voxgig/system'
10
+
11
+ import { basic, base } from '../shared/basic'
12
+
13
+ import Pkg from '../../../package.json'
14
+ import Model from '../../../model/model.json'
15
+
16
+
17
+ const STAGE = process.env.STAGE || 'local'
18
+
19
+ const Main = Model.main as any
20
+
21
+ let seneca: any = null
22
+
23
+
24
+ async function getSeneca(srvname: string, complete: Function): Promise<any> {
25
+ const { deep } = Seneca.util
26
+
27
+ if (null == seneca) {
28
+ const srv = Main.srv[srvname]
29
+
30
+ seneca = Seneca(deep(base.seneca, {
31
+ tag: srvname + '-$$name$$-' + STAGE + '@' + Pkg.version,
32
+ timeout: srv.env.lambda.timeout * 60 * 1000,
33
+ })).test()
34
+
35
+ seneca.context.model = Model
36
+ seneca.context.srvname = srvname
37
+ seneca.context.stage = STAGE
38
+ seneca.context.env = 'lambda'
39
+ seneca.context.pkg = Pkg
40
+
41
+ basic(seneca, { reload: { active: false } })
42
+
43
+ seneca
44
+ .use('gateway')
45
+ .use('gateway-lambda', {
46
+ auth: {
47
+ token: {
48
+ name: '$$name$$-auth',
49
+ },
50
+ },
51
+ })
52
+ .use('gateway-auth', {
53
+ spec: {
54
+ lambda_cookie: {
55
+ active: true,
56
+ token: {
57
+ name: '$$name$$-auth',
58
+ },
59
+ user: {
60
+ auth: true,
61
+ require: srv.user?.required ?? true,
62
+ },
63
+ },
64
+ },
65
+ })
66
+
67
+ seneca.use(Live, {
68
+ srv: {
69
+ name: srvname,
70
+ folder: __dirname + '/../../srv',
71
+ },
72
+ })
73
+
74
+ // Call ready() exactly once - a second ready() on an already-ready
75
+ // instance never resolves under seneca 4.0.0-rc4.
76
+ await seneca.ready()
77
+
78
+ if (complete) {
79
+ await complete(seneca)
80
+ }
81
+ }
82
+
83
+ return seneca
84
+ }
85
+
86
+
87
+ export {
88
+ getSeneca,
89
+ }
@@ -0,0 +1,23 @@
1
+ # $$Name$$ backend - Serverless Framework config (generated; customize via
2
+ # tm/env/aws/). Composes the model-generated pieces: per-service function
3
+ # definitions (srv.yml) and resources (res.yml) live beside this file and
4
+ # are regenerated by model-build - edit the model, not those files.
5
+ service: $$name$$-backend
6
+
7
+ frameworkVersion: '4'
8
+
9
+ provider:
10
+ name: aws
11
+ runtime: nodejs$$node$$.x
12
+ region: $$region$$
13
+ stage: ${opt:stage, '$$stage$$'}
14
+
15
+ custom:
16
+ # res.yml derives the IAM role name suffix from this index.
17
+ index:
18
+ BasicLambdaRole: '01'
19
+
20
+ functions: ${file(./srv.yml)}
21
+
22
+ resources:
23
+ Resources: ${file(./res.yml)}
@@ -0,0 +1,7 @@
1
+ # $$Name$$ - azure environment (starting point)
2
+
3
+ Azure Functions host config for the $$Name$$ backend. This is a starting
4
+ point: Azure needs one function.json binding per exposed function - derive
5
+ them from the service definitions the model generates for aws
6
+ (gen/env/aws/srv.yml lists every handler and route). Eject
7
+ env/azure/host.json.frag to customize.
@@ -0,0 +1,49 @@
1
+
2
+ // $$Name$$ backend - azure environment entry (generated once; this file is
3
+ // yours to edit). STARTING POINT: an Azure Functions HTTP handler shape -
4
+ // wire the Seneca gateway the way src/env/lambda/lambda.ts does for AWS.
5
+
6
+ import Seneca from 'seneca'
7
+
8
+ import { basic, base } from '../shared/basic'
9
+
10
+ import Pkg from '../../../package.json'
11
+ import Model from '../../../model/model.json'
12
+
13
+
14
+ let seneca: any = null
15
+
16
+ async function getSeneca(): Promise<any> {
17
+ if (null == seneca) {
18
+ seneca = Seneca(Seneca.util.deep(base.seneca, {
19
+ tag: '$$name$$-azure@' + Pkg.version,
20
+ })).test()
21
+
22
+ seneca.context.model = Model
23
+ seneca.context.env = 'azure'
24
+ seneca.context.pkg = Pkg
25
+
26
+ basic(seneca, { reload: { active: false } })
27
+
28
+ await seneca.ready()
29
+ }
30
+ return seneca
31
+ }
32
+
33
+
34
+ // Azure Functions v4 programming model handler (add @azure/functions and
35
+ // register per-route handlers derived from the model - see
36
+ // gen/env/aws/srv.yml for the full route list).
37
+ async function handler(request: any, _context: any) {
38
+ await getSeneca()
39
+ return {
40
+ status: 501,
41
+ jsonBody: { ok: false, why: '$$name$$-backend azure entry not yet wired' },
42
+ }
43
+ }
44
+
45
+
46
+ export {
47
+ getSeneca,
48
+ handler,
49
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "version": "2.0",
3
+ "logging": {
4
+ "applicationInsights": {
5
+ "samplingSettings": { "isEnabled": true }
6
+ }
7
+ }
8
+ }
@@ -0,0 +1,7 @@
1
+ # $$Name$$ - basic environment (remote server)
2
+
3
+ Runs the backend like local, on a plain server under systemd.
4
+
5
+ BASIC_HOST=user@host sh gen/env/basic/deploy.sh
6
+
7
+ Installs to /opt/$$name$$/backend with unit $$name$$-backend.service.
@@ -0,0 +1,14 @@
1
+ # systemd unit for the $$Name$$ backend (generated; customize via tm/env/basic/)
2
+ [Unit]
3
+ Description=$$Name$$ backend
4
+ After=network.target
5
+
6
+ [Service]
7
+ WorkingDirectory=/opt/$$name$$/backend
8
+ ExecStart=/usr/bin/node dist/env/local/local.js
9
+ Restart=always
10
+ Environment=NODE_ENV=production
11
+ Environment=PORT=$$port$$
12
+
13
+ [Install]
14
+ WantedBy=multi-user.target
@@ -0,0 +1,13 @@
1
+ #!/bin/sh
2
+ # Deploy the $$Name$$ backend to a plain remote server (generated).
3
+ # Usage: BASIC_HOST=user@host sh deploy.sh
4
+ set -e
5
+ : "${BASIC_HOST:?set BASIC_HOST=user@host}"
6
+ cd "$(dirname "$0")/../../.."
7
+ npm run build
8
+ rsync -az --delete \
9
+ --exclude node_modules --exclude gen --exclude dist-test \
10
+ ./ "$BASIC_HOST:/opt/$$name$$/backend/"
11
+ ssh "$BASIC_HOST" "cd /opt/$$name$$/backend && npm install --omit=dev \
12
+ && sudo cp gen/env/basic/$$name$$-backend.service /etc/systemd/system/ \
13
+ && sudo systemctl daemon-reload && sudo systemctl restart $$name$$-backend"
@@ -0,0 +1,7 @@
1
+ # $$Name$$ - cloudflare environment (starting point)
2
+
3
+ cd gen/env/cloudflare && npx wrangler deploy
4
+
5
+ The worker entry (src/env/cloudflare/worker.ts - yours to edit, wrangler
6
+ bundles the TS directly) is a 501 stub: wire the Seneca gateway into the
7
+ fetch handler (src/env/lambda/lambda.ts is the AWS model to follow).
@@ -0,0 +1,13 @@
1
+ // $$Name$$ backend - Cloudflare Worker entry (generated once; this file is
2
+ // yours to edit). STARTING POINT: Workers use a fetch handler rather than
3
+ // a long-lived process - adapt the gateway wiring (src/env/lambda/lambda.ts
4
+ // is the AWS equivalent) to route requests into Seneca here.
5
+
6
+ export default {
7
+ async fetch(_request: Request, _env: unknown, _ctx: unknown) {
8
+ return new Response(JSON.stringify({
9
+ ok: false,
10
+ why: '$$name$$-backend worker entry not yet wired',
11
+ }), { status: 501, headers: { 'content-type': 'application/json' } })
12
+ },
13
+ }
@@ -0,0 +1,7 @@
1
+ # $$Name$$ backend - Cloudflare Workers config (generated; starting point)
2
+ name = "$$name$$-backend"
3
+ main = "../../../src/env/cloudflare/worker.ts"
4
+ compatibility_date = "2026-01-01"
5
+
6
+ [vars]
7
+ NODE_ENV = "production"
@@ -0,0 +1,10 @@
1
+ # $$Name$$ backend image (generated; customize via tm/env/docker/)
2
+ FROM node:$$node$$-slim
3
+ WORKDIR /app
4
+ COPY package*.json ./
5
+ RUN npm ci --omit=dev
6
+ COPY model/model.json model/model.json
7
+ COPY dist/ dist/
8
+ ENV NODE_ENV=production
9
+ EXPOSE $$port$$
10
+ CMD ["node", "dist/env/local/local.js"]
@@ -0,0 +1,7 @@
1
+ # $$Name$$ - docker environment
2
+
3
+ cd backend && npm run build
4
+ docker compose -f gen/env/docker/compose.yml up --build
5
+
6
+ Port $$port$$. The image runs the local (in-memory) runner; wire a real
7
+ store before production use.
@@ -0,0 +1,10 @@
1
+ # $$Name$$ backend - docker compose (generated; customize via tm/env/docker/)
2
+ services:
3
+ $$name$$-backend:
4
+ build:
5
+ context: ../../..
6
+ dockerfile: gen/env/docker/Dockerfile
7
+ ports:
8
+ - "$$port$$:$$port$$"
9
+ environment:
10
+ NODE_ENV: production
@@ -0,0 +1,7 @@
1
+ # $$Name$$ - local environment
2
+
3
+ Runs the backend in-process with the in-memory store:
4
+
5
+ sh gen/env/local/run.sh # or: cd backend && npm run local
6
+
7
+ Port: $$port$$. No external services required.
@@ -0,0 +1,6 @@
1
+ #!/bin/sh
2
+ # $$Name$$ backend - local run (generated; customize via tm/env/local/)
3
+ # In-process Seneca instance, in-memory store, port $$port$$.
4
+ cd "$(dirname "$0")/../../.."
5
+ export NODE_ENV=development
6
+ exec npm run local
@@ -0,0 +1,48 @@
1
+
2
+ // $$Name$$ backend - $$env$$ environment entry (generated once; this file
3
+ // is yours to edit). A long-lived server process using the shared Seneca
4
+ // setup (src/env/shared/basic.ts); reads its env config from the model
5
+ // (main.env.$$env$$).
6
+
7
+ import Seneca from 'seneca'
8
+ import { Local } from '@voxgig/system'
9
+
10
+ import { basic, base } from '../shared/basic'
11
+
12
+ import Pkg from '../../../package.json'
13
+ import Model from '../../../model/model.json'
14
+
15
+
16
+ run()
17
+
18
+
19
+ async function run() {
20
+ const { deep } = Seneca.util
21
+
22
+ const envdef: any = (Model as any).main.env?.['$$env$$'] || {}
23
+
24
+ const seneca = Seneca(deep(base.seneca, {
25
+ tag: '$$name$$-$$env$$',
26
+ log: { level: envdef.log || 'warn' },
27
+ }, envdef.seneca || {}))
28
+
29
+ seneca.context.model = Model
30
+ seneca.context.env = '$$env$$'
31
+ seneca.context.stage = process.env.STAGE || '$$env$$'
32
+ seneca.context.srvname = 'all'
33
+ seneca.context.pkg = Pkg
34
+
35
+ basic(seneca)
36
+
37
+ seneca.use(Local, {
38
+ srv: {
39
+ folder: __dirname + '/../../../dist/srv',
40
+ },
41
+ })
42
+
43
+ await seneca.ready()
44
+
45
+ console.log('$$name$$-backend started', {
46
+ env: '$$env$$', version: Pkg.version, port: $$port$$,
47
+ })
48
+ }
@@ -0,0 +1,5 @@
1
+ # $$Name$$ - vm environment
2
+
3
+ Boot any cloud VM with gen/env/vm/cloud-init.yaml as user-data, then push
4
+ code with the basic deploy script (BASIC_HOST=user@vm sh
5
+ gen/env/basic/deploy.sh) or your own pipeline.
@@ -0,0 +1,23 @@
1
+ #cloud-config
2
+ # $$Name$$ backend VM bootstrap (generated; customize via tm/env/vm/)
3
+ packages:
4
+ - nodejs
5
+ - npm
6
+ - rsync
7
+ write_files:
8
+ - path: /etc/systemd/system/$$name$$-backend.service
9
+ content: |
10
+ [Unit]
11
+ Description=$$Name$$ backend
12
+ After=network.target
13
+ [Service]
14
+ WorkingDirectory=/opt/$$name$$/backend
15
+ ExecStart=/usr/bin/node dist/env/local/local.js
16
+ Restart=always
17
+ Environment=NODE_ENV=production
18
+ [Install]
19
+ WantedBy=multi-user.target
20
+ runcmd:
21
+ - mkdir -p /opt/$$name$$/backend
22
+ - systemctl daemon-reload
23
+ - systemctl enable $$name$$-backend
@@ -0,0 +1,6 @@
1
+ $$resname$$:
2
+ Type: "AWS::SQS::Queue"
3
+ Properties:
4
+ QueueName: '$$queueName$$'
5
+ VisibilityTimeout: $$queueTimeout$$
6
+
@@ -0,0 +1,35 @@
1
+
2
+ Basic$$AppName$$LambdaRole:
3
+ Type: AWS::IAM::Role
4
+ Properties:
5
+ RoleName: Basic$$AppName$$LambdaRole${self:custom.index.BasicLambdaRole,"01"}
6
+ AssumeRolePolicyDocument:
7
+ Version: '2012-10-17'
8
+ Statement:
9
+ - Effect: Allow
10
+ Principal:
11
+ Service:
12
+ - lambda.amazonaws.com
13
+ - events.amazonaws.com
14
+ - ecs-tasks.amazonaws.com
15
+ Action: sts:AssumeRole
16
+ Policies:
17
+ - PolicyName: LambdaServiceAccess
18
+ PolicyDocument:
19
+ Version: '2012-10-17'
20
+ Statement:
21
+ - Effect: Allow
22
+ Action:
23
+ - dynamodb:DescribeTable
24
+ - dynamodb:GetItem
25
+ - dynamodb:PutItem
26
+ - dynamodb:UpdateItem
27
+ - dynamodb:DeleteItem
28
+ - dynamodb:Query
29
+ - dynamodb:Scan
30
+ Resource:
31
+ $$dynamoArns$$
32
+ $$customPolicy$$
33
+ ManagedPolicyArns:
34
+ - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
35
+
@@ -0,0 +1,6 @@
1
+ $$name$$:
2
+ handler: $$handler$$
3
+ role: Basic$$AppName$$LambdaRole
4
+ timeout: $$timeout$$
5
+ memorySize: $$memory$$
6
+ $$events$$