@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
@@ -16,6 +16,7 @@ const srv_yml = async (model, spec) => {
16
16
  const core = (0, conf_1.CoreConfShape)(model.main.conf.core);
17
17
  let appname = core.name;
18
18
  let AppName = (0, util_1.camelify)(appname);
19
+ const frag = (0, generate_1.loadFragment)('srv.yml.frag', spec);
19
20
  let srv_yml_prefix_path = path_1.default.join(spec.folder, 'srv.prefix.yml');
20
21
  let srv_yml_suffix_path = path_1.default.join(spec.folder, 'srv.suffix.yml');
21
22
  let prefixContent = fs_1.default.existsSync(srv_yml_prefix_path) ?
@@ -37,13 +38,6 @@ const srv_yml = async (model, spec) => {
37
38
  if ((_c = (_b = (_a = srv.gen) === null || _a === void 0 ? void 0 : _a.custom) === null || _b === void 0 ? void 0 : _b.lambda) === null || _c === void 0 ? void 0 : _c.srv_yml) {
38
39
  return srv.gen.custom.lambda.srv_yml;
39
40
  }
40
- // TODO: this should be a JSON structure exported as YAML
41
- let srvyml = `${name}:
42
- handler: ${handler.path.prefix}${name}${handler.path.suffix}
43
- role: Basic${AppName}LambdaRole
44
- timeout: ${lambda.timeout}
45
- memorySize: ${lambda.memory || 1024}
46
- `;
47
41
  const web = srv.api.web;
48
42
  let events = '';
49
43
  let onEvents = srv.on;
@@ -148,13 +142,21 @@ ${corsprops}
148
142
  }
149
143
  }
150
144
  }
