@voxgig/build 3.1.0 → 4.1.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.
@@ -0,0 +1,10 @@
1
+ declare const srv_handler: (model: any, spec: {
2
+ folder: string;
3
+ start?: string;
4
+ env?: {
5
+ folder: string;
6
+ };
7
+ lang?: string;
8
+ tm?: string;
9
+ }) => Promise<void>;
10
+ export { srv_handler, };
@@ -0,0 +1,101 @@
1
+ "use strict";
2
+ /* Copyright © 2022-2026 Voxgig Ltd, MIT License. */
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.srv_handler = void 0;
5
+ // Lambda handler template: one handler source file per lambda service,
6
+ // bootstrapping Seneca via the env folder and delegating to gateway-lambda.
7
+ const util_1 = require("@voxgig/util");
8
+ const msg_1 = require("../../shape/msg");
9
+ const generate_1 = require("./generate");
10
+ // Only create if does not exist
11
+ const srv_handler = async (model, spec) => {
12
+ let lang = spec.lang || 'js';
13
+ const frag = (0, generate_1.loadFragment)('srv_handler.' + lang + '.frag', spec);
14
+ const files = [];
15
+ Object
16
+ .entries(model.main.srv)
17
+ .filter((entry) => { var _a; return (_a = entry[1].env) === null || _a === void 0 ? void 0 : _a.lambda; })
18
+ .forEach((entry) => {
19
+ var _a;
20
+ const name = entry[0];
21
+ const srv = entry[1];
22
+ if ('custom' === srv.env.lambda.kind) {
23
+ return;
24
+ }
25
+ let start = spec.start || 'setup';
26
+ let envFolder = ((_a = spec.env) === null || _a === void 0 ? void 0 : _a.folder) || '../../../env/lambda';
27
+ let handler = 'handler';
28
+ let modify = '';
29
+ // if (!srv.api.web.active) {
30
+ // if (srv.on && 0 < Object.keys(srv.on).length) {
31
+ // handler = 'eventhandler'
32
+ // modify = `
33
+ // event = {
34
+ // ...event,
35
+ // // TODO: @voxgig/system? util needed to handle this dynamically
36
+ // seneca$: { msg: '${srv.on[Object.keys(srv.on)[0]].events[0].msg}' },
37
+ // }
38
+ // `
39
+ // }
40
+ // }
41
+ let prepare = '';
42
+ let complete = '';
43
+ (0, util_1.dive)(model.main.msg.aim[name], 128).map((entry) => {
44
+ var _a, _b;
45
+ let path = ['aim', name, ...entry[0]];
46
+ let msgMeta = (0, msg_1.MsgMetaShape)(entry[1]);
47
+ let pin = (0, util_1.pinify)(path);
48
+ if ((_b = (_a = msgMeta.transport) === null || _a === void 0 ? void 0 : _a.queue) === null || _b === void 0 ? void 0 : _b.active) {
49
+ complete += `
50
+ seneca.listen({type:'sqs',pin:'${pin}'})`;
51
+ }
52
+ });
53
+ (0, util_1.dive)(model.main.srv[name].out, 128).map((entry) => {
54
+ var _a, _b;
55
+ let path = entry[0];
56
+ let msgMetaMaybe = (0, util_1.get)(model.main.msg, path);
57
+ // console.log(name, path, msgMetaMaybe)
58
+ if (msgMetaMaybe === null || msgMetaMaybe === void 0 ? void 0 : msgMetaMaybe.$) {
59
+ let msgMeta = (0, msg_1.MsgMetaShape)(msgMetaMaybe === null || msgMetaMaybe === void 0 ? void 0 : msgMetaMaybe.$);
60
+ let pin = (0, util_1.pinify)(path);
61
+ if ((_b = (_a = msgMeta.transport) === null || _a === void 0 ? void 0 : _a.queue) === null || _b === void 0 ? void 0 : _b.active) {
62
+ complete += `
63
+ seneca.client({type:'sqs',pin:'${pin}'})`;
64
+ }
65
+ }
66
+ });
67
+ let makeGatewayHandler = false;
68
+ let onlist = model.main.srv[name].on || {};
69
+ Object.entries(onlist).map((onitem) => {
70
+ onitem[1].events.map((event) => {
71
+ if ('s3' === event.source) {
72
+ if (!makeGatewayHandler) {
73
+ complete += `
74
+
75
+ const makeGatewayHandler = seneca.export('s3-store/makeGatewayHandler')`;
76
+ makeGatewayHandler = true;
77
+ }
78
+ complete += `
79
+ seneca
80
+ .act('sys:gateway,kind:lambda,add:hook,hook:handler', {
81
+ handler: makeGatewayHandler('${event.msg}') })`;
82
+ }
83
+ });
84
+ });
85
+ const content = (0, generate_1.renderFragment)(frag, {
86
+ envFolder,
87
+ start,
88
+ name,
89
+ complete,
90
+ modify,
91
+ prepare,
92
+ handler,
93
+ });
94
+ files.push({ name: name + '.' + lang, content });
95
+ });
96
+ if (0 < files.length) {
97
+ await (0, generate_1.generate)(spec.folder, files);
98
+ }
99
+ };
100
+ exports.srv_handler = srv_handler;
101
+ //# sourceMappingURL=srv_handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"srv_handler.js","sourceRoot":"","sources":["../../../env/lambda/srv_handler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ declare const srv_yml: (model: any, spec: {
2
+ folder: string;
3
+ tm?: string;
4
+ }) => Promise<void>;
5
+ export { srv_yml, };
@@ -0,0 +1,165 @@
1
+ "use strict";
2
+ /* Copyright © 2022-2026 Voxgig Ltd, MIT License. */
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.srv_yml = void 0;
8
+ // gen/serverless/srv.yml template: one Serverless function definition per
9
+ // lambda-active service, derived from the model.
10
+ const fs_1 = __importDefault(require("fs"));
11
+ const path_1 = __importDefault(require("path"));
12
+ const util_1 = require("@voxgig/util");
13
+ const conf_1 = require("../../shape/conf");
14
+ const generate_1 = require("./generate");
15
+ const srv_yml = async (model, spec) => {
16
+ const core = (0, conf_1.CoreConfShape)(model.main.conf.core);
17
+ let appname = core.name;
18
+ let AppName = (0, util_1.camelify)(appname);
19
+ const frag = (0, generate_1.loadFragment)('srv.yml.frag', spec);
20
+ let srv_yml_prefix_path = path_1.default.join(spec.folder, 'srv.prefix.yml');
21
+ let srv_yml_suffix_path = path_1.default.join(spec.folder, 'srv.suffix.yml');
22
+ let prefixContent = fs_1.default.existsSync(srv_yml_prefix_path) ?
23
+ fs_1.default.readFileSync(srv_yml_prefix_path) : '';
24
+ let suffixContent = fs_1.default.existsSync(srv_yml_suffix_path) ?
25
+ fs_1.default.readFileSync(srv_yml_suffix_path) : '';
26
+ let content = prefixContent +
27
+ Object
28
+ .entries(model.main.srv)
29
+ .filter((entry) => { var _a, _b; return (_b = (_a = entry[1].env) === null || _a === void 0 ? void 0 : _a.lambda) === null || _b === void 0 ? void 0 : _b.active; })
30
+ .map((entry) => {
31
+ var _a, _b, _c, _d;
32
+ const name = entry[0];
33
+ const srv = entry[1];
34
+ const lambda = srv.env.lambda;
35
+ const handler = lambda.handler;
36
+ // NOTE: gen.custom convention: allows for complete overwrite
37
+ // as a get-out-of-jail
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) {
39
+ return srv.gen.custom.lambda.srv_yml;
40
+ }
41
+ const web = srv.api.web;
42
+ let events = '';
43
+ let onEvents = srv.on;
44
+ if (onEvents) {
45
+ Object.entries(onEvents).forEach((entry) => {
46
+ // let name = entry[0]
47
+ let spec = entry[1];
48
+ if ('aws' === spec.provider) {
49
+ spec.events.forEach((ev) => {
50
+ if ('s3' === ev.source) {
51
+ events += (0, generate_1.TM)(`
52
+ - s3:
53
+ bucket: ${ev.bucket}
54
+ event: ${ev.event}
55
+ existing: true
56
+ `);
57
+ if (ev.rules) {
58
+ events += (0, generate_1.TM)(`
59
+ rules:
60
+ `);
61
+ if (ev.rules.prefix) {
62
+ events += (0, generate_1.TM)(`
63
+ - prefix: ${ev.rules.prefix}
64
+ `);
65
+ }
66
+ if (ev.rules.suffix) {
67
+ events += (0, generate_1.TM)(`
68
+ - suffix: ${ev.rules.suffix}
69
+ `);
70
+ }
71
+ }
72
+ }
73
+ else if ('schedule' === ev.source) {
74
+ let entries = 'string' === typeof ev.recur ? [ev.recur] : (ev.recur || []);
75
+ let recur = entries.map((entry) => {
76
+ let schedule = `
77
+ - schedule:
78
+ rate: ${entry}`;
79
+ if (ev.msg) {
80
+ schedule += `
81
+ input:
82
+ msg: ${JSON.stringify(ev.msg)} `;
83
+ }
84
+ return schedule;
85
+ });
86
+ events += (0, generate_1.TM)(`
87
+ ${recur}
88
+ `);
89
+ }
90
+ else if ('sqs' === ev.source) {
91
+ events += (0, generate_1.TM)(`
92
+ - sqs:
93
+ arn:
94
+ Fn::GetAtt:
95
+ - ${ev.qrn}
96
+ - Arn
97
+ batchSize: 1
98
+ `);
99
+ }
100
+ });
101
+ }
102
+ });
103
+ }
104
+ // TODO: move to `on`
105
+ if (web.active) {
106
+ let prefix = web.path.prefix;
107
+ let suffix = web.path.suffix;
108
+ let area = web.path.area;
109
+ let method = web.method;
110
+ let corsflag = 'false';
111
+ let corsprops = '';
112
+ let methods = method.split(',');
113
+ // console.log('METHODS', methods)
114
+ if (web.cors.active) {
115
+ corsflag = 'true';
116
+ if (web.cors.props && !(0, generate_1.empty)(web.cors.props)) {
117
+ corsflag = '';
118
+ corsprops = Object
119
+ .entries(web.cors.props)
120
+ .reduce(((a, nv) => (a += ` ${nv[0]}: ${nv[1]}\n`
121
+ , a)), '');
122
+ }
123
+ }
124
+ if ('v2' === ((_d = web.lambda) === null || _d === void 0 ? void 0 : _d.gateway)) {
125
+ for (let method of methods) {
126
+ events += (0, generate_1.TM)(`
127
+ - httpApi:
128
+ path: "${prefix}${area}${name}${suffix}"
129
+ method: ${method}
130
+ `);
131
+ }
132
+ }
133
+ else {
134
+ for (let method of methods) {
135
+ events += (0, generate_1.TM)(`
136
+ - http:
137
+ path: "${prefix}${area}${name}${suffix}"
138
+ method: ${method}
139
+ cors: ${corsflag}
140
+ ${corsprops}
141
+ `);
142
+ }
143
+ }
144
+ }
145
+ let eventsBlock = '';
146
+ if ('' !== events) {
147
+ eventsBlock = (0, generate_1.TM)(`
148
+ events:
149
+ ${events}
150
+ `);
151
+ }
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
+ });
160
+ }).join('\n\n\n') +
161
+ suffixContent;
162
+ await (0, generate_1.generate)(spec.folder, [{ name: 'srv.yml', content }]);
163
+ };
164
+ exports.srv_yml = srv_yml;
165
+ //# sourceMappingURL=srv_yml.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"srv_yml.js","sourceRoot":"","sources":["../../../env/lambda/srv_yml.ts"],"names":[],"mappings":"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"}
@@ -44,7 +44,7 @@ declare const CloudConfShape: {
44
44
  }[];
