@mettlecast/domain-cdk-packer 0.2.1 → 0.2.4

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.
@@ -2,6 +2,8 @@ import * as cdk from 'aws-cdk-lib';
2
2
  import * as lambda from 'aws-cdk-lib/aws-lambda';
3
3
  import * as nodejs from 'aws-cdk-lib/aws-lambda-nodejs';
4
4
  import { Construct } from 'constructs';
5
+ import { createRequire } from 'module';
6
+ const require = createRequire(import.meta.url);
5
7
  export class HealthConstruct extends Construct {
6
8
  healthFn;
7
9
  readyFn;
@@ -14,6 +14,8 @@ export interface HandlerEntry {
14
14
  export interface GroupedLambdaProps {
15
15
  /** Domain ID this Lambda belongs to. */
16
16
  domainId: string;
17
+ /** Absolute path to the domain root directory. Required for dedicated mode. */
18
+ domainRoot?: string;
17
19
  /** The primitive type being handled (api, subscriber, etc.). */
18
20
  primitiveType: PrimitiveType;
19
21
  /** All handler entries for this primitive type within the domain. */
@@ -36,8 +38,8 @@ export interface GroupedLambdaProps {
36
38
  /**
37
39
  * Creates either a single grouped Lambda (default) or per-handler dedicated Lambdas.
38
40
  *
39
- * Grouped Lambdas use an internal dispatch router: TIB_HANDLER_MAP lists all handler IDs,
40
- * and the incoming event/request carries a handler ID to route to the correct function.
41
- * When dedicated=true (escape hatch for hot/critical handlers), each handler gets its own Lambda.
41
+ * Dedicated mode uses NodejsFunction (esbuild on-the-fly) with auto-generated
42
+ * adapter wrappers no pre-compiled dist/domains/ assets needed.
43
+ * Grouped mode retains Code.fromAsset for backward compatibility.
42
44
  */
43
45
  export declare function createGroupedLambdas(scope: Construct, props: GroupedLambdaProps): lambda.Function[];
@@ -1,26 +1,85 @@
1
1
  import * as lambda from 'aws-cdk-lib/aws-lambda';
2
+ import * as lambdaNode from 'aws-cdk-lib/aws-lambda-nodejs';
2
3
  import * as logs from 'aws-cdk-lib/aws-logs';
3
4
  import * as cdk from 'aws-cdk-lib';
5
+ import { writeFileSync, mkdirSync } from 'fs';
6
+ import { join } from 'path';
7
+ import { tmpdir } from 'os';
8
+ function camelCase(str) {
9
+ return str.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
10
+ }
11
+ function toPascalCase(str) {
12
+ return str.charAt(0).toUpperCase() + camelCase(str).slice(1);
13
+ }
14
+ function generateDedicatedEntry(domainRoot, entry, primitiveType) {
15
+ const exportName = camelCase(entry.id);
16
+ if (primitiveType === 'schedule') {
17
+ return [
18
+ `import { hydrateCtx } from '@mettlecast/domain-runtime';`,
19
+ `import { ${exportName} } from '${domainRoot}/${entry.handlerFile}';`,
20
+ ``,
21
+ `export const handler = async (event: any) => {`,
22
+ ` const ctx = await hydrateCtx(event, {`,
23
+ ` databaseUrl: process.env.DATABASE_URL,`,
24
+ ` eventBusName: process.env.EVENT_BUS_NAME,`,
25
+ ` });`,
26
+ ` try { await ${exportName}.handler(ctx); } finally { try { await ctx.db.release(); } catch {} }`,
27
+ `};`,
28
+ ].join('\n');
29
+ }
30
+ const adapterMap = {
31
+ api: 'createApiLambdaHandler',
32
+ subscriber: 'createSubscriberLambdaHandler',
33
+ job: 'createJobLambdaHandler',
34
+ webhook: 'createWebhookLambdaHandler',
35
+ action: 'createActionLambdaHandler',
36
+ };
37
+ const adapter = adapterMap[primitiveType] ?? 'createApiLambdaHandler';
38
+ return [
39
+ `import { ${adapter} } from '@mettlecast/domain-runtime';`,
40
+ `import { ${exportName} } from '${domainRoot}/${entry.handlerFile}';`,
41
+ '',
42
+ `export const handler = ${adapter}(${exportName});`,
43
+ ].join('\n');
44
+ }
45
+ function writeTempEntry(content) {
46
+ const dir = join(tmpdir(), 'tib-domain-entries', `${Date.now()}-${Math.random().toString(36).slice(2)}`);
47
+ mkdirSync(dir, { recursive: true });
48
+ const filePath = join(dir, 'entry.ts');
49
+ writeFileSync(filePath, content, 'utf8');
50
+ return filePath;
51
+ }
52
+ const adapterCache = new Map();
4
53
  /**
5
54
  * Creates either a single grouped Lambda (default) or per-handler dedicated Lambdas.
6
55
  *
7
- * Grouped Lambdas use an internal dispatch router: TIB_HANDLER_MAP lists all handler IDs,
8
- * and the incoming event/request carries a handler ID to route to the correct function.
9
- * When dedicated=true (escape hatch for hot/critical handlers), each handler gets its own Lambda.
56
+ * Dedicated mode uses NodejsFunction (esbuild on-the-fly) with auto-generated
57
+ * adapter wrappers no pre-compiled dist/domains/ assets needed.
58
+ * Grouped mode retains Code.fromAsset for backward compatibility.
10
59
  */
11
60
  export function createGroupedLambdas(scope, props) {
12
61
  const vpcConfig = props.vpc ? { vpc: props.vpc, securityGroups: props.securityGroups } : {};
13
62
  const logRetention = toLogRetention(props.logRetentionDays ?? 30);
14
63
  const powertoolsLayerArn = `arn:aws:lambda:${cdk.Stack.of(scope).region}:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:26`;
15
64
  if (props.dedicated) {
16
- return props.handlerEntries.map(entry => {
65
+ if (!props.domainRoot)
66
+ throw new Error('domainRoot is required when dedicated=true');
67
+ const domainRoot = props.domainRoot;
68
+ const fns = props.handlerEntries.map(entry => {
17
69
  const powertoolsLayer = lambda.LayerVersion.fromLayerVersionArn(scope, `PowertoolsLayer${props.domainId}-${props.primitiveType}-${entry.id}`, powertoolsLayerArn);
18
- return new lambda.Function(scope, `${props.domainId}-${props.primitiveType}-${entry.id}`, {
70
+ const entryContent = generateDedicatedEntry(domainRoot, entry, props.primitiveType);
71
+ const entryPath = writeTempEntry(entryContent);
72
+ return new lambdaNode.NodejsFunction(scope, `${props.domainId}-${props.primitiveType}-${entry.id}`, {
19
73
  runtime: lambda.Runtime.NODEJS_22_X,
20
74
  architecture: lambda.Architecture.ARM_64,
21
- handler: 'index.handler',
22
- code: lambda.Code.fromAsset(`dist/domains/${props.domainId}/${props.primitiveType}/${entry.id}`),
75
+ entry: entryPath,
76
+ handler: 'handler',
23
77
  layers: [powertoolsLayer],
78
+ bundling: {
79
+ minify: true,
80
+ sourceMap: true,
81
+ externalModules: ['@aws-sdk/*'],
82
+ },
24
83
  environment: {
25
84
  ...props.environment,
26
85
  POWERTOOLS_SERVICE_NAME: `${props.domainId}-${props.primitiveType}`,
@@ -35,6 +94,7 @@ export function createGroupedLambdas(scope, props) {
35
94
  ...vpcConfig,
36
95
  });
37
96
  });
97
+ return fns;
38
98
  }
39
99
  // Single grouped Lambda — all handlers for this primitive type bundled together
40
100
  const powertoolsLayer = lambda.LayerVersion.fromLayerVersionArn(scope, `PowertoolsLayer${props.domainId}-${props.primitiveType}`, powertoolsLayerArn);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mettlecast/domain-cdk-packer",
3
- "version": "0.2.1",
3
+ "version": "0.2.4",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org",