Skip to content

Commit 076e45c

Browse files
committed
Merge branch 'main' into grypez/add-logger-package
2 parents 6730821 + 2148c20 commit 076e45c

File tree

23 files changed

+415
-211
lines changed

23 files changed

+415
-211
lines changed

packages/cli/src/app.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,6 @@ await yargs(hideBin(process.argv))
116116
const closeHandlers: (() => Promise<void>)[] = [];
117117
const resolvedDir = path.resolve(args.dir);
118118

119-
await bundleSource(resolvedDir, logger);
120-
121119
const handleClose = async (): Promise<void> => {
122120
await Promise.all(
123121
closeHandlers.map(async (close) => withTimeout(close(), 400)),

packages/cli/src/commands/watch.test.ts

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { unlink } from 'fs/promises';
88
import { describe, it, expect, vi, beforeEach } from 'vitest';
99

1010
import { bundleFile } from './bundle.ts';
11-
import { watchDir, makeWatchEvents, filterOnlyJsFiles } from './watch.ts';
11+
import { watchDir, makeWatchEvents, shouldIgnore } from './watch.ts';
1212

1313
vi.mock('fs/promises', () => ({
1414
unlink: vi.fn(async () => new Promise<void>(() => undefined)),
@@ -46,21 +46,22 @@ describe('watchDir', () => {
4646
});
4747
});
4848

49-
describe('filterOnlyJsFiles', () => {
49+
describe('shouldIgnore', () => {
5050
const missingStats = undefined as unknown as Stats;
5151
const fileStats = { isFile: () => true } as unknown as Stats;
5252
const nonFileStats = { isFile: () => false } as unknown as Stats;
5353

5454
it.each`
55-
description | file | stats | expectation
56-
${'a file with missing stats'} | ${'test.js'} | ${missingStats} | ${false}
57-
${'a non-file'} | ${'test.js'} | ${nonFileStats} | ${false}
58-
${'a .ts file'} | ${'test.ts'} | ${fileStats} | ${false}
59-
${'a .bundle file'} | ${'test.bundle'} | ${fileStats} | ${false}
60-
${'a .txt file'} | ${'test.txt'} | ${nonFileStats} | ${false}
61-
${'a .js file'} | ${'test.js'} | ${fileStats} | ${true}
55+
description | file | stats | expectation
56+
${'a file with missing stats'} | ${'test.js'} | ${missingStats} | ${false}
57+
${'a non-file'} | ${'test.js'} | ${nonFileStats} | ${false}
58+
${'a .js file'} | ${'test.js'} | ${fileStats} | ${false}
59+
${'a .ts file'} | ${'test.ts'} | ${fileStats} | ${true}
60+
${'a .bundle file'} | ${'test.bundle'} | ${fileStats} | ${true}
61+
${'a .txt file'} | ${'test.txt'} | ${fileStats} | ${true}
62+
${'a .js file in node_modules'} | ${'node_modules/test.js'} | ${fileStats} | ${true}
6263
`('returns $expectation for $description', ({ file, expectation, stats }) => {
63-
expect(filterOnlyJsFiles(file, stats)).toBe(expectation);
64+
expect(shouldIgnore(file, stats)).toBe(expectation);
6465
});
6566
});
6667

packages/cli/src/commands/watch.ts

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,11 @@ export const makeWatchEvents = (
5656
error: (error: Error) => throwError(error),
5757
});
5858

59-
export const filterOnlyJsFiles: MatchFunction = (file, stats) =>
60-
(stats?.isFile() ?? false) && file.endsWith('.js');
59+
export const shouldIgnore: MatchFunction = (file, stats): boolean =>
60+
// Ignore files and directories in `node_modules`.
61+
file.includes('node_modules') ||
62+
// Watch non-files, but ignore files that are not JavaScript.
63+
((stats?.isFile() ?? false) && !file.endsWith('.js'));
6164

6265
/**
6366
* Start a watcher that bundles `.js` files in the target dir.
@@ -77,14 +80,8 @@ export function watchDir(dir: string, logger: Logger): WatchDirReturn {
7780
const { reject: throwError, promise: errorPromise } = makePromiseKit<never>();
7881

7982
let watcher = watch(resolvedDir, {
80-
ignoreInitial: true,
81-
ignored: [
82-
'**/node_modules/**',
83-
'**/*.test.js',
84-
'**/*.test.ts',
85-
'**/*.bundle',
86-
filterOnlyJsFiles,
87-
],
83+
ignoreInitial: false,
84+
ignored: shouldIgnore,
8885
});
8986

9087
const events = makeWatchEvents(watcher, readyResolve, throwError, logger);

packages/extension/src/kernel-integration/VatWorkerClient.ts

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
import { isJsonRpcResponse } from '@metamask/utils';
2-
import type {
3-
JsonRpcId,
4-
JsonRpcRequest,
5-
JsonRpcResponse,
6-
} from '@metamask/utils';
2+
import type { JsonRpcId, JsonRpcResponse } from '@metamask/utils';
73
import type { VatWorkerManager, VatId, VatConfig } from '@ocap/kernel';
84
import { vatWorkerServiceMethodSpecs } from '@ocap/kernel/rpc';
95
import { Logger } from '@ocap/logger';
@@ -17,7 +13,7 @@ import type {
1713
PostMessageEnvelope,
1814
PostMessageTarget,
1915
} from '@ocap/streams/browser';
20-
import type { JsonRpcMessage } from '@ocap/utils';
16+
import type { JsonRpcCall, JsonRpcMessage } from '@ocap/utils';
2117
import { isJsonRpcMessage, stringify } from '@ocap/utils';
2218

2319
// Appears in the docs.
@@ -26,7 +22,7 @@ import type { ExtensionVatWorkerService } from './VatWorkerServer.ts';
2622

2723
export type VatWorkerClientStream = PostMessageDuplexStream<
2824
MessageEvent<JsonRpcResponse>,
29-
PostMessageEnvelope<JsonRpcRequest>
25+
PostMessageEnvelope<JsonRpcCall>
3026
>;
3127

3228
export class ExtensionVatWorkerClient implements VatWorkerManager {
@@ -62,8 +58,10 @@ export class ExtensionVatWorkerClient implements VatWorkerManager {
6258
this.#rpcClient = new RpcClient(
6359
vatWorkerServiceMethodSpecs,
6460
async (request) => {
65-
if (request.method === 'launch') {
66-
this.#portMap.set(request.id, undefined);
61+
if ('id' in request) {
62+
if (request.method === 'launch') {
63+
this.#portMap.set(request.id, undefined);
64+
}
6765
}
6866
await this.#stream.write({ payload: request, transfer: [] });
6967
},

packages/extension/src/kernel-integration/kernel-worker.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { JsonRpcEngine } from '@metamask/json-rpc-engine';
22
import type { JsonRpcRequest, JsonRpcResponse } from '@metamask/utils';
3-
import { isJsonRpcRequest } from '@metamask/utils';
43
import type { ClusterConfig } from '@ocap/kernel';
54
import { ClusterConfigStruct, Kernel } from '@ocap/kernel';
65
import { Logger } from '@ocap/logger';
@@ -10,7 +9,8 @@ import {
109
MessagePortDuplexStream,
1110
receiveMessagePort,
1211
} from '@ocap/streams/browser';
13-
import { fetchValidatedJson } from '@ocap/utils';
12+
import { fetchValidatedJson, isJsonRpcCall } from '@ocap/utils';
13+
import type { JsonRpcCall } from '@ocap/utils';
1414

1515
import { makeLoggingMiddleware } from './middleware/logging.ts';
1616
import { createPanelMessageMiddleware } from './middleware/panel-message.ts';
@@ -40,9 +40,9 @@ async function main(): Promise<void> {
4040
);
4141

4242
const kernelStream = await MessagePortDuplexStream.make<
43-
JsonRpcRequest,
43+
JsonRpcCall,
4444
JsonRpcResponse
45-
>(port, isJsonRpcRequest);
45+
>(port, isJsonRpcCall);
4646

4747
// Initialize kernel dependencies
4848
const vatWorkerClient = ExtensionVatWorkerClient.make(
@@ -64,7 +64,11 @@ async function main(): Promise<void> {
6464
const kernelEngine = new JsonRpcEngine();
6565
kernelEngine.push(makeLoggingMiddleware(logger.subLogger('kernel-command')));
6666
kernelEngine.push(createPanelMessageMiddleware(kernel, kernelDatabase));
67-
receiveUiConnections(async (request) => kernelEngine.handle(request), logger);
67+
// JsonRpcEngine type error: does not handle JSON-RPC notifications
68+
receiveUiConnections(
69+
async (request) => kernelEngine.handle(request as JsonRpcRequest),
70+
logger,
71+
);
6872
const launchDefaultSubcluster = firstTime || ALWAYS_RESET_STORAGE;
6973

7074
const defaultSubcluster = await fetchValidatedJson<ClusterConfig>(

packages/extension/src/kernel-integration/ui-connections.test.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
import type { JsonRpcRequest, JsonRpcResponse } from '@metamask/utils';
1+
import type { JsonRpcResponse } from '@metamask/utils';
22
import { Logger } from '@ocap/logger';
33
import type { PostMessageTarget } from '@ocap/streams/browser';
44
import { delay } from '@ocap/test-utils';
55
import { TestDuplexStream } from '@ocap/test-utils/streams';
6+
import type { JsonRpcCall } from '@ocap/utils';
67
import { describe, it, expect, vi, beforeEach } from 'vitest';
78

89
import {
@@ -161,7 +162,7 @@ describe('ui-connections', () => {
161162
const logger = makeMockLogger();
162163

163164
const mockHandleMessage = vi.fn(
164-
async (_request: JsonRpcRequest): Promise<JsonRpcResponse> => ({
165+
async (_request: JsonRpcCall): Promise<JsonRpcResponse> => ({
165166
id: 'foo',
166167
jsonrpc: '2.0' as const,
167168
result: { vats: [], clusterConfig },

packages/extension/src/kernel-integration/ui-connections.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import { isJsonRpcRequest, isJsonRpcResponse } from '@metamask/utils';
2-
import type { JsonRpcRequest, JsonRpcResponse } from '@metamask/utils';
2+
import type { JsonRpcResponse } from '@metamask/utils';
33
import type { Logger } from '@ocap/logger';
44
import { PostMessageDuplexStream } from '@ocap/streams/browser';
55
import { stringify } from '@ocap/utils';
6+
import type { JsonRpcCall } from '@ocap/utils';
67
import { nanoid } from 'nanoid';
78

89
import { isUiControlCommand } from './ui-control-command.ts';
@@ -11,18 +12,16 @@ import type { UiControlCommand } from './ui-control-command.ts';
1112
export const UI_CONTROL_CHANNEL_NAME = 'ui-control';
1213

1314
export type KernelControlStream = PostMessageDuplexStream<
14-
JsonRpcRequest,
15+
JsonRpcCall,
1516
JsonRpcResponse
1617
>;
1718

1819
export type KernelControlReplyStream = PostMessageDuplexStream<
1920
JsonRpcResponse,
20-
JsonRpcRequest
21+
JsonRpcCall
2122
>;
2223

23-
type HandleInstanceMessage = (
24-
request: JsonRpcRequest,
25-
) => Promise<JsonRpcResponse>;
24+
type HandleInstanceMessage = (request: JsonRpcCall) => Promise<JsonRpcResponse>;
2625

2726
/**
2827
* Establishes a connection between a UI instance and the kernel. Should be called
@@ -45,7 +44,7 @@ export const establishKernelConnection = async (
4544

4645
const kernelStream = await PostMessageDuplexStream.make<
4746
JsonRpcResponse,
48-
JsonRpcRequest
47+
JsonRpcCall
4948
>({
5049
validateInput: isJsonRpcResponse,
5150
messageTarget: instanceChannel,

packages/extension/src/offscreen.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import { isJsonRpcRequest, isJsonRpcResponse } from '@metamask/utils';
2-
import type { JsonRpcRequest, JsonRpcResponse } from '@metamask/utils';
1+
2+
import { isJsonRpcResponse } from '@metamask/utils';
3+
import type { JsonRpcResponse } from '@metamask/utils';
34
import { Logger } from '@ocap/logger';
45
import type { DuplexStream } from '@ocap/streams';
56
import {
@@ -8,7 +9,8 @@ import {
89
MessagePortDuplexStream,
910
} from '@ocap/streams/browser';
1011
import type { PostMessageTarget } from '@ocap/streams/browser';
11-
import { delay } from '@ocap/utils';
12+
import { delay, isJsonRpcCall } from '@ocap/utils';
13+
import type { JsonRpcCall } from '@ocap/utils';
1214

1315
import { makeIframeVatWorker } from './kernel-integration/iframe-vat-worker.ts';
1416
import { ExtensionVatWorkerService } from './kernel-integration/VatWorkerServer.ts';
@@ -26,9 +28,9 @@ async function main(): Promise<void> {
2628

2729
// Create stream for messages from the background script
2830
const backgroundStream = await ChromeRuntimeDuplexStream.make<
29-
JsonRpcRequest,
31+
JsonRpcCall,
3032
JsonRpcResponse
31-
>(chrome.runtime, 'offscreen', 'background', isJsonRpcRequest);
33+
>(chrome.runtime, 'offscreen', 'background', isJsonRpcCall);
3234

3335
const { kernelStream, vatWorkerService } = await makeKernelWorker();
3436

@@ -46,7 +48,7 @@ async function main(): Promise<void> {
4648
* @returns The message port stream for worker communication
4749
*/
4850
async function makeKernelWorker(): Promise<{
49-
kernelStream: DuplexStream<JsonRpcResponse, JsonRpcRequest>;
51+
kernelStream: DuplexStream<JsonRpcResponse, JsonRpcCall>;
5052
vatWorkerService: ExtensionVatWorkerService;
5153
}> {
5254
const worker = new Worker('kernel-worker.js', { type: 'module' });
@@ -57,7 +59,7 @@ async function makeKernelWorker(): Promise<{
5759

5860
const kernelStream = await MessagePortDuplexStream.make<
5961
JsonRpcResponse,
60-
JsonRpcRequest
62+
JsonRpcCall
6163
>(port, isJsonRpcResponse);
6264

6365
const vatWorkerService = ExtensionVatWorkerService.make(

packages/kernel/src/Kernel.ts

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type { CapData } from '@endo/marshal';
22
import { serializeError } from '@metamask/rpc-errors';
3-
import type { JsonRpcRequest, JsonRpcResponse } from '@metamask/utils';
3+
import { hasProperty } from '@metamask/utils';
4+
import type { JsonRpcResponse } from '@metamask/utils';
45
import {
56
StreamReadError,
67
VatAlreadyExistsError,
@@ -11,6 +12,7 @@ import { RpcService } from '@ocap/rpc-methods';
1112
import type { ExtractParams, ExtractResult } from '@ocap/rpc-methods';
1213
import type { KernelDatabase } from '@ocap/store';
1314
import type { DuplexStream } from '@ocap/streams';
15+
import type { JsonRpcCall } from '@ocap/utils';
1416

1517
import { KernelQueue } from './KernelQueue.ts';
1618
import { KernelRouter } from './KernelRouter.ts';
@@ -33,7 +35,7 @@ import { VatHandle } from './VatHandle.ts';
3335

3436
export class Kernel {
3537
/** Command channel from the controlling console/browser extension/test driver */
36-
readonly #commandStream: DuplexStream<JsonRpcRequest, JsonRpcResponse>;
38+
readonly #commandStream: DuplexStream<JsonRpcCall, JsonRpcResponse>;
3739

3840
readonly #rpcService: RpcService<typeof kernelHandlers>;
3941

@@ -70,7 +72,7 @@ export class Kernel {
7072
*/
7173
// eslint-disable-next-line no-restricted-syntax
7274
private constructor(
73-
commandStream: DuplexStream<JsonRpcRequest, JsonRpcResponse>,
75+
commandStream: DuplexStream<JsonRpcCall, JsonRpcResponse>,
7476
vatWorkerService: VatWorkerManager,
7577
kernelDatabase: KernelDatabase,
7678
options: {
@@ -108,7 +110,7 @@ export class Kernel {
108110
* @returns A promise for the new kernel instance.
109111
*/
110112
static async make(
111-
commandStream: DuplexStream<JsonRpcRequest, JsonRpcResponse>,
113+
commandStream: DuplexStream<JsonRpcCall, JsonRpcResponse>,
112114
vatWorkerService: VatWorkerManager,
113115
kernelDatabase: KernelDatabase,
114116
options: {
@@ -155,25 +157,29 @@ export class Kernel {
155157
*
156158
* @param message - The message to handle.
157159
*/
158-
async #handleCommandMessage(message: JsonRpcRequest): Promise<void> {
160+
async #handleCommandMessage(message: JsonRpcCall): Promise<void> {
159161
try {
160162
this.#rpcService.assertHasMethod(message.method);
161163
const result = await this.#rpcService.execute(
162164
message.method,
163165
message.params,
164166
);
165-
await this.#commandStream.write({
166-
id: message.id,
167-
jsonrpc: '2.0',
168-
result,
169-
});
167+
if (hasProperty(message, 'id') && typeof message.id === 'string') {
168+
await this.#commandStream.write({
169+
id: message.id,
170+
jsonrpc: '2.0',
171+
result,
172+
});
173+
}
170174
} catch (error) {
171175
this.#logger.error('Error executing command', error);
172-
await this.#commandStream.write({
173-
id: message.id,
174-
jsonrpc: '2.0',
175-
error: serializeError(error),
176-
});
176+
if (hasProperty(message, 'id') && typeof message.id === 'string') {
177+
await this.#commandStream.write({
178+
id: message.id,
179+
jsonrpc: '2.0',
180+
error: serializeError(error),
181+
});
182+
}
177183
}
178184
}
179185

packages/kernel/src/rpc/kernel/index.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
1-
import type { MethodRequest } from '@ocap/rpc-methods';
1+
import type {
2+
HandlerRecord,
3+
MethodRequest,
4+
MethodSpecRecord,
5+
} from '@ocap/rpc-methods';
26

37
import { pingHandler, pingSpec } from '../vat/ping.ts';
48

59
export const kernelHandlers = {
610
ping: pingHandler,
7-
} as const;
11+
} as HandlerRecord<typeof pingHandler>;
812

913
export const kernelMethodSpecs = {
1014
ping: pingSpec,
11-
} as const;
15+
} as MethodSpecRecord<typeof pingSpec>;
1216

1317
type Handlers = (typeof kernelHandlers)[keyof typeof kernelHandlers];
1418

0 commit comments

Comments
 (0)