Skip to content

Commit d486a0d

Browse files
authored
build(kernel-test): Bundle test vats from typescript source (#801)
## refactor(kernel-test): Convert vat source files to TypeScript ### Summary - Convert test vat source files from JavaScript to TypeScript with proper type annotations - Add `TestPowers` type and `unwrapTestLogger` utility for test vats that need structured logging ### Changes **ocap-kernel:** - Add `buildRootObject` parameter types **kernel-test:** - Rename all 38 vat source files from `.js` to `.ts` - Add TypeScript type annotations to all vat source files - Create `test-powers.ts` with `TestPowers` type and `unwrapTestLogger` utility - Update vats to use `TestPowers` for typed logger access **cli:** - Update vat bundler glob pattern to include `.ts` files (still matches `.js`, too) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Mostly test and tooling changes, but it touches the CLI bundling glob and exports new public types from `@MetaMask/ocap-kernel`, which could affect downstream builds if assumptions about source extensions or type exports differ. > > **Overview** > **Test vats are now authored in TypeScript and bundled from `.ts` sources.** The CLI `bundleDir` command expands its glob to include `*.{js,ts}` so vat bundles can be generated directly from TS entrypoints. > > **`kernel-test` vats were converted from `.js` to `.ts` with stronger typing and standardized logging.** A new `TestPowers` type plus `unwrapTestLogger` helper centralize structured test logging, and vats add explicit parameter/service/baggage types (including durable `Baggage` use). > > **`ocap-kernel` exposes additional public types.** `VatPowers` and `Baggage` are now exported from `@MetaMask/ocap-kernel` to support typed vat power signatures in tests. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 30f557f. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
1 parent dee4dca commit d486a0d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+1008
-629
lines changed

packages/cli/src/commands/bundle.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ export async function bundleDir(
5050
const { logger } = options;
5151
logger.info('Bundling directory:', sourceDir);
5252
await Promise.all(
53-
(await glob(join(sourceDir, '*.js'))).map(
53+
(await glob(join(sourceDir, '*.{js,ts}'))).map(
5454
async (source) => await bundleFile(source, { logger }),
5555
),
5656
);
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import type { Logger } from '@metamask/logger';
2+
import type { VatPowers } from '@metamask/ocap-kernel';
3+
4+
/**
5+
* Powers provided to test vats that need structured logging.
6+
* Extends VatPowers to maintain type compatibility with production vat powers.
7+
*/
8+
export type TestPowers = VatPowers & {
9+
logger: Logger;
10+
};
11+
12+
/**
13+
* Extract a tlog function from test vat powers.
14+
*
15+
* @param powers - The vat powers containing a logger.
16+
* @param name - The vat name to include in log tags.
17+
* @returns A function that logs with 'test' and name tags.
18+
*/
19+
export function unwrapTestLogger(
20+
powers: TestPowers,
21+
name: string,
22+
): (message: string, ...args: unknown[]) => void {
23+
const logger = powers.logger.subLogger({ tags: ['test', name] });
24+
return (message: string, ...args: unknown[]): void =>
25+
logger.log(message, ...args);
26+
}

packages/kernel-test/src/vats/async-generator-iterator-vat.js

Lines changed: 0 additions & 44 deletions
This file was deleted.
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { E } from '@endo/eventual-send';
2+
import { makeDefaultExo } from '@metamask/kernel-utils/exo';
3+
import { makeEventualIterator, makeExoGenerator } from '@ocap/remote-iterables';
4+
5+
import { unwrapTestLogger } from '../test-powers.ts';
6+
import type { TestPowers } from '../test-powers.ts';
7+
8+
/**
9+
* Build function for testing async generators.
10+
*
11+
* @param vatPowers - The powers of the vat.
12+
* @param vatPowers.logger - The logger to use.
13+
* @param parameters - The parameters of the vat.
14+
* @param parameters.name - The name of the vat.
15+
* @returns The root object for the vat.
16+
*/
17+
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
18+
export function buildRootObject(
19+
vatPowers: TestPowers,
20+
{ name }: { name: string },
21+
) {
22+
const tlog = unwrapTestLogger(vatPowers, name);
23+
24+
tlog(`${name} buildRootObject`);
25+
26+
return makeDefaultExo('root', {
27+
async bootstrap(
28+
{ consumer, producer }: { consumer: unknown; producer: unknown },
29+
_services: unknown,
30+
) {
31+
tlog(`${name} is bootstrap`);
32+
await E(consumer).iterate(producer);
33+
},
34+
35+
generate: async (stop: number) =>
36+
makeExoGenerator(
37+
(async function* () {
38+
for (let i = 0; i < stop; i++) {
39+
tlog(`${name} generating ${i}`);
40+
yield i;
41+
}
42+
// Note the IIFE.
43+
})(),
44+
),
45+
46+
iterate: async (producer: unknown) => {
47+
const remoteGenerator = await E(producer).generate(5);
48+
for await (const value of makeEventualIterator(remoteGenerator)) {
49+
tlog(`${name} iterating ${String(value)}`);
50+
}
51+
},
52+
});
53+
}

packages/kernel-test/src/vats/discoverable-capability-vat.js renamed to packages/kernel-test/src/vats/discoverable-capability-vat.ts

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,23 @@ import { makeDefaultExo } from '@metamask/kernel-utils/exo';
44
/**
55
* Build function for a vat that exports a discoverable exo capability.
66
*
7-
* @param {*} _vatPowers - Special powers granted to this vat (not used here).
8-
* @param {*} _parameters - Initialization parameters from the vat's config object.
9-
* @param {*} _baggage - Root of vat's persistent state (not used here).
10-
* @returns {*} The root object for the new vat.
7+
* @param _vatPowers - Special powers granted to this vat (not used here).
8+
* @param _parameters - Initialization parameters from the vat's config object.
9+
* @param _baggage - Root of vat's persistent state (not used here).
10+
* @returns The root object for the new vat.
1111
*/
12-
export function buildRootObject(_vatPowers, _parameters, _baggage) {
12+
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
13+
export function buildRootObject(
14+
_vatPowers: unknown,
15+
_parameters: unknown = {},
16+
_baggage: unknown = null,
17+
) {
1318
const calculator = makeDiscoverableExo(
1419
'Calculator',
1520
{
16-
add: (a, b) => a + b,
17-
multiply: (a, b) => a * b,
18-
greet: (name) => `Hello, ${name}!`,
21+
add: (a: number, b: number) => a + b,
22+
multiply: (a: number, b: number) => a * b,
23+
greet: (name: string) => `Hello, ${name}!`,
1924
},
2025
{
2126
add: {

packages/kernel-test/src/vats/endowment-fetch.js

Lines changed: 0 additions & 36 deletions
This file was deleted.
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { makeDefaultExo } from '@metamask/kernel-utils/exo';
2+
3+
import { unwrapTestLogger } from '../test-powers.ts';
4+
import type { TestPowers } from '../test-powers.ts';
5+
6+
/**
7+
* Build a root object for a vat that uses the fetch capability.
8+
*
9+
* @param vatPowers - The powers of the vat.
10+
* @param vatPowers.logger - The logger for the vat.
11+
* @returns The root object.
12+
*/
13+
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
14+
export async function buildRootObject(vatPowers: TestPowers) {
15+
const tlog = unwrapTestLogger(vatPowers, 'endowment-user');
16+
17+
tlog('buildRootObject');
18+
19+
const root = makeDefaultExo('root', {
20+
bootstrap: () => {
21+
tlog('bootstrap');
22+
},
23+
hello: async (url: string) => {
24+
try {
25+
const response = await fetch(url);
26+
const text = await response.text();
27+
tlog(`response: ${text}`);
28+
return text;
29+
} catch (error) {
30+
tlog(`error: ${String(error)}`);
31+
throw error;
32+
}
33+
},
34+
});
35+
36+
return root;
37+
}

packages/kernel-test/src/vats/error-bootstrap-throw.js renamed to packages/kernel-test/src/vats/error-bootstrap-throw.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
11
import { makeDefaultExo } from '@metamask/kernel-utils/exo';
22

3+
// eslint-disable-next-line no-console
34
console.log('bootstrap throw');
45

56
/**
67
* Build function for vats that will throw an error during bootstrap.
78
*
8-
* @returns {object} The root object for the new vat.
9+
* @returns The root object for the new vat.
910
*/
11+
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
1012
export function buildRootObject() {
13+
// eslint-disable-next-line no-console
1114
console.log('buildRootObject');
1215
return makeDefaultExo('root', {
1316
bootstrap: () => {
17+
// eslint-disable-next-line no-console
1418
console.log('bootstrap');
1519
throw new Error('from bootstrap');
1620
},

packages/kernel-test/src/vats/error-bootstrap-uncaught-rejection.js renamed to packages/kernel-test/src/vats/error-bootstrap-uncaught-rejection.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
11
import { makePromiseKit } from '@endo/promise-kit';
22
import { makeDefaultExo } from '@metamask/kernel-utils/exo';
33

4+
// eslint-disable-next-line no-console
45
console.log('bootstrap uncaught rejection');
56

67
/**
78
* Build function for vats that will reject a promise during bootstrap.
89
*
9-
* @returns {object} The root object for the new vat.
10+
* @returns The root object for the new vat.
1011
*/
12+
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
1113
export function buildRootObject() {
14+
// eslint-disable-next-line no-console
1215
console.log('buildRootObject');
1316
return makeDefaultExo('root', {
1417
bootstrap: () => {
18+
// eslint-disable-next-line no-console
1519
console.log('bootstrap');
1620
const { reject } = makePromiseKit();
1721
reject('from bootstrap');
Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1+
// eslint-disable-next-line no-console
12
console.log('build throw');
23

34
/**
45
* Build function for vats that will throw an error during buildRootObject.
5-
*
6-
* @returns {never} Always throws an error.
6+
* This function always throws and never returns.
77
*/
8-
export function buildRootObject() {
8+
export function buildRootObject(): never {
9+
// eslint-disable-next-line no-console
910
console.log('buildRootObject');
1011
throw new Error('from buildRootObject');
1112
}

0 commit comments

Comments
 (0)