diff --git a/packages/cli/src/commands/adopt.js b/packages/cli/src/commands/adopt.js index 37184fbfe0..ddde44a584 100644 --- a/packages/cli/src/commands/adopt.js +++ b/packages/cli/src/commands/adopt.js @@ -2,6 +2,7 @@ import os from 'os'; import { E } from '@endo/far'; import { withEndoAgent } from '../context.js'; +import { parsePetNamePath } from '../pet-name.js'; export const adoptCommand = async ({ messageNumberText, @@ -12,5 +13,5 @@ export const adoptCommand = async ({ withEndoAgent(agentNames, { os, process }, async ({ agent }) => { // TODO less bad number parsing. const messageNumber = Number(messageNumberText); - await E(agent).adopt(messageNumber, edgeName, name); + await E(agent).adopt(messageNumber, edgeName, parsePetNamePath(name)); }); diff --git a/packages/cli/src/commands/eval.js b/packages/cli/src/commands/eval.js index 583c2bb910..e54e6199c9 100644 --- a/packages/cli/src/commands/eval.js +++ b/packages/cli/src/commands/eval.js @@ -35,7 +35,7 @@ export const evalCommand = async ({ source, codeNames, petNames, - resultName, + parsePetNamePath(resultName), ); console.log(result); }); diff --git a/packages/cli/src/commands/install.js b/packages/cli/src/commands/install.js index 3d5a0c7278..564abf5a52 100644 --- a/packages/cli/src/commands/install.js +++ b/packages/cli/src/commands/install.js @@ -8,6 +8,7 @@ import { makeReaderRef } from '@endo/daemon'; import bundleSource from '@endo/bundle-source'; import { withEndoAgent } from '../context.js'; +import { parsePetNamePath } from '../pet-name.js'; import { randomHex16 } from '../random.js'; const textEncoder = new TextEncoder(); @@ -25,6 +26,7 @@ export const install = async ({ let bundleReaderRef; /** @type {string | undefined} */ let temporaryBundleName; + await null; if (programPath !== undefined) { if (bundleName === undefined) { // TODO alternately, make a temporary session-scoped GC pet store @@ -41,6 +43,7 @@ export const install = async ({ await withEndoAgent(agentNames, { os, process }, async ({ agent }) => { // Prepare a bundle, with the given name. + await null; if (bundleReaderRef !== undefined) { await E(agent).storeBlob(bundleReaderRef, bundleName); } @@ -53,7 +56,7 @@ export const install = async ({ )}, $id, $cancelled)`, ['apps', 'bundle', 'powers'], ['APPS', bundleName, powersName], - webletName, + parsePetNamePath(webletName), ); const webletLocation = await E(weblet).getLocation(); process.stdout.write(`${webletLocation}\n`); diff --git a/packages/cli/src/commands/mkdir.js b/packages/cli/src/commands/mkdir.js index de357ae6e1..a9e36b9c74 100644 --- a/packages/cli/src/commands/mkdir.js +++ b/packages/cli/src/commands/mkdir.js @@ -6,5 +6,5 @@ import { parsePetNamePath } from '../pet-name.js'; export const mkdir = async ({ agentNames, directoryPath }) => withEndoAgent(agentNames, { os, process }, async ({ agent }) => { - await E(agent).makeDirectory(...parsePetNamePath(directoryPath)); + await E(agent).makeDirectory(parsePetNamePath(directoryPath)); }); diff --git a/packages/cli/src/commands/remove.js b/packages/cli/src/commands/remove.js index ba0c7c5455..3e8321b3ae 100644 --- a/packages/cli/src/commands/remove.js +++ b/packages/cli/src/commands/remove.js @@ -2,8 +2,13 @@ import os from 'os'; import { E } from '@endo/far'; import { withEndoAgent } from '../context.js'; +import { parsePetNamePath } from '../pet-name.js'; -export const remove = async ({ petNames, agentNames }) => +export const remove = async ({ petNamePaths, agentNames }) => withEndoAgent(agentNames, { os, process }, async ({ agent }) => - Promise.all(petNames.map(petName => E(agent).remove(petName))), + Promise.all( + petNamePaths.map(petNamePath => + E(agent).remove(...parsePetNamePath(petNamePath)), + ), + ), ); diff --git a/packages/cli/src/commands/request.js b/packages/cli/src/commands/request.js index 153942a33d..24a79a4a40 100644 --- a/packages/cli/src/commands/request.js +++ b/packages/cli/src/commands/request.js @@ -2,6 +2,7 @@ import os from 'os'; import { E } from '@endo/far'; import { withEndoAgent } from '../context.js'; +import { parsePetNamePath } from '../pet-name.js'; export const request = async ({ description, @@ -10,7 +11,11 @@ export const request = async ({ agentNames, }) => { await withEndoAgent(agentNames, { os, process }, async ({ agent }) => { - const result = await E(agent).request(toName, description, resultName); + const result = await E(agent).request( + toName, + description, + parsePetNamePath(resultName), + ); console.log(result); }); }; diff --git a/packages/cli/src/commands/spawn.js b/packages/cli/src/commands/spawn.js index e4462f0207..8697f3dddc 100644 --- a/packages/cli/src/commands/spawn.js +++ b/packages/cli/src/commands/spawn.js @@ -3,8 +3,13 @@ import os from 'os'; import { E } from '@endo/far'; import { withEndoAgent } from '../context.js'; +import { parsePetNamePath } from '../pet-name.js'; -export const spawn = async ({ petNames, agentNames }) => +export const spawn = async ({ petNamePaths, agentNames }) => withEndoAgent(agentNames, { os, process }, async ({ agent }) => - Promise.all(petNames.map(petName => E(agent).provideWorker(petName))), + Promise.all( + petNamePaths.map(petNamePath => + E(agent).provideWorker(parsePetNamePath(petNamePath)), + ), + ), ); diff --git a/packages/cli/src/endo.js b/packages/cli/src/endo.js index fcfbb56756..64e13b8ed3 100644 --- a/packages/cli/src/endo.js +++ b/packages/cli/src/endo.js @@ -162,7 +162,7 @@ export const main = async rawArgs => { UNCONFINED: importPath, name: resultName, bundle: bundleName, - worker: workerName = 'NEW', + worker: workerName = undefined, as: agentNames, powers: powersName = 'NONE', } = cmd.opts(); @@ -291,10 +291,10 @@ export const main = async rawArgs => { .command('remove [names...]') .description('forget a named value') .option(...commonOptions.as) - .action(async (petNames, cmd) => { + .action(async (petNamePaths, cmd) => { const { as: agentNames } = cmd.opts(); const { remove } = await import('./commands/remove.js'); - return remove({ petNames, agentNames }); + return remove({ petNamePaths, agentNames }); }); program @@ -405,10 +405,10 @@ export const main = async rawArgs => { .command('spawn [names...]') .description('creates a worker') .option(...commonOptions.as) - .action(async (petNames, cmd) => { + .action(async (petNamePaths, cmd) => { const { as: agentNames } = cmd.opts(); const { spawn } = await import('./commands/spawn.js'); - return spawn({ petNames, agentNames }); + return spawn({ petNamePaths, agentNames }); }); program @@ -591,6 +591,7 @@ export const main = async rawArgs => { .description('erases persistent state and stops if running') .action(async cmd => { const { force } = cmd.opts(); + await null; const doPurge = force || /^y(es)?$/u.test( diff --git a/packages/daemon/src/daemon.js b/packages/daemon/src/daemon.js index 87ec483fb0..97330db49d 100644 --- a/packages/daemon/src/daemon.js +++ b/packages/daemon/src/daemon.js @@ -439,7 +439,7 @@ const makeDaemonCore = async ( context.thisDiesIfThatDies(hubId); const hub = provide(hubId, 'hub'); - return E(hub).lookup(...path); + return E(hub).lookup(path); }; /** @@ -708,6 +708,7 @@ const makeDaemonCore = async ( * @param {Context} context */ const evaluateFormula = async (id, formulaNumber, formula, context) => { + await null; if (Object.hasOwn(makers, formula.type)) { const make = makers[formula.type]; const value = await /** @type {unknown} */ ( @@ -839,6 +840,7 @@ const makeDaemonCore = async ( const formulateReadableBlob = async (readerRef, deferredTasks) => { const { formulaNumber, contentSha512 } = await formulaGraphJobs.enqueue( async () => { + await null; const values = { formulaNumber: await randomHex512(), contentSha512: await contentStore.store(makeRefReader(readerRef)), @@ -988,6 +990,7 @@ const makeDaemonCore = async ( * @type {DaemonCore['formulateWorker']} */ const formulateWorker = async deferredTasks => { + await null; return formulateNumberedWorker( await formulaGraphJobs.enqueue(async () => { const formulaNumber = await randomHex512(); @@ -1011,6 +1014,7 @@ const makeDaemonCore = async ( const { specifiedWorkerId, ...remainingSpecifiedIdentifiers } = specifiedIdentifiers; + await null; const storeId = (await formulateNumberedPetStore(await randomHex512())).id; const hostFormulaNumber = await randomHex512(); @@ -1064,6 +1068,7 @@ const makeDaemonCore = async ( deferredTasks, specifiedWorkerId, ) => { + await null; return formulateNumberedHost( await formulaGraphJobs.enqueue(async () => { const identifiers = await formulateHostDependencies({ @@ -1123,6 +1128,7 @@ const makeDaemonCore = async ( /** @type {DaemonCore['formulateGuest']} */ const formulateGuest = async (hostAgentId, hostHandleId, deferredTasks) => { + await null; return formulateNumberedGuest( await formulaGraphJobs.enqueue(async () => { const identifiers = await formulateGuestDependencies( @@ -1212,6 +1218,7 @@ const makeDaemonCore = async ( if (typeof formulaIdOrPath === 'string') { return formulaIdOrPath; } + await null; return ( /* eslint-disable no-use-before-define */ ( @@ -1657,11 +1664,19 @@ const makeDaemonCore = async ( const petStore = await provide(petStoreId, 'pet-store'); /** - * @param {string} petName - The pet name to inspect. + * @param {string|string[]} petName - The pet name to inspect. * @returns {Promise} An * inspector for the value of the given pet name. */ const lookup = async petName => { + if (Array.isArray(petName)) { + if (petName.length !== 1) { + throw Error( + 'PetStoreInspector.lookup(path) requires path length of 1', + ); + } + petName = petName[0]; + } const id = petStore.identifyLocal(petName); if (id === undefined) { throw new Error(`Unknown pet name ${petName}`); diff --git a/packages/daemon/src/directory.js b/packages/daemon/src/directory.js index 773b45f68d..3852f6dd5d 100644 --- a/packages/daemon/src/directory.js +++ b/packages/daemon/src/directory.js @@ -26,8 +26,12 @@ export const makeDirectoryMaker = ({ /** @type {MakeDirectoryNode} */ const makeDirectoryNode = petStore => { /** @type {EndoDirectory['lookup']} */ - const lookup = (...petNamePath) => { + const lookup = petNamePath => { + if (typeof petNamePath === 'string') { + petNamePath = [petNamePath]; + } const [headName, ...tailNames] = petNamePath; + const id = petStore.identifyLocal(headName); if (id === undefined) { throw new TypeError(`Unknown pet name: ${q(headName)}`); @@ -41,6 +45,7 @@ export const makeDirectoryMaker = ({ /** @type {EndoDirectory['reverseLookup']} */ const reverseLookup = async presence => { + await null; const id = getIdForRef(await presence); if (id === undefined) { return harden([]); @@ -62,7 +67,7 @@ export const makeDirectoryMaker = ({ // eslint-disable-next-line no-use-before-define return { hub: directory, name: tailName }; } - const nameHub = /** @type {NameHub} */ (await lookup(...headPath)); + const nameHub = /** @type {NameHub} */ (await lookup(headPath)); return { hub: nameHub, name: tailName }; }; @@ -126,12 +131,13 @@ export const makeDirectoryMaker = ({ if (petNamePath.length === 0) { return petStore.list(); } - const hub = /** @type {NameHub} */ (await lookup(...petNamePath)); + const hub = /** @type {NameHub} */ (await lookup(petNamePath)); return hub.list(); }; /** @type {EndoDirectory['listIdentifiers']} */ const listIdentifiers = async (...petNamePath) => { + petNamePath = petNamePath || []; const names = await list(...petNamePath); const identities = new Set(); await Promise.all( @@ -153,12 +159,13 @@ export const makeDirectoryMaker = ({ yield* petStore.followNameChanges(); return; } - const hub = /** @type {NameHub} */ (await lookup(...petNamePath)); + const hub = /** @type {NameHub} */ (await lookup(petNamePath)); yield* hub.followNameChanges(); }; /** @type {EndoDirectory['remove']} */ const remove = async (...petNamePath) => { + await null; if (petNamePath.length === 1) { const petName = petNamePath[0]; await petStore.remove(petName); @@ -211,6 +218,7 @@ export const makeDirectoryMaker = ({ if (typeof petNamePath === 'string') { petNamePath = [petNamePath]; } + await null; if (petNamePath.length === 1) { const petName = petNamePath[0]; await petStore.write(petName, id); @@ -221,7 +229,7 @@ export const makeDirectoryMaker = ({ }; /** @type {EndoDirectory['makeDirectory']} */ - const makeDirectory = async (...directoryPetNamePath) => { + const makeDirectory = async directoryPetNamePath => { const { value: directory, id } = await formulateDirectory(); await write(directoryPetNamePath, id); return directory; diff --git a/packages/daemon/src/guest.js b/packages/daemon/src/guest.js index d7d1740638..1f3c00299f 100644 --- a/packages/daemon/src/guest.js +++ b/packages/daemon/src/guest.js @@ -44,13 +44,14 @@ export const makeGuestMaker = ({ provide, makeMailbox, makeDirectoryNode }) => { HOST: hostHandleId, }); + const directory = makeDirectoryNode(specialStore); const mailbox = makeMailbox({ petStore: specialStore, + directory, selfId: handleId, context, }); - const { petStore, handle } = mailbox; - const directory = makeDirectoryNode(petStore); + const { handle } = mailbox; const { reverseIdentify } = specialStore; const { diff --git a/packages/daemon/src/host.js b/packages/daemon/src/host.js index b17ec66ea9..2a39892c6d 100644 --- a/packages/daemon/src/host.js +++ b/packages/daemon/src/host.js @@ -8,7 +8,11 @@ import { E } from '@endo/far'; import { makeExo } from '@endo/exo'; import { makeError, q } from '@endo/errors'; import { makeIteratorRef } from './reader-ref.js'; -import { assertPetName, petNamePathFrom } from './pet-name.js'; +import { + assertPetName, + assertPetNamePath, + petNamePathFrom, +} from './pet-name.js'; import { parseId, formatId } from './formula-identifier.js'; import { makePetSitter } from './pet-sitter.js'; import { makeDeferredTasks } from './deferred-tasks.js'; @@ -89,19 +93,21 @@ export const makeHostMaker = ({ ...platformNames, AGENT: hostId, SELF: handleId, + MAIN: mainWorkerId, ENDO: endoId, NETS: networksDirectoryId, INFO: inspectorId, NONE: leastAuthorityId, }); + const directory = makeDirectoryNode(specialStore); const mailbox = makeMailbox({ petStore: specialStore, + directory, selfId: handleId, context, }); const { petStore, handle } = mailbox; - const directory = makeDirectoryNode(petStore); const getEndoBootstrap = async () => provide(endoId, 'endo'); @@ -138,33 +144,30 @@ export const makeHostMaker = ({ }; /** - * @param {string} workerName + * @param {string[]} workerNamePath */ - const provideWorker = async workerName => { - /** @type {DeferredTasks} */ - const tasks = makeDeferredTasks(); - // eslint-disable-next-line no-use-before-define - const workerId = prepareWorkerFormulation(workerName, tasks.push); + const provideWorker = async workerNamePath => { + const workerId = await E(directory).identify(...workerNamePath); if (workerId !== undefined) { return provide(workerId, 'worker'); } - const { value } = await formulateWorker(tasks); + /** @type {DeferredTasks} */ + const tasks = makeDeferredTasks(); + const { value, id } = await formulateWorker(tasks); + await E(directory).write(workerNamePath, id); return value; }; /** - * @param {string} workerName + * @param {string | undefined} workerName * @param {DeferredTasks<{ workerId: string }>['push']} deferTask */ const prepareWorkerFormulation = (workerName, deferTask) => { - if (workerName === 'MAIN') { - return mainWorkerId; - } else if (workerName === 'NEW') { + if (workerName === undefined) { return undefined; } - const workerId = petStore.identifyLocal(workerName); if (workerId === undefined) { deferTask(identifiers => @@ -175,11 +178,11 @@ export const makeHostMaker = ({ }; /** - * @param {string | 'MAIN' | 'NEW'} workerName + * @param {string | 'MAIN' | undefined} workerName * @param {string} source * @param {string[]} codeNames * @param {(string | string[])[]} petNamePaths - * @param {string} resultName + * @param {string[]} resultName */ const evaluate = async ( workerName, @@ -189,7 +192,7 @@ export const makeHostMaker = ({ resultName, ) => { if (resultName !== undefined) { - assertPetName(resultName); + assertPetNamePath(resultName); } if (petNamePaths.length !== codeNames.length) { throw new Error('Evaluator requires one pet name for each code name'); @@ -222,7 +225,7 @@ export const makeHostMaker = ({ if (resultName !== undefined) { tasks.push(identifiers => - petStore.write(resultName, identifiers.evalId), + E(directory).write(resultName, identifiers.evalId), ); } @@ -240,7 +243,7 @@ export const makeHostMaker = ({ /** * Helper function for makeUnconfined and makeBundle. * @param {string} powersName - * @param {string} workerName + * @param {string | undefined} workerName * @param {string | string[]} [resultName] */ const prepareMakeCaplet = (powersName, workerName, resultName) => { @@ -294,7 +297,7 @@ export const makeHostMaker = ({ }; /** - * @param {string | 'MAIN' | 'NEW'} workerName + * @param {string | 'MAIN' | undefined} workerName * @param {string} bundleName * @param {string | 'NONE' | 'SELF' | 'ENDO'} powersName * @param {string} resultName @@ -398,6 +401,7 @@ export const makeHostMaker = ({ { introducedNames = {}, agentName = undefined } = {}, ) => { let host = getNamedAgent(petName, 'host'); + await null; if (host === undefined) { const { value, id } = // Behold, recursion: @@ -431,6 +435,7 @@ export const makeHostMaker = ({ { introducedNames = {}, agentName = undefined } = {}, ) => { let guest = getNamedAgent(handleName, 'guest'); + await null; if (guest === undefined) { const { value, id } = // Behold, recursion: diff --git a/packages/daemon/src/mail.js b/packages/daemon/src/mail.js index 93134de85f..b205583d5d 100644 --- a/packages/daemon/src/mail.js +++ b/packages/daemon/src/mail.js @@ -5,7 +5,7 @@ import { makeExo } from '@endo/exo'; import { makePromiseKit } from '@endo/promise-kit'; import { q } from '@endo/errors'; import { makeChangeTopic } from './pubsub.js'; -import { assertPetName } from './pet-name.js'; +import { assertPetName, assertPetNamePath } from './pet-name.js'; import { ResponderInterface, @@ -54,7 +54,7 @@ const makeEnvelope = () => makeExo('Envelope', EnvelopeInterface, {}); export const makeMailboxMaker = ({ provide }) => { /** @type {MakeMailbox} */ - const makeMailbox = ({ selfId, petStore, context }) => { + const makeMailbox = ({ selfId, petStore, directory, context }) => { /** @type {Map} */ const messages = new Map(); @@ -218,9 +218,9 @@ export const makeMailboxMaker = ({ provide }) => { }; /** @type {Mail['adopt']} */ - const adopt = async (messageNumber, edgeName, petName) => { + const adopt = async (messageNumber, edgeName, petNamePath) => { assertPetName(edgeName); - assertPetName(petName); + assertPetNamePath(petNamePath); if ( typeof messageNumber !== 'number' || messageNumber >= Number.MAX_SAFE_INTEGER @@ -249,13 +249,14 @@ export const makeMailboxMaker = ({ provide }) => { ); } context.thisDiesIfThatDies(id); - await petStore.write(petName, id); + await E(directory).write(petNamePath, id); }; /** @type {Mail['request']} */ const request = async (toName, description, responseName) => { + await null; if (responseName !== undefined) { - const responseId = petStore.identifyLocal(responseName); + const responseId = await E(directory).identify(responseName); if (responseId !== undefined) { return provide(responseId); } @@ -280,7 +281,7 @@ export const makeMailboxMaker = ({ provide }) => { const responseP = provide(responseId); if (responseName !== undefined) { - await petStore.write(responseName, responseId); + await E(directory).write(responseName, responseId); } return responseP; diff --git a/packages/daemon/src/pet-name.js b/packages/daemon/src/pet-name.js index c5ec49edaf..abaf402e98 100644 --- a/packages/daemon/src/pet-name.js +++ b/packages/daemon/src/pet-name.js @@ -18,6 +18,18 @@ export const assertPetName = petName => { } }; +/** + * @param {string[]} petNamePath + */ +export const assertPetNamePath = petNamePath => { + if (!Array.isArray(petNamePath) || petNamePath.length < 1) { + throw new Error(`Invalid pet name path`); + } + for (const petName of petNamePath) { + assertPetName(petName); + } +}; + /** * @param {string | string[]} petNameOrPetNamePath */ diff --git a/packages/daemon/src/types.d.ts b/packages/daemon/src/types.d.ts index 3e112d4dec..794ca6b098 100644 --- a/packages/daemon/src/types.d.ts +++ b/packages/daemon/src/types.d.ts @@ -444,7 +444,7 @@ export interface NameHub { followNameChanges( ...petNamePath: string[] ): AsyncGenerator; - lookup(...petNamePath: string[]): Promise; + lookup(petNamePath: string | string[]): Promise; reverseLookup(value: unknown): Array; write(petNamePath: string | string[], id: string): Promise; remove(...petNamePath: string[]): Promise; @@ -453,7 +453,7 @@ export interface NameHub { } export interface EndoDirectory extends NameHub { - makeDirectory(...petNamePath: string[]): Promise; + makeDirectory(petNamePath: string[]): Promise; } export type MakeDirectoryNode = (petStore: PetStore) => EndoDirectory; @@ -470,7 +470,7 @@ export interface Mail { adopt( messageNumber: number, edgeName: string, - petName: string, + petName: string[], ): Promise; dismiss(messageNumber: number): Promise; request( @@ -490,6 +490,7 @@ export interface Mail { export type MakeMailbox = (args: { selfId: string; petStore: PetStore; + directory: EndoDirectory; context: Context; }) => Mail; @@ -580,17 +581,17 @@ export interface EndoHost extends EndoAgent { petName?: string, opts?: MakeHostOrGuestOptions, ): Promise; - makeDirectory(petName: string): Promise; - provideWorker(petName: string): Promise; + makeDirectory(petNamePath: string[]): Promise; + provideWorker(petNamePath: string[]): Promise; evaluate( workerPetName: string | undefined, source: string, codeNames: Array, petNames: Array, - resultName?: string, + resultName?: string[], ): Promise; makeUnconfined( - workerName: string | 'NEW' | 'MAIN', + workerName: string | undefined | 'MAIN', specifier: string, powersName: string | 'NONE' | 'SELF' | 'ENDO', resultName?: string, diff --git a/packages/daemon/test/endo.test.js b/packages/daemon/test/endo.test.js index 96e1841c1a..4e6cd36ec9 100644 --- a/packages/daemon/test/endo.test.js +++ b/packages/daemon/test/endo.test.js @@ -41,6 +41,7 @@ const dirname = url.fileURLToPath(new URL('..', import.meta.url)).toString(); const takeCount = async (asyncIterator, count) => { const values = []; + await null; // eslint-disable-next-line no-plusplus for (let i = 0; i < count; i++) { // eslint-disable-next-line no-await-in-loop @@ -71,6 +72,7 @@ const prepareFollowNameChangesIterator = async host => { * @param {string} locator */ const prepareFollowLocatorNameChangesIterator = async (host, locator) => { + await null; const changesIterator = makeRefIterator( await E(host).followLocatorNameChanges(locator), ); @@ -247,7 +249,7 @@ test('lifecycle', async t => { ); const bootstrap = getBootstrap(); const host = E(bootstrap).host(); - await E(host).provideWorker('worker'); + await E(host).provideWorker(['worker']); await E(host).cancel('worker'); cancel(new Error('Cancelled')); await closed.catch(() => {}); @@ -276,7 +278,7 @@ test('store pass-copy values', async t => { { const { host } = await makeHost(config, cancelled); - const restoredValue = await E(host).lookup('value'); + const restoredValue = await E(host).lookup(['value']); t.deepEqual(restoredValue, storedValue); } }); @@ -286,7 +288,7 @@ test('store formula values', async t => { { const { host } = await makeHost(config, cancelled); - await E(host).provideWorker('w1'); + await E(host).provideWorker(['w1']); const counter = await E(host).evaluate( 'w1', ` @@ -304,7 +306,7 @@ test('store formula values', async t => { `, [], [], - 'temporary-retainer', + ['temporary-retainer'], ); await E(host).storeValue(counter, 'counter'); await E(host).remove('temporary-retainer'); @@ -314,7 +316,7 @@ test('store formula values', async t => { { const { host } = await makeHost(config, cancelled); - const counter = await E(host).lookup('counter'); + const counter = await E(host).lookup(['counter']); t.is(1, await E(counter).incr()); t.is(2, await E(counter).incr()); } @@ -323,7 +325,7 @@ test('store formula values', async t => { { const { host } = await makeHost(config, cancelled); - const counter = await E(host).lookup('counter'); + const counter = await E(host).lookup(['counter']); t.is(1, await E(counter).incr()); t.is(2, await E(counter).incr()); } @@ -334,14 +336,14 @@ test('fail to store non-formula exos', async t => { const { cancelled, config } = await prepareConfig(t); const { host } = await makeHost(config, cancelled); await t.throwsAsync(() => E(host).storeValue(noFormulaExo, 'exo'), { - message: 'No corresponding formula for (an object)', + message: /^No corresponding formula for/, }); }); test('spawn and evaluate', async t => { const { host } = await prepareHost(t); - await E(host).provideWorker('w1'); + await E(host).provideWorker(['w1']); const ten = await E(host).evaluate('w1', '10', [], []); t.is(ten, 10); }); @@ -353,13 +355,6 @@ test('anonymous spawn and evaluate', async t => { t.is(ten, 10); }); -test('anonymous spawn and evaluate with new worker', async t => { - const { host } = await prepareHost(t); - - const ten = await E(host).evaluate('NEW', '10', [], []); - t.is(ten, 10); -}); - // Regression test for https://github.com/endojs/endo/issues/2147 test('spawning a worker does not overwrite existing non-worker name', async t => { const { host } = await prepareHost(t); @@ -368,8 +363,8 @@ test('spawning a worker does not overwrite existing non-worker name', async t => // This resolves with the existing value of 'foo' rather than overwriting it // with a new worker. - await E(host).provideWorker('foo'); - await t.throwsAsync(() => E(host).evaluate('foo', '20', [], [], 'bar'), { + await E(host).provideWorker(['foo']); + await t.throwsAsync(() => E(host).evaluate('foo', '20', [], [], ['bar']), { message: 'Cannot evaluate using non-worker', }); }); @@ -380,16 +375,16 @@ test('persist spawn and evaluation', async t => { { const { host } = await makeHost(config, cancelled); - await E(host).provideWorker('w1'); + await E(host).provideWorker(['w1']); - const ten = await E(host).evaluate('w1', '10', [], [], 'ten'); + const ten = await E(host).evaluate('w1', '10', [], [], ['ten']); t.is(ten, 10); const twenty = await E(host).evaluate( 'w1', 'number * 2', ['number'], ['ten'], - 'twenty', + ['twenty'], ); // Forget the pet name of the intermediate formula, demonstrating that pet @@ -405,7 +400,7 @@ test('persist spawn and evaluation', async t => { { const { host } = await makeHost(config, cancelled); - const retwenty = await E(host).lookup('twenty'); + const retwenty = await E(host).lookup(['twenty']); t.is(20, retwenty); } }); @@ -432,7 +427,7 @@ test('store with name', async t => { { const { host } = await makeHost(config, cancelled); - const readable = await E(host).lookup('hello-text'); + const readable = await E(host).lookup(['hello-text']); const actualText = await E(readable).text(); t.is(actualText, 'hello\n'); } @@ -466,13 +461,13 @@ test('move renames value, overwriting the "to" name', async t => { t.false(await E(host).has('ten')); t.true(await E(host).has('decimus')); - const decimusValue = await E(host).lookup('decimus'); + const decimusValue = await E(host).lookup(['decimus']); t.is(decimusValue, 10); }); test('move moves value, from the host to a different name hub', async t => { const { host } = await prepareHost(t); - const directory = await E(host).makeDirectory('directory'); + const directory = await E(host).makeDirectory(['directory']); await E(host).storeValue(10, 'ten'); @@ -590,7 +585,7 @@ test('move preserves original name if writing to new name hub fails', async t => message: 'I had one job.', }); - const tenValue = await E(host).lookup('ten'); + const tenValue = await E(host).lookup(['ten']); t.is(tenValue, 10); }); @@ -599,7 +594,7 @@ test('closure state lost by restart', async t => { { const { host } = await makeHost(config, cancelled); - await E(host).provideWorker('w1'); + await E(host).provideWorker(['w1']); await E(host).evaluate( 'w1', @@ -621,14 +616,14 @@ test('closure state lost by restart', async t => { `, [], [], - 'counter-maker', + ['counter-maker'], ); await E(host).evaluate( 'w1', `E(cm).makeCounter() `, ['cm'], ['counter-maker'], - 'counter', + ['counter'], ); const one = await E(host).evaluate( 'w1', @@ -657,7 +652,7 @@ test('closure state lost by restart', async t => { { const { host } = await makeHost(config, cancelled); - await E(host).lookup('w1'); + await E(host).lookup(['w1']); const one = await E(host).evaluate( 'w1', `E(counter).incr()`, @@ -690,7 +685,7 @@ test('persist unconfined services and their requests', async t => { makePromiseKit(); cancelled.catch(cancelFollower); const { host } = await makeHost(config, followerCancelled); - await E(host).provideWorker('user-worker'); + await E(host).provideWorker(['user-worker']); await E(host).evaluate( 'user-worker', @@ -701,7 +696,7 @@ test('persist unconfined services and their requests', async t => { `, [], [], - 'grant', + ['grant'], ); const iteratorRef = E(host).followMessages(); const { value: message } = await E(iteratorRef).next(); @@ -713,7 +708,7 @@ test('persist unconfined services and their requests', async t => { const requesterFinished = (async () => { const { host } = await makeHost(config, cancelled); - await E(host).provideWorker('w1'); + await E(host).provideWorker(['w1']); await E(host).provideGuest('h1', { agentName: 'a1', }); @@ -722,13 +717,13 @@ test('persist unconfined services and their requests', async t => { const serviceLocation = url.pathToFileURL(servicePath).href; await E(host).makeUnconfined('w1', serviceLocation, 'a1', 's1'); - await E(host).provideWorker('w2'); + await E(host).provideWorker(['w2']); const answer = await E(host).evaluate( 'w2', 'E(service).ask()', ['service'], ['s1'], - 'answer', + ['answer'], ); const number = await E(answer).value(); t.is(number, 42); @@ -740,7 +735,7 @@ test('persist unconfined services and their requests', async t => { { const { host } = await makeHost(config, cancelled); - const answer = await E(host).lookup('answer'); + const answer = await E(host).lookup(['answer']); const number = await E(answer).value(); t.is(number, 42); } @@ -754,7 +749,7 @@ test('persist confined services and their requests', async t => { makePromiseKit(); cancelled.catch(cancelFollower); const { host } = await makeHost(config, followerCancelled); - await E(host).provideWorker('user-worker'); + await E(host).provideWorker(['user-worker']); await E(host).evaluate( 'user-worker', @@ -765,7 +760,7 @@ test('persist confined services and their requests', async t => { `, [], [], - 'grant', + ['grant'], ); const iteratorRef = E(host).followMessages(); const { value: message } = await E(iteratorRef).next(); @@ -777,7 +772,7 @@ test('persist confined services and their requests', async t => { const requesterFinished = (async () => { const { host } = await makeHost(config, cancelled); - await E(host).provideWorker('w1'); + await E(host).provideWorker(['w1']); await E(host).provideGuest('h1', { agentName: 'a1' }); const servicePath = path.join(dirname, 'test', 'service.js'); @@ -785,13 +780,13 @@ test('persist confined services and their requests', async t => { E(host).makeBundle('w1', bundleName, 'a1', 's1'), ); - await E(host).provideWorker('w2'); + await E(host).provideWorker(['w2']); const answer = await E(host).evaluate( 'w2', 'E(service).ask()', ['service'], ['s1'], - 'answer', + ['answer'], ); const number = await E(answer).value(); t.is(number, 42); @@ -803,7 +798,7 @@ test('persist confined services and their requests', async t => { { const { host } = await makeHost(config, cancelled); - const answer = await E(host).lookup('answer'); + const answer = await E(host).lookup(['answer']); const number = await E(answer).value(); t.is(number, 42); } @@ -813,8 +808,8 @@ test('guest facet receives a message for host', async t => { const { host } = await prepareHost(t); const guest = E(host).provideGuest('guest'); - await E(host).provideWorker('worker'); - await E(host).evaluate('worker', '10', [], [], 'ten1'); + await E(host).provideWorker(['worker']); + await E(host).evaluate('worker', '10', [], [], ['ten1']); const iteratorRef = E(host).followMessages(); E.sendOnly(guest).request('HOST', 'a number', 'number'); @@ -826,8 +821,8 @@ test('guest facet receives a message for host', async t => { const { value: message1 } = await E(iteratorRef).next(); t.is(message1.number, 1); - await E(host).adopt(message1.number, 'gift', 'ten2'); - const ten = await E(host).lookup('ten2'); + await E(host).adopt(message1.number, 'gift', ['ten2']); + const ten = await E(host).lookup(['ten2']); t.is(ten, 10); const guestId = await E(host).identify('guest'); @@ -1093,7 +1088,7 @@ test('followLocatorNameChanges does not notify of redundant pet store writes', a test('direct cancellation', async t => { const { host } = await prepareHost(t); - await E(host).provideWorker('worker'); + await E(host).provideWorker(['worker']); const counterPath = path.join(dirname, 'test', 'counter.js'); const counterLocation = url.pathToFileURL(counterPath).href; @@ -1160,7 +1155,7 @@ test('direct cancellation', async t => { test('indirect cancellation via worker', async t => { const { host } = await prepareHost(t); - await E(host).provideWorker('worker'); + await E(host).provideWorker(['worker']); const counterPath = path.join(dirname, 'test', 'counter.js'); const counterLocation = url.pathToFileURL(counterPath).href; @@ -1228,12 +1223,12 @@ test('indirect cancellation via worker', async t => { test.failing('indirect cancellation via caplet', async t => { const { host } = await prepareHost(t); - await E(host).provideWorker('w1'); + await E(host).provideWorker(['w1']); const counterPath = path.join(dirname, 'test', 'counter.js'); const counterLocation = url.pathToFileURL(counterPath).href; await E(host).makeUnconfined('w1', counterLocation, 'AGENT', 'counter'); - await E(host).provideWorker('w2'); + await E(host).provideWorker(['w2']); await E(host).provideGuest('guest', { agentName: 'guest-agent' }); const doublerPath = path.join(dirname, 'test', 'doubler.js'); const doublerLocation = url.pathToFileURL(doublerPath).href; @@ -1268,7 +1263,7 @@ test.failing('indirect cancellation via caplet', async t => { test('cancel because of requested capability', async t => { const { host } = await prepareHost(t); - await E(host).provideWorker('worker'); + await E(host).provideWorker(['worker']); await E(host).provideGuest('guest', { agentName: 'guest-agent' }); const messages = E(host).followMessages(); @@ -1277,7 +1272,7 @@ test('cancel because of requested capability', async t => { const counterLocation = url.pathToFileURL(counterPath).href; E(host).makeUnconfined('worker', counterLocation, 'guest-agent', 'counter'); - await E(host).evaluate('worker', '0', [], [], 'zero'); + await E(host).evaluate('worker', '0', [], [], ['zero']); await E(messages).next(); E(host).resolve(0, 'zero'); @@ -1343,7 +1338,7 @@ test('cancel because of requested capability', async t => { test('unconfined service can respond to cancellation', async t => { const { host } = await prepareHost(t); - await E(host).provideWorker('worker'); + await E(host).provideWorker(['worker']); const capletPath = path.join(dirname, 'test', 'context-consumer.js'); const capletLocation = url.pathToFileURL(capletPath).href; @@ -1367,7 +1362,7 @@ test('unconfined service can respond to cancellation', async t => { test('confined service can respond to cancellation', async t => { const { host } = await prepareHost(t); - await E(host).provideWorker('worker'); + await E(host).provideWorker(['worker']); const capletPath = path.join(dirname, 'test', 'context-consumer.js'); await doMakeBundle(host, capletPath, bundleName => @@ -1388,7 +1383,7 @@ test('make a host', async t => { const { host } = await prepareHost(t); const host2 = E(host).provideHost('fellow-host'); - await E(host2).provideWorker('w1'); + await E(host2).provideWorker(['w1']); const ten = await E(host2).evaluate('w1', '10', [], []); t.is(ten, 10); }); @@ -1396,23 +1391,23 @@ test('make a host', async t => { test('name and reuse inspector', async t => { const { host } = await prepareHost(t); - await E(host).provideWorker('worker'); + await E(host).provideWorker(['worker']); const counterPath = path.join(dirname, 'test', 'counter.js'); await E(host).makeUnconfined('worker', counterPath, 'NONE', 'counter'); const inspector = await E(host).evaluate( 'worker', - 'E(INFO).lookup("counter")', + 'E(INFO).lookup(["counter"])', ['INFO'], ['INFO'], - 'inspector', + ['inspector'], ); t.regex(String(inspector), /Alleged: Inspector.+make-unconfined/u); const worker = await E(host).evaluate( 'worker', - 'E(inspector).lookup("worker")', + 'E(inspector).lookup(["worker"])', ['inspector'], ['inspector'], ); @@ -1423,7 +1418,7 @@ test('name and reuse inspector', async t => { test('eval-mediated worker name', async t => { const { host } = await prepareHost(t); - await E(host).provideWorker('worker'); + await E(host).provideWorker(['worker']); const counterPath = path.join(dirname, 'test', 'counter.js'); await E(host).makeUnconfined('worker', counterPath, 'NONE', 'counter'); @@ -1442,10 +1437,10 @@ test('eval-mediated worker name', async t => { // Note that while `worker === counter-worker`, it doesn't matter here. const counterWorker = await E(host).evaluate( 'worker', - 'E(E(INFO).lookup("counter")).lookup("worker")', + 'E(E(INFO).lookup(["counter"])).lookup(["worker"])', ['INFO'], ['INFO'], - 'counter-worker', + ['counter-worker'], ); t.regex(String(counterWorker), /Alleged: EndoWorker/u); @@ -1469,7 +1464,7 @@ test('lookup with single petname', async t => { const resolvedValue = await E(host).evaluate( 'MAIN', - 'E(AGENT).lookup("ten")', + 'E(AGENT).lookup(["ten"])', ['AGENT'], ['AGENT'], ); @@ -1479,11 +1474,11 @@ test('lookup with single petname', async t => { test('lookup with petname path (inspector)', async t => { const { host } = await prepareHost(t); - await E(host).evaluate('MAIN', '10', [], [], 'ten'); + await E(host).evaluate('MAIN', '10', [], [], ['ten']); const resolvedValue = await E(host).evaluate( 'MAIN', - 'E(AGENT).lookup("INFO", "ten", "source")', + 'E(AGENT).lookup(["INFO", "ten", "source"])', ['AGENT'], ['AGENT'], ); @@ -1498,7 +1493,7 @@ test('lookup with petname path (caplet with lookup method)', async t => { const resolvedValue = await E(host).evaluate( 'MAIN', - 'E(AGENT).lookup("lookup", "name")', + 'E(AGENT).lookup(["lookup", "name"])', ['AGENT'], ['AGENT'], ); @@ -1512,7 +1507,7 @@ test('lookup with petname path (value has no lookup method)', async t => { await t.throwsAsync( E(host).evaluate( 'MAIN', - 'E(AGENT).lookup("ten", "someName")', + 'E(AGENT).lookup(["ten", "someName"])', ['AGENT'], ['AGENT'], ), @@ -1523,7 +1518,7 @@ test('lookup with petname path (value has no lookup method)', async t => { test('evaluate name resolved by lookup path', async t => { const { host } = await prepareHost(t); - await E(host).evaluate('MAIN', '10', [], [], 'ten'); + await E(host).evaluate('MAIN', '10', [], [], ['ten']); const resolvedValue = await E(host).evaluate( 'MAIN', @@ -1557,8 +1552,8 @@ test('guest cannot access host methods', async t => { const { host } = await prepareHost(t); const guest = E(host).provideGuest('guest'); - const guestsHost = E(guest).lookup('HOST'); - await t.throwsAsync(() => E(guestsHost).lookup(), { + const guestsHost = E(guest).lookup(['HOST']); + await t.throwsAsync(() => E(guestsHost).lookup([]), { message: /target has no method "lookup"/u, }); const revealedTarget = await E.get(guestsHost).targetId; @@ -1578,7 +1573,7 @@ test('read unknown node id', async t => { await E(host).write(['abc'], id); // observe reification failure - await t.throwsAsync(() => E(host).lookup('abc'), { + await t.throwsAsync(() => E(host).lookup(['abc']), { message: /No peer found for node identifier /u, }); }); @@ -1591,13 +1586,13 @@ test('read remote value', async t => { await E(hostA).addPeerInfo(await E(hostB).getPeerInfo()); // create value to share - await E(hostB).evaluate('MAIN', '"hello, world!"', [], [], 'salutations'); + await E(hostB).evaluate('MAIN', '"hello, world!"', [], [], ['salutations']); const hostBValueIdentifier = await E(hostB).identify('salutations'); // insert in hostA out of band await E(hostA).write(['greetings'], hostBValueIdentifier); - const hostAValue = await E(hostA).lookup('greetings'); + const hostAValue = await E(hostA).lookup(['greetings']); t.is(hostAValue, 'hello, world!'); }); @@ -1614,7 +1609,7 @@ test('round-trip remotable identity', async t => { 'Far("Echoer", { echo: value => value })', [], [], - 'echoer', + ['echoer'], ); const echoerId = await E(hostB).identify('echoer'); await E(hostA).write(['echoer'], echoerId); @@ -1641,10 +1636,10 @@ test('hello from afar', async t => { await E(hostB).addPeerInfo(await E(hostA).getPeerInfo()); // Induce B to connect to A - await E(hostA).evaluate('MAIN', '42', [], [], 'ft'); + await E(hostA).evaluate('MAIN', '42', [], [], ['ft']); const ftId = await E(hostA).identify('ft'); await E(hostB).write(['ft'], ftId); - const ft = await E(hostB).lookup('ft'); + const ft = await E(hostB).lookup(['ft']); t.is(ft, 42); await E(hostB).evaluate( @@ -1652,7 +1647,7 @@ test('hello from afar', async t => { 'Far("Echoer", { echo: value => value })', [], [], - 'echoer', + ['echoer'], ); const echoerId = await E(hostB).identify('echoer'); await E(hostA).write(['echoer'], echoerId); @@ -1707,7 +1702,7 @@ test('locate remote value', async t => { await E(hostB).addPeerInfo(await E(hostA).getPeerInfo()); // create value to share - await E(hostB).evaluate('MAIN', '"hello, world!"', [], [], 'salutations'); + await E(hostB).evaluate('MAIN', '"hello, world!"', [], [], ['salutations']); const hostBValueIdentifier = await E(hostB).identify('salutations'); // insert in hostA out of band @@ -1727,7 +1722,7 @@ test('invite, accept, and send mail', async t => { await E(hostB).accept(invitationLocator, 'alice'); // create value to share - await E(hostA).evaluate('MAIN', '"hello, world!"', [], [], 'salutations'); + await E(hostA).evaluate('MAIN', '"hello, world!"', [], [], ['salutations']); const expectedSalutationsId = await E(hostA).identify('salutations'); await E(hostA).send('bob', ['Hello'], ['salutations'], ['salutations']); @@ -1779,7 +1774,7 @@ test('reverse locate remote value', async t => { await E(hostB).addPeerInfo(await E(hostA).getPeerInfo()); // create value to share - await E(hostB).evaluate('MAIN', '"hello, world!"', [], [], 'salutations'); + await E(hostB).evaluate('MAIN', '"hello, world!"', [], [], ['salutations']); const hostBValueIdentifier = await E(hostB).identify('salutations'); // insert in hostA out of band