Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
2143660
replace sqlite-wasm with better-sqlite3
grypez Dec 12, 2024
0b49574
vitest endoified node worker with node duplex stream (wip)
grypez Dec 17, 2024
1cc265c
lint
grypez Dec 17, 2024
479a3ad
node kernel worker (somehow)
grypez Dec 18, 2024
768a18b
simplify example node worker
grypez Dec 18, 2024
8137927
add multiplex node test
grypez Dec 19, 2024
e8aa67d
getting closer
grypez Dec 19, 2024
5b344ce
something works
grypez Dec 19, 2024
263475a
update build things
grypez Dec 19, 2024
d44780a
change vitest version to 2.1.4
grypez Dec 19, 2024
75cfa11
thresholds
grypez Dec 19, 2024
0a3280d
type fixes
grypez Dec 19, 2024
26029c0
add -f force option to build-sqlite3
grypez Dec 19, 2024
604e53e
dedupe prop names in endoify shim
grypez Dec 19, 2024
83e59bf
add vite plugin deps
grypez Dec 19, 2024
2bc6c0b
add nodejs build:sqlite3 to top level build:special
grypez Dec 19, 2024
629e556
prepend nodejs build sqlite3 to CI test
grypez Dec 19, 2024
68658d4
remove db file
grypez Dec 19, 2024
07f328a
use ocap cli for serving bundles
grypez Jan 6, 2025
8f6c7a9
test(nodejs): delineate e2e tests
grypez Jan 7, 2025
81d5a8d
chore(nodejs): Clean up dependencies
grypez Jan 7, 2025
0550c42
fix(nodejs): run test:e2e from test-e2e-ci
grypez Jan 7, 2025
54198c7
test(nodejs): Add separate vitest config for e2e tests
grypez Jan 7, 2025
a12c1c4
add top level test:e2e:ci command
grypez Jan 7, 2025
383c815
more explicit include/exclude paths
grypez Jan 7, 2025
fb084ac
force build sqlite3 before e2e test
grypez Jan 7, 2025
68872de
use --no-silent flag for e2e test
grypez Jan 7, 2025
98e3c18
thresholds
grypez Jan 7, 2025
a586f84
force build sqlite3 in e2e
grypez Jan 7, 2025
2c21c0c
no-silent
grypez Jan 7, 2025
b9fcb25
debug: VWS
grypez Jan 7, 2025
e412686
test(nodejs): build immediately before e2e
grypez Jan 8, 2025
abd3734
build b4 test
grypez Jan 8, 2025
46d2d62
remove build b4 test
grypez Jan 8, 2025
3014497
trivialize node unit tests
grypez Jan 8, 2025
39c46e8
remove sqlite3 build from test stage
grypez Jan 8, 2025
c518393
remove unused node dir
grypez Jan 8, 2025
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
3 changes: 3 additions & 0 deletions .depcheckrc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ ignores:
- 'typedoc'
- 'typescript'

# Used by @ocap/nodejs to build the sqlite3 bindings
- 'node-gyp'

