Skip to content

Commit aa9dc13

Browse files
msonnbcodex
andcommitted
fix(aws-serverless): Support pnpm handler paths
Co-Authored-By: OpenAI Codex <codex@openai.com>
1 parent 28613a7 commit aa9dc13

3 files changed

Lines changed: 50 additions & 22 deletions

File tree

‎dev-packages/e2e-tests/test-applications/aws-serverless/src/stack.ts‎

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,6 @@ function resolvePackagesDir(): string {
2727
return path.resolve(__dirname, '../../../../../packages');
2828
}
2929

30-
function materializePackage(lambdaPath: string, packageName: string): void {
31-
const packagePath = path.join(lambdaPath, 'node_modules', ...packageName.split('/'));
32-
const resolvedPackagePath = fs.realpathSync(packagePath);
33-
34-
fs.rmSync(packagePath, { recursive: true, force: true });
35-
fs.cpSync(resolvedPackagePath, packagePath, { recursive: true, dereference: true });
36-
}
37-
3830
export class LocalLambdaStack extends Stack {
3931
constructor(scope: Construct, id: string, props: StackProps, hostIp: string) {
4032
console.log('[LocalLambdaStack] Creating local SAM Lambda Stack');
@@ -87,15 +79,6 @@ export class LocalLambdaStack extends Stack {
8779
dependencies[name] = `file:${relativePath.replace(/\\/g, '/')}`;
8880
}
8981

90-
const awsServerlessPackageJson = JSON.parse(
91-
fs.readFileSync(path.join(packagesDir, 'aws-serverless', 'package.json'), 'utf8'),
92-
) as { dependencies: Record<string, string> };
93-
const conventionsVersion = awsServerlessPackageJson.dependencies['@sentry/conventions'];
94-
if (!conventionsVersion) {
95-
throw new Error('[LocalLambdaStack] @sentry/aws-serverless does not declare @sentry/conventions');
96-
}
97-
dependencies['@sentry/conventions'] = conventionsVersion;
98-
9982
console.log(`[LocalLambdaStack] Install dependencies for ${functionName}`);
10083

10184
if (fs.existsSync(lockfilePath)) {
@@ -119,9 +102,6 @@ export class LocalLambdaStack extends Stack {
119102
stdio: 'inherit',
120103
});
121104

122-
// Lambda handler names cannot contain pnpm's `.pnpm` virtual-store path.
123-
materializePackage(lambdaPath, '@sentry/aws-serverless');
124-
125105
if (!process.env.NODE_VERSION) {
126106
throw new Error('[LocalLambdaStack] NODE_VERSION is not set');
127107
}

‎packages/aws-serverless/src/integration/awslambda.ts‎

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,38 @@
11
import type { IntegrationFn } from '@sentry/core';
22
import { debug, defineIntegration, getCurrentScope, safeSetSpanJSONAttributes } from '@sentry/core';
3+
import { existsSync } from 'node:fs';
34
import { createRequire } from 'node:module';
5+
import { sep, join } from 'node:path';
46
import { DEBUG_BUILD } from '../debug-build';
57
import { parseHandlerString, resolveHandlerFile } from '../handlerResolution';
68

79
const SHIM_MODULE_ID = '@sentry/aws-serverless/run-lambda-handler';
810

11+
export function findHandlerShimFile(resolvedShimFile: string, nodeModulesPaths: string[] | null): string | undefined {
12+
const nodeModulesMarker = `${sep}node_modules${sep}`;
13+
const lastNodeModulesIndex = resolvedShimFile.lastIndexOf(nodeModulesMarker);
14+
const packageRelativePath =
15+
lastNodeModulesIndex < 0 ? undefined : resolvedShimFile.slice(lastNodeModulesIndex + nodeModulesMarker.length);
16+
17+
const logicalShimFiles = packageRelativePath
18+
? (nodeModulesPaths ?? []).map(nodeModulesPath => join(nodeModulesPath, packageRelativePath))
19+
: [];
20+
21+
return [...logicalShimFiles, resolvedShimFile].find(shimFile => !shimFile.includes('..') && existsSync(shimFile));
22+
}
23+
924
function resolveShimFile(): string | undefined {
1025
try {
1126
// In the CJS build `require` exists; in the ESM build (and when running the TS source
1227
// directly, e.g. in tests) we create one. Rollup converts `import.meta.url` to an
1328
// equivalent for the CJS build, so both branches are always syntactically valid.
1429
const resolve = typeof require === 'function' ? require.resolve : createRequire(import.meta.url).resolve;
15-
return resolve(SHIM_MODULE_ID);
30+
const resolvedShimFile = resolve(SHIM_MODULE_ID);
31+
const shimFile = findHandlerShimFile(resolvedShimFile, resolve.paths(SHIM_MODULE_ID));
32+
if (!shimFile) {
33+
DEBUG_BUILD && debug.warn(`Could not find a Lambda-compatible path for ${SHIM_MODULE_ID}.`);
34+
}
35+
return shimFile;
1636
} catch (error) {
1737
DEBUG_BUILD && debug.warn(`Could not resolve ${SHIM_MODULE_ID}, not instrumenting the Lambda handler.`, error);
1838
return undefined;

‎packages/aws-serverless/test/awslambda-integration.test.ts‎

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import * as fs from 'node:fs';
33
import * as os from 'node:os';
44
import * as path from 'node:path';
55
import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest';
6-
import { awsLambdaIntegration, redirectLambdaHandler } from '../src/integration/awslambda';
6+
import { awsLambdaIntegration, findHandlerShimFile, redirectLambdaHandler } from '../src/integration/awslambda';
77

88
const mockGetScopeData = vi.fn();
99

@@ -45,6 +45,34 @@ describe('redirectLambdaHandler', () => {
4545
expect(process.env._HANDLER).not.toContain('..');
4646
});
4747

48+
test('uses a logical package path when pnpm resolves the shim to an invalid virtual-store path', () => {
49+
const nodeModulesPath = path.join(taskRoot, 'node_modules');
50+
const logicalShimFile = path.join(
51+
nodeModulesPath,
52+
'@sentry',
53+
'aws-serverless',
54+
'build',
55+
'npm',
56+
'run-lambda-handler.mjs',
57+
);
58+
fs.mkdirSync(path.dirname(logicalShimFile), { recursive: true });
59+
fs.writeFileSync(logicalShimFile, 'export const handler = () => {};');
60+
61+
const resolvedShimFile = path.join(
62+
nodeModulesPath,
63+
'.pnpm',
64+
'@sentry+aws-serverless@file+..+..+packages+aws-serverless',
65+
'node_modules',
66+
'@sentry',
67+
'aws-serverless',
68+
'build',
69+
'npm',
70+
'run-lambda-handler.mjs',
71+
);
72+
73+
expect(findHandlerShimFile(resolvedShimFile, [nodeModulesPath])).toBe(logicalShimFile);
74+
});
75+
4876
test('does nothing when LAMBDA_TASK_ROOT or _HANDLER are not set', () => {
4977
process.env._HANDLER = 'index.handler';
5078

0 commit comments

Comments
 (0)