45
45
  ctx: any;
46
46
  });
47
- toJSON(): any & {
47
+ toJSON(): /*elided*/ any & {
48
48
  err: any;
49
49
  name: string;
50
50
  message: string;
@@ -105,7 +105,7 @@ declare const CoreConfShape: {
105
105
  }[];
106
106
  ctx: any;
107
107
  });
108
- toJSON(): any & {
108
+ toJSON(): /*elided*/ any & {
109
109
  err: any;
110
110
  name: string;
111
111
  message: string;
@@ -68,7 +68,7 @@ declare const EntShape: {
68
68
  }[];
69
69
  ctx: any;
70
70
  });
71
- toJSON(): any & {
71
+ toJSON(): /*elided*/ any & {
72
72
  err: any;
73
73
  name: string;
74
74
  message: string;
@@ -48,7 +48,7 @@ declare const MsgMetaShape: {
48
48
  }[];
49
49
  ctx: any;
50
50
  });
51
- toJSON(): any & {
51
+ toJSON(): /*elided*/ any & {
52
52
  err: any;
53
53
  name: string;
54
54
  message: string;
@@ -0,0 +1,105 @@
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 folder: 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.
23
+ const PKG_TM = [
24
+ Path.join(__dirname, '..', '..', '..', 'tm', 'lambda'),
25
+ Path.join(__dirname, '..', '..', 'tm', 'lambda'),
26
+ ].find((p) => Fs.existsSync(p)) ||
27
+ Path.join(__dirname, '..', '..', '..', 'tm', 'lambda')
28
+
29
+
30
+ function loadFragment(name: string, spec?: { tm?: string }): string {
31
+ const candidates = []
32
+ if (spec?.tm) {
33
+ candidates.push(Path.join(spec.tm, name))
34
+ }
35
+ candidates.push(Path.join(PKG_TM, name))
36
+
37
+ for (const c of candidates) {
38
+ if (Fs.existsSync(c)) {
39
+ let src = Fs.readFileSync(c, 'utf8')
40
+ if (src.endsWith('\n')) {
41
+ src = src.substring(0, src.length - 1)
42
+ }
43
+ return src
44
+ }
45
+ }
46
+ throw new Error('@voxgig/build: fragment not found: ' + name +
47
+ ' (looked in ' + candidates.join(', ') + ')')
48
+ }
49
+
50
+
51
+ // Literal $$slot$$ substitution (split/join - values are never
52
+ // interpreted, so ${...}, $&, etc. pass through untouched).
53
+ function renderFragment(src: string, slots: Record<string, any>): string {
54
+ let out = src
55
+ for (const key of Object.keys(slots)) {
56
+ out = out.split('$$' + key + '$$').join(String(slots[key]))
57
+ }
58
+ return out
59
+ }
60
+
61
+
62
+ // Fragment names shipped by this package (for tooling: list/eject).
63
+ function listFragments(): string[] {
64
+ return Fs.readdirSync(PKG_TM).filter((f) => f.endsWith('.frag')).sort()
65
+ }
66
+
67
+
68
+ // Generate one or more files in folder, each with exact content.
69
+ async function generate(
70
+ folder: string,
71
+ files: { name: string, content: string }[]
72
+ ) {
73
+ const jostraca = Jostraca()
74
+
75
+ await jostraca.generate({ folder }, () => {
76
+ Project({}, () => {
77
+ for (const f of files) {
78
+ File({ name: f.name }, () => {
79
+ Content(f.content)
80
+ })
81
+ }
82
+ })
83
+ })
84
+ }
85
+
86
+
87
+ function empty(o: any) {
88
+ return null == o ? true : 0 === Object.keys(o).length
89
+ }
90
+
91
+ // Strip inital newline
92
+ function TM(str: string) {
93
+ return str.replace(/^\n/, '')
94
+ }
95
+
96
+
97
+ export {
98
+ generate,
99
+ empty,
100
+ TM,
101
+ loadFragment,
102
+ renderFragment,
103
+ listFragments,
104
+ PKG_TM,
105
+ }
@@ -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
+ }