# These are peer dependencies of various modules we actually do
# depend on, which have been elevated to full dependencies (even
# though we don't actually depend on them) in order to work around a
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/lint-build-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ jobs:
node-version: ${{ matrix.node-version }}
cache: yarn
- run: yarn --immutable
- run: yarn build
- run: yarn build -f
- run: yarn test:e2e:ci
- name: Require clean working directory
shell: bash
Expand Down
11 changes: 7 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"build:clean": "yarn clean && yarn build",
"build:docs": "yarn workspaces foreach --all --exclude @ocap/monorepo --exclude @ocap/extension --parallel --interlaced --verbose run build:docs",
"build:source": "ts-bridge --project tsconfig.build.json --verbose && yarn build:special",
"build:special": "yarn workspace @ocap/shims run build && yarn workspace @ocap/extension run build",
"build:special": "yarn workspace @ocap/shims run build && yarn workspace @ocap/extension run build && yarn workspace @ocap/nodejs run build:sqlite3",
"bundle": "node ./scripts/bundle-vat.js",
"changelog:update": "yarn workspaces foreach --all --no-private --parallel --interlaced --verbose run changelog:update",
"changelog:validate": "yarn workspaces foreach --all --no-private --parallel --interlaced --verbose run changelog:validate",
Expand All @@ -33,6 +33,7 @@
"test": "vitest run",
"test:clean": "yarn test --no-cache --coverage.clean",
"test:dev": "yarn test --coverage false",
"test:e2e:ci": "yarn workspaces foreach -A run test:e2e:ci --no-silent",
"test:verbose": "yarn test --reporter verbose",
"test:watch": "vitest",
"why:batch": "./scripts/why-batch.sh"
Expand Down Expand Up @@ -66,7 +67,8 @@
"@typescript-eslint/eslint-plugin": "^8.8.1",
"@typescript-eslint/parser": "^8.8.1",
"@typescript-eslint/utils": "^8.8.1",
"@vitest/coverage-istanbul": "2.1.3",
"@vitest/browser": "2.1.4",
"@vitest/coverage-istanbul": "2.1.4",
"@vitest/eslint-plugin": "^1.1.7",
"@yarnpkg/types": "^4.0.0",
"depcheck": "^1.4.7",
Expand All @@ -91,7 +93,7 @@
"typescript-eslint": "^8.8.1",
"vite": "^5.3.5",
"vite-tsconfig-paths": "^4.3.2",
"vitest": "^2.1.2",
"vitest": "2.1.4",
"vitest-fetch-mock": "^0.4.2"
},
"packageManager": "yarn@4.2.2",
Expand All @@ -106,7 +108,8 @@
"simple-git-hooks": false,
"vitest>@vitest/browser>webdriverio>@wdio/utils>edgedriver": false,
"vitest>@vitest/browser>webdriverio>@wdio/utils>geckodriver": false,
"vitest>@vitest/mocker>msw": false
"vitest>@vitest/mocker>msw": false,
"@vitest/browser>msw": false
}
},
"resolutions": {
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@
"typescript": "~5.5.4",
"typescript-eslint": "^8.8.1",
"vite": "^5.3.5",
"vitest": "^2.1.2"
"vitest": "2.1.4"
},
"engines": {
"node": "^20 || >=22"
Expand Down
2 changes: 1 addition & 1 deletion packages/errors/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@
"typescript": "~5.5.4",
"typescript-eslint": "^8.8.1",
"vite": "^5.3.5",
"vitest": "^2.1.2"
"vitest": "2.1.4"
},
"engines": {
"node": "^20 || >=22"
Expand Down
2 changes: 1 addition & 1 deletion packages/extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@
"vite": "^5.3.5",
"vite-plugin-checker": "^0.8.0",
"vite-plugin-static-copy": "^1.0.6",
"vitest": "^2.1.2"
"vitest": "2.1.4"
},
"engines": {
"node": "^20 || >=22"
Expand Down
2 changes: 1 addition & 1 deletion packages/kernel/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@
"typescript": "~5.5.4",
"typescript-eslint": "^8.8.1",
"vite": "^5.3.5",
"vitest": "^2.1.2"
"vitest": "2.1.4"
},
"engines": {
"node": "^20 || >=22"
Expand Down
31 changes: 21 additions & 10 deletions packages/nodejs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
"dist/"
],
"scripts": {
"build": "ts-bridge --project tsconfig.build.json --clean",
"build": "ts-bridge --project tsconfig.build.json --clean && yarn build:sqlite3",
"build:e2e": "ts-bridge --project tsconfig.build.json --clean && yarn build:sqlite3 -f",
"build:sqlite3": "scripts/build-sqlite3.sh",
"changelog:validate": "../../scripts/validate-changelog.sh @ocap/nodejs",
"clean": "rimraf --glob ./dist './*.tsbuildinfo'",
"lint": "yarn lint:ts && yarn lint:eslint && yarn lint:misc --check && yarn constraints && yarn lint:dependencies",
Expand All @@ -23,24 +25,25 @@
"lint:ts": "tsc --project tsconfig.lint.json",
"publish:preview": "yarn npm publish --tag preview",
"start": "yarn build:vite:dev --watch",
"test": "yarn build && vitest",
"test": "vitest run --config vitest.config.ts",
"test:e2e": "vitest run --config vitest.config.e2e.ts --no-silent",
"test:e2e:ci": "./scripts/test-e2e-ci.sh",
"test:clean": "yarn test --no-cache --coverage.clean",
"test:dev": "yarn test --coverage false",
"test:verbose": "yarn test --reporter verbose"
"test:verbose": "yarn test --reporter verbose",
"build:docs": "typedoc",
"test:watch": "vitest --config vitest.config.ts"
},
"dependencies": {
"@endo/eventual-send": "^1.2.6",
"@endo/exo": "^1.5.4",
"@endo/patterns": "^1.4.4",
"@endo/promise-kit": "^1.1.6",
"@metamask/snaps-utils": "^8.3.0",
"@metamask/utils": "^9.3.0",
"@ocap/errors": "workspace:^",
"@ocap/kernel": "workspace:^",
"@ocap/shims": "workspace:^",
"@ocap/streams": "workspace:^",
"@ocap/utils": "workspace:^",
"@sqlite.org/sqlite-wasm": "3.47.0-build1",
"better-sqlite3": "^11.7.0",
"ses": "^1.9.0"
},
"devDependencies": {
Expand All @@ -50,12 +53,14 @@
"@metamask/eslint-config-nodejs": "^14.0.0",
"@metamask/eslint-config-typescript": "^14.0.0",
"@ocap/cli": "workspace:^",
"@ocap/test-utils": "workspace:^",
"@ts-bridge/cli": "^0.5.1",
"@types/better-sqlite3": "^7.6.12",
"@types/chrome": "^0.0.268",
"@typescript-eslint/eslint-plugin": "^8.8.1",
"@typescript-eslint/parser": "^8.8.1",
"@typescript-eslint/utils": "^8.8.1",
"@vitest/browser": "2.1.4",
"@vitest/coverage-istanbul": "2.1.4",
"depcheck": "^1.4.7",
"eslint": "^9.12.0",
"eslint-config-prettier": "^9.1.0",
Expand All @@ -65,15 +70,21 @@
"eslint-plugin-n": "^17.11.1",
"eslint-plugin-prettier": "^5.2.1",
"eslint-plugin-promise": "^7.1.0",
"node-gyp": "^11.0.0",
"prettier": "^3.3.3",
"rimraf": "^6.0.1",
"typedoc": "^0.26.8",
"typescript": "~5.5.4",
"typescript-eslint": "^8.8.1",
"vite": "^5.3.5",
"vitest": "^2.1.2"
"vite-plugin-checker": "^0.8.0",
"vite-plugin-static-copy": "^1.0.6",
"vitest": "2.1.4"
},
"engines": {
"node": "^18.18 || >=20"
"node": "^20 || >=22"
},
"exports": {
"./package.json": "./package.json"
}
}
11 changes: 11 additions & 0 deletions packages/nodejs/scripts/build-constants.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import path from 'path';

