Skip to content

Commit bebddf8

Browse files
committed
reserve describe methodName for discoverableExo
1 parent ebe4791 commit bebddf8

File tree

2 files changed

+71
-12
lines changed

2 files changed

+71
-12
lines changed

packages/kernel-utils/src/discoverable.test.ts

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,16 @@
1-
import { describe, expect, it } from 'vitest';
1+
import { describe, expect, it, vi } from 'vitest';
22

33
import { makeDiscoverableExo } from './discoverable.ts';
44
import type { MethodSchema } from './schema.ts';
55

6+
const makeExoMock = vi.hoisted(() =>
7+
vi.fn((_name, _interfaceGuard, methods) => methods),
8+
);
9+
10+
vi.mock('@endo/exo', () => ({
11+
makeExo: makeExoMock,
12+
}));
13+
614
describe('makeDiscoverableExo', () => {
715
const greetSchema: MethodSchema = {
816
description: 'Greets a person by name',
@@ -113,4 +121,37 @@ describe('makeDiscoverableExo', () => {
113121
doSomething: schema.doSomething,
114122
});
115123
});
124+
125+
it('throws if describe is already a method', () => {
126+
const methods = {
127+
describe: () => 'original describe',
128+
greet: (name: string) => `Hello, ${name}!`,
129+
};
130+
const schema: Record<keyof typeof methods, MethodSchema> = {
131+
describe: {
132+
description: 'Original describe method',
133+
args: {},
134+
returns: { type: 'string', description: 'Original description' },
135+
},
136+
greet: greetSchema,
137+
};
138+
139+
expect(() => {
140+
makeDiscoverableExo('TestExo', methods, schema);
141+
}).toThrow('The `describe` method name is reserved for discoverable exos.');
142+
});
143+
144+
it('re-throws errors from makeExo that are not about describe key', () => {
145+
const testError = new Error('Some other error from makeExo');
146+
makeExoMock.mockImplementation(() => {
147+
throw testError;
148+
});
149+
150+
const methods = { greet: (name: string) => `Hello, ${name}!` };
151+
const schema = { greet: greetSchema };
152+
153+
expect(() => {
154+
makeDiscoverableExo('TestExo', methods, schema);
155+
}).toThrow('Some other error from makeExo');
156+
});
116157
});

packages/kernel-utils/src/discoverable.ts

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import type { Methods } from '@endo/exo';
33
import type { InterfaceGuard } from '@endo/patterns';
44

55
import { makeDefaultInterface } from './exo.ts';
6+
import { mergeDisjointRecords } from './merge-disjoint-records.ts';
67
import type { MethodSchema } from './schema.ts';
78

89
/**
@@ -50,14 +51,31 @@ export const makeDiscoverableExo = <
5051
methods: Interface,
5152
schema: Schema,
5253
interfaceGuard: InterfaceGuard = makeDefaultInterface(name),
53-
): DiscoverableExo<Interface, Schema> =>
54-
// @ts-expect-error We're intentionally not specifying method-specific interface guards.
55-
makeExo(name, interfaceGuard, {
56-
...methods,
57-
/**
58-
* Describe the methods of the discoverable.
59-
*
60-
* @returns A schema of the methods.
61-
*/
62-
describe: () => schema,
63-
});
54+
): DiscoverableExo<Interface, Schema> => {
55+
try {
56+
// @ts-expect-error We're intentionally not specifying method-specific interface guards.
57+
return makeExo(
58+
name,
59+
interfaceGuard,
60+
// @ts-expect-error We're intentionally not specifying method-specific interface guards.
61+
mergeDisjointRecords(methods, {
62+
/**
63+
* Describe the methods of the discoverable.
64+
*
65+
* @returns A schema of the methods.
66+
*/
67+
describe: () => schema,
68+
}),
69+
);
70+
} catch (error) {
71+
if (
72+
error instanceof Error &&
73+
error.message.includes('Duplicate keys in records: describe')
74+
) {
75+
throw new Error(
76+
'The `describe` method name is reserved for discoverable exos.',
77+
);
78+
}
79+
throw error;
80+
}
81+
};

0 commit comments

Comments
 (0)