@emarketeer/ts-microservice-commons 10.0.0 → 10.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.
- package/dist/cdk/cjs/index.js +98 -19
- package/dist/cdk/cjs/index.js.map +1 -1
- package/dist/cdk/index.js +99 -22
- package/dist/cdk/index.js.map +1 -1
- package/dist/handler-bundler.js +170 -0
- package/dist/lib/em-commons.js +7 -22
- package/dist/types/cdk/constructs/lambda-with-queue.d.ts +3 -0
- package/dist/types/cdk/types/common.d.ts +9 -0
- package/dist/types/cdk/utils/bundling.d.ts +56 -0
- package/dist/types/cdk/utils/handler-path.d.ts +12 -3
- package/dist/types/cdk/utils/index.d.ts +1 -0
- package/package.json +2 -5
- package/dist/build-handlers.js +0 -197
- package/dist/esbuild-plugins.js +0 -76
- package/dist/types/find-entry-points.d.ts +0 -20
- package/dist/types/find-entry-points.test.d.ts +0 -1
- /package/dist/types/{build-handlers.d.ts → handler-bundler.d.ts} +0 -0
package/dist/cdk/cjs/index.js
CHANGED
|
@@ -9,6 +9,8 @@ var awsLogs = require('aws-cdk-lib/aws-logs');
|
|
|
9
9
|
var constructs = require('constructs');
|
|
10
10
|
var awsSsm = require('aws-cdk-lib/aws-ssm');
|
|
11
11
|
var path = require('path');
|
|
12
|
+
var fs = require('fs');
|
|
13
|
+
var child_process = require('child_process');
|
|
12
14
|
var awsDynamodb = require('aws-cdk-lib/aws-dynamodb');
|
|
13
15
|
var awsApigateway = require('aws-cdk-lib/aws-apigateway');
|
|
14
16
|
var awsApigatewayv2 = require('aws-cdk-lib/aws-apigatewayv2');
|
|
@@ -46,6 +48,7 @@ function _interopNamespace(e) {
|
|
|
46
48
|
|
|
47
49
|
var cdk__namespace = /*#__PURE__*/_interopNamespace(cdk);
|
|
48
50
|
var path__namespace = /*#__PURE__*/_interopNamespace(path);
|
|
51
|
+
var fs__namespace = /*#__PURE__*/_interopNamespace(fs);
|
|
49
52
|
var ec2__namespace = /*#__PURE__*/_interopNamespace(ec2);
|
|
50
53
|
|
|
51
54
|
/**
|
|
@@ -458,29 +461,30 @@ const resolveRecapDevEndpoint = (scope) => {
|
|
|
458
461
|
const DEFAULT_LAMBDA_RUNTIME = awsLambda.Runtime.NODEJS_24_X;
|
|
459
462
|
|
|
460
463
|
const DEFAULT_HANDLERS_DIR = 'src/handlers';
|
|
461
|
-
const DEFAULT_OUT_DIR = 'dist/handlers';
|
|
462
464
|
/**
|
|
463
|
-
* Resolve `handlerPath` into `
|
|
465
|
+
* Resolve `handlerPath` into `entryFile`, `handler`, and optionally `functionName`.
|
|
464
466
|
*
|
|
465
467
|
* Given `handlerPath: 'src/handlers/capture-screenshot/capture-screenshot-from-url'`:
|
|
466
|
-
* - `
|
|
468
|
+
* - `entryFile` → `'src/handlers/capture-screenshot/capture-screenshot-from-url.ts'`
|
|
467
469
|
* - `handler` → `'index.handler'`
|
|
468
470
|
* - `functionName` → `'capture-screenshot-from-url'` (only when not explicitly provided)
|
|
469
471
|
*
|
|
472
|
+
* When `codePath` is provided, `entryFile` is left unset — the construct will
|
|
473
|
+
* package `codePath` directly (no bundling).
|
|
474
|
+
*
|
|
470
475
|
* When `handlerPath` is not provided, `functionName` is required.
|
|
471
|
-
* `handler` and `codePath` may remain undefined if the caller has its own defaults.
|
|
472
476
|
*/
|
|
473
477
|
function resolveHandlerPath(config) {
|
|
474
478
|
const { handlerPath } = config;
|
|
475
479
|
if (handlerPath) {
|
|
476
480
|
const normalised = handlerPath.replace(/\.ts$/, '');
|
|
477
|
-
const startsWithHandlersDir = normalised.startsWith(DEFAULT_HANDLERS_DIR
|
|
481
|
+
const startsWithHandlersDir = normalised.startsWith(`${DEFAULT_HANDLERS_DIR}/`);
|
|
478
482
|
const containsSeparator = normalised.includes('/') || normalised.includes(path__namespace.sep);
|
|
479
483
|
if (!startsWithHandlersDir && (path__namespace.isAbsolute(normalised) || containsSeparator)) {
|
|
480
484
|
// A bare basename like 'get-data' is fine (treated as relative to
|
|
481
485
|
// src/handlers). Anything with directory components must be rooted at
|
|
482
486
|
// DEFAULT_HANDLERS_DIR — otherwise we'd silently produce e.g.
|
|
483
|
-
// '
|
|
487
|
+
// 'src/lambdas/foo.ts' and fail at synth with an opaque
|
|
484
488
|
// Code.fromAsset error far from the call site.
|
|
485
489
|
throw new Error(`resolveHandlerPath: handlerPath "${handlerPath}" must either be a bare basename or start with "${DEFAULT_HANDLERS_DIR}/".`);
|
|
486
490
|
}
|
|
@@ -490,7 +494,8 @@ function resolveHandlerPath(config) {
|
|
|
490
494
|
return {
|
|
491
495
|
functionName: config.functionName ?? path__namespace.basename(relative),
|
|
492
496
|
handler: config.handler ?? 'index.handler',
|
|
493
|
-
|
|
497
|
+
entryFile: config.codePath ? undefined : path__namespace.join(DEFAULT_HANDLERS_DIR, `${relative}.ts`),
|
|
498
|
+
codePath: config.codePath
|
|
494
499
|
};
|
|
495
500
|
}
|
|
496
501
|
if (!config.functionName) {
|
|
@@ -503,6 +508,70 @@ function resolveHandlerPath(config) {
|
|
|
503
508
|
};
|
|
504
509
|
}
|
|
505
510
|
|
|
511
|
+
const HANDLER_BUNDLER_RELATIVE_PATH = path__namespace.join('dist', 'handler-bundler.js');
|
|
512
|
+
const PACKAGE_NAME = '@emarketeer/ts-microservice-commons';
|
|
513
|
+
let cachedBundlerPath;
|
|
514
|
+
function getHandlerBundlerPath() {
|
|
515
|
+
if (cachedBundlerPath) {
|
|
516
|
+
return cachedBundlerPath;
|
|
517
|
+
}
|
|
518
|
+
const cwd = process.cwd();
|
|
519
|
+
const candidates = [
|
|
520
|
+
path__namespace.join(cwd, 'node_modules', PACKAGE_NAME, HANDLER_BUNDLER_RELATIVE_PATH),
|
|
521
|
+
path__namespace.join(cwd, HANDLER_BUNDLER_RELATIVE_PATH)
|
|
522
|
+
];
|
|
523
|
+
for (const candidate of candidates) {
|
|
524
|
+
if (fs__namespace.existsSync(candidate)) {
|
|
525
|
+
cachedBundlerPath = candidate;
|
|
526
|
+
return candidate;
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
throw new Error(`Could not locate the handler bundler. Searched:\n${candidates.map((c) => ` - ${c}`).join('\n')}\n`
|
|
530
|
+
+ `Ensure ${PACKAGE_NAME} is installed.`);
|
|
531
|
+
}
|
|
532
|
+
/**
|
|
533
|
+
* Build the `Code` asset for a Lambda function.
|
|
534
|
+
*
|
|
535
|
+
* - When `codePath` is set, packages that directory directly (no bundling).
|
|
536
|
+
* - Otherwise bundles `entryFile` via the project handler bundler at synth
|
|
537
|
+
* time, with overrides applied on top of the defaults.
|
|
538
|
+
*
|
|
539
|
+
* Bundling uses `assetHashType: OUTPUT` so the asset hash is computed from
|
|
540
|
+
* the bundled output rather than from the (transitive) source tree.
|
|
541
|
+
*/
|
|
542
|
+
function resolveLambdaCode(options) {
|
|
543
|
+
if (options.codePath) {
|
|
544
|
+
return awsLambda.Code.fromAsset(options.codePath);
|
|
545
|
+
}
|
|
546
|
+
if (!options.entryFile) {
|
|
547
|
+
throw new Error('resolveLambdaCode: either `entryFile` or `codePath` is required.');
|
|
548
|
+
}
|
|
549
|
+
const entry = path__namespace.resolve(options.entryFile);
|
|
550
|
+
if (!fs__namespace.existsSync(entry)) {
|
|
551
|
+
throw new Error(`resolveLambdaCode: entry file not found: ${entry}`);
|
|
552
|
+
}
|
|
553
|
+
const overrides = options.bundling;
|
|
554
|
+
const bundlerPath = getHandlerBundlerPath();
|
|
555
|
+
return awsLambda.Code.fromAsset(path__namespace.dirname(entry), {
|
|
556
|
+
assetHashType: cdk.AssetHashType.OUTPUT,
|
|
557
|
+
bundling: {
|
|
558
|
+
// CDK requires `image` even when local bundling succeeds. We never use
|
|
559
|
+
// the Docker fallback — `tryBundle` always returns true.
|
|
560
|
+
image: cdk.DockerImage.fromRegistry('node:24'),
|
|
561
|
+
local: {
|
|
562
|
+
tryBundle(outputDir) {
|
|
563
|
+
const stdin = JSON.stringify({ entry, outDir: outputDir, overrides });
|
|
564
|
+
child_process.execFileSync('node', [bundlerPath], {
|
|
565
|
+
input: stdin,
|
|
566
|
+
stdio: ['pipe', 'inherit', 'inherit']
|
|
567
|
+
});
|
|
568
|
+
return true;
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
});
|
|
573
|
+
}
|
|
574
|
+
|
|
506
575
|
class EmLambdaFunction extends constructs.Construct {
|
|
507
576
|
constructor(scope, id, config) {
|
|
508
577
|
super(scope, id);
|
|
@@ -539,14 +608,22 @@ class EmLambdaFunction extends constructs.Construct {
|
|
|
539
608
|
});
|
|
540
609
|
const handler = resolved.handler ?? config.handler;
|
|
541
610
|
const codePath = resolved.codePath ?? config.codePath;
|
|
542
|
-
if (!handler
|
|
543
|
-
throw new Error(`EmLambdaFunction requires either \`handlerPath\` or
|
|
611
|
+
if (!handler) {
|
|
612
|
+
throw new Error(`EmLambdaFunction requires either \`handlerPath\` or \`handler\` for "${resolved.functionName}".`);
|
|
613
|
+
}
|
|
614
|
+
if (!resolved.entryFile && !codePath) {
|
|
615
|
+
throw new Error(`EmLambdaFunction requires either \`handlerPath\` or \`codePath\` for "${resolved.functionName}".`);
|
|
544
616
|
}
|
|
617
|
+
const code = resolveLambdaCode({
|
|
618
|
+
entryFile: resolved.entryFile,
|
|
619
|
+
codePath,
|
|
620
|
+
bundling: config.bundling
|
|
621
|
+
});
|
|
545
622
|
this.function = new awsLambda.Function(this, 'Function', {
|
|
546
623
|
functionName,
|
|
547
624
|
runtime: config.runtime ?? DEFAULT_LAMBDA_RUNTIME,
|
|
548
625
|
handler,
|
|
549
|
-
code
|
|
626
|
+
code,
|
|
550
627
|
memorySize: config.memorySize ?? 1024,
|
|
551
628
|
timeout: config.timeout ?? cdk.Duration.seconds(15),
|
|
552
629
|
environment: {
|
|
@@ -1827,7 +1904,15 @@ class LambdaWithQueue extends constructs.Construct {
|
|
|
1827
1904
|
const resourceName = props.resourceName ?? shortName;
|
|
1828
1905
|
const functionName = props.physicalName ?? generateLambdaName(props.stage, props.serviceName, shortName);
|
|
1829
1906
|
const handler = resolved.handler ?? props.handler ?? 'index.handler';
|
|
1830
|
-
const codePath = resolved.codePath ?? props.codePath
|
|
1907
|
+
const codePath = resolved.codePath ?? props.codePath;
|
|
1908
|
+
if (!resolved.entryFile && !codePath) {
|
|
1909
|
+
throw new Error(`LambdaWithQueue requires either \`handlerPath\` or \`codePath\` for "${shortName}".`);
|
|
1910
|
+
}
|
|
1911
|
+
const code = resolveLambdaCode({
|
|
1912
|
+
entryFile: resolved.entryFile,
|
|
1913
|
+
codePath,
|
|
1914
|
+
bundling: props.bundling
|
|
1915
|
+
});
|
|
1831
1916
|
if (props.reservedConcurrency === 0) {
|
|
1832
1917
|
throw new Error(`reservedConcurrency:0 disables the Lambda entirely for ${shortName}. Omit the prop to use account-level concurrency.`);
|
|
1833
1918
|
}
|
|
@@ -1860,7 +1945,7 @@ class LambdaWithQueue extends constructs.Construct {
|
|
|
1860
1945
|
functionName,
|
|
1861
1946
|
runtime: props.runtime ?? DEFAULT_LAMBDA_RUNTIME,
|
|
1862
1947
|
handler,
|
|
1863
|
-
code
|
|
1948
|
+
code,
|
|
1864
1949
|
architecture: props.architecture ?? awsLambda.Architecture.ARM_64,
|
|
1865
1950
|
memorySize,
|
|
1866
1951
|
timeout,
|
|
@@ -2165,16 +2250,9 @@ class EmStack extends cdk__namespace.Stack {
|
|
|
2165
2250
|
const merged = this.mergeConfig(config);
|
|
2166
2251
|
const resolved = resolveHandlerPath(merged);
|
|
2167
2252
|
const functionName = resolved.functionName;
|
|
2168
|
-
const handler = resolved.handler ?? merged.handler;
|
|
2169
|
-
const codePath = resolved.codePath ?? merged.codePath;
|
|
2170
|
-
if (!handler || !codePath) {
|
|
2171
|
-
throw new Error(`createFunction() requires either \`handlerPath\` or all of \`functionName\`, \`handler\`, and \`codePath\` for "${functionName}".`);
|
|
2172
|
-
}
|
|
2173
2253
|
const fn = new EmLambdaFunction(this, id, {
|
|
2174
2254
|
...merged,
|
|
2175
2255
|
functionName,
|
|
2176
|
-
handler,
|
|
2177
|
-
codePath,
|
|
2178
2256
|
stage: merged.stage ?? this.stage,
|
|
2179
2257
|
serviceName: merged.serviceName ?? this.serviceName,
|
|
2180
2258
|
role: merged.role ?? this.sharedRole
|
|
@@ -2805,6 +2883,7 @@ exports.overrideFunctionLogicalIds = overrideFunctionLogicalIds;
|
|
|
2805
2883
|
exports.overrideLayerLogicalId = overrideLayerLogicalId;
|
|
2806
2884
|
exports.overrideRoleLogicalId = overrideRoleLogicalId;
|
|
2807
2885
|
exports.resolveHandlerPath = resolveHandlerPath;
|
|
2886
|
+
exports.resolveLambdaCode = resolveLambdaCode;
|
|
2808
2887
|
exports.resolveRecapDevEndpoint = resolveRecapDevEndpoint;
|
|
2809
2888
|
exports.stageToUpperCase = stageToUpperCase;
|
|
2810
2889
|
exports.toServerlessLogicalIdPrefix = toServerlessLogicalIdPrefix;
|