export const sourceDir = './src';
export const buildDir = path.resolve(sourceDir, '../dist');

export const trustedPreludes = {
'kernel-worker': path.resolve(
sourceDir,
'env/kernel-worker-trusted-prelude.js',
),
};
40 changes: 40 additions & 0 deletions packages/nodejs/scripts/build-sqlite3.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#!/usr/bin/env bash

# set -x
set -e
set -o pipefail

dir=$(pwd)

package_root="$(dirname "$0")/.."
cd $package_root
package_root=$(pwd)
monorepo_root="$package_root/../.."

while getopts ":ab:" opt; do
case $OPTARG in
f) force=1;;
\?) echo "Invalid option: -$OPTARG"; exit 1;;
esac
done

if ! [ "$force" = "1" ] && [ -f "node_modules/better-sqlite3/build/better_sqlite3.node" ]; then
echo "Found better-sqlite3 bindings."
exit 0
fi

echo "Building better-sqlite3 bindings."

# build better-sqlite at the monorepo root
cd $monorepo_root
cd node_modules/better-sqlite3
yarn build-release

# move back to the source folder
cd $package_root

# copy the build to this package
mkdir -p node_modules/better-sqlite3/build/
cp -r ../../node_modules/better-sqlite3/build/Release/ node_modules/better-sqlite3/build/

cd $dir
26 changes: 26 additions & 0 deletions packages/nodejs/scripts/test-e2e-ci.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/usr/bin/env bash

set -x
set -e
set -o pipefail

# force build sqlite3 so it aligns with node version
yarn build:e2e

# We borrow the vat definition from extension for now
yarn ocap bundle "../extension/src/vats"

# Start the server in background and capture its PID
yarn ocap serve "../extension/src/vats" &
SERVER_PID=$!

function cleanup() {
# Kill the server if it's still running
if kill -0 $SERVER_PID 2>/dev/null; then
kill $SERVER_PID
fi
}
# Ensure we always close the server
trap cleanup EXIT