145
+ let eventsBlock = '';
151
146
  if ('' !== events) {
152
- srvyml += (0, generate_1.TM)(`
147
+ eventsBlock = (0, generate_1.TM)(`
153
148
  events:
154
149
  ${events}
155
150
  `);
156
151
  }
157
- return srvyml;
152
+ return (0, generate_1.renderFragment)(frag, {
153
+ name,
154
+ handler: handler.path.prefix + name + handler.path.suffix,
155
+ AppName,
156
+ timeout: lambda.timeout,
157
+ memory: lambda.memory || 1024,
158
+ events: eventsBlock,
159
+ });
158
160
  }).join('\n\n\n') +
159
161
  suffixContent;
160
162
  await (0, generate_1.generate)(spec.folder, [{ name: 'srv.yml', content }]);
@@ -1 +1 @@
1
- {"version":3,"file":"srv_yml.js","sourceRoot":"","sources":["../../../env/lambda/srv_yml.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"srv_yml.js","sourceRoot":"","sources":["../../../env/lambda/srv_yml.ts"],"names":[],"mappings":"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"}
package/env/env_gen.ts ADDED
@@ -0,0 +1,165 @@
1
+ /* Copyright © 2026 Voxgig Ltd, MIT License. */
2
+
3
+ // EnvGen: per-environment deployment artifact generation. The project
4
+ // model declares its target environments under `main: env:`:
5
+ //
6
+ // main: env: local: { active: true }
7
+ // main: env: aws: { active: true, region: 'eu-west-1', stage: 'dev' }
8
+ //
9
+ // For each active environment this generates gen/env/<name>/ from the
10
+ // fragment set tm/env/<kind>/ (kind defaults to the env name, so a
11
+ // project can declare e.g. `aws2: { kind: 'aws', region: ... }`).
12
+ // Fragments are project-shadowable via spec.tm (the project's tm/env
13
+ // folder), like the lambda templates.
14
+
15
+ import Fs from 'fs'
16
+ import Path from 'path'
17
+
18
+ import { camelify } from '@voxgig/util'
19
+
20
+ import { CoreConfShape } from '../shape/conf'
21
+
22
+ import { generate, loadFragment, renderFragment } from './lambda/generate'
23
+
24
+
25
+ // The supported environment kinds and the files each generates.
26
+ // `out` may contain $$slots$$ (rendered with the same slot values).
27
+ const ENV_FILES: Record<string, { frag: string, out: string }[]> = {
28
+ local: [
29
+ { frag: 'local/run.sh.frag', out: 'run.sh' },
30
+ { frag: 'local/README.md.frag', out: 'README.md' },
31
+ ],
32
+ basic: [
33
+ { frag: 'basic/backend.service.frag', out: '$$name$$-backend.service' },
34
+ { frag: 'basic/deploy.sh.frag', out: 'deploy.sh' },
35
+ { frag: 'basic/README.md.frag', out: 'README.md' },
36
+ ],
37
+ docker: [
38
+ { frag: 'docker/Dockerfile.frag', out: 'Dockerfile' },
39
+ { frag: 'docker/compose.yml.frag', out: 'compose.yml' },
40
+ { frag: 'docker/README.md.frag', out: 'README.md' },
41
+ ],
42
+ vm: [
43
+ { frag: 'vm/cloud-init.yaml.frag', out: 'cloud-init.yaml' },
44
+ { frag: 'vm/README.md.frag', out: 'README.md' },
45
+ ],
46
+ aws: [
47
+ { frag: 'aws/serverless.yml.frag', out: 'serverless.yml' },
48
+ { frag: 'aws/README.md.frag', out: 'README.md' },
49
+ ],
50
+ azure: [
51
+ { frag: 'azure/host.json.frag', out: 'host.json' },
52
+ { frag: 'azure/README.md.frag', out: 'README.md' },
53
+ ],
54
+ cloudflare: [
55
+ { frag: 'cloudflare/wrangler.toml.frag', out: 'wrangler.toml' },
56
+ { frag: 'cloudflare/README.md.frag', out: 'README.md' },
57
+ ],
58
+ }
59
+
60
+ // The runtime entry point + Seneca config setup each environment needs
61
+ // under src/env/. These are generated ONCE (only when missing): after
62
+ // creation the project owns them, like the scaffold's local entry. All
63
+ // entries route Seneca configuration through src/env/shared/basic.ts.
64
+ // `dir` is relative to the project src/env folder.
65
+ const ENV_SRC: Record<string, { frag: string, dir: string, out: string }[]> = {
66
+ local: [], // scaffold provides src/env/local/local.ts
67
+ basic: [
68
+ { frag: 'server.entry.ts.frag', dir: 'basic', out: 'basic.ts' },
69
+ ],
70
+ docker: [
71
+ { frag: 'server.entry.ts.frag', dir: 'docker', out: 'docker.ts' },
72
+ ],
73
+ vm: [
74
+ { frag: 'server.entry.ts.frag', dir: 'vm', out: 'vm.ts' },
75
+ ],
76
+ aws: [
77
+ // The Lambda bootstrap the generated handlers import.
78
+ { frag: 'aws/lambda.entry.ts.frag', dir: 'lambda', out: 'lambda.ts' },
79
+ ],
80
+ azure: [
81
+ { frag: 'azure/entry.ts.frag', dir: 'azure', out: 'azure.ts' },
82
+ ],
83
+ cloudflare: [
84
+ { frag: 'cloudflare/worker.ts.frag', dir: 'cloudflare', out: 'worker.ts' },
85
+ ],
86
+ }
87
+
88
+ const KINDS = Object.keys(ENV_FILES)
89
+
90
+
91
+ const env_gen = async (model: any, spec: {
92
+ folder: string // gen/env output root; each env writes <folder>/<name>/
93
+ tm?: string // project tm/env folder (fragment shadowing)
94
+ src?: string // project src/env folder: runtime entries generated
95
+ // here ONCE (existing files are never overwritten)
96
+ }) => {
97
+
98
+ const core = CoreConfShape(model.main.conf.core)
99
+ const envs = model.main.env || {}
100
+
101
+ for (const entry of Object.entries(envs)) {
102
+ const name = entry[0]
103
+ const def: any = entry[1] || {}
104
+
105
+ if (false === def.active) {
106
+ continue
107
+ }
108
+
109
+ const kind = def.kind || name
110
+ const filedefs = ENV_FILES[kind]
111
+ if (null == filedefs) {
112
+ throw new Error('@voxgig/build: unknown environment kind: ' + kind +
113
+ ' (env ' + name + '; known kinds: ' + KINDS.join(', ') + ')')
114
+ }
115
+
116
+ // Slot values: project identity, ports, and per-env config with
117
+ // sensible defaults. Additional scalar config keys on the env
118
+ // definition become slots too.
119
+ const slots: Record<string, any> = {
120
+ name: core.name,
121
+ Name: camelify(core.name),
122
+ env: name,
123
+ port: model.main.conf.port?.backend || 8080,
124
+ node: def.node || '22',
125
+ region: def.region || 'us-east-1',
126
+ stage: def.stage || 'dev',
127
+ }
128
+ for (const key of Object.keys(def)) {
129
+ if ('object' !== typeof def[key] && null == slots[key]) {
130
+ slots[key] = def[key]
131
+ }
132
+ }
133
+
134
+ // Slot for the env name inside entry fragments.
135
+ slots.env = name
136
+
137
+ const files = filedefs.map((fd) => ({
138
+ name: renderFragment(fd.out, slots),
139
+ content: renderFragment(loadFragment(fd.frag, spec, 'env'), slots),
140
+ }))
141
+
142
+ await generate(spec.folder + '/' + name, files)
143
+
144
+ // Runtime entries: create-once into src/env (user-owned afterwards).
145
+ if (null != spec.src) {
146
+ for (const sd of (ENV_SRC[kind] || [])) {
147
+ const dest = Path.join(spec.src, sd.dir, renderFragment(sd.out, slots))
148
+ if (!Fs.existsSync(dest)) {
149
+ const content =
150
+ renderFragment(loadFragment(sd.frag, spec, 'env'), slots)
151
+ Fs.mkdirSync(Path.dirname(dest), { recursive: true })
152
+ Fs.writeFileSync(dest, content)
153
+ }
154
+ }
155
+ }
156
+ }
157
+ }
158
+
159
+
160
+ export {
161
+ env_gen,
162
+ ENV_FILES,
163
+ ENV_SRC,
164
+ KINDS,
165
+ }
@@ -0,0 +1,112 @@
1
+ /* Copyright © 2022-2026 Voxgig Ltd, MIT License. */
2
+
3
+ // Shared generation utilities for the lambda templates. File output goes
4
+ // through the jostraca templating library (Project/File/Content components),
5
+ // which also maintains .jostraca/ build metadata next to the outputs.
6
+
7
+ import Fs from 'fs'
8
+ import Path from 'path'
9
+
10
+ import { Jostraca, Project, File, Content } from 'jostraca'
11
+
12
+
13
+ // The text shape of each generated output lives in a jostraca-style
14
+ // fragment file with $$slot$$ placeholders. Fragments ship with this
15
+ // package under tm/lambda/, and a project can shadow any of them by
16
+ // placing a same-named file in its own tm folder (passed as spec.tm by
17
+ // the project's build actions). The fragment file's final newline is
18
+ // dropped at load, so slot values fully control trailing bytes.
19
+
20
+ // Package tm root: compiled code lives at <pkg>/dist/env/lambda (three
21
+ // levels down), but test transforms run the source at <pkg>/env/lambda
22
+ // (two levels down) - probe both. Areas (tm/<area>/...) group fragment
23
+ // sets: 'lambda' (the EnvLambda templates) and 'env' (per-environment
24
+ // deployment templates).
25
+ const PKG_TM_ROOT = [
26
+ Path.join(__dirname, '..', '..', '..', 'tm'),
27
+ Path.join(__dirname, '..', '..', 'tm'),
28
+ ].find((p) => Fs.existsSync(p)) ||
29
+ Path.join(__dirname, '..', '..', '..', 'tm')
30
+
31
+ const PKG_TM = Path.join(PKG_TM_ROOT, 'lambda')
32
+
33
+
34
+ function loadFragment(
35
+ name: string, spec?: { tm?: string }, area: string = 'lambda'
36
+ ): string {
37
+ const candidates = []
38
+ if (spec?.tm) {
39
+ candidates.push(Path.join(spec.tm, name))
40
+ }
41
+ candidates.push(Path.join(PKG_TM_ROOT, area, name))
42
+
43
+ for (const c of candidates) {
44
+ if (Fs.existsSync(c)) {
45
+ let src = Fs.readFileSync(c, 'utf8')
46
+ if (src.endsWith('\n')) {
47
+ src = src.substring(0, src.length - 1)
48
+ }
49
+ return src
50
+ }
51
+ }
52
+ throw new Error('@voxgig/build: fragment not found: ' + name +
53
+ ' (looked in ' + candidates.join(', ') + ')')
54
+ }
55
+
56
+
57
+ // Literal $$slot$$ substitution (split/join - values are never
58
+ // interpreted, so ${...}, $&, etc. pass through untouched).
59
+ function renderFragment(src: string, slots: Record<string, any>): string {
60
+ let out = src
61
+ for (const key of Object.keys(slots)) {
62
+ out = out.split('$$' + key + '$$').join(String(slots[key]))
63
+ }
64
+ return out
65
+ }
66
+
67
+
68
+ // Fragment names shipped by this package (for tooling: list/eject).
69
+ function listFragments(): string[] {
70
+ return Fs.readdirSync(PKG_TM).filter((f) => f.endsWith('.frag')).sort()
71
+ }
72
+
73
+
74
+ // Generate one or more files in folder, each with exact content.
75
+ async function generate(
76
+ folder: string,
77
+ files: { name: string, content: string }[]
78
+ ) {
79
+ const jostraca = Jostraca()
80
+
81
+ await jostraca.generate({ folder }, () => {
82
+ Project({}, () => {
83
+ for (const f of files) {
84
+ File({ name: f.name }, () => {
85
+ Content(f.content)
86
+ })
87
+ }
88
+ })
89
+ })
90
+ }
91
+
92
+
93
+ function empty(o: any) {
94
+ return null == o ? true : 0 === Object.keys(o).length
95
+ }
96
+
97
+ // Strip inital newline
98
+ function TM(str: string) {
99
+ return str.replace(/^\n/, '')
100
+ }
101
+
102
+
103
+ export {
104
+ generate,
105
+ empty,
106
+ TM,
107
+ loadFragment,
108
+ renderFragment,
109
+ listFragments,
110
+ PKG_TM,
111
+ PKG_TM_ROOT,
112
+ }
@@ -0,0 +1,140 @@
1
+ /* Copyright © 2022-2026 Voxgig Ltd, MIT License. */
2
+
3
+ // gen/serverless resources template: SQS queues, DynamoDB tables (via
4
+ // yml/res_dynamo_yml), and the basic Lambda IAM role.
5
+
6
+ import Fs from 'fs'
7
+ import Path from 'path'
8
+
9
+ import { dive, camelify } from '@voxgig/util'
10
+
11
+ import { MsgMetaShape } from '../../shape/msg'
12
+ import { CoreConfShape, CloudConfShape } from '../../shape/conf'
13
+
14
+ import { res_dynamo_yml } from '../../yml/res_dynamo_yml'
15
+
16
+ import { generate, loadFragment, renderFragment } from './generate'
17
+
18
+
19
+ const resources_yml = async (model: any, spec: {
20
+ folder: string,
21
+ filename: string
22
+ custom: string,
23
+ tm?: string
24
+ }) => {
25
+
26
+ const queueFrag = loadFragment('res.queue.yml.frag', spec)
27
+ const roleFrag = loadFragment('res.role.yml.frag', spec)
28
+
29
+ const core = CoreConfShape(model.main.conf.core)
30
+
31
+ const appname = core.name
32
+ const AppName = camelify(appname)
33
+
34
+ const cloud = CloudConfShape(model.main.conf.cloud)
35
+
36
+ const region = cloud.aws.region
37
+ const accountid = cloud.aws.accountid
38
+
39
+ let filename = spec.filename || 'resources.yml'
40
+
41
+ let resources_yml_prefix_path = Path.join(spec.folder, 'res.prefix.yml')
42
+ let resources_yml_suffix_path = Path.join(spec.folder, 'res.suffix.yml')
43
+
44
+ let prefixContent = Fs.existsSync(resources_yml_prefix_path) ?
45
+ Fs.readFileSync(resources_yml_prefix_path) : ''
46
+ let suffixContent = Fs.existsSync(resources_yml_suffix_path) ?
47
+ Fs.readFileSync(resources_yml_suffix_path) : ''
48
+
49
+ const dynamoResources: { arn: string }[] = []
50
+
51
+ let content =
52
+ `# START
53
+ `
54
+
55
+ content +=
56
+ prefixContent +
57
+
58
+ await res_dynamo_yml(model, { dynamoResources, region, accountid })
59
+
60
+ // content +=
61
+ let queueDefs = dive(model.main.msg, 128).map((entry: any) => {
62
+ let path = entry[0]
63
+ let msgMeta = MsgMetaShape(entry[1])
64
+
65
+ let pathname = path
66
+ .map((p: string) =>
67
+ (p[0] + '').toUpperCase() + p.substring(1))
68
+ .join('')
69
+
70
+ // console.log('MQ', pathname, msgMeta)
71
+
72
+ if (msgMeta.transport?.queue?.active) {
73
+ // console.log('MM', path, msgMeta)
74
+ let queue = msgMeta.transport.queue
75
+ let name = queue.name || pathname
76
+
77
+ // TODO: aontu should do this, but needs recursive child conjuncts
78
+ let stage_suffix =
79
+ (false === queue.stage?.active) ? '' : '-${self:provider.stage,"dev"}'
80
+
81
+ let queue_suffix = (null == queue.suffix || '' == queue.suffix) ? '' :
82
+ '-' + queue.suffix
83
+
84
+ let resname = 'Queue' + name
85
+
86
+ let queueName =
87
+ (queue.prefix || '') +
88
+ path.reduce((s: string, p: string, i: number) =>
89
+ (s += p + (i % 2 ?
90
+ (i == path.length - 1 ? '' : '-') : '_')), '') +
91
+ (queue_suffix || '') +
92
+ (stage_suffix || '')
93
+
94
+ let queueTimeout = queue.timeout || 30
95
+
96
+ return renderFragment(queueFrag, {
97
+ resname,
98
+ queueName,
99
+ queueTimeout,
100
+ })
101
+ }
102
+ return ''
103
+ }).filter(n => '' !== n).join('')
104
+
105
+ // console.log('queueDefs', queueDefs)
106
+
107
+ content += '\n\n' + queueDefs
108
+
109
+ let customLambdaPolicyStatementPath =
110
+ Path.join(spec.folder, 'res.lambda.policy.statements.yml')
111
+ let customLambdaPolicyStatementContent = Fs.existsSync(customLambdaPolicyStatementPath) ?
112
+ Fs.readFileSync(customLambdaPolicyStatementPath) : ''
113
+
114
+
115
+
116
+ content += renderFragment(roleFrag, {
117
+ AppName,
118
+ dynamoArns: dynamoResources.map(r => ' - ' + r.arn).join('\n'),
119
+ customPolicy: customLambdaPolicyStatementContent,
120
+ })
121
+
122
+
123
+
124
+ if (spec.custom) {
125
+ content = Fs.readFileSync(spec.custom).toString() + '\n\n\n' + content
126
+ }
127
+
128
+ content += suffixContent
129
+
130
+ content += `
131
+ # END
132
+ `
133
+
134
+ await generate(spec.folder, [{ name: filename, content }])
135
+ }
136
+
137
+
138
+ export {
139
+ resources_yml,
140
+ }
@@ -0,0 +1,132 @@
1
+ /* Copyright © 2022-2026 Voxgig Ltd, MIT License. */
2
+
3
+ // Lambda handler template: one handler source file per lambda service,
4
+ // bootstrapping Seneca via the env folder and delegating to gateway-lambda.
5
+
6
+ import { dive, get, pinify } from '@voxgig/util'
7
+
8
+ import { MsgMetaShape } from '../../shape/msg'
9
+
10
+ import { generate, loadFragment, renderFragment } from './generate'
11
+
12
+
13
+ // Only create if does not exist
14
+ const srv_handler = async (model: any, spec: {
15
+ folder: string
16
+ start?: string
17
+ env?: {
18
+ folder: string
19
+ }
20
+ lang?: string
21
+ tm?: string
22
+ }) => {
23
+ let lang = spec.lang || 'js'
24
+
25
+ const frag = loadFragment('srv_handler.' + lang + '.frag', spec)
26
+
27
+ const files: { name: string, content: string }[] = []
28
+
29
+ Object
30
+ .entries(model.main.srv)
31
+ .filter((entry: any) => entry[1].env?.lambda)
32
+ .forEach((entry: any) => {
33
+ const name = entry[0]
34
+ const srv = entry[1]
35
+
36
+ if ('custom' === srv.env.lambda.kind) {
37
+ return
38
+ }
39
+
40
+ let start = spec.start || 'setup'
41
+ let envFolder = spec.env?.folder || '../../../env/lambda'
42
+
43
+ let handler = 'handler'
44
+ let modify = ''
45
+
46
+ // if (!srv.api.web.active) {
47
+ // if (srv.on && 0 < Object.keys(srv.on).length) {
48
+ // handler = 'eventhandler'
49
+ // modify = `
50
+ // event = {
51
+ // ...event,
52
+ // // TODO: @voxgig/system? util needed to handle this dynamically
53
+ // seneca$: { msg: '${srv.on[Object.keys(srv.on)[0]].events[0].msg}' },
54
+ // }
55
+ // `
56
+ // }
57
+ // }
58
+
59
+
60
+ let prepare = ''
61
+ let complete = ''
62
+
63
+
64
+ dive(model.main.msg.aim[name], 128).map((entry: any) => {
65
+ let path = ['aim', name, ...entry[0]]
66
+ let msgMeta = MsgMetaShape(entry[1])
67
+ let pin = pinify(path)
68
+ if (msgMeta.transport?.queue?.active) {
69
+ complete += `
70
+ seneca.listen({type:'sqs',pin:'${pin}'})`
71
+ }
72
+ })
73
+
74
+
75
+ dive(model.main.srv[name].out, 128).map((entry: any) => {
76
+ let path = entry[0]
77
+ let msgMetaMaybe = get(model.main.msg, path)
78
+ // console.log(name, path, msgMetaMaybe)
79
+ if (msgMetaMaybe?.$) {
80
+ let msgMeta = MsgMetaShape(msgMetaMaybe?.$)
81
+ let pin = pinify(path)
82
+
83
+ if (msgMeta.transport?.queue?.active) {
84
+ complete += `
85
+ seneca.client({type:'sqs',pin:'${pin}'})`
86
+ }
87
+ }
88
+ })
89
+
90
+ let makeGatewayHandler = false
91
+ let onlist = model.main.srv[name].on || {}
92
+ Object.entries(onlist).map((onitem: any) => {
93
+ onitem[1].events.map((event: any) => {
94
+ if ('s3' === event.source) {
95
+ if (!makeGatewayHandler) {
96
+ complete += `
97
+
98
+ const makeGatewayHandler = seneca.export('s3-store/makeGatewayHandler')`
99
+ makeGatewayHandler = true
100
+ }
101
+
102
+ complete += `
103
+ seneca
104
+ .act('sys:gateway,kind:lambda,add:hook,hook:handler', {
105
+ handler: makeGatewayHandler('${event.msg}') })`
106
+ }
107
+ })
108
+ })
109
+
110
+
111
+ const content = renderFragment(frag, {
112
+ envFolder,
113
+ start,
114
+ name,
115
+ complete,
116
+ modify,
117
+ prepare,
118
+ handler,
119
+ })
120
+
121
+ files.push({ name: name + '.' + lang, content })
122
+ })
123
+
124
+ if (0 < files.length) {
125
+ await generate(spec.folder, files)
126
+ }
127
+ }
128
+
129
+
130
+ export {
131
+ srv_handler,
132
+ }