Skip to content

Commit 86682ae

Browse files
committed
fix(apps): keep backend runtime context private
1 parent 30ef62c commit 86682ae

2 files changed

Lines changed: 22 additions & 17 deletions

File tree

packages/plugins/apps/src/backend/virtual-entry.test.ts

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,6 @@ describe('Backend Functions - generateVirtualEntryContent', () => {
3838
expect(result).toContain('export async function main($)');
3939
});
4040

41-
test('Should set globalThis.$ = $', () => {
42-
const result = generateVirtualEntryContent(
43-
'myHandler',
44-
'/src/handler.ts',
45-
PROJECT_ROOT,
46-
);
47-
expect(result).toContain('globalThis.$ = $');
48-
});
49-
5041
test('Should read args from $.backendFunctionArgs (no source-text substitution)', () => {
5142
const result = generateVirtualEntryContent(
5243
'myHandler',
@@ -69,7 +60,7 @@ describe('Backend Functions - generateVirtualEntryContent', () => {
6960
'/src/handler.ts',
7061
PROJECT_ROOT,
7162
);
72-
expect(result).toContain('await myHandler(...args)');
63+
expect(result).toContain('await myHandler(...args, $)');
7364
});
7465

7566
test('Should include the setExecuteActionImplementation bridge snippet', () => {
@@ -175,9 +166,8 @@ describe('Backend Functions - args round-trip via $.backendFunctionArgs', () =>
175166
.filter((line) => !line.trimStart().startsWith('import '))
176167
.join('\n')
177168
// Replace the call site with a $-bound handler we control.
178-
.replace(/await myHandler\(\.\.\.args\)/, 'await $.__handler(...args)');
179-
// The generated code declares globalThis.$, which has no effect in this
180-
// sandbox but is harmless. Wrap the body so we can return main().
169+
.replace(/await myHandler\(\.\.\.args, \$\)/, 'await $.__handler(...args, $)');
170+
// Wrap the executable body so we can return main().
181171
const wrapper = `${body}\nreturn main($);`;
182172
// eslint-disable-next-line @typescript-eslint/no-implied-eval, no-new-func
183173
const fn = new Function(
@@ -222,11 +212,26 @@ describe('Backend Functions - args round-trip via $.backendFunctionArgs', () =>
222212
const source = generateVirtualEntryContent('myHandler', '/src/handler.ts', PROJECT_ROOT);
223213
let received: unknown[] | undefined;
224214
const handler = (...args: unknown[]) => {
225-
received = args;
215+
// Slice off the final implicitly passed $ context argument to check user-supplied args
216+
received = args.slice(0, -1);
226217
return 'ok';
227218
};
228219
const main = buildMainFromSource(source, handler);
229220
await main({});
230221
expect(received).toEqual([]);
231222
});
223+
224+
test('Should keep the runtime context out of customer global scope', async () => {
225+
const source = generateVirtualEntryContent('myHandler', '/src/handler.ts', PROJECT_ROOT);
226+
let exposedContext: unknown;
227+
const handler = () => {
228+
exposedContext = Reflect.get(global, '$');
229+
return 'ok';
230+
};
231+
const main = buildMainFromSource(source, handler);
232+
233+
await main({ backendFunctionArgs: [], privateRuntimeValue: 'secret' });
234+
235+
expect(exposedContext).toBeUndefined();
236+
});
232237
});

packages/plugins/apps/src/backend/virtual-entry.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,13 @@ export function generateVirtualEntryContent(
2828
lines.push('');
2929
lines.push('/** @param {import("./context.types").Context} $ */');
3030
lines.push('export async function main($) {');
31-
lines.push(' globalThis.$ = $;');
32-
lines.push('');
3331
lines.push(` // Register the $.Actions-based implementation for executeAction`);
3432
lines.push(SET_EXECUTE_ACTION_SNIPPET);
3533
lines.push('');
3634
lines.push(' const args = $.backendFunctionArgs ?? [];');
37-
lines.push(` const result = await ${functionName}(...args);`);
35+
lines.push(` // To maintain backward compatibility with legacy handlers, keep passing $ as
36+
// the final argument. This will be removed in a future major release.
37+
const result = await ${functionName}(...args, $);`);
3838
lines.push(' return result;');
3939
lines.push('}');
4040

0 commit comments

Comments
 (0)