yarn test:e2e
1 change: 1 addition & 0 deletions packages/nodejs/src/env/endoify.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import '@ocap/shims/endoify';
2 changes: 2 additions & 0 deletions packages/nodejs/src/env/kernel-worker-trusted-prelude.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// eslint-disable-next-line import-x/no-unresolved
import './endoify.js';
29 changes: 22 additions & 7 deletions packages/nodejs/src/kernel/VatWorkerService.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { makePromiseKit } from '@endo/promise-kit';
import type { VatWorkerService, VatId } from '@ocap/kernel';
import { NodeWorkerMultiplexer } from '@ocap/streams';
import type { StreamMultiplexer } from '@ocap/streams';
import { NodeWorkerMultiplexer, StreamMultiplexer } from '@ocap/streams';
import { makeLogger } from '@ocap/utils';
import type { Logger } from '@ocap/utils';
import { readFile } from 'node:fs/promises';
import { Worker as NodeWorker } from 'node:worker_threads';

// Worker file loads from the built dist directory, requires rebuild after change
Expand All @@ -11,7 +12,6 @@ const workerFileURL = new URL('../../dist/vat/inside.mjs', import.meta.url)
.pathname;

export class NodejsVatWorkerService implements VatWorkerService {
// eslint-disable-next-line no-unused-private-class-members
readonly #logger: Logger;

workers = new Map<
Expand All @@ -30,10 +30,25 @@ export class NodejsVatWorkerService implements VatWorkerService {
}

async launch(vatId: VatId): Promise<StreamMultiplexer> {
const worker = new NodeWorker(workerFileURL);
const multiplexer = new NodeWorkerMultiplexer(worker);
this.workers.set(vatId, { worker, multiplexer });
return multiplexer;
const { promise, resolve } = makePromiseKit<StreamMultiplexer>();
this.#logger.debug('launching', vatId);
this.#logger.debug('fileUrl', workerFileURL);
this.#logger.debug(
`fileContent\n===\n${(await readFile(workerFileURL)).toString()}\n===\n`,
);
const worker = new NodeWorker(workerFileURL, {
env: {
NODE_VAT_ID: vatId,
},
});
this.#logger.debug('launched', vatId);
worker.once('online', () => {
const multiplexer = new NodeWorkerMultiplexer(worker, 'vat');
this.workers.set(vatId, { worker, multiplexer });
resolve(multiplexer);
this.#logger.debug('launched', vatId);
});
return promise;
}

async terminate(vatId: VatId): Promise<undefined> {
Expand Down
29 changes: 18 additions & 11 deletions packages/nodejs/src/kernel/kernel-worker.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import './env.js';
import '@ocap/shims/endoify';
import type { NonEmptyArray } from '@metamask/utils';
import type { KernelCommand, KernelCommandReply, VatId } from '@ocap/kernel';
import { Kernel, VatCommandMethod } from '@ocap/kernel';
Expand Down Expand Up @@ -31,6 +31,9 @@ export async function makeKernel(port: NodeMessagePort): Promise<Kernel> {
return kernel;
}

const sampleOne = <Ele>(from: NonEmptyArray<Ele>): Ele =>
from[Math.floor(Math.random() * from.length)] as Ele;

/**
* Runs the full lifecycle of an array of vats, including their creation,
* restart, message passing, and termination.
Expand All @@ -42,27 +45,31 @@ export async function runVatLifecycle(
kernel: Kernel,
vats: NonEmptyArray<VatId>,
): Promise<void> {
console.time(`Created vats: ${vats.join(', ')}`);
console.log('runVatLifecycle Start...');
const vatLabel = vats.join(', ');
console.time(`Created vats: ${vatLabel}`);
await Promise.all(
vats.map(async () =>
kernel.launchVat({
bundleName: 'sample-vat',
parameters: { name: 'Nodeen' },
}),
vats.map(
async () =>
await kernel.launchVat({
bundleSpec: 'http://localhost:3000/sample-vat.bundle',
parameters: { name: 'Nodeen' },
}),
),
);
console.timeEnd(`Created vats: ${vats.join(', ')}`);

console.timeEnd(`Created vats: ${vatLabel}`);
console.log('Kernel vats:', kernel.getVatIds().join(', '));

const knownVats = kernel.getVatIds() as NonEmptyArray<VatId>;

// Restart a randomly selected vat from the array.
const vatToRestart = vats[Math.floor(Math.random() * vats.length)] as VatId;
const vatToRestart = sampleOne(knownVats);
console.time(`Vat "${vatToRestart}" restart`);
await kernel.restartVat(vatToRestart);
console.timeEnd(`Vat "${vatToRestart}" restart`);

// Send a "Ping" message to a randomly selected vat.
const vatToPing = vats[Math.floor(Math.random() * vats.length)] as VatId;
const vatToPing = sampleOne(knownVats);
console.time(`Ping Vat "${vatToPing}"`);
await kernel.sendMessage(vatToPing, {
method: VatCommandMethod.ping,
Expand Down
Loading
Loading