Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,12 @@ const config = createConfig([
files: ['**/*.test.ts', '**/*.test.tsx'],
extends: [metamaskVitestConfig],
rules: {
// It's fine to do this in tests.
'@typescript-eslint/no-non-null-assertion': 'off',
// This causes false positives in tests especially.
'@typescript-eslint/unbound-method': 'off',
// We should enable this instead, but the rule is unreleased.
// See https://github.com/vitest-dev/eslint-plugin-vitest/issues/359
// See https://github.com/vitest-dev/eslint-plugin-vitest/issues/591
// 'vitest/unbound-method': 'error',
},
},
Expand Down
2 changes: 1 addition & 1 deletion packages/kernel-browser-runtime/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
},
"dependencies": {
"@endo/marshal": "^1.8.0",
"@metamask/json-rpc-engine": "^10.0.3",
"@metamask/json-rpc-engine": "^10.2.0",
"@metamask/kernel-errors": "workspace:^",
"@metamask/kernel-rpc-methods": "workspace:^",
"@metamask/kernel-store": "workspace:^",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { JsonRpcEngine } from '@metamask/json-rpc-engine';
import { JsonRpcServer } from '@metamask/json-rpc-engine/v2';
import { makeSQLKernelDatabase } from '@metamask/kernel-store/sqlite/wasm';
import { isJsonRpcCall } from '@metamask/kernel-utils';
import type { JsonRpcCall } from '@metamask/kernel-utils';
Expand All @@ -9,14 +9,14 @@ import {
MessagePortDuplexStream,
receiveMessagePort,
} from '@metamask/streams/browser';
import type { JsonRpcRequest, JsonRpcResponse } from '@metamask/utils';
import type { JsonRpcResponse } from '@metamask/utils';

import defaultSubcluster from '../default-cluster.json';
import { PlatformServicesClient } from '../PlatformServicesClient.ts';
import { receiveUiConnections } from '../ui-connections.ts';
import { getRelaysFromCurrentLocation } from '../utils/relay-query-string.ts';
import { makeLoggingMiddleware } from './middleware/logging.ts';
import { createPanelMessageMiddleware } from './middleware/panel-message.ts';
import { makePanelMessageMiddleware } from './middleware/panel-message.ts';

const logger = new Logger('kernel-worker');
const DB_FILENAME = 'store.db';
Expand Down Expand Up @@ -57,13 +57,15 @@ async function main(): Promise<void> {
},
);

const kernelEngine = new JsonRpcEngine();
kernelEngine.push(makeLoggingMiddleware(logger.subLogger('kernel-command')));
kernelEngine.push(createPanelMessageMiddleware(kernel, kernelDatabase));
// JsonRpcEngine type error: does not handle JSON-RPC notifications
const rpcServer = new JsonRpcServer({
middleware: [
makeLoggingMiddleware(logger.subLogger('kernel-command')),
makePanelMessageMiddleware(kernel, kernelDatabase),
],
});

receiveUiConnections({
handleInstanceMessage: async (request) =>
kernelEngine.handle(request as JsonRpcRequest),
handleInstanceMessage: async (request) => rpcServer.handle(request),
logger,
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,31 +1,25 @@
import {
createAsyncMiddleware,
JsonRpcEngine,
} from '@metamask/json-rpc-engine';
import { JsonRpcEngineV2 } from '@metamask/json-rpc-engine/v2';
import { Logger } from '@metamask/logger';
import type { JsonRpcRequest, JsonRpcSuccess } from '@metamask/utils';
import type { JsonRpcRequest } from '@metamask/utils';
import { delay } from '@ocap/repo-tools/test-utils';
import { describe, it, expect, vi, beforeEach } from 'vitest';

import { makeLoggingMiddleware } from './logging.ts';

describe('loggingMiddleware', () => {
let engine: JsonRpcEngine;
let logger: Logger;

beforeEach(() => {
vi.clearAllMocks();
engine = new JsonRpcEngine();
logger = new Logger('test');
engine.push(makeLoggingMiddleware(logger));
});

it('should pass the request to the next middleware', async () => {
// Create a spy middleware to verify the request is passed through
const nextSpy = vi.fn((_req, res, next) => {
res.result = 'success';
return next();
const nextSpy = vi.fn(() => 'success');
const engine = JsonRpcEngineV2.create({
middleware: [makeLoggingMiddleware(logger), nextSpy],
});
engine.push(nextSpy);

const request: JsonRpcRequest = {
id: 1,
Expand All @@ -40,9 +34,8 @@ describe('loggingMiddleware', () => {

it('should return the result from the next middleware', async () => {
// Add a middleware that sets a result
engine.push((_req, res, _next, end) => {
res.result = 'test result';
return end();
const engine = JsonRpcEngineV2.create({
middleware: [makeLoggingMiddleware(logger), () => 'test result'],
});

const request: JsonRpcRequest = {
Expand All @@ -52,20 +45,21 @@ describe('loggingMiddleware', () => {
params: {},
};

const response = (await engine.handle(request)) as JsonRpcSuccess;
expect(response.result).toBe('test result');
const result = await engine.handle(request);
expect(result).toBe('test result');
});

it('should log the execution duration', async () => {
const debugSpy = vi.spyOn(logger, 'debug');

// Add a middleware that introduces a delay
engine.push(
createAsyncMiddleware(async (_req, res, _next) => {
await new Promise((resolve) => setTimeout(resolve, 10));
res.result = 'delayed result';
}),
);
const nextSpy = vi.fn(async () => {
await delay(10);
return 'delayed result';
});
const engine = JsonRpcEngineV2.create({
middleware: [makeLoggingMiddleware(logger), nextSpy],
});

const request: JsonRpcRequest = {
id: 3,
Expand All @@ -86,8 +80,13 @@ describe('loggingMiddleware', () => {
const error = new Error('Test error');

// Add a middleware that throws an error
engine.push(() => {
throw error;
const engine = JsonRpcEngineV2.create({
middleware: [
makeLoggingMiddleware(logger),
() => {
throw error;
},
],
});

const request: JsonRpcRequest = {
Expand All @@ -97,11 +96,7 @@ describe('loggingMiddleware', () => {
params: {},
};

expect(await engine.handle(request)).toMatchObject({
error: expect.objectContaining({
message: 'Test error',
}),
});
await expect(engine.handle(request)).rejects.toThrow(error);

expect(debugSpy).toHaveBeenCalledWith(
expect.stringMatching(/Command executed in \d*\.?\d+ms/u),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { createAsyncMiddleware } from '@metamask/json-rpc-engine';
import type { JsonRpcMiddleware } from '@metamask/json-rpc-engine';
import type { JsonRpcMiddleware } from '@metamask/json-rpc-engine/v2';
import { Logger } from '@metamask/logger';
import type { Json, JsonRpcParams } from '@metamask/utils';

export const makeLoggingMiddleware = (
logger: Logger,
): JsonRpcMiddleware<JsonRpcParams, Json> =>
createAsyncMiddleware(async (_req, _res, next) => {
export const makeLoggingMiddleware =
(logger: Logger): JsonRpcMiddleware =>
async ({ next }) => {
const start = performance.now();
// eslint-disable-next-line n/callback-return
await next();
const duration = performance.now() - start;
logger.debug(`Command executed in ${duration}ms`);
});
try {
// eslint-disable-next-line n/callback-return
await next();
} finally {
const duration = performance.now() - start;
logger.debug(`Command executed in ${duration}ms`);
}
};
Loading
Loading